diff options
Diffstat (limited to 'app')
544 files changed, 15136 insertions, 10446 deletions
diff --git a/app/controllers/about_controller.rb b/app/controllers/about_controller.rb index d3f03374f..104348614 100644 --- a/app/controllers/about_controller.rb +++ b/app/controllers/about_controller.rb @@ -1,72 +1,19 @@ # frozen_string_literal: true class AboutController < ApplicationController - include RegistrationSpamConcern + include WebAppControllerConcern - before_action :set_pack + skip_before_action :require_functional! - layout 'public' - - before_action :require_open_federation!, only: [:show, :more] - before_action :set_body_classes, only: :show before_action :set_instance_presenter - before_action :set_expires_in, only: [:more] - before_action :set_registration_form_time, only: :show - - skip_before_action :require_functional!, only: [:more] - - def show; end - - def more - flash.now[:notice] = I18n.t('about.instance_actor_flash') if params[:instance_actor] - - toc_generator = TOCGenerator.new(@instance_presenter.extended_description) - @rules = Rule.ordered - @contents = toc_generator.html - @table_of_contents = toc_generator.toc - @blocks = DomainBlock.with_user_facing_limitations.by_severity if display_blocks? + def show + expires_in 0, public: true unless user_signed_in? end - helper_method :display_blocks? - helper_method :display_blocks_rationale? - helper_method :public_fetch_mode? - helper_method :new_user - private - def require_open_federation! - not_found if whitelist_mode? - end - - def display_blocks? - Setting.show_domain_blocks == 'all' || (Setting.show_domain_blocks == 'users' && user_signed_in?) - end - - def display_blocks_rationale? - Setting.show_domain_blocks_rationale == 'all' || (Setting.show_domain_blocks_rationale == 'users' && user_signed_in?) - end - - def new_user - User.new.tap do |user| - user.build_account - user.build_invite_request - end - end - - def set_pack - use_pack 'public' - end - 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/account_follow_controller.rb b/app/controllers/account_follow_controller.rb deleted file mode 100644 index 33394074d..000000000 --- a/app/controllers/account_follow_controller.rb +++ /dev/null @@ -1,12 +0,0 @@ -# frozen_string_literal: true - -class AccountFollowController < ApplicationController - include AccountControllerConcern - - before_action :authenticate_user! - - def create - FollowService.new.call(current_user.account, @account, with_rate_limit: true) - redirect_to account_path(@account) - end -end diff --git a/app/controllers/account_unfollow_controller.rb b/app/controllers/account_unfollow_controller.rb deleted file mode 100644 index 378ec86dc..000000000 --- a/app/controllers/account_unfollow_controller.rb +++ /dev/null @@ -1,12 +0,0 @@ -# frozen_string_literal: true - -class AccountUnfollowController < ApplicationController - include AccountControllerConcern - - before_action :authenticate_user! - - def create - UnfollowService.new.call(current_user.account, @account) - redirect_to account_path(@account) - end -end diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb index 02f3c3dd7..f36a0c859 100644 --- a/app/controllers/accounts_controller.rb +++ b/app/controllers/accounts_controller.rb @@ -9,7 +9,6 @@ class AccountsController < ApplicationController before_action :require_account_signature!, if: -> { request.format == :json && authorized_fetch_mode? } before_action :set_cache_headers - before_action :set_body_classes skip_around_action :set_locale, if: -> { [:json, :rss].include?(request.format&.to_sym) } skip_before_action :require_functional!, unless: :whitelist_mode? @@ -17,26 +16,7 @@ class AccountsController < ApplicationController def show respond_to do |format| format.html do - use_pack 'public' expires_in 0, public: true unless user_signed_in? - - @pinned_statuses = [] - @endorsed_accounts = @account.endorsed_accounts.to_a.sample(4) - @featured_hashtags = @account.featured_tags.order(statuses_count: :desc) - - if current_account && @account.blocking?(current_account) - @statuses = [] - return - end - - @pinned_statuses = cached_filtered_status_pins if show_pinned_statuses? - @statuses = cached_filtered_status_page - @rss_url = rss_url - - unless @statuses.empty? - @older_url = older_url if @statuses.last.id > filtered_statuses.last.id - @newer_url = newer_url if @statuses.first.id < filtered_statuses.first.id - end end format.rss do @@ -56,18 +36,6 @@ class AccountsController < ApplicationController private - def set_body_classes - @body_classes = 'with-modals' - end - - def show_pinned_statuses? - [replies_requested?, media_requested?, tag_requested?, params[:max_id].present?, params[:min_id].present?].none? - end - - def filtered_pinned_statuses - @account.pinned_statuses.not_local_only.where(visibility: [:public, :unlisted]) - end - def filtered_statuses default_statuses.tap do |statuses| statuses.merge!(hashtag_scope) if tag_requested? @@ -114,26 +82,6 @@ class AccountsController < ApplicationController end end - def older_url - pagination_url(max_id: @statuses.last.id) - end - - def newer_url - pagination_url(min_id: @statuses.first.id) - end - - def pagination_url(max_id: nil, min_id: nil) - if tag_requested? - short_account_tag_url(@account, params[:tag], max_id: max_id, min_id: min_id) - elsif media_requested? - short_account_media_url(@account, max_id: max_id, min_id: min_id) - elsif replies_requested? - short_account_with_replies_url(@account, max_id: max_id, min_id: min_id) - else - short_account_url(@account, max_id: max_id, min_id: min_id) - end - end - def media_requested? request.path.split('.').first.end_with?('/media') && !tag_requested? end @@ -146,13 +94,6 @@ class AccountsController < ApplicationController request.path.split('.').first.end_with?(Addressable::URI.parse("/tagged/#{params[:tag]}").normalize) end - def cached_filtered_status_pins - cache_collection( - filtered_pinned_statuses, - Status - ) - end - def cached_filtered_status_page cache_collection_paginated_by_id( filtered_statuses, diff --git a/app/controllers/admin/custom_emojis_controller.rb b/app/controllers/admin/custom_emojis_controller.rb index 1fae60f5b..431dc1524 100644 --- a/app/controllers/admin/custom_emojis_controller.rb +++ b/app/controllers/admin/custom_emojis_controller.rb @@ -34,7 +34,7 @@ module Admin @form = Form::CustomEmojiBatch.new(form_custom_emoji_batch_params.merge(current_account: current_account, action: action_from_button)) @form.save rescue ActionController::ParameterMissing - flash[:alert] = I18n.t('admin.accounts.no_account_selected') + flash[:alert] = I18n.t('admin.custom_emojis.no_emoji_selected') rescue Mastodon::NotPermittedError flash[:alert] = I18n.t('admin.custom_emojis.not_permitted') rescue ActiveRecord::RecordInvalid => e diff --git a/app/controllers/admin/export_domain_blocks_controller.rb b/app/controllers/admin/export_domain_blocks_controller.rb index db8863551..545bd94ed 100644 --- a/app/controllers/admin/export_domain_blocks_controller.rb +++ b/app/controllers/admin/export_domain_blocks_controller.rb @@ -62,7 +62,7 @@ module Admin def export_data CSV.generate(headers: export_headers, write_headers: true) do |content| - DomainBlock.with_user_facing_limitations.each do |instance| + DomainBlock.with_limitations.each do |instance| content << [instance.domain, instance.severity, instance.reject_media, instance.reject_reports, instance.public_comment, instance.obfuscate] end end diff --git a/app/controllers/admin/ip_blocks_controller.rb b/app/controllers/admin/ip_blocks_controller.rb index a87520f4e..1bd7ec805 100644 --- a/app/controllers/admin/ip_blocks_controller.rb +++ b/app/controllers/admin/ip_blocks_controller.rb @@ -5,7 +5,7 @@ module Admin def index authorize :ip_block, :index? - @ip_blocks = IpBlock.page(params[:page]) + @ip_blocks = IpBlock.order(ip: :asc).page(params[:page]) @form = Form::IpBlockBatch.new end diff --git a/app/controllers/admin/settings/about_controller.rb b/app/controllers/admin/settings/about_controller.rb new file mode 100644 index 000000000..86327fe39 --- /dev/null +++ b/app/controllers/admin/settings/about_controller.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +class Admin::Settings::AboutController < Admin::SettingsController + private + + def after_update_redirect_path + admin_settings_about_path + end +end diff --git a/app/controllers/admin/settings/appearance_controller.rb b/app/controllers/admin/settings/appearance_controller.rb new file mode 100644 index 000000000..39b2448d8 --- /dev/null +++ b/app/controllers/admin/settings/appearance_controller.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +class Admin::Settings::AppearanceController < Admin::SettingsController + private + + def after_update_redirect_path + admin_settings_appearance_path + end +end diff --git a/app/controllers/admin/settings/branding_controller.rb b/app/controllers/admin/settings/branding_controller.rb new file mode 100644 index 000000000..4a4d76f49 --- /dev/null +++ b/app/controllers/admin/settings/branding_controller.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +class Admin::Settings::BrandingController < Admin::SettingsController + private + + def after_update_redirect_path + admin_settings_branding_path + end +end diff --git a/app/controllers/admin/settings/content_retention_controller.rb b/app/controllers/admin/settings/content_retention_controller.rb new file mode 100644 index 000000000..b88336a2c --- /dev/null +++ b/app/controllers/admin/settings/content_retention_controller.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +class Admin::Settings::ContentRetentionController < Admin::SettingsController + private + + def after_update_redirect_path + admin_settings_content_retention_path + end +end diff --git a/app/controllers/admin/settings/discovery_controller.rb b/app/controllers/admin/settings/discovery_controller.rb new file mode 100644 index 000000000..be4b57f79 --- /dev/null +++ b/app/controllers/admin/settings/discovery_controller.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +class Admin::Settings::DiscoveryController < Admin::SettingsController + private + + def after_update_redirect_path + admin_settings_discovery_path + end +end diff --git a/app/controllers/admin/settings/registrations_controller.rb b/app/controllers/admin/settings/registrations_controller.rb new file mode 100644 index 000000000..b4a74349c --- /dev/null +++ b/app/controllers/admin/settings/registrations_controller.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +class Admin::Settings::RegistrationsController < Admin::SettingsController + private + + def after_update_redirect_path + admin_settings_registrations_path + end +end diff --git a/app/controllers/admin/settings_controller.rb b/app/controllers/admin/settings_controller.rb index dc1c79b7f..338a3638c 100644 --- a/app/controllers/admin/settings_controller.rb +++ b/app/controllers/admin/settings_controller.rb @@ -2,7 +2,7 @@ module Admin class SettingsController < BaseController - def edit + def show authorize :settings, :show? @admin_settings = Form::AdminSettings.new @@ -15,14 +15,18 @@ module Admin if @admin_settings.save flash[:notice] = I18n.t('generic.changes_saved_msg') - redirect_to edit_admin_settings_path + redirect_to after_update_redirect_path else - render :edit + render :show end end private + def after_update_redirect_path + raise NotImplementedError + end + def settings_params params.require(:form_admin_settings).permit(*Form::AdminSettings::KEYS) end diff --git a/app/controllers/admin/site_uploads_controller.rb b/app/controllers/admin/site_uploads_controller.rb index cacecedb0..a5d2cf41c 100644 --- a/app/controllers/admin/site_uploads_controller.rb +++ b/app/controllers/admin/site_uploads_controller.rb @@ -9,7 +9,7 @@ module Admin @site_upload.destroy! - redirect_to edit_admin_settings_path, notice: I18n.t('admin.site_uploads.destroyed_msg') + redirect_to admin_settings_path, notice: I18n.t('admin.site_uploads.destroyed_msg') end private diff --git a/app/controllers/admin/statuses_controller.rb b/app/controllers/admin/statuses_controller.rb index 084921ceb..b80cd20f5 100644 --- a/app/controllers/admin/statuses_controller.rb +++ b/app/controllers/admin/statuses_controller.rb @@ -3,18 +3,23 @@ module Admin class StatusesController < BaseController before_action :set_account - before_action :set_statuses + before_action :set_statuses, except: :show + before_action :set_status, only: :show PER_PAGE = 20 def index - authorize :status, :index? + authorize [:admin, :status], :index? @status_batch_action = Admin::StatusBatchAction.new end + def show + authorize [:admin, @status], :show? + end + def batch - authorize :status, :index? + authorize [:admin, :status], :index? @status_batch_action = Admin::StatusBatchAction.new(admin_status_batch_action_params.merge(current_account: current_account, report_id: params[:report_id], type: action_from_button)) @status_batch_action.save! @@ -32,6 +37,7 @@ module Admin def after_create_redirect_path report_id = @status_batch_action&.report_id || params[:report_id] + if report_id.present? admin_report_path(report_id) else @@ -43,6 +49,10 @@ module Admin @account = Account.find(params[:account_id]) end + def set_status + @status = @account.statuses.find(params[:id]) + end + def set_statuses @statuses = Admin::StatusFilter.new(@account, filter_params).results.preload(:application, :preloadable_poll, :media_attachments, active_mentions: :account, reblog: [:account, :application, :preloadable_poll, :media_attachments, active_mentions: :account]).page(params[:page]).per(PER_PAGE) end diff --git a/app/controllers/admin/trends/links/preview_card_providers_controller.rb b/app/controllers/admin/trends/links/preview_card_providers_controller.rb index 97dee8eca..768b79f8d 100644 --- a/app/controllers/admin/trends/links/preview_card_providers_controller.rb +++ b/app/controllers/admin/trends/links/preview_card_providers_controller.rb @@ -14,7 +14,7 @@ class Admin::Trends::Links::PreviewCardProvidersController < Admin::BaseControll @form = Trends::PreviewCardProviderBatch.new(trends_preview_card_provider_batch_params.merge(current_account: current_account, action: action_from_button)) @form.save rescue ActionController::ParameterMissing - flash[:alert] = I18n.t('admin.accounts.no_account_selected') + flash[:alert] = I18n.t('admin.trends.links.publishers.no_publisher_selected') ensure redirect_to admin_trends_links_preview_card_providers_path(filter_params) end diff --git a/app/controllers/admin/trends/links_controller.rb b/app/controllers/admin/trends/links_controller.rb index a497eae41..83d68eba6 100644 --- a/app/controllers/admin/trends/links_controller.rb +++ b/app/controllers/admin/trends/links_controller.rb @@ -4,6 +4,7 @@ class Admin::Trends::LinksController < Admin::BaseController def index authorize :preview_card, :review? + @locales = PreviewCardTrend.pluck('distinct language') @preview_cards = filtered_preview_cards.page(params[:page]) @form = Trends::PreviewCardBatch.new end @@ -14,7 +15,7 @@ class Admin::Trends::LinksController < Admin::BaseController @form = Trends::PreviewCardBatch.new(trends_preview_card_batch_params.merge(current_account: current_account, action: action_from_button)) @form.save rescue ActionController::ParameterMissing - flash[:alert] = I18n.t('admin.accounts.no_account_selected') + flash[:alert] = I18n.t('admin.trends.links.no_link_selected') ensure redirect_to admin_trends_links_path(filter_params) end diff --git a/app/controllers/admin/trends/statuses_controller.rb b/app/controllers/admin/trends/statuses_controller.rb index c538962f9..3d8b53ea8 100644 --- a/app/controllers/admin/trends/statuses_controller.rb +++ b/app/controllers/admin/trends/statuses_controller.rb @@ -2,19 +2,20 @@ class Admin::Trends::StatusesController < Admin::BaseController def index - authorize :status, :review? + authorize [:admin, :status], :review? + @locales = StatusTrend.pluck('distinct language') @statuses = filtered_statuses.page(params[:page]) @form = Trends::StatusBatch.new end def batch - authorize :status, :review? + authorize [:admin, :status], :review? @form = Trends::StatusBatch.new(trends_status_batch_params.merge(current_account: current_account, action: action_from_button)) @form.save rescue ActionController::ParameterMissing - flash[:alert] = I18n.t('admin.accounts.no_account_selected') + flash[:alert] = I18n.t('admin.trends.statuses.no_status_selected') ensure redirect_to admin_trends_statuses_path(filter_params) end diff --git a/app/controllers/admin/trends/tags_controller.rb b/app/controllers/admin/trends/tags_controller.rb index 98dd6c8ec..f5946448a 100644 --- a/app/controllers/admin/trends/tags_controller.rb +++ b/app/controllers/admin/trends/tags_controller.rb @@ -14,7 +14,7 @@ class Admin::Trends::TagsController < Admin::BaseController @form = Trends::TagBatch.new(trends_tag_batch_params.merge(current_account: current_account, action: action_from_button)) @form.save rescue ActionController::ParameterMissing - flash[:alert] = I18n.t('admin.accounts.no_account_selected') + flash[:alert] = I18n.t('admin.trends.tags.no_tag_selected') ensure redirect_to admin_trends_tags_path(filter_params) end diff --git a/app/controllers/api/base_controller.rb b/app/controllers/api/base_controller.rb index 7ce6599c5..c46fde65b 100644 --- a/app/controllers/api/base_controller.rb +++ b/app/controllers/api/base_controller.rb @@ -24,6 +24,10 @@ class Api::BaseController < ApplicationController render json: { error: 'Duplicate record' }, status: 422 end + rescue_from Date::Error do + render json: { error: 'Invalid date supplied' }, status: 422 + end + rescue_from ActiveRecord::RecordNotFound do render json: { error: 'Record not found' }, status: 404 end diff --git a/app/controllers/api/v1/admin/accounts_controller.rb b/app/controllers/api/v1/admin/accounts_controller.rb index 0dee02e94..ae7f7d076 100644 --- a/app/controllers/api/v1/admin/accounts_controller.rb +++ b/app/controllers/api/v1/admin/accounts_controller.rb @@ -60,14 +60,13 @@ class Api::V1::Admin::AccountsController < Api::BaseController def reject authorize @account.user, :reject? DeleteAccountService.new.call(@account, reserve_email: false, reserve_username: false) - render json: @account, serializer: REST::Admin::AccountSerializer + render_empty end def destroy authorize @account, :destroy? - json = render_to_body json: @account, serializer: REST::Admin::AccountSerializer Admin::AccountDeletionWorker.perform_async(@account.id) - render json: json + render_empty end def unsensitive diff --git a/app/controllers/api/v1/admin/canonical_email_blocks_controller.rb b/app/controllers/api/v1/admin/canonical_email_blocks_controller.rb index bf8a6a131..9ef1b3be7 100644 --- a/app/controllers/api/v1/admin/canonical_email_blocks_controller.rb +++ b/app/controllers/api/v1/admin/canonical_email_blocks_controller.rb @@ -35,20 +35,16 @@ class Api::V1::Admin::CanonicalEmailBlocksController < Api::BaseController def create authorize :canonical_email_block, :create? - @canonical_email_block = CanonicalEmailBlock.create!(resource_params) log_action :create, @canonical_email_block - render json: @canonical_email_block, serializer: REST::Admin::CanonicalEmailBlockSerializer end def destroy authorize @canonical_email_block, :destroy? - @canonical_email_block.destroy! log_action :destroy, @canonical_email_block - - render json: @canonical_email_block, serializer: REST::Admin::CanonicalEmailBlockSerializer + render_empty end private diff --git a/app/controllers/api/v1/admin/domain_allows_controller.rb b/app/controllers/api/v1/admin/domain_allows_controller.rb index 59aa807d6..0658199f0 100644 --- a/app/controllers/api/v1/admin/domain_allows_controller.rb +++ b/app/controllers/api/v1/admin/domain_allows_controller.rb @@ -43,7 +43,7 @@ class Api::V1::Admin::DomainAllowsController < Api::BaseController authorize @domain_allow, :destroy? UnallowDomainService.new.call(@domain_allow) log_action :destroy, @domain_allow - render json: @domain_allow, serializer: REST::Admin::DomainAllowSerializer + render_empty end private diff --git a/app/controllers/api/v1/admin/domain_blocks_controller.rb b/app/controllers/api/v1/admin/domain_blocks_controller.rb index de8fd9d08..df5b1b3fc 100644 --- a/app/controllers/api/v1/admin/domain_blocks_controller.rb +++ b/app/controllers/api/v1/admin/domain_blocks_controller.rb @@ -40,7 +40,6 @@ class Api::V1::Admin::DomainBlocksController < Api::BaseController def update authorize @domain_block, :update? - @domain_block.update(domain_block_params) severity_changed = @domain_block.severity_changed? @domain_block.save! @@ -53,7 +52,7 @@ class Api::V1::Admin::DomainBlocksController < Api::BaseController authorize @domain_block, :destroy? UnblockDomainService.new.call(@domain_block) log_action :destroy, @domain_block - render json: @domain_block, serializer: REST::Admin::DomainBlockSerializer + render_empty end private diff --git a/app/controllers/api/v1/admin/email_domain_blocks_controller.rb b/app/controllers/api/v1/admin/email_domain_blocks_controller.rb index ac16f70b0..e53d0b157 100644 --- a/app/controllers/api/v1/admin/email_domain_blocks_controller.rb +++ b/app/controllers/api/v1/admin/email_domain_blocks_controller.rb @@ -39,11 +39,9 @@ class Api::V1::Admin::EmailDomainBlocksController < Api::BaseController def destroy authorize @email_domain_block, :destroy? - @email_domain_block.destroy! log_action :destroy, @email_domain_block - - render json: @email_domain_block, serializer: REST::Admin::EmailDomainBlockSerializer + render_empty end private diff --git a/app/controllers/api/v1/admin/ip_blocks_controller.rb b/app/controllers/api/v1/admin/ip_blocks_controller.rb index f13d63267..201ab6b1f 100644 --- a/app/controllers/api/v1/admin/ip_blocks_controller.rb +++ b/app/controllers/api/v1/admin/ip_blocks_controller.rb @@ -20,10 +20,8 @@ class Api::V1::Admin::IpBlocksController < Api::BaseController def create authorize :ip_block, :create? - @ip_block = IpBlock.create!(resource_params) log_action :create, @ip_block - render json: @ip_block, serializer: REST::Admin::IpBlockSerializer end @@ -39,20 +37,16 @@ class Api::V1::Admin::IpBlocksController < Api::BaseController def update authorize @ip_block, :update? - @ip_block.update(resource_params) log_action :update, @ip_block - render json: @ip_block, serializer: REST::Admin::IpBlockSerializer end def destroy authorize @ip_block, :destroy? - @ip_block.destroy! log_action :destroy, @ip_block - - render json: @ip_block, serializer: REST::Admin::IpBlockSerializer + render_empty end private diff --git a/app/controllers/api/v1/featured_tags_controller.rb b/app/controllers/api/v1/featured_tags_controller.rb index c1ead4f54..edb42a94e 100644 --- a/app/controllers/api/v1/featured_tags_controller.rb +++ b/app/controllers/api/v1/featured_tags_controller.rb @@ -13,12 +13,12 @@ class Api::V1::FeaturedTagsController < Api::BaseController end def create - @featured_tag = current_account.featured_tags.create!(featured_tag_params) - render json: @featured_tag, serializer: REST::FeaturedTagSerializer + featured_tag = CreateFeaturedTagService.new.call(current_account, featured_tag_params[:name]) + render json: featured_tag, serializer: REST::FeaturedTagSerializer end def destroy - @featured_tag.destroy! + RemoveFeaturedTagWorker.perform_async(current_account.id, @featured_tag.id) render_empty end diff --git a/app/controllers/api/v1/instances/domain_blocks_controller.rb b/app/controllers/api/v1/instances/domain_blocks_controller.rb new file mode 100644 index 000000000..37a6906fb --- /dev/null +++ b/app/controllers/api/v1/instances/domain_blocks_controller.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +class Api::V1::Instances::DomainBlocksController < Api::BaseController + skip_before_action :require_authenticated_user!, unless: :whitelist_mode? + + before_action :require_enabled_api! + before_action :set_domain_blocks + + def index + expires_in 3.minutes, public: true + render json: @domain_blocks, each_serializer: REST::DomainBlockSerializer, with_comment: (Setting.show_domain_blocks_rationale == 'all' || (Setting.show_domain_blocks_rationale == 'users' && user_signed_in?)) + end + + private + + def require_enabled_api! + head 404 unless Setting.show_domain_blocks == 'all' || (Setting.show_domain_blocks == 'users' && user_signed_in?) + end + + def set_domain_blocks + @domain_blocks = DomainBlock.with_user_facing_limitations.by_severity + end +end diff --git a/app/controllers/api/v1/instances/extended_descriptions_controller.rb b/app/controllers/api/v1/instances/extended_descriptions_controller.rb new file mode 100644 index 000000000..c72e16cff --- /dev/null +++ b/app/controllers/api/v1/instances/extended_descriptions_controller.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +class Api::V1::Instances::ExtendedDescriptionsController < Api::BaseController + skip_before_action :require_authenticated_user!, unless: :whitelist_mode? + + before_action :set_extended_description + + def show + expires_in 3.minutes, public: true + render json: @extended_description, serializer: REST::ExtendedDescriptionSerializer + end + + private + + def set_extended_description + @extended_description = ExtendedDescription.current + end +end diff --git a/app/controllers/api/v1/instances/privacy_policies_controller.rb b/app/controllers/api/v1/instances/privacy_policies_controller.rb new file mode 100644 index 000000000..dbd69f54d --- /dev/null +++ b/app/controllers/api/v1/instances/privacy_policies_controller.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +class Api::V1::Instances::PrivacyPoliciesController < Api::BaseController + skip_before_action :require_authenticated_user!, unless: :whitelist_mode? + + before_action :set_privacy_policy + + def show + expires_in 1.day, public: true + render json: @privacy_policy, serializer: REST::PrivacyPolicySerializer + end + + private + + def set_privacy_policy + @privacy_policy = PrivacyPolicy.current + end +end diff --git a/app/controllers/api/v1/statuses_controller.rb b/app/controllers/api/v1/statuses_controller.rb index b2cee3e92..f8069b720 100644 --- a/app/controllers/api/v1/statuses_controller.rb +++ b/app/controllers/api/v1/statuses_controller.rb @@ -66,6 +66,7 @@ class Api::V1::StatusesController < Api::BaseController text: status_params[:status], media_ids: status_params[:media_ids], sensitive: status_params[:sensitive], + language: status_params[:language], spoiler_text: status_params[:spoiler_text], poll: status_params[:poll], content_type: status_params[:content_type] @@ -79,6 +80,7 @@ class Api::V1::StatusesController < Api::BaseController authorize @status, :destroy? @status.discard + StatusPin.find_by(status: @status)&.destroy @status.account.statuses_count = @status.account.statuses_count - 1 json = render_to_body json: @status, serializer: REST::StatusSerializer, source_requested: true diff --git a/app/controllers/api/v1/timelines/public_controller.rb b/app/controllers/api/v1/timelines/public_controller.rb index 493fe4776..2ee5aaf18 100644 --- a/app/controllers/api/v1/timelines/public_controller.rb +++ b/app/controllers/api/v1/timelines/public_controller.rb @@ -35,6 +35,7 @@ class Api::V1::Timelines::PublicController < Api::BaseController def public_feed PublicFeed.new( current_account, + locale: content_locale, local: truthy_param?(:local), remote: truthy_param?(:remote), only_media: truthy_param?(:only_media), diff --git a/app/controllers/api/v1/trends/links_controller.rb b/app/controllers/api/v1/trends/links_controller.rb index 1a9f918f2..8ff3b364e 100644 --- a/app/controllers/api/v1/trends/links_controller.rb +++ b/app/controllers/api/v1/trends/links_controller.rb @@ -28,7 +28,9 @@ class Api::V1::Trends::LinksController < Api::BaseController end def links_from_trends - Trends.links.query.allowed.in_locale(content_locale) + scope = Trends.links.query.allowed.in_locale(content_locale) + scope = scope.filtered_for(current_account) if user_signed_in? + scope end def insert_pagination_headers diff --git a/app/controllers/api/v2/search_controller.rb b/app/controllers/api/v2/search_controller.rb index 77eeab5b0..b084eae42 100644 --- a/app/controllers/api/v2/search_controller.rb +++ b/app/controllers/api/v2/search_controller.rb @@ -5,8 +5,8 @@ class Api::V2::SearchController < Api::BaseController RESULTS_LIMIT = (ENV['MAX_SEARCH_RESULTS'] || 20).to_i - before_action -> { doorkeeper_authorize! :read, :'read:search' } - before_action :require_user! + before_action -> { authorize_if_got_token! :read, :'read:search' } + before_action :validate_search_params! def index @search = Search.new(search_results) @@ -19,6 +19,16 @@ class Api::V2::SearchController < Api::BaseController private + def validate_search_params! + params.require(:q) + + return if user_signed_in? + + return render json: { error: 'Search queries pagination is not supported without authentication' }, status: 401 if params[:offset].present? + + render json: { error: 'Search queries that resolve remote resources are not supported without authentication' }, status: 401 if truthy_param?(:resolve) + end + def search_results SearchService.new.call( params[:q], diff --git a/app/controllers/auth/registrations_controller.rb b/app/controllers/auth/registrations_controller.rb index 486edcdcb..edef0d5bb 100644 --- a/app/controllers/auth/registrations_controller.rb +++ b/app/controllers/auth/registrations_controller.rb @@ -15,6 +15,8 @@ class Auth::RegistrationsController < Devise::RegistrationsController before_action :set_body_classes, only: [:new, :create, :edit, :update] before_action :require_not_suspended!, only: [:update] before_action :set_cache_headers, only: [:edit, :update] + before_action :set_rules, only: :new + before_action :require_rules_acceptance!, only: :new before_action :set_registration_form_time, only: :new skip_before_action :require_functional!, only: [:edit, :update] @@ -56,7 +58,7 @@ class Auth::RegistrationsController < Devise::RegistrationsController def configure_sign_up_params devise_parameter_sanitizer.permit(:sign_up) do |u| - u.permit({ account_attributes: [:username], invite_request_attributes: [:text] }, :email, :password, :password_confirmation, :invite_code, :agreement, :website, :confirm_password) + u.permit({ account_attributes: [:username, :display_name], invite_request_attributes: [:text] }, :email, :password, :password_confirmation, :invite_code, :agreement, :website, :confirm_password) end end @@ -143,6 +145,19 @@ class Auth::RegistrationsController < Devise::RegistrationsController forbidden if current_account.suspended? end + def set_rules + @rules = Rule.ordered + end + + def require_rules_acceptance! + return if @rules.empty? || (session[:accept_token].present? && params[:accept] == session[:accept_token]) + + @accept_token = session[:accept_token] = SecureRandom.hex + @invite_code = invite_code + + set_locale { render :rules } + end + def set_cache_headers response.headers['Cache-Control'] = 'no-cache, no-store, max-age=0, must-revalidate' end diff --git a/app/controllers/concerns/account_controller_concern.rb b/app/controllers/concerns/account_controller_concern.rb index 11eac0eb6..2f7d84df0 100644 --- a/app/controllers/concerns/account_controller_concern.rb +++ b/app/controllers/concerns/account_controller_concern.rb @@ -3,13 +3,12 @@ module AccountControllerConcern extend ActiveSupport::Concern + include WebAppControllerConcern include AccountOwnedConcern FOLLOW_PER_PAGE = 12 included do - layout 'public' - before_action :set_instance_presenter before_action :set_link_headers, if: -> { request.format.nil? || request.format == :html } end diff --git a/app/controllers/concerns/web_app_controller_concern.rb b/app/controllers/concerns/web_app_controller_concern.rb new file mode 100644 index 000000000..b6050c913 --- /dev/null +++ b/app/controllers/concerns/web_app_controller_concern.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +module WebAppControllerConcern + extend ActiveSupport::Concern + + included do + before_action :set_pack + before_action :redirect_unauthenticated_to_permalinks! + before_action :set_app_body_class + before_action :set_referrer_policy_header + end + + def set_app_body_class + @body_classes = 'app-body' + end + + def set_referrer_policy_header + response.headers['Referrer-Policy'] = 'origin' + end + + def redirect_unauthenticated_to_permalinks! + return if user_signed_in? + + redirect_path = PermalinkRedirector.new(request.path).redirect_path + + redirect_to(redirect_path) if redirect_path.present? + end + + def set_pack + use_pack 'home' + end +end diff --git a/app/controllers/directories_controller.rb b/app/controllers/directories_controller.rb deleted file mode 100644 index 2263f286b..000000000 --- a/app/controllers/directories_controller.rb +++ /dev/null @@ -1,37 +0,0 @@ -# frozen_string_literal: true - -class DirectoriesController < ApplicationController - layout 'public' - - before_action :authenticate_user!, if: :whitelist_mode? - before_action :require_enabled! - before_action :set_instance_presenter - before_action :set_accounts - before_action :set_pack - - skip_before_action :require_functional!, unless: :whitelist_mode? - - def index - render :index - end - - private - - def set_pack - use_pack 'share' - end - - def require_enabled! - return not_found unless Setting.profile_directory - end - - def set_accounts - @accounts = Account.local.discoverable.by_recent_status.page(params[:page]).per(20).tap do |query| - query.merge!(Account.not_excluded_by_account(current_account)) if current_account - end - end - - def set_instance_presenter - @instance_presenter = InstancePresenter.new - end -end diff --git a/app/controllers/follower_accounts_controller.rb b/app/controllers/follower_accounts_controller.rb index 0d9e624ef..35ce31f80 100644 --- a/app/controllers/follower_accounts_controller.rb +++ b/app/controllers/follower_accounts_controller.rb @@ -3,6 +3,7 @@ class FollowerAccountsController < ApplicationController include AccountControllerConcern include SignatureVerification + include WebAppControllerConcern before_action :require_account_signature!, if: -> { request.format == :json && authorized_fetch_mode? } before_action :set_cache_headers @@ -13,12 +14,7 @@ class FollowerAccountsController < ApplicationController def index respond_to do |format| format.html do - use_pack 'public' expires_in 0, public: true unless user_signed_in? - - next if @account.hide_collections? - - follows end format.json do diff --git a/app/controllers/following_accounts_controller.rb b/app/controllers/following_accounts_controller.rb index 68e1a79be..f84dca1e5 100644 --- a/app/controllers/following_accounts_controller.rb +++ b/app/controllers/following_accounts_controller.rb @@ -3,6 +3,7 @@ class FollowingAccountsController < ApplicationController include AccountControllerConcern include SignatureVerification + include WebAppControllerConcern before_action :require_account_signature!, if: -> { request.format == :json && authorized_fetch_mode? } before_action :set_cache_headers @@ -13,12 +14,7 @@ class FollowingAccountsController < ApplicationController def index respond_to do |format| format.html do - use_pack 'public' expires_in 0, public: true unless user_signed_in? - - next if @account.hide_collections? - - follows end format.json do diff --git a/app/controllers/home_controller.rb b/app/controllers/home_controller.rb index 61b1690fa..d8ee82a7a 100644 --- a/app/controllers/home_controller.rb +++ b/app/controllers/home_controller.rb @@ -1,47 +1,16 @@ # frozen_string_literal: true class HomeController < ApplicationController - before_action :redirect_unauthenticated_to_permalinks! + include WebAppControllerConcern - before_action :set_pack - before_action :set_referrer_policy_header before_action :set_instance_presenter def index - @body_classes = 'app-body' + expires_in 0, public: true unless user_signed_in? end private - def redirect_unauthenticated_to_permalinks! - return if user_signed_in? - - redirect_path = PermalinkRedirector.new(request.path).redirect_path - redirect_path ||= default_redirect_path - - redirect_to(redirect_path) if redirect_path.present? - end - - def set_pack - use_pack 'home' - end - - def default_redirect_path - if whitelist_mode? - new_user_session_path - elsif request.path.start_with?('/web') - nil - elsif single_user_mode? - short_account_path(Account.local.without_suspended.where('id > 0').first) - else - about_path - end - end - - def set_referrer_policy_header - response.headers['Referrer-Policy'] = 'origin' - end - def set_instance_presenter @instance_presenter = InstancePresenter.new end diff --git a/app/controllers/privacy_controller.rb b/app/controllers/privacy_controller.rb index 126bb0128..2c98bf3bf 100644 --- a/app/controllers/privacy_controller.rb +++ b/app/controllers/privacy_controller.rb @@ -1,28 +1,19 @@ # frozen_string_literal: true class PrivacyController < ApplicationController - layout 'public' + include WebAppControllerConcern - before_action :set_pack + skip_before_action :require_functional! before_action :set_instance_presenter - before_action :set_expires_in - - skip_before_action :require_functional! - def show; end + def show + expires_in 0, public: true if current_account.nil? + end private - def set_pack - use_pack 'public' - end - def set_instance_presenter @instance_presenter = InstancePresenter.new end - - def set_expires_in - expires_in 0, public: true - end end diff --git a/app/controllers/public_timelines_controller.rb b/app/controllers/public_timelines_controller.rb deleted file mode 100644 index eb5bb191b..000000000 --- a/app/controllers/public_timelines_controller.rb +++ /dev/null @@ -1,31 +0,0 @@ -# frozen_string_literal: true - -class PublicTimelinesController < ApplicationController - before_action :set_pack - layout 'public' - - before_action :authenticate_user!, if: :whitelist_mode? - before_action :require_enabled! - before_action :set_body_classes - before_action :set_instance_presenter - - def show; end - - private - - def require_enabled! - not_found unless Setting.timeline_preview - end - - def set_body_classes - @body_classes = 'with-modals' - end - - def set_instance_presenter - @instance_presenter = InstancePresenter.new - end - - def set_pack - use_pack 'about' - end -end diff --git a/app/controllers/remote_follow_controller.rb b/app/controllers/remote_follow_controller.rb deleted file mode 100644 index 93a0a7476..000000000 --- a/app/controllers/remote_follow_controller.rb +++ /dev/null @@ -1,46 +0,0 @@ -# frozen_string_literal: true - -class RemoteFollowController < ApplicationController - include AccountOwnedConcern - - layout 'modal' - - before_action :set_pack - before_action :set_body_classes - - skip_before_action :require_functional! - - def new - @remote_follow = RemoteFollow.new(session_params) - end - - def create - @remote_follow = RemoteFollow.new(resource_params) - - if @remote_follow.valid? - session[:remote_follow] = @remote_follow.acct - redirect_to @remote_follow.subscribe_address_for(@account) - else - render :new - end - end - - private - - def resource_params - params.require(:remote_follow).permit(:acct) - end - - def session_params - { acct: session[:remote_follow] || current_account&.username } - end - - def set_pack - use_pack 'modal' - end - - def set_body_classes - @body_classes = 'modal-layout' - @hide_header = true - end -end diff --git a/app/controllers/remote_interaction_controller.rb b/app/controllers/remote_interaction_controller.rb deleted file mode 100644 index a277bfa10..000000000 --- a/app/controllers/remote_interaction_controller.rb +++ /dev/null @@ -1,60 +0,0 @@ -# frozen_string_literal: true - -class RemoteInteractionController < ApplicationController - include Authorization - - layout 'modal' - - before_action :authenticate_user!, if: :whitelist_mode? - before_action :set_interaction_type - before_action :set_status - before_action :set_body_classes - before_action :set_pack - - skip_before_action :require_functional!, unless: :whitelist_mode? - - def new - @remote_follow = RemoteFollow.new(session_params) - end - - def create - @remote_follow = RemoteFollow.new(resource_params) - - if @remote_follow.valid? - session[:remote_follow] = @remote_follow.acct - redirect_to @remote_follow.interact_address_for(@status) - else - render :new - end - end - - private - - def resource_params - params.require(:remote_follow).permit(:acct) - end - - def session_params - { acct: session[:remote_follow] || current_account&.username } - end - - def set_status - @status = Status.find(params[:id]) - authorize @status, :show? - rescue Mastodon::NotPermittedError - not_found - end - - def set_body_classes - @body_classes = 'modal-layout' - @hide_header = true - end - - def set_pack - use_pack 'modal' - end - - def set_interaction_type - @interaction_type = %w(reply reblog favourite).include?(params[:type]) ? params[:type] : 'reply' - end -end diff --git a/app/controllers/settings/deletes_controller.rb b/app/controllers/settings/deletes_controller.rb index e0dd5edcb..bb096567a 100644 --- a/app/controllers/settings/deletes_controller.rb +++ b/app/controllers/settings/deletes_controller.rb @@ -4,7 +4,6 @@ class Settings::DeletesController < Settings::BaseController skip_before_action :require_functional! before_action :require_not_suspended! - before_action :check_enabled_deletion def show @confirmation = Form::DeleteConfirmation.new @@ -21,10 +20,6 @@ class Settings::DeletesController < Settings::BaseController private - def check_enabled_deletion - redirect_to root_path unless Setting.open_deletion - end - def resource_params params.require(:form_delete_confirmation).permit(:password, :username) end diff --git a/app/controllers/settings/featured_tags_controller.rb b/app/controllers/settings/featured_tags_controller.rb index aadff7c83..b3db04a42 100644 --- a/app/controllers/settings/featured_tags_controller.rb +++ b/app/controllers/settings/featured_tags_controller.rb @@ -10,9 +10,9 @@ class Settings::FeaturedTagsController < Settings::BaseController end def create - @featured_tag = current_account.featured_tags.new(featured_tag_params) + @featured_tag = CreateFeaturedTagService.new.call(current_account, featured_tag_params[:name], force: false) - if @featured_tag.save + if @featured_tag.valid? redirect_to settings_featured_tags_path else set_featured_tags @@ -23,7 +23,7 @@ class Settings::FeaturedTagsController < Settings::BaseController end def destroy - @featured_tag.destroy! + RemoveFeaturedTagWorker.perform_async(current_account.id, @featured_tag.id) redirect_to settings_featured_tags_path end diff --git a/app/controllers/statuses_controller.rb b/app/controllers/statuses_controller.rb index 55cc3790f..6986176ea 100644 --- a/app/controllers/statuses_controller.rb +++ b/app/controllers/statuses_controller.rb @@ -1,21 +1,19 @@ # frozen_string_literal: true class StatusesController < ApplicationController + include WebAppControllerConcern include StatusControllerConcern include SignatureAuthentication include Authorization include AccountOwnedConcern - layout 'public' - before_action :require_account_signature!, only: [:show, :activity], if: -> { request.format == :json && authorized_fetch_mode? } before_action :set_status before_action :set_instance_presenter before_action :set_link_headers before_action :redirect_to_original, only: :show - before_action :set_referrer_policy_header, only: :show before_action :set_cache_headers - before_action :set_body_classes + before_action :set_body_classes, only: :embed skip_around_action :set_locale, if: -> { request.format == :json } skip_before_action :require_functional!, only: [:show, :embed], unless: :whitelist_mode? @@ -27,11 +25,7 @@ class StatusesController < ApplicationController def show respond_to do |format| format.html do - use_pack 'public' - expires_in 10.seconds, public: true if current_account.nil? - set_ancestors - set_descendants end format.json do @@ -80,8 +74,4 @@ class StatusesController < ApplicationController def redirect_to_original redirect_to ActivityPub::TagManager.instance.url_for(@status.reblog) if @status.reblog? end - - def set_referrer_policy_header - response.headers['Referrer-Policy'] = 'origin' unless @status.distributable? - end end diff --git a/app/controllers/tags_controller.rb b/app/controllers/tags_controller.rb index 315eabb3d..f0a099350 100644 --- a/app/controllers/tags_controller.rb +++ b/app/controllers/tags_controller.rb @@ -2,18 +2,16 @@ class TagsController < ApplicationController include SignatureVerification + include WebAppControllerConcern PAGE_SIZE = 20 PAGE_SIZE_MAX = 200 - layout 'public' - before_action :require_account_signature!, if: -> { request.format == :json && authorized_fetch_mode? } before_action :authenticate_user!, if: :whitelist_mode? before_action :set_local before_action :set_tag before_action :set_statuses - before_action :set_body_classes before_action :set_instance_presenter skip_before_action :require_functional!, unless: :whitelist_mode? @@ -21,8 +19,7 @@ class TagsController < ApplicationController def show respond_to do |format| format.html do - use_pack 'about' - expires_in 0, public: true + expires_in 0, public: true unless user_signed_in? end format.rss do @@ -55,10 +52,6 @@ class TagsController < ApplicationController end end - def set_body_classes - @body_classes = 'with-modals' - end - def set_instance_presenter @instance_presenter = InstancePresenter.new end diff --git a/app/helpers/accounts_helper.rb b/app/helpers/accounts_helper.rb index 2a17b69e3..e15aee6df 100644 --- a/app/helpers/accounts_helper.rb +++ b/app/helpers/accounts_helper.rb @@ -20,54 +20,10 @@ module AccountsHelper end def account_action_button(account) - if user_signed_in? - if account.id == current_user.account_id - link_to settings_profile_url, class: 'button logo-button' do - safe_join([logo_as_symbol, t('settings.edit_profile')]) - end - elsif current_account.following?(account) || current_account.requested?(account) - link_to account_unfollow_path(account), class: 'button logo-button button--destructive', data: { method: :post } do - safe_join([logo_as_symbol, t('accounts.unfollow')]) - end - elsif !(account.memorial? || account.moved?) - link_to account_follow_path(account), class: "button logo-button#{account.blocking?(current_account) ? ' disabled' : ''}", data: { method: :post } do - safe_join([logo_as_symbol, t('accounts.follow')]) - end - end - elsif !(account.memorial? || account.moved?) - link_to account_remote_follow_path(account), class: 'button logo-button modal-button', target: '_new' do - safe_join([logo_as_symbol, t('accounts.follow')]) - end - end - end - - def minimal_account_action_button(account) - if user_signed_in? - return if account.id == current_user.account_id - - if current_account.following?(account) || current_account.requested?(account) - link_to account_unfollow_path(account), class: 'icon-button active', data: { method: :post }, title: t('accounts.unfollow') do - fa_icon('user-times fw') - end - elsif !(account.memorial? || account.moved?) - link_to account_follow_path(account), class: "icon-button#{account.blocking?(current_account) ? ' disabled' : ''}", data: { method: :post }, title: t('accounts.follow') do - fa_icon('user-plus fw') - end - end - elsif !(account.memorial? || account.moved?) - link_to account_remote_follow_path(account), class: 'icon-button modal-button', target: '_new', title: t('accounts.follow') do - fa_icon('user-plus fw') - end - end - end + return if account.memorial? || account.moved? - def account_badge(account) - if account.bot? - content_tag(:div, content_tag(:div, t('accounts.roles.bot'), class: 'account-role bot'), class: 'roles') - elsif account.group? - content_tag(:div, content_tag(:div, t('accounts.roles.group'), class: 'account-role group'), class: 'roles') - elsif account.user_role&.highlighted? - content_tag(:div, content_tag(:div, account.user_role.name, class: "account-role user-role-#{account.user_role.id}"), class: 'roles') + link_to ActivityPub::TagManager.instance.url_for(account), class: 'button logo-button', target: '_new' do + safe_join([logo_as_symbol, t('accounts.follow')]) end end diff --git a/app/helpers/admin/settings_helper.rb b/app/helpers/admin/settings_helper.rb index f99a2b8c8..552a3ee5a 100644 --- a/app/helpers/admin/settings_helper.rb +++ b/app/helpers/admin/settings_helper.rb @@ -1,14 +1,6 @@ # frozen_string_literal: true module Admin::SettingsHelper - def site_upload_delete_hint(hint, var) - upload = SiteUpload.find_by(var: var.to_s) - return hint unless upload - - link = link_to t('admin.site_uploads.delete'), admin_site_upload_path(upload), data: { method: :delete } - safe_join([hint, link], '<br/>'.html_safe) - end - def captcha_available? ENV['HCAPTCHA_SECRET_KEY'].present? && ENV['HCAPTCHA_SITE_KEY'].present? end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 62739b964..c5374a195 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -87,10 +87,6 @@ module ApplicationHelper link_to label, omniauth_authorize_path(:user, provider), class: "button button-#{provider}", method: :post end - def open_deletion? - Setting.open_deletion - end - def locale_direction if RTL_LOCALES.include?(I18n.locale) 'rtl' @@ -199,10 +195,7 @@ module ApplicationHelper def render_initial_state state_params = { - settings: { - known_fediverse: Setting.show_known_fediverse_at_about_page, - }, - + settings: {}, text: [params[:title], params[:text], params[:url]].compact.join(' '), } @@ -219,6 +212,10 @@ module ApplicationHelper state_params[:admin] = Account.find_local(Setting.site_contact_username.strip.gsub(/\A@/, '')) end + if single_user_mode? + state_params[:owner] = Account.local.without_suspended.where('id > 0').first + end + json = ActiveModelSerializers::SerializableResource.new(InitialStatePresenter.new(state_params), serializer: InitialStateSerializer).to_json # rubocop:disable Rails/OutputSafety content_tag(:script, json_escape(json).html_safe, id: 'initial-state', type: 'application/json') diff --git a/app/helpers/home_helper.rb b/app/helpers/home_helper.rb index 4da68500a..f41104709 100644 --- a/app/helpers/home_helper.rb +++ b/app/helpers/home_helper.rb @@ -23,7 +23,7 @@ module HomeHelper else link_to(path || ActivityPub::TagManager.instance.url_for(account), class: 'account__display-name') do content_tag(:div, class: 'account__avatar-wrapper') do - image_tag(full_asset_url(current_account&.user&.setting_auto_play_gif ? account.avatar_original_url : account.avatar_static_url), class: 'account__avatar') + image_tag(full_asset_url(current_account&.user&.setting_auto_play_gif ? account.avatar_original_url : account.avatar_static_url), class: 'account__avatar', width: 46, height: 46) end + content_tag(:span, class: 'display-name') do content_tag(:bdi) do diff --git a/app/helpers/languages_helper.rb b/app/helpers/languages_helper.rb index 4077e19bd..e5bae2c6b 100644 --- a/app/helpers/languages_helper.rb +++ b/app/helpers/languages_helper.rb @@ -97,7 +97,7 @@ module LanguagesHelper lg: ['Ganda', 'Luganda'].freeze, li: ['Limburgish', 'Limburgs'].freeze, ln: ['Lingala', 'Lingála'].freeze, - lo: ['Lao', 'ພາສາ'].freeze, + lo: ['Lao', 'ລາວ'].freeze, lt: ['Lithuanian', 'lietuvių kalba'].freeze, lu: ['Luba-Katanga', 'Tshiluba'].freeze, lv: ['Latvian', 'latviešu valoda'].freeze, diff --git a/app/javascript/core/admin.js b/app/javascript/core/admin.js index c84f566a3..3175ff560 100644 --- a/app/javascript/core/admin.js +++ b/app/javascript/core/admin.js @@ -4,6 +4,24 @@ import 'packs/public-path'; import { delegate } from '@rails/ujs'; import ready from '../mastodon/ready'; +const setAnnouncementEndsAttributes = (target) => { + const valid = target?.value && target?.validity?.valid; + const element = document.querySelector('input[type="datetime-local"]#announcement_ends_at'); + if (valid) { + element.classList.remove('optional'); + element.required = true; + element.min = target.value; + } else { + element.classList.add('optional'); + element.removeAttribute('required'); + element.removeAttribute('min'); + } +}; + +delegate(document, 'input[type="datetime-local"]#announcement_starts_at', 'change', ({ target }) => { + setAnnouncementEndsAttributes(target); +}); + const batchCheckboxClassName = '.batch-checkbox input[type="checkbox"]'; const showSelectAll = () => { @@ -143,6 +161,20 @@ const onChangeRegistrationMode = (target) => { }); }; +const convertUTCDateTimeToLocal = (value) => { + const date = new Date(value + 'Z'); + const twoChars = (x) => (x.toString().padStart(2, '0')); + return `${date.getFullYear()}-${twoChars(date.getMonth()+1)}-${twoChars(date.getDate())}T${twoChars(date.getHours())}:${twoChars(date.getMinutes())}`; +}; + +const convertLocalDatetimeToUTC = (value) => { + const re = /^([0-9]{4,})-([0-9]{2})-([0-9]{2})T([0-9]{2}):([0-9]{2})/; + const match = re.exec(value); + const date = new Date(match[1], match[2] - 1, match[3], match[4], match[5]); + const fullISO8601 = date.toISOString(); + return fullISO8601.slice(0, fullISO8601.indexOf('T') + 6); +}; + delegate(document, '#form_admin_settings_registrations_mode', 'change', ({ target }) => onChangeRegistrationMode(target)); ready(() => { @@ -170,4 +202,26 @@ ready(() => { e.target.href = url; } }); + + [].forEach.call(document.querySelectorAll('input[type="datetime-local"]'), element => { + if (element.value) { + element.value = convertUTCDateTimeToLocal(element.value); + } + if (element.placeholder) { + element.placeholder = convertUTCDateTimeToLocal(element.placeholder); + } + }); + + delegate(document, 'form', 'submit', ({ target }) => { + [].forEach.call(target.querySelectorAll('input[type="datetime-local"]'), element => { + if (element.value && element.validity.valid) { + element.value = convertLocalDatetimeToUTC(element.value); + } + }); + }); + + const announcementStartsAt = document.querySelector('input[type="datetime-local"]#announcement_starts_at'); + if (announcementStartsAt) { + setAnnouncementEndsAttributes(announcementStartsAt); + } }); diff --git a/app/javascript/core/public.js b/app/javascript/core/public.js index b67fb13e5..5c7a51f44 100644 --- a/app/javascript/core/public.js +++ b/app/javascript/core/public.js @@ -6,28 +6,6 @@ import ready from '../mastodon/ready'; const { delegate } = require('@rails/ujs'); const { length } = require('stringz'); -delegate(document, '.webapp-btn', 'click', ({ target, button }) => { - if (button !== 0) { - return true; - } - window.location.href = target.href; - return false; -}); - -delegate(document, '.modal-button', 'click', e => { - e.preventDefault(); - - let href; - - if (e.target.nodeName !== 'A') { - href = e.target.parentNode.href; - } else { - href = e.target.href; - } - - window.open(href, 'mastodon-intent', 'width=445,height=600,resizable=no,menubar=no,status=no,scrollbars=yes'); -}); - const getProfileAvatarAnimationHandler = (swapTo) => { //animate avatar gifs on the profile page when moused over return ({ target }) => { diff --git a/app/javascript/flavours/glitch/actions/compose.js b/app/javascript/flavours/glitch/actions/compose.js index 02aa4f144..15476fc59 100644 --- a/app/javascript/flavours/glitch/actions/compose.js +++ b/app/javascript/flavours/glitch/actions/compose.js @@ -1,19 +1,21 @@ -import api from '../api'; -import { CancelToken, isCancel } from 'axios'; +import axios from 'axios'; import { throttle } from 'lodash'; +import { defineMessages } from 'react-intl'; +import api from 'flavours/glitch/api'; import { search as emojiSearch } from 'flavours/glitch/features/emoji/emoji_mart_search_light'; -import { useEmoji } from './emojis'; -import { tagHistory } from '../settings'; +import { tagHistory } from 'flavours/glitch/settings'; import { recoverHashtags } from 'flavours/glitch/utils/hashtag'; import resizeImage from 'flavours/glitch/utils/resize_image'; +import { showAlert, showAlertForError } from './alerts'; +import { useEmoji } from './emojis'; import { importFetchedAccounts } from './importer'; -import { updateTimeline } from './timelines'; -import { showAlertForError } from './alerts'; -import { showAlert } from './alerts'; import { openModal } from './modal'; -import { defineMessages } from 'react-intl'; +import { updateTimeline } from './timelines'; -let cancelFetchComposeSuggestionsAccounts, cancelFetchComposeSuggestionsTags; +/** @type {AbortController | undefined} */ +let fetchComposeSuggestionsAccountsController; +/** @type {AbortController | undefined} */ +let fetchComposeSuggestionsTagsController; export const COMPOSE_CHANGE = 'COMPOSE_CHANGE'; export const COMPOSE_CYCLE_ELEFRIEND = 'COMPOSE_CYCLE_ELEFRIEND'; @@ -25,11 +27,13 @@ export const COMPOSE_REPLY_CANCEL = 'COMPOSE_REPLY_CANCEL'; export const COMPOSE_DIRECT = 'COMPOSE_DIRECT'; export const COMPOSE_MENTION = 'COMPOSE_MENTION'; export const COMPOSE_RESET = 'COMPOSE_RESET'; -export const COMPOSE_UPLOAD_REQUEST = 'COMPOSE_UPLOAD_REQUEST'; -export const COMPOSE_UPLOAD_SUCCESS = 'COMPOSE_UPLOAD_SUCCESS'; -export const COMPOSE_UPLOAD_FAIL = 'COMPOSE_UPLOAD_FAIL'; -export const COMPOSE_UPLOAD_PROGRESS = 'COMPOSE_UPLOAD_PROGRESS'; -export const COMPOSE_UPLOAD_UNDO = 'COMPOSE_UPLOAD_UNDO'; + +export const COMPOSE_UPLOAD_REQUEST = 'COMPOSE_UPLOAD_REQUEST'; +export const COMPOSE_UPLOAD_SUCCESS = 'COMPOSE_UPLOAD_SUCCESS'; +export const COMPOSE_UPLOAD_FAIL = 'COMPOSE_UPLOAD_FAIL'; +export const COMPOSE_UPLOAD_PROGRESS = 'COMPOSE_UPLOAD_PROGRESS'; +export const COMPOSE_UPLOAD_PROCESSING = 'COMPOSE_UPLOAD_PROCESSING'; +export const COMPOSE_UPLOAD_UNDO = 'COMPOSE_UPLOAD_UNDO'; export const THUMBNAIL_UPLOAD_REQUEST = 'THUMBNAIL_UPLOAD_REQUEST'; export const THUMBNAIL_UPLOAD_SUCCESS = 'THUMBNAIL_UPLOAD_SUCCESS'; @@ -83,10 +87,8 @@ const messages = defineMessages({ uploadErrorPoll: { id: 'upload_error.poll', defaultMessage: 'File upload not allowed with polls.' }, }); -const COMPOSE_PANEL_BREAKPOINT = 600 + (285 * 1) + (10 * 1); - export const ensureComposeIsVisible = (getState, routerHistory) => { - if (!getState().getIn(['compose', 'mounted']) && window.innerWidth < COMPOSE_PANEL_BREAKPOINT) { + if (!getState().getIn(['compose', 'mounted'])) { routerHistory.push('/publish'); } }; @@ -307,13 +309,16 @@ export function uploadCompose(files) { if (status === 200) { dispatch(uploadComposeSuccess(data, f)); } else if (status === 202) { + dispatch(uploadComposeProcessing()); + let tryCount = 1; + const poll = () => { api(getState).get(`/api/v1/media/${data.id}`).then(response => { if (response.status === 200) { dispatch(uploadComposeSuccess(response.data, f)); } else if (response.status === 206) { - let retryAfter = (Math.log2(tryCount) || 1) * 1000; + const retryAfter = (Math.log2(tryCount) || 1) * 1000; tryCount += 1; setTimeout(() => poll(), retryAfter); } @@ -328,6 +333,10 @@ export function uploadCompose(files) { }; }; +export const uploadComposeProcessing = () => ({ + type: COMPOSE_UPLOAD_PROCESSING, +}); + export const uploadThumbnail = (id, file) => (dispatch, getState) => { dispatch(uploadThumbnailRequest()); @@ -472,8 +481,8 @@ export function undoUploadCompose(media_id) { }; export function clearComposeSuggestions() { - if (cancelFetchComposeSuggestionsAccounts) { - cancelFetchComposeSuggestionsAccounts(); + if (fetchComposeSuggestionsAccountsController) { + fetchComposeSuggestionsAccountsController.abort(); } return { type: COMPOSE_SUGGESTIONS_CLEAR, @@ -481,14 +490,14 @@ export function clearComposeSuggestions() { }; const fetchComposeSuggestionsAccounts = throttle((dispatch, getState, token) => { - if (cancelFetchComposeSuggestionsAccounts) { - cancelFetchComposeSuggestionsAccounts(); + if (fetchComposeSuggestionsAccountsController) { + fetchComposeSuggestionsAccountsController.abort(); } + fetchComposeSuggestionsAccountsController = new AbortController(); + api(getState).get('/api/v1/accounts/search', { - cancelToken: new CancelToken(cancel => { - cancelFetchComposeSuggestionsAccounts = cancel; - }), + signal: fetchComposeSuggestionsAccountsController.signal, params: { q: token.slice(1), @@ -499,9 +508,11 @@ const fetchComposeSuggestionsAccounts = throttle((dispatch, getState, token) => dispatch(importFetchedAccounts(response.data)); dispatch(readyComposeSuggestionsAccounts(token, response.data)); }).catch(error => { - if (!isCancel(error)) { + if (!axios.isCancel(error)) { dispatch(showAlertForError(error)); } + }).finally(() => { + fetchComposeSuggestionsAccountsController = undefined; }); }, 200, { leading: true, trailing: true }); @@ -511,16 +522,16 @@ const fetchComposeSuggestionsEmojis = (dispatch, getState, token) => { }; const fetchComposeSuggestionsTags = throttle((dispatch, getState, token) => { - if (cancelFetchComposeSuggestionsTags) { - cancelFetchComposeSuggestionsTags(); + if (fetchComposeSuggestionsTagsController) { + fetchComposeSuggestionsTagsController.abort(); } dispatch(updateSuggestionTags(token)); + fetchComposeSuggestionsTagsController = new AbortController(); + api(getState).get('/api/v2/search', { - cancelToken: new CancelToken(cancel => { - cancelFetchComposeSuggestionsTags = cancel; - }), + signal: fetchComposeSuggestionsTagsController.signal, params: { type: 'hashtags', @@ -531,9 +542,11 @@ const fetchComposeSuggestionsTags = throttle((dispatch, getState, token) => { }).then(({ data }) => { dispatch(readyComposeSuggestionsTags(token, data.hashtags)); }).catch(error => { - if (!isCancel(error)) { + if (!axios.isCancel(error)) { dispatch(showAlertForError(error)); } + }).finally(() => { + fetchComposeSuggestionsTagsController = undefined; }); }, 200, { leading: true, trailing: true }); diff --git a/app/javascript/flavours/glitch/actions/featured_tags.js b/app/javascript/flavours/glitch/actions/featured_tags.js new file mode 100644 index 000000000..18bb61539 --- /dev/null +++ b/app/javascript/flavours/glitch/actions/featured_tags.js @@ -0,0 +1,34 @@ +import api from '../api'; + +export const FEATURED_TAGS_FETCH_REQUEST = 'FEATURED_TAGS_FETCH_REQUEST'; +export const FEATURED_TAGS_FETCH_SUCCESS = 'FEATURED_TAGS_FETCH_SUCCESS'; +export const FEATURED_TAGS_FETCH_FAIL = 'FEATURED_TAGS_FETCH_FAIL'; + +export const fetchFeaturedTags = (id) => (dispatch, getState) => { + if (getState().getIn(['user_lists', 'featured_tags', id, 'items'])) { + return; + } + + dispatch(fetchFeaturedTagsRequest(id)); + + api(getState).get(`/api/v1/accounts/${id}/featured_tags`) + .then(({ data }) => dispatch(fetchFeaturedTagsSuccess(id, data))) + .catch(err => dispatch(fetchFeaturedTagsFail(id, err))); +}; + +export const fetchFeaturedTagsRequest = (id) => ({ + type: FEATURED_TAGS_FETCH_REQUEST, + id, +}); + +export const fetchFeaturedTagsSuccess = (id, tags) => ({ + type: FEATURED_TAGS_FETCH_SUCCESS, + id, + tags, +}); + +export const fetchFeaturedTagsFail = (id, error) => ({ + type: FEATURED_TAGS_FETCH_FAIL, + id, + error, +}); diff --git a/app/javascript/flavours/glitch/actions/search.js b/app/javascript/flavours/glitch/actions/search.js index 776782693..f21c0058b 100644 --- a/app/javascript/flavours/glitch/actions/search.js +++ b/app/javascript/flavours/glitch/actions/search.js @@ -29,7 +29,8 @@ export function clearSearch() { export function submitSearch() { return (dispatch, getState) => { - const value = getState().getIn(['search', 'value']); + const value = getState().getIn(['search', 'value']); + const signedIn = !!getState().getIn(['meta', 'me']); if (value.length === 0) { dispatch(fetchSearchSuccess({ accounts: [], statuses: [], hashtags: [] }, '')); @@ -41,7 +42,7 @@ export function submitSearch() { api(getState).get('/api/v2/search', { params: { q: value, - resolve: true, + resolve: signedIn, limit: 10, }, }).then(response => { diff --git a/app/javascript/flavours/glitch/actions/server.js b/app/javascript/flavours/glitch/actions/server.js index af8fef780..31d4aea10 100644 --- a/app/javascript/flavours/glitch/actions/server.js +++ b/app/javascript/flavours/glitch/actions/server.js @@ -5,6 +5,14 @@ export const SERVER_FETCH_REQUEST = 'Server_FETCH_REQUEST'; export const SERVER_FETCH_SUCCESS = 'Server_FETCH_SUCCESS'; export const SERVER_FETCH_FAIL = 'Server_FETCH_FAIL'; +export const EXTENDED_DESCRIPTION_REQUEST = 'EXTENDED_DESCRIPTION_REQUEST'; +export const EXTENDED_DESCRIPTION_SUCCESS = 'EXTENDED_DESCRIPTION_SUCCESS'; +export const EXTENDED_DESCRIPTION_FAIL = 'EXTENDED_DESCRIPTION_FAIL'; + +export const SERVER_DOMAIN_BLOCKS_FETCH_REQUEST = 'SERVER_DOMAIN_BLOCKS_FETCH_REQUEST'; +export const SERVER_DOMAIN_BLOCKS_FETCH_SUCCESS = 'SERVER_DOMAIN_BLOCKS_FETCH_SUCCESS'; +export const SERVER_DOMAIN_BLOCKS_FETCH_FAIL = 'SERVER_DOMAIN_BLOCKS_FETCH_FAIL'; + export const fetchServer = () => (dispatch, getState) => { dispatch(fetchServerRequest()); @@ -28,3 +36,56 @@ const fetchServerFail = error => ({ type: SERVER_FETCH_FAIL, error, }); + +export const fetchExtendedDescription = () => (dispatch, getState) => { + dispatch(fetchExtendedDescriptionRequest()); + + api(getState) + .get('/api/v1/instance/extended_description') + .then(({ data }) => dispatch(fetchExtendedDescriptionSuccess(data))) + .catch(err => dispatch(fetchExtendedDescriptionFail(err))); +}; + +const fetchExtendedDescriptionRequest = () => ({ + type: EXTENDED_DESCRIPTION_REQUEST, +}); + +const fetchExtendedDescriptionSuccess = description => ({ + type: EXTENDED_DESCRIPTION_SUCCESS, + description, +}); + +const fetchExtendedDescriptionFail = error => ({ + type: EXTENDED_DESCRIPTION_FAIL, + error, +}); + +export const fetchDomainBlocks = () => (dispatch, getState) => { + dispatch(fetchDomainBlocksRequest()); + + api(getState) + .get('/api/v1/instance/domain_blocks') + .then(({ data }) => dispatch(fetchDomainBlocksSuccess(true, data))) + .catch(err => { + if (err.response.status === 404) { + dispatch(fetchDomainBlocksSuccess(false, [])); + } else { + dispatch(fetchDomainBlocksFail(err)); + } + }); +}; + +const fetchDomainBlocksRequest = () => ({ + type: SERVER_DOMAIN_BLOCKS_FETCH_REQUEST, +}); + +const fetchDomainBlocksSuccess = (isAvailable, blocks) => ({ + type: SERVER_DOMAIN_BLOCKS_FETCH_SUCCESS, + isAvailable, + blocks, +}); + +const fetchDomainBlocksFail = error => ({ + type: SERVER_DOMAIN_BLOCKS_FETCH_FAIL, + error, +}); diff --git a/app/javascript/flavours/glitch/actions/timelines.js b/app/javascript/flavours/glitch/actions/timelines.js index ef1e4dbbb..a1c4dd43a 100644 --- a/app/javascript/flavours/glitch/actions/timelines.js +++ b/app/javascript/flavours/glitch/actions/timelines.js @@ -156,8 +156,8 @@ export const expandHomeTimeline = ({ maxId } = {}, done = noOp) => ex export const expandPublicTimeline = ({ maxId, onlyMedia, onlyRemote, allowLocalOnly } = {}, done = noOp) => expandTimeline(`public${onlyRemote ? ':remote' : (allowLocalOnly ? ':allow_local_only' : '')}${onlyMedia ? ':media' : ''}`, '/api/v1/timelines/public', { remote: !!onlyRemote, allow_local_only: !!allowLocalOnly, max_id: maxId, only_media: !!onlyMedia }, done); export const expandCommunityTimeline = ({ maxId, onlyMedia } = {}, done = noOp) => expandTimeline(`community${onlyMedia ? ':media' : ''}`, '/api/v1/timelines/public', { local: true, max_id: maxId, only_media: !!onlyMedia }, done); export const expandDirectTimeline = ({ maxId } = {}, done = noOp) => expandTimeline('direct', '/api/v1/timelines/direct', { max_id: maxId }, done); -export const expandAccountTimeline = (accountId, { maxId, withReplies } = {}) => expandTimeline(`account:${accountId}${withReplies ? ':with_replies' : ''}`, `/api/v1/accounts/${accountId}/statuses`, { exclude_replies: !withReplies, max_id: maxId }); -export const expandAccountFeaturedTimeline = accountId => expandTimeline(`account:${accountId}:pinned`, `/api/v1/accounts/${accountId}/statuses`, { pinned: true }); +export const expandAccountTimeline = (accountId, { maxId, withReplies, tagged } = {}) => expandTimeline(`account:${accountId}${withReplies ? ':with_replies' : ''}${tagged ? `:${tagged}` : ''}`, `/api/v1/accounts/${accountId}/statuses`, { exclude_replies: !withReplies, tagged, max_id: maxId }); +export const expandAccountFeaturedTimeline = (accountId, { tagged } = {}) => expandTimeline(`account:${accountId}:pinned`, `/api/v1/accounts/${accountId}/statuses`, { pinned: true, tagged }); export const expandAccountMediaTimeline = (accountId, { maxId } = {}) => expandTimeline(`account:${accountId}:media`, `/api/v1/accounts/${accountId}/statuses`, { max_id: maxId, only_media: true, limit: 40 }); export const expandListTimeline = (id, { maxId } = {}, done = noOp) => expandTimeline(`list:${id}`, `/api/v1/timelines/list/${id}`, { max_id: maxId }, done); export const expandHashtagTimeline = (hashtag, { maxId, tags, local } = {}, done = noOp) => { diff --git a/app/javascript/flavours/glitch/api.js b/app/javascript/flavours/glitch/api.js index 645ef6500..6bbddbef6 100644 --- a/app/javascript/flavours/glitch/api.js +++ b/app/javascript/flavours/glitch/api.js @@ -1,20 +1,31 @@ +// @ts-check + import axios from 'axios'; import LinkHeader from 'http-link-header'; import ready from './ready'; +/** + * @param {import('axios').AxiosResponse} response + * @returns {LinkHeader} + */ export const getLinks = response => { const value = response.headers.link; if (!value) { - return { refs: [] }; + return new LinkHeader(); } return LinkHeader.parse(value); }; +/** @type {import('axios').RawAxiosRequestHeaders} */ const csrfHeader = {}; +/** + * @returns {void} + */ const setCSRFHeader = () => { + /** @type {HTMLMetaElement | null} */ const csrfToken = document.querySelector('meta[name=csrf-token]'); if (csrfToken) { @@ -24,6 +35,10 @@ const setCSRFHeader = () => { ready(setCSRFHeader); +/** + * @param {() => import('immutable').Map} getState + * @returns {import('axios').RawAxiosRequestHeaders} + */ const authorizationHeaderFromState = getState => { const accessToken = getState && getState().getIn(['meta', 'access_token'], ''); @@ -36,17 +51,25 @@ const authorizationHeaderFromState = getState => { }; }; -export default getState => axios.create({ - headers: { - ...csrfHeader, - ...authorizationHeaderFromState(getState), - }, - - transformResponse: [function (data) { - try { - return JSON.parse(data); - } catch(Exception) { - return data; - } - }], -}); +/** + * @param {() => import('immutable').Map} getState + * @returns {import('axios').AxiosInstance} + */ +export default function api(getState) { + return axios.create({ + headers: { + ...csrfHeader, + ...authorizationHeaderFromState(getState), + }, + + transformResponse: [ + function (data) { + try { + return JSON.parse(data); + } catch { + return data; + } + }, + ], + }); +} diff --git a/app/javascript/flavours/glitch/components/avatar.js b/app/javascript/flavours/glitch/components/avatar.js index ce91d401d..38fd99af5 100644 --- a/app/javascript/flavours/glitch/components/avatar.js +++ b/app/javascript/flavours/glitch/components/avatar.js @@ -70,6 +70,8 @@ export default class Avatar extends React.PureComponent { onMouseLeave={this.handleMouseLeave} style={style} data-avatar-of={account && `@${account.get('acct')}`} + role='img' + aria-label={account?.get('acct')} /> ); } diff --git a/app/javascript/flavours/glitch/components/dismissable_banner.js b/app/javascript/flavours/glitch/components/dismissable_banner.js new file mode 100644 index 000000000..ff52a619d --- /dev/null +++ b/app/javascript/flavours/glitch/components/dismissable_banner.js @@ -0,0 +1,51 @@ +import React from 'react'; +import IconButton from './icon_button'; +import PropTypes from 'prop-types'; +import { injectIntl, defineMessages } from 'react-intl'; +import { bannerSettings } from 'flavours/glitch/settings'; + +const messages = defineMessages({ + dismiss: { id: 'dismissable_banner.dismiss', defaultMessage: 'Dismiss' }, +}); + +export default @injectIntl +class DismissableBanner extends React.PureComponent { + + static propTypes = { + id: PropTypes.string.isRequired, + children: PropTypes.node, + intl: PropTypes.object.isRequired, + }; + + state = { + visible: !bannerSettings.get(this.props.id), + }; + + handleDismiss = () => { + const { id } = this.props; + this.setState({ visible: false }, () => bannerSettings.set(id, true)); + } + + render () { + const { visible } = this.state; + + if (!visible) { + return null; + } + + const { children, intl } = this.props; + + return ( + <div className='dismissable-banner'> + <div className='dismissable-banner__message'> + {children} + </div> + + <div className='dismissable-banner__action'> + <IconButton icon='times' title={intl.formatMessage(messages.dismiss)} onClick={this.handleDismiss} /> + </div> + </div> + ); + } + +} diff --git a/app/javascript/flavours/glitch/components/error_boundary.js b/app/javascript/flavours/glitch/components/error_boundary.js index fd3659de7..e0ca3e2b0 100644 --- a/app/javascript/flavours/glitch/components/error_boundary.js +++ b/app/javascript/flavours/glitch/components/error_boundary.js @@ -4,6 +4,7 @@ import { FormattedMessage } from 'react-intl'; import { source_url } from 'flavours/glitch/initial_state'; import { preferencesLink } from 'flavours/glitch/utils/backend_links'; import StackTrace from 'stacktrace-js'; +import { Helmet } from 'react-helmet'; export default class ErrorBoundary extends React.PureComponent { @@ -122,6 +123,10 @@ export default class ErrorBoundary extends React.PureComponent { )} </ul> </div> + + <Helmet> + <meta name='robots' content='noindex' /> + </Helmet> </div> ); } diff --git a/app/javascript/flavours/glitch/components/hashtag.js b/app/javascript/flavours/glitch/components/hashtag.js index 2bb7f02f7..422b9a8fa 100644 --- a/app/javascript/flavours/glitch/components/hashtag.js +++ b/app/javascript/flavours/glitch/components/hashtag.js @@ -1,7 +1,7 @@ // @ts-check import React from 'react'; import { Sparklines, SparklinesCurve } from 'react-sparklines'; -import { FormattedMessage, injectIntl, defineMessages } from 'react-intl'; +import { FormattedMessage } from 'react-intl'; import PropTypes from 'prop-types'; import ImmutablePropTypes from 'react-immutable-proptypes'; import Permalink from './permalink'; @@ -9,10 +9,6 @@ import ShortNumber from 'flavours/glitch/components/short_number'; import Skeleton from 'flavours/glitch/components/skeleton'; import classNames from 'classnames'; -const messages = defineMessages({ - totalVolume: { id: 'hashtag.total_volume', defaultMessage: 'Total volume in the last {days, plural, one {day} other {{days} days}}' }, -}); - class SilentErrorBoundary extends React.Component { static propTypes = { @@ -60,7 +56,6 @@ export const ImmutableHashtag = ({ hashtag }) => ( href={hashtag.get('url')} to={`/tags/${hashtag.get('name')}`} people={hashtag.getIn(['history', 0, 'accounts']) * 1 + hashtag.getIn(['history', 1, 'accounts']) * 1} - uses={hashtag.getIn(['history', 0, 'uses']) * 1 + hashtag.getIn(['history', 1, 'uses']) * 1} history={hashtag.get('history').reverse().map((day) => day.get('uses')).toArray()} /> ); @@ -69,39 +64,52 @@ ImmutableHashtag.propTypes = { hashtag: ImmutablePropTypes.map.isRequired, }; -const Hashtag = injectIntl(({ name, href, to, people, uses, history, className, intl }) => ( +const Hashtag = ({ name, href, to, people, uses, history, className, description, withGraph }) => ( <div className={classNames('trends__item', className)}> <div className='trends__item__name'> <Permalink href={href} to={to}> {name ? <React.Fragment>#<span>{name}</span></React.Fragment> : <Skeleton width={50} />} </Permalink> - {typeof people !== 'undefined' ? <ShortNumber value={people} renderer={accountsCountRenderer} /> : <Skeleton width={100} />} + {description ? ( + <span>{description}</span> + ) : ( + typeof people !== 'undefined' ? <ShortNumber value={people} renderer={accountsCountRenderer} /> : <Skeleton width={100} /> + )} </div> - <abbr className='trends__item__current' title={intl.formatMessage(messages.totalVolume, { days: 2 })}> - {typeof uses !== 'undefined' ? <ShortNumber value={uses} /> : <Skeleton width={42} height={36} />} - <span className='trends__item__current__asterisk'>*</span> - </abbr> - - <div className='trends__item__sparkline'> - <SilentErrorBoundary> - <Sparklines width={50} height={28} data={history ? history : Array.from(Array(7)).map(() => 0)}> - <SparklinesCurve style={{ fill: 'none' }} /> - </Sparklines> - </SilentErrorBoundary> - </div> + {typeof uses !== 'undefined' && ( + <div className='trends__item__current'> + <ShortNumber value={uses} /> + </div> + )} + + {withGraph && ( + <div className='trends__item__sparkline'> + <SilentErrorBoundary> + <Sparklines width={50} height={28} data={history ? history : Array.from(Array(7)).map(() => 0)}> + <SparklinesCurve style={{ fill: 'none' }} /> + </Sparklines> + </SilentErrorBoundary> + </div> + )} </div> -)); +); Hashtag.propTypes = { name: PropTypes.string, href: PropTypes.string, to: PropTypes.string, people: PropTypes.number, + description: PropTypes.node, uses: PropTypes.number, history: PropTypes.arrayOf(PropTypes.number), className: PropTypes.string, + withGraph: PropTypes.bool, +}; + +Hashtag.defaultProps = { + withGraph: true, }; export default Hashtag; diff --git a/app/javascript/flavours/glitch/components/image.js b/app/javascript/flavours/glitch/components/image.js new file mode 100644 index 000000000..6e81ddf08 --- /dev/null +++ b/app/javascript/flavours/glitch/components/image.js @@ -0,0 +1,33 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import Blurhash from './blurhash'; +import classNames from 'classnames'; + +export default class Image extends React.PureComponent { + + static propTypes = { + src: PropTypes.string, + srcSet: PropTypes.string, + blurhash: PropTypes.string, + className: PropTypes.string, + }; + + state = { + loaded: false, + }; + + handleLoad = () => this.setState({ loaded: true }); + + render () { + const { src, srcSet, blurhash, className } = this.props; + const { loaded } = this.state; + + return ( + <div className={classNames('image', { loaded }, className)} role='presentation'> + {blurhash && <Blurhash hash={blurhash} className='image__preview' />} + <img src={src} srcSet={srcSet} alt='' onLoad={this.handleLoad} /> + </div> + ); + } + +} diff --git a/app/javascript/flavours/glitch/components/logo.js b/app/javascript/flavours/glitch/components/logo.js index 3570b3644..ee5c22496 100644 --- a/app/javascript/flavours/glitch/components/logo.js +++ b/app/javascript/flavours/glitch/components/logo.js @@ -1,7 +1,8 @@ import React from 'react'; const Logo = () => ( - <svg viewBox='0 0 261 66' className='logo'> + <svg viewBox='0 0 261 66' className='logo' role='img'> + <title>Mastodon</title> <use xlinkHref='#logo-symbol-wordmark' /> </svg> ); diff --git a/app/javascript/flavours/glitch/components/missing_indicator.js b/app/javascript/flavours/glitch/components/missing_indicator.js index ee5bf7c1e..08e39c236 100644 --- a/app/javascript/flavours/glitch/components/missing_indicator.js +++ b/app/javascript/flavours/glitch/components/missing_indicator.js @@ -3,6 +3,7 @@ import PropTypes from 'prop-types'; import { FormattedMessage } from 'react-intl'; import illustration from 'flavours/glitch/images/elephant_ui_disappointed.svg'; import classNames from 'classnames'; +import { Helmet } from 'react-helmet'; const MissingIndicator = ({ fullPage }) => ( <div className={classNames('regeneration-indicator', { 'regeneration-indicator--without-header': fullPage })}> @@ -14,6 +15,10 @@ const MissingIndicator = ({ fullPage }) => ( <FormattedMessage id='missing_indicator.label' tagName='strong' defaultMessage='Not found' /> <FormattedMessage id='missing_indicator.sublabel' defaultMessage='This resource could not be found' /> </div> + + <Helmet> + <meta name='robots' content='noindex' /> + </Helmet> </div> ); diff --git a/app/javascript/flavours/glitch/components/navigation_portal.js b/app/javascript/flavours/glitch/components/navigation_portal.js new file mode 100644 index 000000000..16a8ca3f5 --- /dev/null +++ b/app/javascript/flavours/glitch/components/navigation_portal.js @@ -0,0 +1,30 @@ +import React from 'react'; +import { Switch, Route, withRouter } from 'react-router-dom'; +import { showTrends } from 'flavours/glitch/initial_state'; +import Trends from 'flavours/glitch/features/getting_started/containers/trends_container'; +import AccountNavigation from 'flavours/glitch/features/account/navigation'; + +const DefaultNavigation = () => ( + <> + {showTrends && ( + <> + <div className='flex-spacer' /> + <Trends /> + </> + )} + </> +); + +export default @withRouter +class NavigationPortal extends React.PureComponent { + + render () { + return ( + <Switch> + <Route path='/@:acct/(tagged/:tagged?)?' component={AccountNavigation} /> + <Route component={DefaultNavigation} /> + </Switch> + ); + } + +} diff --git a/app/javascript/flavours/glitch/components/server_banner.js b/app/javascript/flavours/glitch/components/server_banner.js index 16360ec56..9cb0ef13c 100644 --- a/app/javascript/flavours/glitch/components/server_banner.js +++ b/app/javascript/flavours/glitch/components/server_banner.js @@ -1,19 +1,21 @@ -import React from 'react'; import PropTypes from 'prop-types'; -import { domain } from 'flavours/glitch/initial_state'; -import { fetchServer } from 'flavours/glitch/actions/server'; +import React from 'react'; +import { FormattedMessage, defineMessages, injectIntl } from 'react-intl'; import { connect } from 'react-redux'; -import Account from 'flavours/glitch/containers/account_container'; +import { fetchServer } from 'flavours/glitch/actions/server'; import ShortNumber from 'flavours/glitch/components/short_number'; import Skeleton from 'flavours/glitch/components/skeleton'; -import { FormattedMessage, injectIntl, defineMessages } from 'react-intl'; +import Account from 'flavours/glitch/containers/account_container'; +import { domain } from 'flavours/glitch/initial_state'; +import Image from 'flavours/glitch/components/image'; +import { Link } from 'react-router-dom'; const messages = defineMessages({ aboutActiveUsers: { id: 'server_banner.about_active_users', defaultMessage: 'People using this server during the last 30 days (Monthly Active Users)' }, }); const mapStateToProps = state => ({ - server: state.get('server'), + server: state.getIn(['server', 'server']), }); export default @connect(mapStateToProps) @@ -41,7 +43,7 @@ class ServerBanner extends React.PureComponent { <FormattedMessage id='server_banner.introduction' defaultMessage='{domain} is part of the decentralized social network powered by {mastodon}.' values={{ domain: <strong>{domain}</strong>, mastodon: <a href='https://joinmastodon.org' target='_blank'>Mastodon</a> }} /> </div> - <img src={server.get('thumbnail')} alt={server.get('title')} className='server-banner__hero' /> + <Image blurhash={server.getIn(['thumbnail', 'blurhash'])} src={server.getIn(['thumbnail', 'url'])} className='server-banner__hero' /> <div className='server-banner__description'> {isLoading ? ( @@ -83,7 +85,7 @@ class ServerBanner extends React.PureComponent { <hr className='spacer' /> - <a className='button button--block button-secondary' href='/about/more' target='_blank'><FormattedMessage id='server_banner.learn_more' defaultMessage='Learn more' /></a> + <Link className='button button--block button-secondary' to='/about'><FormattedMessage id='server_banner.learn_more' defaultMessage='Learn more' /></Link> </div> ); } diff --git a/app/javascript/flavours/glitch/components/skeleton.js b/app/javascript/flavours/glitch/components/skeleton.js index 09093e99c..6a17ffb26 100644 --- a/app/javascript/flavours/glitch/components/skeleton.js +++ b/app/javascript/flavours/glitch/components/skeleton.js @@ -4,8 +4,8 @@ import PropTypes from 'prop-types'; const Skeleton = ({ width, height }) => <span className='skeleton' style={{ width, height }}>‌</span>; Skeleton.propTypes = { - width: PropTypes.number, - height: PropTypes.number, + width: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), + height: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), }; export default Skeleton; diff --git a/app/javascript/flavours/glitch/components/status_action_bar.js b/app/javascript/flavours/glitch/components/status_action_bar.js index deb9cfc15..b260b5bca 100644 --- a/app/javascript/flavours/glitch/components/status_action_bar.js +++ b/app/javascript/flavours/glitch/components/status_action_bar.js @@ -242,7 +242,7 @@ class StatusActionBar extends ImmutablePureComponent { } if (writtenByMe) { - // menu.push({ text: intl.formatMessage(messages.edit), action: this.handleEditClick }); + menu.push({ text: intl.formatMessage(messages.edit), action: this.handleEditClick }); menu.push({ text: intl.formatMessage(messages.delete), action: this.handleDeleteClick }); menu.push({ text: intl.formatMessage(messages.redraft), action: this.handleRedraftClick }); } else { diff --git a/app/javascript/flavours/glitch/components/status_content.js b/app/javascript/flavours/glitch/components/status_content.js index fe0d4c043..61788f350 100644 --- a/app/javascript/flavours/glitch/components/status_content.js +++ b/app/javascript/flavours/glitch/components/status_content.js @@ -124,6 +124,9 @@ export default class StatusContent extends React.PureComponent { link.setAttribute('title', link.href); link.classList.add('unhandled-link'); + link.setAttribute('target', '_blank'); + link.setAttribute('rel', 'noopener nofollow noreferrer'); + try { if (tagLinks && isLinkMisleading(link)) { // Add a tag besides the link to display its origin @@ -149,9 +152,6 @@ export default class StatusContent extends React.PureComponent { if (tagLinks && e instanceof TypeError) link.removeAttribute('href'); } } - - link.setAttribute('target', '_blank'); - link.setAttribute('rel', 'noopener noreferrer'); } } diff --git a/app/javascript/flavours/glitch/containers/mastodon.js b/app/javascript/flavours/glitch/containers/mastodon.js index bc0311293..cf870102b 100644 --- a/app/javascript/flavours/glitch/containers/mastodon.js +++ b/app/javascript/flavours/glitch/containers/mastodon.js @@ -1,22 +1,25 @@ -import React from 'react'; -import { Provider } from 'react-redux'; import PropTypes from 'prop-types'; -import configureStore from 'flavours/glitch/store/configureStore'; +import React from 'react'; +import { Helmet } from 'react-helmet'; +import { IntlProvider, addLocaleData } from 'react-intl'; +import { Provider as ReduxProvider } from 'react-redux'; import { BrowserRouter, Route } from 'react-router-dom'; import { ScrollContext } from 'react-router-scroll-4'; +import configureStore from 'flavours/glitch/store/configureStore'; import UI from 'flavours/glitch/features/ui'; import { fetchCustomEmojis } from 'flavours/glitch/actions/custom_emojis'; import { hydrateStore } from 'flavours/glitch/actions/store'; -import { connectUserStream } from 'flavours/glitch/actions/streaming'; import { checkDeprecatedLocalSettings } from 'flavours/glitch/actions/local_settings'; -import { IntlProvider, addLocaleData } from 'react-intl'; -import { getLocale } from 'locales'; -import initialState from 'flavours/glitch/initial_state'; +import { connectUserStream } from 'flavours/glitch/actions/streaming'; import ErrorBoundary from 'flavours/glitch/components/error_boundary'; +import initialState, { title as siteTitle } from 'flavours/glitch/initial_state'; +import { getLocale } from 'locales'; const { localeData, messages } = getLocale(); addLocaleData(localeData); +const title = process.env.NODE_ENV === 'production' ? siteTitle : `${siteTitle} (Dev)`; + export const store = configureStore(); const hydrateAction = hydrateStore(initialState); store.dispatch(hydrateAction); @@ -78,15 +81,17 @@ export default class Mastodon extends React.PureComponent { return ( <IntlProvider locale={locale} messages={messages}> - <Provider store={store}> + <ReduxProvider store={store}> <ErrorBoundary> - <BrowserRouter basename='/web'> + <BrowserRouter> <ScrollContext shouldUpdateScroll={this.shouldUpdateScroll}> <Route path='/' component={UI} /> </ScrollContext> </BrowserRouter> + + <Helmet defaultTitle={title} titleTemplate={`%s - ${title}`} /> </ErrorBoundary> - </Provider> + </ReduxProvider> </IntlProvider> ); } diff --git a/app/javascript/flavours/glitch/extra_polyfills.js b/app/javascript/flavours/glitch/extra_polyfills.js index 3acc55abd..0d45c23b0 100644 --- a/app/javascript/flavours/glitch/extra_polyfills.js +++ b/app/javascript/flavours/glitch/extra_polyfills.js @@ -1,3 +1,4 @@ +import 'abortcontroller-polyfill/dist/abortcontroller-polyfill-only'; import 'intersection-observer'; import 'requestidlecallback'; import objectFitImages from 'object-fit-images'; diff --git a/app/javascript/flavours/glitch/features/about/index.js b/app/javascript/flavours/glitch/features/about/index.js new file mode 100644 index 000000000..3d26c59bc --- /dev/null +++ b/app/javascript/flavours/glitch/features/about/index.js @@ -0,0 +1,222 @@ +import React from 'react'; +import ImmutablePropTypes from 'react-immutable-proptypes'; +import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; +import { connect } from 'react-redux'; +import PropTypes from 'prop-types'; +import Column from 'flavours/glitch/components/column'; +import LinkFooter from 'flavours/glitch/features/ui/components/link_footer'; +import { Helmet } from 'react-helmet'; +import { fetchServer, fetchExtendedDescription, fetchDomainBlocks } from 'flavours/glitch/actions/server'; +import Account from 'flavours/glitch/containers/account_container'; +import Skeleton from 'flavours/glitch/components/skeleton'; +import Icon from 'flavours/glitch/components/icon'; +import classNames from 'classnames'; +import Image from 'flavours/glitch/components/image'; + +const messages = defineMessages({ + title: { id: 'column.about', defaultMessage: 'About' }, + rules: { id: 'about.rules', defaultMessage: 'Server rules' }, + blocks: { id: 'about.blocks', defaultMessage: 'Moderated servers' }, + silenced: { id: 'about.domain_blocks.silenced.title', defaultMessage: 'Limited' }, + silencedExplanation: { id: 'about.domain_blocks.silenced.explanation', defaultMessage: 'You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.' }, + suspended: { id: 'about.domain_blocks.suspended.title', defaultMessage: 'Suspended' }, + suspendedExplanation: { id: 'about.domain_blocks.suspended.explanation', defaultMessage: 'No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.' }, +}); + +const severityMessages = { + silence: { + title: messages.silenced, + explanation: messages.silencedExplanation, + }, + + suspend: { + title: messages.suspended, + explanation: messages.suspendedExplanation, + }, +}; + +const mapStateToProps = state => ({ + server: state.getIn(['server', 'server']), + extendedDescription: state.getIn(['server', 'extendedDescription']), + domainBlocks: state.getIn(['server', 'domainBlocks']), +}); + +class Section extends React.PureComponent { + + static propTypes = { + title: PropTypes.string, + children: PropTypes.node, + open: PropTypes.bool, + onOpen: PropTypes.func, + }; + + state = { + collapsed: !this.props.open, + }; + + handleClick = () => { + const { onOpen } = this.props; + const { collapsed } = this.state; + + this.setState({ collapsed: !collapsed }, () => onOpen && onOpen()); + } + + render () { + const { title, children } = this.props; + const { collapsed } = this.state; + + return ( + <div className={classNames('about__section', { active: !collapsed })}> + <div className='about__section__title' role='button' tabIndex='0' onClick={this.handleClick}> + <Icon id={collapsed ? 'chevron-right' : 'chevron-down'} fixedWidth /> {title} + </div> + + {!collapsed && ( + <div className='about__section__body'>{children}</div> + )} + </div> + ); + } + +} + +export default @connect(mapStateToProps) +@injectIntl +class About extends React.PureComponent { + + static propTypes = { + server: ImmutablePropTypes.map, + extendedDescription: ImmutablePropTypes.map, + domainBlocks: ImmutablePropTypes.contains({ + isLoading: PropTypes.bool, + isAvailable: PropTypes.bool, + items: ImmutablePropTypes.list, + }), + dispatch: PropTypes.func.isRequired, + intl: PropTypes.object.isRequired, + multiColumn: PropTypes.bool, + }; + + componentDidMount () { + const { dispatch } = this.props; + dispatch(fetchServer()); + dispatch(fetchExtendedDescription()); + } + + handleDomainBlocksOpen = () => { + const { dispatch } = this.props; + dispatch(fetchDomainBlocks()); + } + + render () { + const { multiColumn, intl, server, extendedDescription, domainBlocks } = this.props; + const isLoading = server.get('isLoading'); + + return ( + <Column bindToDocument={!multiColumn} label={intl.formatMessage(messages.title)}> + <div className='scrollable about'> + <div className='about__header'> + <Image blurhash={server.getIn(['thumbnail', 'blurhash'])} src={server.getIn(['thumbnail', 'url'])} srcSet={server.getIn(['thumbnail', 'versions'])?.map((value, key) => `${value} ${key.replace('@', '')}`).join(', ')} className='about__header__hero' /> + <h1>{isLoading ? <Skeleton width='10ch' /> : server.get('domain')}</h1> + <p><FormattedMessage id='about.powered_by' defaultMessage='Decentralized social media powered by {mastodon}' values={{ mastodon: <a href='https://joinmastodon.org' className='about__mail' target='_blank'>Mastodon</a> }} /></p> + </div> + + <div className='about__meta'> + <div className='about__meta__column'> + <h4><FormattedMessage id='server_banner.administered_by' defaultMessage='Administered by:' /></h4> + + <Account id={server.getIn(['contact', 'account', 'id'])} /> + </div> + + <hr className='about__meta__divider' /> + + <div className='about__meta__column'> + <h4><FormattedMessage id='about.contact' defaultMessage='Contact:' /></h4> + + {isLoading ? <Skeleton width='10ch' /> : <a className='about__mail' href={`mailto:${server.getIn(['contact', 'email'])}`}>{server.getIn(['contact', 'email'])}</a>} + </div> + </div> + + <Section open title={intl.formatMessage(messages.title)}> + {extendedDescription.get('isLoading') ? ( + <> + <Skeleton width='100%' /> + <br /> + <Skeleton width='100%' /> + <br /> + <Skeleton width='100%' /> + <br /> + <Skeleton width='70%' /> + </> + ) : (extendedDescription.get('content')?.length > 0 ? ( + <div + className='prose' + dangerouslySetInnerHTML={{ __html: extendedDescription.get('content') }} + /> + ) : ( + <p><FormattedMessage id='about.not_available' defaultMessage='This information has not been made available on this server.' /></p> + ))} + </Section> + + <Section title={intl.formatMessage(messages.rules)}> + {!isLoading && (server.get('rules').isEmpty() ? ( + <p><FormattedMessage id='about.not_available' defaultMessage='This information has not been made available on this server.' /></p> + ) : ( + <ol className='rules-list'> + {server.get('rules').map(rule => ( + <li key={rule.get('id')}> + <span className='rules-list__text'>{rule.get('text')}</span> + </li> + ))} + </ol> + ))} + </Section> + + <Section title={intl.formatMessage(messages.blocks)} onOpen={this.handleDomainBlocksOpen}> + {domainBlocks.get('isLoading') ? ( + <> + <Skeleton width='100%' /> + <br /> + <Skeleton width='70%' /> + </> + ) : (domainBlocks.get('isAvailable') ? ( + <> + <p><FormattedMessage id='about.domain_blocks.preamble' defaultMessage='Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.' /></p> + + <table className='about__domain-blocks'> + <thead> + <tr> + <th><FormattedMessage id='about.domain_blocks.domain' defaultMessage='Domain' /></th> + <th><FormattedMessage id='about.domain_blocks.severity' defaultMessage='Severity' /></th> + <th><FormattedMessage id='about.domain_blocks.comment' defaultMessage='Reason' /></th> + </tr> + </thead> + + <tbody> + {domainBlocks.get('items').map(block => ( + <tr key={block.get('domain')}> + <td><span title={`SHA-256: ${block.get('digest')}`}>{block.get('domain')}</span></td> + <td><span title={intl.formatMessage(severityMessages[block.get('severity')].explanation)}>{intl.formatMessage(severityMessages[block.get('severity')].title)}</span></td> + <td>{block.get('comment')}</td> + </tr> + ))} + </tbody> + </table> + </> + ) : ( + <p><FormattedMessage id='about.not_available' defaultMessage='This information has not been made available on this server.' /></p> + ))} + </Section> + + <LinkFooter /> + </div> + + <Helmet> + <title>{intl.formatMessage(messages.title)}</title> + <meta name='robots' content='all' /> + </Helmet> + </Column> + ); + } + +} diff --git a/app/javascript/flavours/glitch/features/account/components/featured_tags.js b/app/javascript/flavours/glitch/features/account/components/featured_tags.js new file mode 100644 index 000000000..d646b08b2 --- /dev/null +++ b/app/javascript/flavours/glitch/features/account/components/featured_tags.js @@ -0,0 +1,53 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import ImmutablePropTypes from 'react-immutable-proptypes'; +import ImmutablePureComponent from 'react-immutable-pure-component'; +import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; +import Hashtag from 'flavours/glitch/components/hashtag'; + +const messages = defineMessages({ + lastStatusAt: { id: 'account.featured_tags.last_status_at', defaultMessage: 'Last post on {date}' }, + empty: { id: 'account.featured_tags.last_status_never', defaultMessage: 'No posts' }, +}); + +export default @injectIntl +class FeaturedTags extends ImmutablePureComponent { + + static contextTypes = { + router: PropTypes.object, + }; + + static propTypes = { + account: ImmutablePropTypes.map, + featuredTags: ImmutablePropTypes.list, + tagged: PropTypes.string, + intl: PropTypes.object.isRequired, + }; + + render () { + const { account, featuredTags, intl } = this.props; + + if (!account || account.get('suspended') || featuredTags.isEmpty()) { + return null; + } + + return ( + <div className='getting-started__trends'> + <h4><FormattedMessage id='account.featured_tags.title' defaultMessage="{name}'s featured hashtags" values={{ name: <bdi dangerouslySetInnerHTML={{ __html: account.get('display_name_html') }} /> }} /></h4> + + {featuredTags.take(3).map(featuredTag => ( + <Hashtag + key={featuredTag.get('name')} + name={featuredTag.get('name')} + href={featuredTag.get('url')} + to={`/@${account.get('acct')}/tagged/${featuredTag.get('name')}`} + uses={featuredTag.get('statuses_count')} + withGraph={false} + description={((featuredTag.get('statuses_count') * 1) > 0) ? intl.formatMessage(messages.lastStatusAt, { date: intl.formatDate(featuredTag.get('last_status_at'), { month: 'short', day: '2-digit' }) }) : intl.formatMessage(messages.empty)} + /> + ))} + </div> + ); + } + +} diff --git a/app/javascript/flavours/glitch/features/account/components/header.js b/app/javascript/flavours/glitch/features/account/components/header.js index 0f0e40268..cf1494f05 100644 --- a/app/javascript/flavours/glitch/features/account/components/header.js +++ b/app/javascript/flavours/glitch/features/account/components/header.js @@ -3,7 +3,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes'; import PropTypes from 'prop-types'; import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import ImmutablePureComponent from 'react-immutable-pure-component'; -import { autoPlayGif, me, title, domain } from 'flavours/glitch/initial_state'; +import { autoPlayGif, me, domain } from 'flavours/glitch/initial_state'; import { preferencesLink, profileLink, accountAdminLink } from 'flavours/glitch/utils/backend_links'; import classNames from 'classnames'; import Icon from 'flavours/glitch/components/icon'; @@ -19,7 +19,7 @@ import { Helmet } from 'react-helmet'; const messages = defineMessages({ unfollow: { id: 'account.unfollow', defaultMessage: 'Unfollow' }, follow: { id: 'account.follow', defaultMessage: 'Follow' }, - cancel_follow_request: { id: 'account.cancel_follow_request', defaultMessage: 'Cancel follow request' }, + cancel_follow_request: { id: 'account.cancel_follow_request', defaultMessage: 'Withdraw follow request' }, requested: { id: 'account.requested', defaultMessage: 'Awaiting approval. Click to cancel follow request' }, unblock: { id: 'account.unblock', defaultMessage: 'Unblock @{name}' }, edit_profile: { id: 'account.edit_profile', defaultMessage: 'Edit profile' }, @@ -273,7 +273,9 @@ class Header extends ImmutablePureComponent { const content = { __html: account.get('note_emojified') }; const displayNameHtml = { __html: account.get('display_name_html') }; const fields = account.get('fields'); - const acct = account.get('acct').indexOf('@') === -1 && domain ? `${account.get('acct')}@${domain}` : account.get('acct'); + const isLocal = account.get('acct').indexOf('@') === -1; + const acct = isLocal && domain ? `${account.get('acct')}@${domain}` : account.get('acct'); + const isIndexable = !account.get('noindex'); let badge; @@ -352,7 +354,8 @@ class Header extends ImmutablePureComponent { </div> <Helmet> - <title>{titleFromAccount(account)} - {title}</title> + <title>{titleFromAccount(account)}</title> + <meta name='robots' content={(isLocal && isIndexable) ? 'all' : 'noindex'} /> </Helmet> </div> ); diff --git a/app/javascript/flavours/glitch/features/account/containers/featured_tags_container.js b/app/javascript/flavours/glitch/features/account/containers/featured_tags_container.js new file mode 100644 index 000000000..6f0b06941 --- /dev/null +++ b/app/javascript/flavours/glitch/features/account/containers/featured_tags_container.js @@ -0,0 +1,15 @@ +import { connect } from 'react-redux'; +import FeaturedTags from '../components/featured_tags'; +import { makeGetAccount } from 'flavours/glitch/selectors'; +import { List as ImmutableList } from 'immutable'; + +const mapStateToProps = () => { + const getAccount = makeGetAccount(); + + return (state, { accountId }) => ({ + account: getAccount(state, accountId), + featuredTags: state.getIn(['user_lists', 'featured_tags', accountId, 'items'], ImmutableList()), + }); +}; + +export default connect(mapStateToProps)(FeaturedTags); diff --git a/app/javascript/flavours/glitch/features/account/navigation.js b/app/javascript/flavours/glitch/features/account/navigation.js new file mode 100644 index 000000000..edae38ce5 --- /dev/null +++ b/app/javascript/flavours/glitch/features/account/navigation.js @@ -0,0 +1,52 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { connect } from 'react-redux'; +import FeaturedTags from 'flavours/glitch/features/account/containers/featured_tags_container'; +import { normalizeForLookup } from 'flavours/glitch/reducers/accounts_map'; + +const mapStateToProps = (state, { match: { params: { acct } } }) => { + const accountId = state.getIn(['accounts_map', normalizeForLookup(acct)]); + + if (!accountId) { + return { + isLoading: true, + }; + } + + return { + accountId, + isLoading: false, + }; +}; + +export default @connect(mapStateToProps) +class AccountNavigation extends React.PureComponent { + + static propTypes = { + match: PropTypes.shape({ + params: PropTypes.shape({ + acct: PropTypes.string, + tagged: PropTypes.string, + }).isRequired, + }).isRequired, + + accountId: PropTypes.string, + isLoading: PropTypes.bool, + }; + + render () { + const { accountId, isLoading, match: { params: { tagged } } } = this.props; + + if (isLoading) { + return null; + } + + return ( + <> + <div className='flex-spacer' /> + <FeaturedTags accountId={accountId} tagged={tagged} /> + </> + ); + } + +} diff --git a/app/javascript/flavours/glitch/features/account_gallery/index.js b/app/javascript/flavours/glitch/features/account_gallery/index.js index 8df1bf4ca..638224bc0 100644 --- a/app/javascript/flavours/glitch/features/account_gallery/index.js +++ b/app/javascript/flavours/glitch/features/account_gallery/index.js @@ -15,9 +15,10 @@ import ScrollContainer from 'flavours/glitch/containers/scroll_container'; import LoadMore from 'flavours/glitch/components/load_more'; import MissingIndicator from 'flavours/glitch/components/missing_indicator'; import { openModal } from 'flavours/glitch/actions/modal'; +import { normalizeForLookup } from 'flavours/glitch/reducers/accounts_map'; const mapStateToProps = (state, { params: { acct, id } }) => { - const accountId = id || state.getIn(['accounts_map', acct]); + const accountId = id || state.getIn(['accounts_map', normalizeForLookup(acct)]); if (!accountId) { return { diff --git a/app/javascript/flavours/glitch/features/account_timeline/containers/header_container.js b/app/javascript/flavours/glitch/features/account_timeline/containers/header_container.js index c1577e170..e6d8bb3bc 100644 --- a/app/javascript/flavours/glitch/features/account_timeline/containers/header_container.js +++ b/app/javascript/flavours/glitch/features/account_timeline/containers/header_container.js @@ -24,6 +24,7 @@ import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import { unfollowModal } from 'flavours/glitch/initial_state'; const messages = defineMessages({ + cancelFollowRequestConfirm: { id: 'confirmations.cancel_follow_request.confirm', defaultMessage: 'Withdraw request' }, unfollowConfirm: { id: 'confirmations.unfollow.confirm', defaultMessage: 'Unfollow' }, blockDomainConfirm: { id: 'confirmations.domain_block.confirm', defaultMessage: 'Hide entire domain' }, }); @@ -43,7 +44,7 @@ const makeMapStateToProps = () => { const mapDispatchToProps = (dispatch, { intl }) => ({ onFollow (account) { - if (account.getIn(['relationship', 'following']) || account.getIn(['relationship', 'requested'])) { + if (account.getIn(['relationship', 'following'])) { if (unfollowModal) { dispatch(openModal('CONFIRM', { message: <FormattedMessage id='confirmations.unfollow.message' defaultMessage='Are you sure you want to unfollow {name}?' values={{ name: <strong>@{account.get('acct')}</strong> }} />, @@ -53,6 +54,14 @@ const mapDispatchToProps = (dispatch, { intl }) => ({ } else { dispatch(unfollowAccount(account.get('id'))); } + } else if (account.getIn(['relationship', 'requested'])) { + if (unfollowModal) { + dispatch(openModal('CONFIRM', { + message: <FormattedMessage id='confirmations.cancel_follow_request.message' defaultMessage='Are you sure you want to withdraw your request to follow {name}?' values={{ name: <strong>@{account.get('acct')}</strong> }} />, + confirm: intl.formatMessage(messages.cancelFollowRequestConfirm), + onConfirm: () => dispatch(unfollowAccount(account.get('id'))), + })); + } } else { dispatch(followAccount(account.get('id'))); } diff --git a/app/javascript/flavours/glitch/features/account_timeline/index.js b/app/javascript/flavours/glitch/features/account_timeline/index.js index 68d558e66..b735af0ac 100644 --- a/app/javascript/flavours/glitch/features/account_timeline/index.js +++ b/app/javascript/flavours/glitch/features/account_timeline/index.js @@ -17,19 +17,22 @@ import MissingIndicator from 'flavours/glitch/components/missing_indicator'; import TimelineHint from 'flavours/glitch/components/timeline_hint'; import LimitedAccountHint from './components/limited_account_hint'; import { getAccountHidden } from 'flavours/glitch/selectors'; +import { normalizeForLookup } from 'flavours/glitch/reducers/accounts_map'; +import { fetchFeaturedTags } from '../../actions/featured_tags'; const emptyList = ImmutableList(); -const mapStateToProps = (state, { params: { acct, id }, withReplies = false }) => { - const accountId = id || state.getIn(['accounts_map', acct]); +const mapStateToProps = (state, { params: { acct, id, tagged }, withReplies = false }) => { + const accountId = id || state.getIn(['accounts_map', normalizeForLookup(acct)]); if (!accountId) { return { isLoading: true, + statusIds: emptyList, }; } - const path = withReplies ? `${accountId}:with_replies` : accountId; + const path = withReplies ? `${accountId}:with_replies` : `${accountId}${tagged ? `:${tagged}` : ''}`; return { accountId, @@ -37,7 +40,7 @@ const mapStateToProps = (state, { params: { acct, id }, withReplies = false }) = remoteUrl: state.getIn(['accounts', accountId, 'url']), isAccount: !!state.getIn(['accounts', accountId]), statusIds: state.getIn(['timelines', `account:${path}`, 'items'], ImmutableList()), - featuredStatusIds: withReplies ? ImmutableList() : state.getIn(['timelines', `account:${accountId}:pinned`, 'items'], ImmutableList()), + featuredStatusIds: withReplies ? ImmutableList() : state.getIn(['timelines', `account:${accountId}:pinned${tagged ? `:${tagged}` : ''}`, 'items'], ImmutableList()), isLoading: state.getIn(['timelines', `account:${path}`, 'isLoading']), hasMore: state.getIn(['timelines', `account:${path}`, 'hasMore']), suspended: state.getIn(['accounts', accountId, 'suspended'], false), @@ -60,6 +63,7 @@ class AccountTimeline extends ImmutablePureComponent { params: PropTypes.shape({ acct: PropTypes.string, id: PropTypes.string, + tagged: PropTypes.string, }).isRequired, accountId: PropTypes.string, dispatch: PropTypes.func.isRequired, @@ -77,14 +81,16 @@ class AccountTimeline extends ImmutablePureComponent { }; _load () { - const { accountId, withReplies, dispatch } = this.props; + const { accountId, withReplies, params: { tagged }, dispatch } = this.props; dispatch(fetchAccount(accountId)); if (!withReplies) { - dispatch(expandAccountFeaturedTimeline(accountId)); + dispatch(expandAccountFeaturedTimeline(accountId, { tagged })); } - dispatch(expandAccountTimeline(accountId, { withReplies })); + + dispatch(fetchFeaturedTags(accountId)); + dispatch(expandAccountTimeline(accountId, { withReplies, tagged })); } componentDidMount () { @@ -98,12 +104,17 @@ class AccountTimeline extends ImmutablePureComponent { } componentDidUpdate (prevProps) { - const { params: { acct }, accountId, dispatch } = this.props; + const { params: { acct, tagged }, accountId, withReplies, dispatch } = this.props; if (prevProps.accountId !== accountId && accountId) { this._load(); } else if (prevProps.params.acct !== acct) { dispatch(lookupAccount(acct)); + } else if (prevProps.params.tagged !== tagged) { + if (!withReplies) { + dispatch(expandAccountFeaturedTimeline(accountId, { tagged })); + } + dispatch(expandAccountTimeline(accountId, { withReplies, tagged })); } } @@ -126,7 +137,7 @@ class AccountTimeline extends ImmutablePureComponent { } handleLoadMore = maxId => { - this.props.dispatch(expandAccountTimeline(this.props.accountId, { maxId, withReplies: this.props.withReplies })); + this.props.dispatch(expandAccountTimeline(this.props.accountId, { maxId, withReplies: this.props.withReplies, tagged: this.props.params.tagged })); } setRef = c => { @@ -136,19 +147,17 @@ class AccountTimeline extends ImmutablePureComponent { render () { const { accountId, statusIds, featuredStatusIds, isLoading, hasMore, suspended, isAccount, hidden, multiColumn, remote, remoteUrl } = this.props; - if (!isAccount) { + if (isLoading && statusIds.isEmpty()) { return ( <Column> - <ColumnBackButton multiColumn={multiColumn} /> - <MissingIndicator /> + <LoadingIndicator /> </Column> ); - } - - if (!statusIds && isLoading) { + } else if (!isLoading && !isAccount) { return ( <Column> - <LoadingIndicator /> + <ColumnBackButton multiColumn={multiColumn} /> + <MissingIndicator /> </Column> ); } @@ -174,7 +183,7 @@ class AccountTimeline extends ImmutablePureComponent { <ProfileColumnHeader onClick={this.handleHeaderClick} multiColumn={multiColumn} /> <StatusList - prepend={<HeaderContainer accountId={this.props.accountId} hideTabs={forceEmptyState} />} + prepend={<HeaderContainer accountId={this.props.accountId} hideTabs={forceEmptyState} tagged={this.props.params.tagged} />} alwaysPrepend append={remoteMessage} scrollKey='account_timeline' diff --git a/app/javascript/flavours/glitch/features/bookmarked_statuses/index.js b/app/javascript/flavours/glitch/features/bookmarked_statuses/index.js index ada8fb068..8978ac5fc 100644 --- a/app/javascript/flavours/glitch/features/bookmarked_statuses/index.js +++ b/app/javascript/flavours/glitch/features/bookmarked_statuses/index.js @@ -1,15 +1,16 @@ -import React from 'react'; -import { connect } from 'react-redux'; +import { debounce } from 'lodash'; import PropTypes from 'prop-types'; +import React from 'react'; +import { Helmet } from 'react-helmet'; +import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import ImmutablePropTypes from 'react-immutable-proptypes'; -import { debounce } from 'lodash'; +import ImmutablePureComponent from 'react-immutable-pure-component'; +import { connect } from 'react-redux'; import { fetchBookmarkedStatuses, expandBookmarkedStatuses } from 'flavours/glitch/actions/bookmarks'; -import Column from 'flavours/glitch/features/ui/components/column'; -import ColumnHeader from 'flavours/glitch/components/column_header'; import { addColumn, removeColumn, moveColumn } from 'flavours/glitch/actions/columns'; +import ColumnHeader from 'flavours/glitch/components/column_header'; import StatusList from 'flavours/glitch/components/status_list'; -import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; -import ImmutablePureComponent from 'react-immutable-pure-component'; +import Column from 'flavours/glitch/features/ui/components/column'; const messages = defineMessages({ heading: { id: 'column.bookmarks', defaultMessage: 'Bookmarks' }, @@ -95,6 +96,11 @@ class Bookmarks extends ImmutablePureComponent { emptyMessage={emptyMessage} bindToDocument={!multiColumn} /> + + <Helmet> + <title>{intl.formatMessage(messages.heading)}</title> + <meta name='robots' content='noindex' /> + </Helmet> </Column> ); } diff --git a/app/javascript/flavours/glitch/features/closed_registrations_modal/index.js b/app/javascript/flavours/glitch/features/closed_registrations_modal/index.js new file mode 100644 index 000000000..cb91636cb --- /dev/null +++ b/app/javascript/flavours/glitch/features/closed_registrations_modal/index.js @@ -0,0 +1,75 @@ +import React from 'react'; +import { connect } from 'react-redux'; +import { FormattedMessage } from 'react-intl'; +import ImmutablePureComponent from 'react-immutable-pure-component'; +import { domain } from 'flavours/glitch/initial_state'; +import { fetchServer } from 'flavours/glitch/actions/server'; + +const mapStateToProps = state => ({ + message: state.getIn(['server', 'server', 'registrations', 'message']), +}); + +export default @connect(mapStateToProps) +class ClosedRegistrationsModal extends ImmutablePureComponent { + + componentDidMount () { + const { dispatch } = this.props; + dispatch(fetchServer()); + } + + render () { + let closedRegistrationsMessage; + + if (this.props.message) { + closedRegistrationsMessage = ( + <p + className='prose' + dangerouslySetInnerHTML={{ __html: this.props.message }} + /> + ); + } else { + closedRegistrationsMessage = ( + <p className='prose'> + <FormattedMessage + id='closed_registrations_modal.description' + defaultMessage='Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.' + values={{ domain: <strong>{domain}</strong> }} + /> + </p> + ); + } + + return ( + <div className='modal-root__modal interaction-modal'> + <div className='interaction-modal__lead'> + <h3><FormattedMessage id='closed_registrations_modal.title' defaultMessage='Signing up on Mastodon' /></h3> + <p> + <FormattedMessage + id='closed_registrations_modal.preamble' + defaultMessage='Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!' + /> + </p> + </div> + + <div className='interaction-modal__choices'> + <div className='interaction-modal__choices__choice'> + <h3><FormattedMessage id='interaction_modal.on_this_server' defaultMessage='On this server' /></h3> + {closedRegistrationsMessage} + </div> + + <div className='interaction-modal__choices__choice'> + <h3><FormattedMessage id='interaction_modal.on_another_server' defaultMessage='On a different server' /></h3> + <p className='prose'> + <FormattedMessage + id='closed_registrations.other_server_instructions' + defaultMessage='Since Mastodon is decentralized, you can create an account on another server and still interact with this one.' + /> + </p> + <a href='https://joinmastodon.org/servers' className='button button--block'><FormattedMessage id='closed_registrations_modal.find_another_server' defaultMessage='Find another server' /></a> + </div> + </div> + </div> + ); + } + +}; diff --git a/app/javascript/flavours/glitch/features/community_timeline/index.js b/app/javascript/flavours/glitch/features/community_timeline/index.js index 5ee46ca3b..67bf54875 100644 --- a/app/javascript/flavours/glitch/features/community_timeline/index.js +++ b/app/javascript/flavours/glitch/features/community_timeline/index.js @@ -10,7 +10,8 @@ import { addColumn, removeColumn, moveColumn } from 'flavours/glitch/actions/col import ColumnSettingsContainer from './containers/column_settings_container'; import { connectCommunityStream } from 'flavours/glitch/actions/streaming'; import { Helmet } from 'react-helmet'; -import { title } from 'flavours/glitch/initial_state'; +import { domain } from 'flavours/glitch/initial_state'; +import DismissableBanner from 'flavours/glitch/components/dismissable_banner'; const messages = defineMessages({ title: { id: 'column.community', defaultMessage: 'Local timeline' }, @@ -138,6 +139,10 @@ class CommunityTimeline extends React.PureComponent { <ColumnSettingsContainer columnId={columnId} /> </ColumnHeader> + <DismissableBanner id='community_timeline'> + <FormattedMessage id='dismissable_banner.community_timeline' defaultMessage='These are the most recent public posts from people whose accounts are hosted by {domain}.' values={{ domain }} /> + </DismissableBanner> + <StatusListContainer trackScroll={!pinned} scrollKey={`community_timeline-${columnId}`} @@ -149,7 +154,8 @@ class CommunityTimeline extends React.PureComponent { /> <Helmet> - <title>{intl.formatMessage(messages.title)} - {title}</title> + <title>{intl.formatMessage(messages.title)}</title> + <meta name='robots' content='noindex' /> </Helmet> </Column> ); diff --git a/app/javascript/flavours/glitch/features/compose/components/search.js b/app/javascript/flavours/glitch/features/compose/components/search.js index a59418e46..326fe5b70 100644 --- a/app/javascript/flavours/glitch/features/compose/components/search.js +++ b/app/javascript/flavours/glitch/features/compose/components/search.js @@ -21,6 +21,7 @@ import Motion from '../../ui/util/optional_motion'; const messages = defineMessages({ placeholder: { id: 'search.placeholder', defaultMessage: 'Search' }, + placeholderSignedIn: { id: 'search.search_or_paste', defaultMessage: 'Search or paste URL' }, }); class SearchPopout extends React.PureComponent { @@ -62,6 +63,7 @@ class Search extends React.PureComponent { static contextTypes = { router: PropTypes.object.isRequired, + identity: PropTypes.object.isRequired, }; static propTypes = { @@ -137,6 +139,7 @@ class Search extends React.PureComponent { render () { const { intl, value, submitted } = this.props; const { expanded } = this.state; + const { signedIn } = this.context.identity; const hasValue = value.length > 0 || submitted; return ( @@ -147,7 +150,7 @@ class Search extends React.PureComponent { ref={this.setRef} className='search__input' type='text' - placeholder={intl.formatMessage(messages.placeholder)} + placeholder={intl.formatMessage(signedIn ? messages.placeholderSignedIn : messages.placeholder)} value={value || ''} onChange={this.handleChange} onKeyUp={this.handleKeyUp} diff --git a/app/javascript/flavours/glitch/features/compose/components/upload_form.js b/app/javascript/flavours/glitch/features/compose/components/upload_form.js index 43039c674..35880ddcc 100644 --- a/app/javascript/flavours/glitch/features/compose/components/upload_form.js +++ b/app/javascript/flavours/glitch/features/compose/components/upload_form.js @@ -4,7 +4,6 @@ import UploadProgressContainer from '../containers/upload_progress_container'; import ImmutablePureComponent from 'react-immutable-pure-component'; import UploadContainer from '../containers/upload_container'; import SensitiveButtonContainer from '../containers/sensitive_button_container'; -import { FormattedMessage } from 'react-intl'; export default class UploadForm extends ImmutablePureComponent { static propTypes = { @@ -16,7 +15,7 @@ export default class UploadForm extends ImmutablePureComponent { return ( <div className='composer--upload_form'> - <UploadProgressContainer icon='upload' message={<FormattedMessage id='upload_progress.label' defaultMessage='Uploading…' />} /> + <UploadProgressContainer /> {mediaIds.size > 0 && ( <div className='content'> diff --git a/app/javascript/flavours/glitch/features/compose/components/upload_progress.js b/app/javascript/flavours/glitch/features/compose/components/upload_progress.js index 8896bbffd..c7c33c418 100644 --- a/app/javascript/flavours/glitch/features/compose/components/upload_progress.js +++ b/app/javascript/flavours/glitch/features/compose/components/upload_progress.js @@ -3,26 +3,34 @@ import PropTypes from 'prop-types'; import Motion from '../../ui/util/optional_motion'; import spring from 'react-motion/lib/spring'; import Icon from 'flavours/glitch/components/icon'; +import { FormattedMessage } from 'react-intl'; export default class UploadProgress extends React.PureComponent { static propTypes = { active: PropTypes.bool, progress: PropTypes.number, - icon: PropTypes.string.isRequired, - message: PropTypes.node.isRequired, + isProcessing: PropTypes.bool, }; render () { - const { active, progress, icon, message } = this.props; + const { active, progress, isProcessing } = this.props; if (!active) { return null; } + let message; + + if (isProcessing) { + message = <FormattedMessage id='upload_progress.processing' defaultMessage='Processing…' />; + } else { + message = <FormattedMessage id='upload_progress.label' defaultMessage='Uploading…' />; + } + return ( <div className='composer--upload_form--progress'> - <Icon id={icon} /> + <Icon id='upload' /> <div className='message'> {message} diff --git a/app/javascript/flavours/glitch/features/compose/containers/upload_progress_container.js b/app/javascript/flavours/glitch/features/compose/containers/upload_progress_container.js index 0cfee96da..b18c76a43 100644 --- a/app/javascript/flavours/glitch/features/compose/containers/upload_progress_container.js +++ b/app/javascript/flavours/glitch/features/compose/containers/upload_progress_container.js @@ -4,6 +4,7 @@ import UploadProgress from '../components/upload_progress'; const mapStateToProps = state => ({ active: state.getIn(['compose', 'is_uploading']), progress: state.getIn(['compose', 'progress']), + isProcessing: state.getIn(['compose', 'is_processing']), }); export default connect(mapStateToProps)(UploadProgress); diff --git a/app/javascript/flavours/glitch/features/compose/index.js b/app/javascript/flavours/glitch/features/compose/index.js index 567bb3711..8ca378672 100644 --- a/app/javascript/flavours/glitch/features/compose/index.js +++ b/app/javascript/flavours/glitch/features/compose/index.js @@ -14,6 +14,8 @@ import SearchResultsContainer from './containers/search_results_container'; import { me, mascot } from 'flavours/glitch/initial_state'; import { cycleElefriendCompose } from 'flavours/glitch/actions/compose'; import HeaderContainer from './containers/header_container'; +import Column from 'flavours/glitch/components/column'; +import { Helmet } from 'react-helmet'; const messages = defineMessages({ compose: { id: 'navigation_bar.compose', defaultMessage: 'Compose new post' }, @@ -21,7 +23,7 @@ const messages = defineMessages({ const mapStateToProps = (state, ownProps) => ({ elefriend: state.getIn(['compose', 'elefriend']), - showSearch: ownProps.multiColumn ? state.getIn(['search', 'submitted']) && !state.getIn(['search', 'hidden']) : ownProps.isSearchPage, + showSearch: ownProps.multiColumn ? state.getIn(['search', 'submitted']) && !state.getIn(['search', 'hidden']) : false, }); const mapDispatchToProps = (dispatch, { intl }) => ({ @@ -44,7 +46,6 @@ class Compose extends React.PureComponent { static propTypes = { multiColumn: PropTypes.bool, showSearch: PropTypes.bool, - isSearchPage: PropTypes.bool, elefriend: PropTypes.number, onClickElefriend: PropTypes.func, onMount: PropTypes.func, @@ -53,19 +54,11 @@ class Compose extends React.PureComponent { }; componentDidMount () { - const { isSearchPage } = this.props; - - if (!isSearchPage) { - this.props.onMount(); - } + this.props.onMount(); } componentWillUnmount () { - const { isSearchPage } = this.props; - - if (!isSearchPage) { - this.props.onUnmount(); - } + this.props.onUnmount(); } render () { @@ -74,37 +67,49 @@ class Compose extends React.PureComponent { intl, multiColumn, onClickElefriend, - isSearchPage, showSearch, } = this.props; const computedClass = classNames('drawer', `mbstobon-${elefriend}`); - return ( - <div className={computedClass} role='region' aria-label={intl.formatMessage(messages.compose)}> - {multiColumn && <HeaderContainer />} + if (multiColumn) { + return ( + <div className={computedClass} role='region' aria-label={intl.formatMessage(messages.compose)}> + <HeaderContainer /> - {(multiColumn || isSearchPage) && <SearchContainer />} + {multiColumn && <SearchContainer />} - <div className='drawer__pager'> - {!isSearchPage && <div className='drawer__inner'> - <NavigationContainer /> + <div className='drawer__pager'> + <div className='drawer__inner'> + <NavigationContainer /> - <ComposeFormContainer /> + <ComposeFormContainer /> - <div className='drawer__inner__mastodon'> - {mascot ? <img alt='' draggable='false' src={mascot} /> : <button className='mastodon' onClick={onClickElefriend} />} + <div className='drawer__inner__mastodon'> + {mascot ? <img alt='' draggable='false' src={mascot} /> : <button className='mastodon' onClick={onClickElefriend} />} + </div> </div> - </div>} - <Motion defaultStyle={{ x: isSearchPage ? 0 : -100 }} style={{ x: spring(showSearch || isSearchPage ? 0 : -100, { stiffness: 210, damping: 20 }) }}> - {({ x }) => ( - <div className='drawer__inner darker' style={{ transform: `translateX(${x}%)`, visibility: x === -100 ? 'hidden' : 'visible' }}> - <SearchResultsContainer /> - </div> - )} - </Motion> + <Motion defaultStyle={{ x: -100 }} style={{ x: spring(showSearch ? 0 : -100, { stiffness: 210, damping: 20 }) }}> + {({ x }) => ( + <div className='drawer__inner darker' style={{ transform: `translateX(${x}%)`, visibility: x === -100 ? 'hidden' : 'visible' }}> + <SearchResultsContainer /> + </div> + )} + </Motion> + </div> </div> - </div> + ); + } + + return ( + <Column> + <NavigationContainer /> + <ComposeFormContainer /> + + <Helmet> + <meta name='robots' content='noindex' /> + </Helmet> + </Column> ); } diff --git a/app/javascript/flavours/glitch/features/direct_timeline/index.js b/app/javascript/flavours/glitch/features/direct_timeline/index.js index 75ca19d17..d55c63c2b 100644 --- a/app/javascript/flavours/glitch/features/direct_timeline/index.js +++ b/app/javascript/flavours/glitch/features/direct_timeline/index.js @@ -1,15 +1,16 @@ +import PropTypes from 'prop-types'; import React from 'react'; +import { Helmet } from 'react-helmet'; +import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import { connect } from 'react-redux'; -import PropTypes from 'prop-types'; -import StatusListContainer from 'flavours/glitch/features/ui/containers/status_list_container'; +import { addColumn, removeColumn, moveColumn } from 'flavours/glitch/actions/columns'; +import { mountConversations, unmountConversations, expandConversations } from 'flavours/glitch/actions/conversations'; +import { connectDirectStream } from 'flavours/glitch/actions/streaming'; +import { expandDirectTimeline } from 'flavours/glitch/actions/timelines'; import Column from 'flavours/glitch/components/column'; import ColumnHeader from 'flavours/glitch/components/column_header'; -import { expandDirectTimeline } from 'flavours/glitch/actions/timelines'; -import { mountConversations, unmountConversations, expandConversations } from 'flavours/glitch/actions/conversations'; -import { addColumn, removeColumn, moveColumn } from 'flavours/glitch/actions/columns'; -import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; +import StatusListContainer from 'flavours/glitch/features/ui/containers/status_list_container'; import ColumnSettingsContainer from './containers/column_settings_container'; -import { connectDirectStream } from 'flavours/glitch/actions/streaming'; import ConversationsListContainer from './containers/conversations_list_container'; const messages = defineMessages({ @@ -143,6 +144,11 @@ class DirectTimeline extends React.PureComponent { </ColumnHeader> {contents} + + <Helmet> + <title>{intl.formatMessage(messages.title)}</title> + <meta name='robots' content='noindex' /> + </Helmet> </Column> ); } diff --git a/app/javascript/flavours/glitch/features/directory/components/account_card.js b/app/javascript/flavours/glitch/features/directory/components/account_card.js index b6785a5f9..8c344c793 100644 --- a/app/javascript/flavours/glitch/features/directory/components/account_card.js +++ b/app/javascript/flavours/glitch/features/directory/components/account_card.js @@ -24,7 +24,7 @@ import classNames from 'classnames'; const messages = defineMessages({ unfollow: { id: 'account.unfollow', defaultMessage: 'Unfollow' }, follow: { id: 'account.follow', defaultMessage: 'Follow' }, - cancel_follow_request: { id: 'account.cancel_follow_request', defaultMessage: 'Cancel follow request' }, + cancel_follow_request: { id: 'account.cancel_follow_request', defaultMessage: 'Withdraw follow request' }, requested: { id: 'account.requested', defaultMessage: 'Awaiting approval. Click to cancel follow request' }, unblock: { id: 'account.unblock_short', defaultMessage: 'Unblock' }, unmute: { id: 'account.unmute_short', defaultMessage: 'Unmute' }, diff --git a/app/javascript/flavours/glitch/features/directory/index.js b/app/javascript/flavours/glitch/features/directory/index.js index dce8fa4e7..94bcd578c 100644 --- a/app/javascript/flavours/glitch/features/directory/index.js +++ b/app/javascript/flavours/glitch/features/directory/index.js @@ -13,7 +13,6 @@ import RadioButton from 'flavours/glitch/components/radio_button'; import LoadMore from 'flavours/glitch/components/load_more'; import ScrollContainer from 'flavours/glitch/containers/scroll_container'; import LoadingIndicator from 'flavours/glitch/components/loading_indicator'; -import { title } from 'flavours/glitch/initial_state'; import { Helmet } from 'react-helmet'; const messages = defineMessages({ @@ -169,7 +168,8 @@ class Directory extends React.PureComponent { {multiColumn && !pinned ? <ScrollContainer scrollKey='directory'>{scrollableArea}</ScrollContainer> : scrollableArea} <Helmet> - <title>{intl.formatMessage(messages.title)} - {title}</title> + <title>{intl.formatMessage(messages.title)}</title> + <meta name='robots' content='noindex' /> </Helmet> </Column> ); diff --git a/app/javascript/flavours/glitch/features/domain_blocks/index.js b/app/javascript/flavours/glitch/features/domain_blocks/index.js index acce87d5a..cb0b55c63 100644 --- a/app/javascript/flavours/glitch/features/domain_blocks/index.js +++ b/app/javascript/flavours/glitch/features/domain_blocks/index.js @@ -11,6 +11,7 @@ import { fetchDomainBlocks, expandDomainBlocks } from '../../actions/domain_bloc import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import ImmutablePureComponent from 'react-immutable-pure-component'; import ScrollableList from 'flavours/glitch/components/scrollable_list'; +import { Helmet } from 'react-helmet'; const messages = defineMessages({ heading: { id: 'column.domain_blocks', defaultMessage: 'Blocked domains' }, @@ -59,6 +60,7 @@ class Blocks extends ImmutablePureComponent { return ( <Column bindToDocument={!multiColumn} icon='minus-circle' heading={intl.formatMessage(messages.heading)}> <ColumnBackButtonSlim /> + <ScrollableList scrollKey='domain_blocks' onLoadMore={this.handleLoadMore} @@ -70,6 +72,10 @@ class Blocks extends ImmutablePureComponent { <DomainContainer key={domain} domain={domain} />, )} </ScrollableList> + + <Helmet> + <meta name='robots' content='noindex' /> + </Helmet> </Column> ); } diff --git a/app/javascript/flavours/glitch/features/explore/index.js b/app/javascript/flavours/glitch/features/explore/index.js index f37793732..24fa26eec 100644 --- a/app/javascript/flavours/glitch/features/explore/index.js +++ b/app/javascript/flavours/glitch/features/explore/index.js @@ -13,7 +13,6 @@ import Search from 'flavours/glitch/features/compose/containers/search_container import SearchResults from './results'; import { showTrends } from 'flavours/glitch/initial_state'; import { Helmet } from 'react-helmet'; -import { title } from 'flavours/glitch/initial_state'; const messages = defineMessages({ title: { id: 'explore.title', defaultMessage: 'Explore' }, @@ -85,7 +84,8 @@ class Explore extends React.PureComponent { </Switch> <Helmet> - <title>{intl.formatMessage(messages.title)} - {title}</title> + <title>{intl.formatMessage(messages.title)}</title> + <meta name='robots' content={isSearching ? 'noindex' : 'all'} /> </Helmet> </React.Fragment> )} diff --git a/app/javascript/flavours/glitch/features/explore/links.js b/app/javascript/flavours/glitch/features/explore/links.js index 6adc2f6fb..092f86b29 100644 --- a/app/javascript/flavours/glitch/features/explore/links.js +++ b/app/javascript/flavours/glitch/features/explore/links.js @@ -6,6 +6,7 @@ import LoadingIndicator from 'flavours/glitch/components/loading_indicator'; import { connect } from 'react-redux'; import { fetchTrendingLinks } from 'flavours/glitch/actions/trends'; import { FormattedMessage } from 'react-intl'; +import DismissableBanner from 'flavours/glitch/components/dismissable_banner'; const mapStateToProps = state => ({ links: state.getIn(['trends', 'links', 'items']), @@ -29,9 +30,17 @@ class Links extends React.PureComponent { render () { const { isLoading, links } = this.props; + const banner = ( + <DismissableBanner id='explore/links'> + <FormattedMessage id='dismissable_banner.explore_links' defaultMessage='These news stories are being talked about by people on this and other servers of the decentralized network right now.' /> + </DismissableBanner> + ); + if (!isLoading && links.isEmpty()) { return ( <div className='explore__links scrollable scrollable--flex'> + {banner} + <div className='empty-column-indicator'> <FormattedMessage id='empty_column.explore_statuses' defaultMessage='Nothing is trending right now. Check back later!' /> </div> @@ -41,6 +50,8 @@ class Links extends React.PureComponent { return ( <div className='explore__links'> + {banner} + {isLoading ? (<LoadingIndicator />) : links.map(link => ( <Story key={link.get('id')} diff --git a/app/javascript/flavours/glitch/features/explore/results.js b/app/javascript/flavours/glitch/features/explore/results.js index e37379686..892980d95 100644 --- a/app/javascript/flavours/glitch/features/explore/results.js +++ b/app/javascript/flavours/glitch/features/explore/results.js @@ -10,7 +10,6 @@ import { ImmutableHashtag as Hashtag } from 'flavours/glitch/components/hashtag' import { List as ImmutableList } from 'immutable'; import LoadMore from 'flavours/glitch/components/load_more'; import LoadingIndicator from 'flavours/glitch/components/loading_indicator'; -import { title } from 'flavours/glitch/initial_state'; import { Helmet } from 'react-helmet'; const messages = defineMessages({ @@ -118,7 +117,7 @@ class Results extends React.PureComponent { </div> <Helmet> - <title>{intl.formatMessage(messages.title, { q })} - {title}</title> + <title>{intl.formatMessage(messages.title, { q })}</title> </Helmet> </React.Fragment> ); diff --git a/app/javascript/flavours/glitch/features/explore/statuses.js b/app/javascript/flavours/glitch/features/explore/statuses.js index fe08ce466..0a5c9de23 100644 --- a/app/javascript/flavours/glitch/features/explore/statuses.js +++ b/app/javascript/flavours/glitch/features/explore/statuses.js @@ -6,6 +6,7 @@ import { FormattedMessage } from 'react-intl'; import { connect } from 'react-redux'; import { fetchTrendingStatuses, expandTrendingStatuses } from 'flavours/glitch/actions/trends'; import { debounce } from 'lodash'; +import DismissableBanner from 'flavours/glitch/components/dismissable_banner'; const mapStateToProps = state => ({ statusIds: state.getIn(['status_lists', 'trending', 'items']), @@ -40,17 +41,23 @@ class Statuses extends React.PureComponent { const emptyMessage = <FormattedMessage id='empty_column.explore_statuses' defaultMessage='Nothing is trending right now. Check back later!' />; return ( - <StatusList - trackScroll - statusIds={statusIds} - scrollKey='explore-statuses' - hasMore={hasMore} - isLoading={isLoading} - onLoadMore={this.handleLoadMore} - emptyMessage={emptyMessage} - bindToDocument={!multiColumn} - withCounters - /> + <> + <DismissableBanner id='explore/statuses'> + <FormattedMessage id='dismissable_banner.explore_statuses' defaultMessage='These posts from this and other servers in the decentralized network are gaining traction on this server right now.' /> + </DismissableBanner> + + <StatusList + trackScroll + statusIds={statusIds} + scrollKey='explore-statuses' + hasMore={hasMore} + isLoading={isLoading} + onLoadMore={this.handleLoadMore} + emptyMessage={emptyMessage} + bindToDocument={!multiColumn} + withCounters + /> + </> ); } diff --git a/app/javascript/flavours/glitch/features/explore/tags.js b/app/javascript/flavours/glitch/features/explore/tags.js index 465fad0df..938036b64 100644 --- a/app/javascript/flavours/glitch/features/explore/tags.js +++ b/app/javascript/flavours/glitch/features/explore/tags.js @@ -6,6 +6,7 @@ import LoadingIndicator from 'flavours/glitch/components/loading_indicator'; import { connect } from 'react-redux'; import { fetchTrendingHashtags } from 'flavours/glitch/actions/trends'; import { FormattedMessage } from 'react-intl'; +import DismissableBanner from 'flavours/glitch/components/dismissable_banner'; const mapStateToProps = state => ({ hashtags: state.getIn(['trends', 'tags', 'items']), @@ -29,9 +30,17 @@ class Tags extends React.PureComponent { render () { const { isLoading, hashtags } = this.props; + const banner = ( + <DismissableBanner id='explore/tags'> + <FormattedMessage id='dismissable_banner.explore_tags' defaultMessage='These hashtags are gaining traction among people on this and other servers of the decentralized network right now.' /> + </DismissableBanner> + ); + if (!isLoading && hashtags.isEmpty()) { return ( <div className='explore__links scrollable scrollable--flex'> + {banner} + <div className='empty-column-indicator'> <FormattedMessage id='empty_column.explore_statuses' defaultMessage='Nothing is trending right now. Check back later!' /> </div> @@ -41,6 +50,8 @@ class Tags extends React.PureComponent { return ( <div className='explore__links'> + {banner} + {isLoading ? (<LoadingIndicator />) : hashtags.map(hashtag => ( <Hashtag key={hashtag.get('name')} hashtag={hashtag} /> ))} diff --git a/app/javascript/flavours/glitch/features/favourited_statuses/index.js b/app/javascript/flavours/glitch/features/favourited_statuses/index.js index 4df3aaa64..a03e1a4eb 100644 --- a/app/javascript/flavours/glitch/features/favourited_statuses/index.js +++ b/app/javascript/flavours/glitch/features/favourited_statuses/index.js @@ -1,15 +1,16 @@ -import React from 'react'; -import { connect } from 'react-redux'; +import { debounce } from 'lodash'; import PropTypes from 'prop-types'; +import React from 'react'; +import { Helmet } from 'react-helmet'; import ImmutablePropTypes from 'react-immutable-proptypes'; -import { debounce } from 'lodash'; +import ImmutablePureComponent from 'react-immutable-pure-component'; +import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; +import { connect } from 'react-redux'; +import { addColumn, removeColumn, moveColumn } from 'flavours/glitch/actions/columns'; import { fetchFavouritedStatuses, expandFavouritedStatuses } from 'flavours/glitch/actions/favourites'; -import Column from 'flavours/glitch/features/ui/components/column'; import ColumnHeader from 'flavours/glitch/components/column_header'; -import { addColumn, removeColumn, moveColumn } from 'flavours/glitch/actions/columns'; import StatusList from 'flavours/glitch/components/status_list'; -import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; -import ImmutablePureComponent from 'react-immutable-pure-component'; +import Column from 'flavours/glitch/features/ui/components/column'; const messages = defineMessages({ heading: { id: 'column.favourites', defaultMessage: 'Favourites' }, @@ -95,6 +96,11 @@ class Favourites extends ImmutablePureComponent { emptyMessage={emptyMessage} bindToDocument={!multiColumn} /> + + <Helmet> + <title>{intl.formatMessage(messages.heading)}</title> + <meta name='robots' content='noindex' /> + </Helmet> </Column> ); } diff --git a/app/javascript/flavours/glitch/features/favourites/index.js b/app/javascript/flavours/glitch/features/favourites/index.js index a51562e71..47c3279c4 100644 --- a/app/javascript/flavours/glitch/features/favourites/index.js +++ b/app/javascript/flavours/glitch/features/favourites/index.js @@ -1,16 +1,17 @@ -import React from 'react'; -import { connect } from 'react-redux'; import PropTypes from 'prop-types'; +import React from 'react'; +import ImmutablePureComponent from 'react-immutable-pure-component'; import ImmutablePropTypes from 'react-immutable-proptypes'; -import LoadingIndicator from 'flavours/glitch/components/loading_indicator'; +import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; +import { connect } from 'react-redux'; +import ColumnHeader from 'flavours/glitch/components/column_header'; +import Icon from 'flavours/glitch/components/icon'; import { fetchFavourites } from 'flavours/glitch/actions/interactions'; +import LoadingIndicator from 'flavours/glitch/components/loading_indicator'; +import ScrollableList from 'flavours/glitch/components/scrollable_list'; import AccountContainer from 'flavours/glitch/containers/account_container'; import Column from 'flavours/glitch/features/ui/components/column'; -import Icon from 'flavours/glitch/components/icon'; -import ColumnHeader from 'flavours/glitch/components/column_header'; -import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; -import ImmutablePureComponent from 'react-immutable-pure-component'; -import ScrollableList from '../../components/scrollable_list'; +import { Helmet } from 'react-helmet'; const messages = defineMessages({ heading: { id: 'column.favourited_by', defaultMessage: 'Favourited by' }, @@ -91,6 +92,10 @@ class Favourites extends ImmutablePureComponent { <AccountContainer key={id} id={id} withNote={false} />, )} </ScrollableList> + + <Helmet> + <meta name='robots' content='noindex' /> + </Helmet> </Column> ); } diff --git a/app/javascript/flavours/glitch/features/follow_recommendations/index.js b/app/javascript/flavours/glitch/features/follow_recommendations/index.js index f934aeb35..d9d962b7c 100644 --- a/app/javascript/flavours/glitch/features/follow_recommendations/index.js +++ b/app/javascript/flavours/glitch/features/follow_recommendations/index.js @@ -12,6 +12,7 @@ import Column from 'flavours/glitch/features/ui/components/column'; import Account from './components/account'; import imageGreeting from 'mastodon/../images/elephant_ui_greeting.svg'; import Button from 'flavours/glitch/components/button'; +import { Helmet } from 'react-helmet'; const mapStateToProps = state => ({ suggestions: state.getIn(['suggestions', 'items']), @@ -104,6 +105,10 @@ class FollowRecommendations extends ImmutablePureComponent { </React.Fragment> )} </div> + + <Helmet> + <meta name='robots' content='noindex' /> + </Helmet> </Column> ); } diff --git a/app/javascript/flavours/glitch/features/follow_requests/index.js b/app/javascript/flavours/glitch/features/follow_requests/index.js index 47ca1e1bf..7b35e3ec9 100644 --- a/app/javascript/flavours/glitch/features/follow_requests/index.js +++ b/app/javascript/flavours/glitch/features/follow_requests/index.js @@ -12,6 +12,7 @@ import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import ImmutablePureComponent from 'react-immutable-pure-component'; import ScrollableList from 'flavours/glitch/components/scrollable_list'; import { me } from 'flavours/glitch/initial_state'; +import { Helmet } from 'react-helmet'; const messages = defineMessages({ heading: { id: 'column.follow_requests', defaultMessage: 'Follow requests' }, @@ -88,6 +89,10 @@ class FollowRequests extends ImmutablePureComponent { <AccountAuthorizeContainer key={id} id={id} />, )} </ScrollableList> + + <Helmet> + <meta name='robots' content='noindex' /> + </Helmet> </Column> ); } diff --git a/app/javascript/flavours/glitch/features/followers/index.js b/app/javascript/flavours/glitch/features/followers/index.js index 27a63b3fd..7122c1905 100644 --- a/app/javascript/flavours/glitch/features/followers/index.js +++ b/app/javascript/flavours/glitch/features/followers/index.js @@ -21,9 +21,10 @@ import ScrollableList from 'flavours/glitch/components/scrollable_list'; import TimelineHint from 'flavours/glitch/components/timeline_hint'; import LimitedAccountHint from '../account_timeline/components/limited_account_hint'; import { getAccountHidden } from 'flavours/glitch/selectors'; +import { normalizeForLookup } from 'flavours/glitch/reducers/accounts_map'; const mapStateToProps = (state, { params: { acct, id } }) => { - const accountId = id || state.getIn(['accounts_map', acct]); + const accountId = id || state.getIn(['accounts_map', normalizeForLookup(acct)]); if (!accountId) { return { diff --git a/app/javascript/flavours/glitch/features/following/index.js b/app/javascript/flavours/glitch/features/following/index.js index aa187bf95..4ad670105 100644 --- a/app/javascript/flavours/glitch/features/following/index.js +++ b/app/javascript/flavours/glitch/features/following/index.js @@ -21,9 +21,10 @@ import ScrollableList from 'flavours/glitch/components/scrollable_list'; import TimelineHint from 'flavours/glitch/components/timeline_hint'; import LimitedAccountHint from '../account_timeline/components/limited_account_hint'; import { getAccountHidden } from 'flavours/glitch/selectors'; +import { normalizeForLookup } from 'flavours/glitch/reducers/accounts_map'; const mapStateToProps = (state, { params: { acct, id } }) => { - const accountId = id || state.getIn(['accounts_map', acct]); + const accountId = id || state.getIn(['accounts_map', normalizeForLookup(acct)]); if (!accountId) { return { diff --git a/app/javascript/flavours/glitch/features/getting_started/index.js b/app/javascript/flavours/glitch/features/getting_started/index.js index f52b769a3..f9d79013b 100644 --- a/app/javascript/flavours/glitch/features/getting_started/index.js +++ b/app/javascript/flavours/glitch/features/getting_started/index.js @@ -17,6 +17,7 @@ import { preferencesLink } from 'flavours/glitch/utils/backend_links'; import NavigationBar from '../compose/components/navigation_bar'; import LinkFooter from 'flavours/glitch/features/ui/components/link_footer'; import TrendsContainer from './containers/trends_container'; +import { Helmet } from 'react-helmet'; const messages = defineMessages({ heading: { id: 'getting_started.heading', defaultMessage: 'Getting started' }, @@ -84,11 +85,12 @@ const NAVIGATION_PANEL_BREAKPOINT = 600 + (285 * 2) + (10 * 2); static contextTypes = { router: PropTypes.object.isRequired, + identity: PropTypes.object, }; static propTypes = { intl: PropTypes.object.isRequired, - myAccount: ImmutablePropTypes.map.isRequired, + myAccount: ImmutablePropTypes.map, columns: ImmutablePropTypes.list, multiColumn: PropTypes.bool, fetchFollowRequests: PropTypes.func.isRequired, @@ -104,10 +106,10 @@ const NAVIGATION_PANEL_BREAKPOINT = 600 + (285 * 2) + (10 * 2); } componentDidMount () { - const { fetchFollowRequests, multiColumn } = this.props; + const { fetchFollowRequests } = this.props; + const { signedIn } = this.context.identity; - if (!multiColumn && window.innerWidth >= NAVIGATION_PANEL_BREAKPOINT) { - this.context.router.history.replace('/home'); + if (!signedIn) { return; } @@ -116,12 +118,13 @@ const NAVIGATION_PANEL_BREAKPOINT = 600 + (285 * 2) + (10 * 2); render () { const { intl, myAccount, columns, multiColumn, unreadFollowRequests, unreadNotifications, lists, openSettings } = this.props; + const { signedIn } = this.context.identity; const navItems = []; let listItems = []; if (multiColumn) { - if (!columns.find(item => item.get('id') === 'HOME')) { + if (signedIn && !columns.find(item => item.get('id') === 'HOME')) { navItems.push(<ColumnLink key='home' icon='home' text={intl.formatMessage(messages.home_timeline)} to='/home' />); } @@ -142,47 +145,58 @@ const NAVIGATION_PANEL_BREAKPOINT = 600 + (285 * 2) + (10 * 2); navItems.push(<ColumnLink key='explore' icon='hashtag' text={intl.formatMessage(messages.explore)} to='/explore' />); } - if (!multiColumn || !columns.find(item => item.get('id') === 'DIRECT')) { - navItems.push(<ColumnLink key='conversations' icon='envelope' text={intl.formatMessage(messages.direct)} to='/conversations' />); - } + if (signedIn) { + if (!multiColumn || !columns.find(item => item.get('id') === 'DIRECT')) { + navItems.push(<ColumnLink key='conversations' icon='envelope' text={intl.formatMessage(messages.direct)} to='/conversations' />); + } - if (!multiColumn || !columns.find(item => item.get('id') === 'BOOKMARKS')) { - navItems.push(<ColumnLink key='bookmarks' icon='bookmark' text={intl.formatMessage(messages.bookmarks)} to='/bookmarks' />); - } + if (!multiColumn || !columns.find(item => item.get('id') === 'BOOKMARKS')) { + navItems.push(<ColumnLink key='bookmarks' icon='bookmark' text={intl.formatMessage(messages.bookmarks)} to='/bookmarks' />); + } - if (myAccount.get('locked') || unreadFollowRequests > 0) { - navItems.push(<ColumnLink key='follow_requests' icon='user-plus' text={intl.formatMessage(messages.follow_requests)} badge={badgeDisplay(unreadFollowRequests, 40)} to='/follow_requests' />); - } + if (myAccount.get('locked') || unreadFollowRequests > 0) { + navItems.push(<ColumnLink key='follow_requests' icon='user-plus' text={intl.formatMessage(messages.follow_requests)} badge={badgeDisplay(unreadFollowRequests, 40)} to='/follow_requests' />); + } - navItems.push(<ColumnLink key='getting_started' icon='ellipsis-h' text={intl.formatMessage(messages.misc)} to='/getting-started-misc' />); + navItems.push(<ColumnLink key='getting_started' icon='ellipsis-h' text={intl.formatMessage(messages.misc)} to='/getting-started-misc' />); - listItems = listItems.concat([ - <div key='9'> - <ColumnLink key='lists' icon='bars' text={intl.formatMessage(messages.lists)} to='/lists' /> - {lists.filter(list => !columns.find(item => item.get('id') === 'LIST' && item.getIn(['params', 'id']) === list.get('id'))).map(list => - <ColumnLink key={`list-${list.get('id')}`} to={`/lists/${list.get('id')}`} icon='list-ul' text={list.get('title')} /> - )} - </div>, - ]); + listItems = listItems.concat([ + <div key='9'> + <ColumnLink key='lists' icon='bars' text={intl.formatMessage(messages.lists)} to='/lists' /> + {lists.filter(list => !columns.find(item => item.get('id') === 'LIST' && item.getIn(['params', 'id']) === list.get('id'))).map(list => + <ColumnLink key={`list-${list.get('id')}`} to={`/lists/${list.get('id')}`} icon='list-ul' text={list.get('title')} /> + )} + </div>, + ]); + } return ( <Column bindToDocument={!multiColumn} name='getting-started' icon='asterisk' heading={intl.formatMessage(messages.heading)} label={intl.formatMessage(messages.menu)} hideHeadingOnMobile> <div className='scrollable optionally-scrollable'> <div className='getting-started__wrapper'> - {!multiColumn && <NavigationBar account={myAccount} />} + {!multiColumn && signedIn && <NavigationBar account={myAccount} />} {multiColumn && <ColumnSubheading text={intl.formatMessage(messages.navigation_subheading)} />} {navItems} - <ColumnSubheading text={intl.formatMessage(messages.lists_subheading)} /> - {listItems} - <ColumnSubheading text={intl.formatMessage(messages.settings_subheading)} /> - { preferencesLink !== undefined && <ColumnLink icon='cog' text={intl.formatMessage(messages.preferences)} href={preferencesLink} /> } - <ColumnLink icon='cogs' text={intl.formatMessage(messages.settings)} onClick={openSettings} /> + {signedIn && ( + <React.Fragment> + <ColumnSubheading text={intl.formatMessage(messages.lists_subheading)} /> + {listItems} + <ColumnSubheading text={intl.formatMessage(messages.settings_subheading)} /> + { preferencesLink !== undefined && <ColumnLink icon='cog' text={intl.formatMessage(messages.preferences)} href={preferencesLink} /> } + <ColumnLink icon='cogs' text={intl.formatMessage(messages.settings)} onClick={openSettings} /> + </React.Fragment> + )} </div> <LinkFooter /> </div> {multiColumn && showTrends && <TrendsContainer />} + + <Helmet> + <title>{intl.formatMessage(messages.menu)}</title> + <meta name='robots' content='noindex' /> + </Helmet> </Column> ); } diff --git a/app/javascript/flavours/glitch/features/hashtag_timeline/index.js b/app/javascript/flavours/glitch/features/hashtag_timeline/index.js index 5e098514a..f1827789f 100644 --- a/app/javascript/flavours/glitch/features/hashtag_timeline/index.js +++ b/app/javascript/flavours/glitch/features/hashtag_timeline/index.js @@ -14,7 +14,6 @@ import { isEqual } from 'lodash'; import { fetchHashtag, followHashtag, unfollowHashtag } from 'flavours/glitch/actions/tags'; import Icon from 'flavours/glitch/components/icon'; import classNames from 'classnames'; -import { title } from 'flavours/glitch/initial_state'; import { Helmet } from 'react-helmet'; const messages = defineMessages({ @@ -228,7 +227,8 @@ class HashtagTimeline extends React.PureComponent { /> <Helmet> - <title>{`#${id}`} - {title}</title> + <title>#{id}</title> + <meta name='robots' content='noindex' /> </Helmet> </Column> ); diff --git a/app/javascript/flavours/glitch/features/home_timeline/index.js b/app/javascript/flavours/glitch/features/home_timeline/index.js index 86aaa0258..23d0440a9 100644 --- a/app/javascript/flavours/glitch/features/home_timeline/index.js +++ b/app/javascript/flavours/glitch/features/home_timeline/index.js @@ -15,7 +15,6 @@ import classNames from 'classnames'; import IconWithBadge from 'flavours/glitch/components/icon_with_badge'; import NotSignedInIndicator from 'flavours/glitch/components/not_signed_in_indicator'; import { Helmet } from 'react-helmet'; -import { title } from 'flavours/glitch/initial_state'; const messages = defineMessages({ title: { id: 'column.home', defaultMessage: 'Home' }, @@ -170,7 +169,8 @@ class HomeTimeline extends React.PureComponent { ) : <NotSignedInIndicator />} <Helmet> - <title>{intl.formatMessage(messages.title)} - {title}</title> + <title>{intl.formatMessage(messages.title)}</title> + <meta name='robots' content='noindex' /> </Helmet> </Column> ); diff --git a/app/javascript/flavours/glitch/features/interaction_modal/index.js b/app/javascript/flavours/glitch/features/interaction_modal/index.js index 5623f8a06..4cd8e51de 100644 --- a/app/javascript/flavours/glitch/features/interaction_modal/index.js +++ b/app/javascript/flavours/glitch/features/interaction_modal/index.js @@ -5,11 +5,19 @@ import { registrationsOpen } from 'flavours/glitch/initial_state'; import { connect } from 'react-redux'; import Icon from 'flavours/glitch/components/icon'; import classNames from 'classnames'; +import { openModal, closeModal } from 'flavours/glitch/actions/modal'; const mapStateToProps = (state, { accountId }) => ({ displayNameHtml: state.getIn(['accounts', accountId, 'display_name_html']), }); +const mapDispatchToProps = (dispatch) => ({ + onSignupClick() { + dispatch(closeModal()); + dispatch(openModal('CLOSED_REGISTRATIONS')); + }, +}); + class Copypaste extends React.PureComponent { static propTypes = { @@ -66,15 +74,20 @@ class Copypaste extends React.PureComponent { } -export default @connect(mapStateToProps) +export default @connect(mapStateToProps, mapDispatchToProps) class InteractionModal extends React.PureComponent { static propTypes = { displayNameHtml: PropTypes.string, url: PropTypes.string, type: PropTypes.oneOf(['reply', 'reblog', 'favourite', 'follow']), + onSignupClick: PropTypes.func.isRequired, }; + handleSignupClick = () => { + this.props.onSignupClick(); + } + render () { const { url, type, displayNameHtml } = this.props; @@ -105,6 +118,22 @@ class InteractionModal extends React.PureComponent { break; } + let signupButton; + + if (registrationsOpen) { + signupButton = ( + <a href='/auth/sign_up' className='button button--block button-tertiary'> + <FormattedMessage id='sign_in_banner.create_account' defaultMessage='Create account' /> + </a> + ); + } else { + signupButton = ( + <button className='button button--block button-tertiary' onClick={this.handleSignupClick}> + <FormattedMessage id='sign_in_banner.create_account' defaultMessage='Create account' /> + </button> + ); + } + return ( <div className='modal-root__modal interaction-modal'> <div className='interaction-modal__lead'> @@ -116,7 +145,7 @@ class InteractionModal extends React.PureComponent { <div className='interaction-modal__choices__choice'> <h3><FormattedMessage id='interaction_modal.on_this_server' defaultMessage='On this server' /></h3> <a href='/auth/sign_in' className='button button--block'><FormattedMessage id='sign_in_banner.sign_in' defaultMessage='Sign in' /></a> - <a href={registrationsOpen ? '/auth/sign_up' : 'https://joinmastodon.org/servers'} className='button button--block button-tertiary'><FormattedMessage id='sign_in_banner.create_account' defaultMessage='Create account' /></a> + {signupButton} </div> <div className='interaction-modal__choices__choice'> diff --git a/app/javascript/flavours/glitch/features/keyboard_shortcuts/index.js b/app/javascript/flavours/glitch/features/keyboard_shortcuts/index.js index 481f76763..2bc0116d4 100644 --- a/app/javascript/flavours/glitch/features/keyboard_shortcuts/index.js +++ b/app/javascript/flavours/glitch/features/keyboard_shortcuts/index.js @@ -1,10 +1,11 @@ import React from 'react'; -import Column from 'flavours/glitch/features/ui/components/column'; -import ColumnBackButtonSlim from 'flavours/glitch/components/column_back_button_slim'; +import Column from 'flavours/glitch/components/column'; import { connect } from 'react-redux'; import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import PropTypes from 'prop-types'; import ImmutablePureComponent from 'react-immutable-pure-component'; +import ColumnHeader from 'flavours/glitch/components/column_header'; +import { Helmet } from 'react-helmet'; const messages = defineMessages({ heading: { id: 'keyboard_shortcuts.heading', defaultMessage: 'Keyboard Shortcuts' }, @@ -28,8 +29,13 @@ class KeyboardShortcuts extends ImmutablePureComponent { const { intl, collapseEnabled, multiColumn } = this.props; return ( - <Column bindToDocument={!multiColumn} icon='question' heading={intl.formatMessage(messages.heading)}> - <ColumnBackButtonSlim /> + <Column> + <ColumnHeader + title={intl.formatMessage(messages.heading)} + icon='question' + multiColumn={multiColumn} + /> + <div className='keyboard-shortcuts scrollable optionally-scrollable'> <table> <thead> @@ -132,6 +138,10 @@ class KeyboardShortcuts extends ImmutablePureComponent { </tbody> </table> </div> + + <Helmet> + <meta name='robots' content='noindex' /> + </Helmet> </Column> ); } diff --git a/app/javascript/flavours/glitch/features/list_timeline/index.js b/app/javascript/flavours/glitch/features/list_timeline/index.js index 08347446b..a94c05c56 100644 --- a/app/javascript/flavours/glitch/features/list_timeline/index.js +++ b/app/javascript/flavours/glitch/features/list_timeline/index.js @@ -1,20 +1,22 @@ -import React from 'react'; -import { connect } from 'react-redux'; import PropTypes from 'prop-types'; +import React from 'react'; +import { Helmet } from 'react-helmet'; import ImmutablePropTypes from 'react-immutable-proptypes'; -import StatusListContainer from 'flavours/glitch/features/ui/containers/status_list_container'; -import Column from 'flavours/glitch/components/column'; -import ColumnHeader from 'flavours/glitch/components/column_header'; -import { addColumn, removeColumn, moveColumn } from 'flavours/glitch/actions/columns'; import { FormattedMessage, defineMessages, injectIntl } from 'react-intl'; -import { connectListStream } from 'flavours/glitch/actions/streaming'; -import { expandListTimeline } from 'flavours/glitch/actions/timelines'; +import { connect } from 'react-redux'; +import { addColumn, removeColumn, moveColumn } from 'flavours/glitch/actions/columns'; import { fetchList, deleteList, updateList } from 'flavours/glitch/actions/lists'; import { openModal } from 'flavours/glitch/actions/modal'; -import MissingIndicator from 'flavours/glitch/components/missing_indicator'; -import LoadingIndicator from 'flavours/glitch/components/loading_indicator'; +import { connectListStream } from 'flavours/glitch/actions/streaming'; +import { expandListTimeline } from 'flavours/glitch/actions/timelines'; +import Column from 'flavours/glitch/components/column'; +import ColumnBackButton from 'flavours/glitch/components/column_back_button'; +import ColumnHeader from 'flavours/glitch/components/column_header'; import Icon from 'flavours/glitch/components/icon'; +import LoadingIndicator from 'flavours/glitch/components/loading_indicator'; +import MissingIndicator from 'flavours/glitch/components/missing_indicator'; import RadioButton from 'flavours/glitch/components/radio_button'; +import StatusListContainer from 'flavours/glitch/features/ui/containers/status_list_container'; const messages = defineMessages({ deleteMessage: { id: 'confirmations.delete_list.message', defaultMessage: 'Are you sure you want to permanently delete this list?' }, @@ -210,6 +212,11 @@ class ListTimeline extends React.PureComponent { emptyMessage={<FormattedMessage id='empty_column.list' defaultMessage='There is nothing in this list yet.' />} bindToDocument={!multiColumn} /> + + <Helmet> + <title>{title}</title> + <meta name='robots' content='noindex' /> + </Helmet> </Column> ); } diff --git a/app/javascript/flavours/glitch/features/lists/index.js b/app/javascript/flavours/glitch/features/lists/index.js index b92389d82..8773be5e6 100644 --- a/app/javascript/flavours/glitch/features/lists/index.js +++ b/app/javascript/flavours/glitch/features/lists/index.js @@ -1,18 +1,19 @@ -import React from 'react'; -import { connect } from 'react-redux'; import PropTypes from 'prop-types'; +import React from 'react'; +import { Helmet } from 'react-helmet'; import ImmutablePropTypes from 'react-immutable-proptypes'; +import ImmutablePureComponent from 'react-immutable-pure-component'; +import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; +import { connect } from 'react-redux'; +import { createSelector } from 'reselect'; +import { fetchLists } from 'flavours/glitch/actions/lists'; +import ColumnBackButtonSlim from 'flavours/glitch/components/column_back_button_slim'; import LoadingIndicator from 'flavours/glitch/components/loading_indicator'; +import ScrollableList from 'flavours/glitch/components/scrollable_list'; import Column from 'flavours/glitch/features/ui/components/column'; -import ColumnBackButtonSlim from 'flavours/glitch/components/column_back_button_slim'; -import { fetchLists } from 'flavours/glitch/actions/lists'; -import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; -import ImmutablePureComponent from 'react-immutable-pure-component'; import ColumnLink from 'flavours/glitch/features/ui/components/column_link'; import ColumnSubheading from 'flavours/glitch/features/ui/components/column_subheading'; import NewListForm from './components/new_list_form'; -import { createSelector } from 'reselect'; -import ScrollableList from 'flavours/glitch/components/scrollable_list'; const messages = defineMessages({ heading: { id: 'column.lists', defaultMessage: 'Lists' }, @@ -76,6 +77,11 @@ class Lists extends ImmutablePureComponent { <ColumnLink key={list.get('id')} to={`/lists/${list.get('id')}`} icon='list-ul' text={list.get('title')} />, )} </ScrollableList> + + <Helmet> + <title>{intl.formatMessage(messages.heading)}</title> + <meta name='robots' content='noindex' /> + </Helmet> </Column> ); } diff --git a/app/javascript/flavours/glitch/features/local_settings/page/index.js b/app/javascript/flavours/glitch/features/local_settings/page/index.js index e154fe1c8..d01eec811 100644 --- a/app/javascript/flavours/glitch/features/local_settings/page/index.js +++ b/app/javascript/flavours/glitch/features/local_settings/page/index.js @@ -181,36 +181,6 @@ class LocalSettingsPage extends React.PureComponent { <FormattedMessage id='settings.wide_view' defaultMessage='Wide view (Desktop mode only)' /> <span className='hint'><FormattedMessage id='settings.wide_view_hint' defaultMessage='Stretches columns to better fill the available space.' /></span> </LocalSettingsPageItem> - <LocalSettingsPageItem - settings={settings} - item={['navbar_under']} - id='mastodon-settings--navbar_under' - onChange={onChange} - > - <FormattedMessage id='settings.navbar_under' defaultMessage='Navbar at the bottom (Mobile only)' /> - </LocalSettingsPageItem> - <DeprecatedLocalSettingsPageItem - id='mastodon-settings--swipe_to_change_columns' - value={!disableSwiping} - > - <FormattedMessage id='settings.swipe_to_change_columns' defaultMessage='Allow swiping to change columns (Mobile only)' /> - <span className='hint'> - <FormattedMessage - id='settings.deprecated_setting' - defaultMessage="This setting is now controlled from Mastodon's {settings_page_link}" - values={{ - settings_page_link: ( - <a href={preferenceLink('user_setting_disable_swiping')}> - <FormattedMessage - id='settings.shared_settings_link' - defaultMessage='user preferences' - /> - </a> - ) - }} - /> - </span> - </DeprecatedLocalSettingsPageItem> </section> </div> ), diff --git a/app/javascript/flavours/glitch/features/mutes/index.js b/app/javascript/flavours/glitch/features/mutes/index.js index 764cbef1a..8da106e47 100644 --- a/app/javascript/flavours/glitch/features/mutes/index.js +++ b/app/javascript/flavours/glitch/features/mutes/index.js @@ -11,6 +11,7 @@ import AccountContainer from 'flavours/glitch/containers/account_container'; import { fetchMutes, expandMutes } from 'flavours/glitch/actions/mutes'; import ImmutablePureComponent from 'react-immutable-pure-component'; import ScrollableList from 'flavours/glitch/components/scrollable_list'; +import { Helmet } from 'react-helmet'; const messages = defineMessages({ heading: { id: 'column.mutes', defaultMessage: 'Muted users' }, @@ -72,6 +73,10 @@ class Mutes extends ImmutablePureComponent { <AccountContainer key={id} id={id} defaultAction='mute' />, )} </ScrollableList> + + <Helmet> + <meta name='robots' content='noindex' /> + </Helmet> </Column> ); } diff --git a/app/javascript/flavours/glitch/features/notifications/components/admin_report.js b/app/javascript/flavours/glitch/features/notifications/components/admin_report.js index 80beeb9da..4662bd953 100644 --- a/app/javascript/flavours/glitch/features/notifications/components/admin_report.js +++ b/app/javascript/flavours/glitch/features/notifications/components/admin_report.js @@ -69,6 +69,10 @@ export default class AdminReport extends ImmutablePureComponent { render () { const { intl, account, notification, unread, report } = this.props; + if (!report) { + return null; + } + // Links to the display name. const displayName = account.get('display_name_html') || account.get('username'); const link = ( diff --git a/app/javascript/flavours/glitch/features/notifications/components/column_settings.js b/app/javascript/flavours/glitch/features/notifications/components/column_settings.js index 42ab9de35..ee05c7fd6 100644 --- a/app/javascript/flavours/glitch/features/notifications/components/column_settings.js +++ b/app/javascript/flavours/glitch/features/notifications/components/column_settings.js @@ -171,7 +171,7 @@ export default class ColumnSettings extends React.PureComponent { </div> </div> - {(this.context.identity.permissions & PERMISSION_MANAGE_USERS === PERMISSION_MANAGE_USERS) && ( + {((this.context.identity.permissions & PERMISSION_MANAGE_USERS) === PERMISSION_MANAGE_USERS) && ( <div role='group' aria-labelledby='notifications-admin-sign-up'> <span id='notifications-status' className='column-settings__section'><FormattedMessage id='notifications.column_settings.admin.sign_up' defaultMessage='New sign-ups:' /></span> @@ -184,7 +184,7 @@ export default class ColumnSettings extends React.PureComponent { </div> )} - {(this.context.identity.permissions & PERMISSION_MANAGE_REPORTS === PERMISSION_MANAGE_REPORTS) && ( + {((this.context.identity.permissions & PERMISSION_MANAGE_REPORTS) === PERMISSION_MANAGE_REPORTS) && ( <div role='group' aria-labelledby='notifications-admin-report'> <span id='notifications-status' className='column-settings__section'><FormattedMessage id='notifications.column_settings.admin.report' defaultMessage='New reports:' /></span> diff --git a/app/javascript/flavours/glitch/features/notifications/index.js b/app/javascript/flavours/glitch/features/notifications/index.js index 26eeba168..67b155ced 100644 --- a/app/javascript/flavours/glitch/features/notifications/index.js +++ b/app/javascript/flavours/glitch/features/notifications/index.js @@ -30,7 +30,6 @@ import compareId from 'flavours/glitch/compare_id'; import NotificationsPermissionBanner from './components/notifications_permission_banner'; import NotSignedInIndicator from 'flavours/glitch/components/not_signed_in_indicator'; import { Helmet } from 'react-helmet'; -import { title } from 'flavours/glitch/initial_state'; import NotificationPurgeButtonsContainer from 'flavours/glitch/containers/notification_purge_buttons_container'; @@ -373,7 +372,8 @@ class Notifications extends React.PureComponent { {scrollContainer} <Helmet> - <title>{intl.formatMessage(messages.title)} - {title}</title> + <title>{intl.formatMessage(messages.title)}</title> + <meta name='robots' content='noindex' /> </Helmet> </Column> ); diff --git a/app/javascript/flavours/glitch/features/pinned_statuses/index.js b/app/javascript/flavours/glitch/features/pinned_statuses/index.js index 518d0294b..eeeab46ab 100644 --- a/app/javascript/flavours/glitch/features/pinned_statuses/index.js +++ b/app/javascript/flavours/glitch/features/pinned_statuses/index.js @@ -8,6 +8,7 @@ import ColumnBackButtonSlim from 'flavours/glitch/components/column_back_button_ import StatusList from 'flavours/glitch/components/status_list'; import { defineMessages, injectIntl } from 'react-intl'; import ImmutablePureComponent from 'react-immutable-pure-component'; +import { Helmet } from 'react-helmet'; const messages = defineMessages({ heading: { id: 'column.pins', defaultMessage: 'Pinned post' }, @@ -54,6 +55,9 @@ class PinnedStatuses extends ImmutablePureComponent { hasMore={hasMore} bindToDocument={!multiColumn} /> + <Helmet> + <meta name='robots' content='noindex' /> + </Helmet> </Column> ); } diff --git a/app/javascript/flavours/glitch/features/privacy_policy/index.js b/app/javascript/flavours/glitch/features/privacy_policy/index.js new file mode 100644 index 000000000..4618d9e32 --- /dev/null +++ b/app/javascript/flavours/glitch/features/privacy_policy/index.js @@ -0,0 +1,61 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { Helmet } from 'react-helmet'; +import { FormattedMessage, FormattedDate, injectIntl, defineMessages } from 'react-intl'; +import Column from 'flavours/glitch/components/column'; +import api from 'flavours/glitch/api'; +import Skeleton from 'flavours/glitch/components/skeleton'; + +const messages = defineMessages({ + title: { id: 'privacy_policy.title', defaultMessage: 'Privacy Policy' }, +}); + +export default @injectIntl +class PrivacyPolicy extends React.PureComponent { + + static propTypes = { + intl: PropTypes.object, + multiColumn: PropTypes.bool, + }; + + state = { + content: null, + lastUpdated: null, + isLoading: true, + }; + + componentDidMount () { + api().get('/api/v1/instance/privacy_policy').then(({ data }) => { + this.setState({ content: data.content, lastUpdated: data.updated_at, isLoading: false }); + }).catch(() => { + this.setState({ isLoading: false }); + }); + } + + render () { + const { intl, multiColumn } = this.props; + const { isLoading, content, lastUpdated } = this.state; + + return ( + <Column bindToDocument={!multiColumn} label={intl.formatMessage(messages.title)}> + <div className='scrollable privacy-policy'> + <div className='column-title'> + <h3><FormattedMessage id='privacy_policy.title' defaultMessage='Privacy Policy' /></h3> + <p><FormattedMessage id='privacy_policy.last_updated' defaultMessage='Last updated {date}' values={{ date: isLoading ? <Skeleton width='10ch' /> : <FormattedDate value={lastUpdated} year='numeric' month='short' day='2-digit' /> }} /></p> + </div> + + <div + className='privacy-policy__body prose' + dangerouslySetInnerHTML={{ __html: content }} + /> + </div> + + <Helmet> + <title>{intl.formatMessage(messages.title)}</title> + <meta name='robots' content='all' /> + </Helmet> + </Column> + ); + } + +} diff --git a/app/javascript/flavours/glitch/features/public_timeline/index.js b/app/javascript/flavours/glitch/features/public_timeline/index.js index aa70acf15..a61a47de1 100644 --- a/app/javascript/flavours/glitch/features/public_timeline/index.js +++ b/app/javascript/flavours/glitch/features/public_timeline/index.js @@ -10,7 +10,7 @@ import { addColumn, removeColumn, moveColumn } from 'flavours/glitch/actions/col import ColumnSettingsContainer from './containers/column_settings_container'; import { connectPublicStream } from 'flavours/glitch/actions/streaming'; import { Helmet } from 'react-helmet'; -import { title } from 'flavours/glitch/initial_state'; +import DismissableBanner from 'flavours/glitch/components/dismissable_banner'; const messages = defineMessages({ title: { id: 'column.public', defaultMessage: 'Federated timeline' }, @@ -143,6 +143,10 @@ class PublicTimeline extends React.PureComponent { <ColumnSettingsContainer columnId={columnId} /> </ColumnHeader> + <DismissableBanner id='public_timeline'> + <FormattedMessage id='dismissable_banner.public_timeline' defaultMessage='These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.' /> + </DismissableBanner> + <StatusListContainer timelineId={`public${onlyRemote ? ':remote' : (allowLocalOnly ? ':allow_local_only' : '')}${onlyMedia ? ':media' : ''}`} onLoadMore={this.handleLoadMore} @@ -154,7 +158,8 @@ class PublicTimeline extends React.PureComponent { /> <Helmet> - <title>{intl.formatMessage(messages.title)} - {title}</title> + <title>{intl.formatMessage(messages.title)}</title> + <meta name='robots' content='noindex' /> </Helmet> </Column> ); diff --git a/app/javascript/flavours/glitch/features/reblogs/index.js b/app/javascript/flavours/glitch/features/reblogs/index.js index ed646c6ed..b097ff9d7 100644 --- a/app/javascript/flavours/glitch/features/reblogs/index.js +++ b/app/javascript/flavours/glitch/features/reblogs/index.js @@ -11,6 +11,7 @@ import ColumnHeader from 'flavours/glitch/components/column_header'; import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import ImmutablePureComponent from 'react-immutable-pure-component'; import ScrollableList from 'flavours/glitch/components/scrollable_list'; +import { Helmet } from 'react-helmet'; const messages = defineMessages({ heading: { id: 'column.reblogged_by', defaultMessage: 'Boosted by' }, @@ -92,6 +93,10 @@ class Reblogs extends ImmutablePureComponent { <AccountContainer key={id} id={id} withNote={false} />, )} </ScrollableList> + + <Helmet> + <meta name='robots' content='noindex' /> + </Helmet> </Column> ); } diff --git a/app/javascript/flavours/glitch/features/report/category.js b/app/javascript/flavours/glitch/features/report/category.js index 43fb7a17c..55c43577b 100644 --- a/app/javascript/flavours/glitch/features/report/category.js +++ b/app/javascript/flavours/glitch/features/report/category.js @@ -5,6 +5,7 @@ import { connect } from 'react-redux'; import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import Button from 'flavours/glitch/components/button'; import Option from './components/option'; +import { List as ImmutableList } from 'immutable'; const messages = defineMessages({ dislike: { id: 'report.reasons.dislike', defaultMessage: 'I don\'t like it' }, @@ -20,7 +21,7 @@ const messages = defineMessages({ }); const mapStateToProps = state => ({ - rules: state.getIn(['server', 'rules']), + rules: state.getIn(['server', 'server', 'rules'], ImmutableList()), }); export default @connect(mapStateToProps) diff --git a/app/javascript/flavours/glitch/features/report/rules.js b/app/javascript/flavours/glitch/features/report/rules.js index 599c04dbd..efcdf1fcf 100644 --- a/app/javascript/flavours/glitch/features/report/rules.js +++ b/app/javascript/flavours/glitch/features/report/rules.js @@ -7,7 +7,7 @@ import Button from 'flavours/glitch/components/button'; import Option from './components/option'; const mapStateToProps = state => ({ - rules: state.getIn(['server', 'rules']), + rules: state.getIn(['server', 'server', 'rules']), }); export default @connect(mapStateToProps) diff --git a/app/javascript/flavours/glitch/features/standalone/hashtag_timeline/index.js b/app/javascript/flavours/glitch/features/standalone/hashtag_timeline/index.js deleted file mode 100644 index 629f5c2ea..000000000 --- a/app/javascript/flavours/glitch/features/standalone/hashtag_timeline/index.js +++ /dev/null @@ -1,90 +0,0 @@ -import React from 'react'; -import { connect } from 'react-redux'; -import PropTypes from 'prop-types'; -import ImmutablePropTypes from 'react-immutable-proptypes'; -import { expandHashtagTimeline } from 'flavours/glitch/actions/timelines'; -import Masonry from 'react-masonry-infinite'; -import { List as ImmutableList } from 'immutable'; -import DetailedStatusContainer from 'flavours/glitch/features/status/containers/detailed_status_container'; -import { debounce } from 'lodash'; -import LoadingIndicator from 'flavours/glitch/components/loading_indicator'; - -const mapStateToProps = (state, { hashtag }) => ({ - statusIds: state.getIn(['timelines', `hashtag:${hashtag}`, 'items'], ImmutableList()), - isLoading: state.getIn(['timelines', `hashtag:${hashtag}`, 'isLoading'], false), - hasMore: state.getIn(['timelines', `hashtag:${hashtag}`, 'hasMore'], false), -}); - -export default @connect(mapStateToProps) -class HashtagTimeline extends React.PureComponent { - - static propTypes = { - dispatch: PropTypes.func.isRequired, - statusIds: ImmutablePropTypes.list.isRequired, - isLoading: PropTypes.bool.isRequired, - hasMore: PropTypes.bool.isRequired, - hashtag: PropTypes.string.isRequired, - local: PropTypes.bool.isRequired, - }; - - static defaultProps = { - local: false, - }; - - componentDidMount () { - const { dispatch, hashtag, local } = this.props; - - dispatch(expandHashtagTimeline(hashtag, { local })); - } - - handleLoadMore = () => { - const { dispatch, hashtag, local, statusIds } = this.props; - const maxId = statusIds.last(); - - if (maxId) { - dispatch(expandHashtagTimeline(hashtag, { maxId, local })); - } - } - - setRef = c => { - this.masonry = c; - } - - handleHeightChange = debounce(() => { - if (!this.masonry) { - return; - } - - this.masonry.forcePack(); - }, 50) - - render () { - const { statusIds, hasMore, isLoading } = this.props; - - const sizes = [ - { columns: 1, gutter: 0 }, - { mq: '415px', columns: 1, gutter: 10 }, - { mq: '640px', columns: 2, gutter: 10 }, - { mq: '960px', columns: 3, gutter: 10 }, - { mq: '1255px', columns: 3, gutter: 10 }, - ]; - - const loader = (isLoading && statusIds.isEmpty()) ? <LoadingIndicator key={0} /> : undefined; - - return ( - <Masonry ref={this.setRef} className='statuses-grid' hasMore={hasMore} loadMore={this.handleLoadMore} sizes={sizes} loader={loader}> - {statusIds.map(statusId => ( - <div className='statuses-grid__item' key={statusId}> - <DetailedStatusContainer - id={statusId} - compact - measureHeight - onHeightChange={this.handleHeightChange} - /> - </div> - )).toArray()} - </Masonry> - ); - } - -} diff --git a/app/javascript/flavours/glitch/features/standalone/public_timeline/index.js b/app/javascript/flavours/glitch/features/standalone/public_timeline/index.js deleted file mode 100644 index 5f8a369ff..000000000 --- a/app/javascript/flavours/glitch/features/standalone/public_timeline/index.js +++ /dev/null @@ -1,100 +0,0 @@ -import React from 'react'; -import { connect } from 'react-redux'; -import PropTypes from 'prop-types'; -import ImmutablePropTypes from 'react-immutable-proptypes'; -import { expandPublicTimeline, expandCommunityTimeline } from 'flavours/glitch/actions/timelines'; -import Masonry from 'react-masonry-infinite'; -import { List as ImmutableList, Map as ImmutableMap } from 'immutable'; -import DetailedStatusContainer from 'flavours/glitch/features/status/containers/detailed_status_container'; -import { debounce } from 'lodash'; -import LoadingIndicator from 'flavours/glitch/components/loading_indicator'; - -const mapStateToProps = (state, { local }) => { - const timeline = state.getIn(['timelines', local ? 'community' : 'public'], ImmutableMap()); - - return { - statusIds: timeline.get('items', ImmutableList()), - isLoading: timeline.get('isLoading', false), - hasMore: timeline.get('hasMore', false), - }; -}; - -export default @connect(mapStateToProps) -class PublicTimeline extends React.PureComponent { - - static propTypes = { - dispatch: PropTypes.func.isRequired, - statusIds: ImmutablePropTypes.list.isRequired, - isLoading: PropTypes.bool.isRequired, - hasMore: PropTypes.bool.isRequired, - local: PropTypes.bool, - }; - - componentDidMount () { - this._connect(); - } - - componentDidUpdate (prevProps) { - if (prevProps.local !== this.props.local) { - this._disconnect(); - this._connect(); - } - } - - _connect () { - const { dispatch, local } = this.props; - - dispatch(local ? expandCommunityTimeline() : expandPublicTimeline()); - } - - handleLoadMore = () => { - const { dispatch, statusIds, local } = this.props; - const maxId = statusIds.last(); - - if (maxId) { - dispatch(local ? expandCommunityTimeline({ maxId }) : expandPublicTimeline({ maxId })); - } - } - - setRef = c => { - this.masonry = c; - } - - handleHeightChange = debounce(() => { - if (!this.masonry) { - return; - } - - this.masonry.forcePack(); - }, 50) - - render () { - const { statusIds, hasMore, isLoading } = this.props; - - const sizes = [ - { columns: 1, gutter: 0 }, - { mq: '415px', columns: 1, gutter: 10 }, - { mq: '640px', columns: 2, gutter: 10 }, - { mq: '960px', columns: 3, gutter: 10 }, - { mq: '1255px', columns: 3, gutter: 10 }, - ]; - - const loader = (isLoading && statusIds.isEmpty()) ? <LoadingIndicator key={0} /> : undefined; - - return ( - <Masonry ref={this.setRef} className='statuses-grid' hasMore={hasMore} loadMore={this.handleLoadMore} sizes={sizes} loader={loader}> - {statusIds.map(statusId => ( - <div className='statuses-grid__item' key={statusId}> - <DetailedStatusContainer - id={statusId} - compact - measureHeight - onHeightChange={this.handleHeightChange} - /> - </div> - )).toArray()} - </Masonry> - ); - } - -} diff --git a/app/javascript/flavours/glitch/features/status/components/action_bar.js b/app/javascript/flavours/glitch/features/status/components/action_bar.js index 9868621fe..0e21ca5cc 100644 --- a/app/javascript/flavours/glitch/features/status/components/action_bar.js +++ b/app/javascript/flavours/glitch/features/status/components/action_bar.js @@ -175,7 +175,7 @@ class ActionBar extends React.PureComponent { menu.push({ text: intl.formatMessage(mutingConversation ? messages.unmuteConversation : messages.muteConversation), action: this.handleConversationMuteClick }); menu.push(null); - // menu.push({ text: intl.formatMessage(messages.edit), action: this.handleEditClick }); + menu.push({ text: intl.formatMessage(messages.edit), action: this.handleEditClick }); menu.push({ text: intl.formatMessage(messages.delete), action: this.handleDeleteClick }); menu.push({ text: intl.formatMessage(messages.redraft), action: this.handleRedraftClick }); } else { diff --git a/app/javascript/flavours/glitch/features/status/index.js b/app/javascript/flavours/glitch/features/status/index.js index c967ef34d..f59e8c7f6 100644 --- a/app/javascript/flavours/glitch/features/status/index.js +++ b/app/javascript/flavours/glitch/features/status/index.js @@ -7,6 +7,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes'; import { createSelector } from 'reselect'; import { fetchStatus } from 'flavours/glitch/actions/statuses'; import MissingIndicator from 'flavours/glitch/components/missing_indicator'; +import LoadingIndicator from 'flavours/glitch/components/loading_indicator'; import DetailedStatus from './components/detailed_status'; import ActionBar from './components/action_bar'; import Column from 'flavours/glitch/features/ui/components/column'; @@ -47,7 +48,7 @@ import { openModal } from 'flavours/glitch/actions/modal'; import { defineMessages, injectIntl } from 'react-intl'; import ImmutablePureComponent from 'react-immutable-pure-component'; import { HotKeys } from 'react-hotkeys'; -import { boostModal, favouriteModal, deleteModal, title } from 'flavours/glitch/initial_state'; +import { boostModal, favouriteModal, deleteModal } from 'flavours/glitch/initial_state'; import { attachFullscreenListener, detachFullscreenListener, isFullscreen } from '../ui/util/fullscreen'; import { autoUnfoldCW } from 'flavours/glitch/utils/content_warning'; import { textForScreenReader, defaultMediaVisibility } from 'flavours/glitch/components/status'; @@ -135,6 +136,7 @@ const makeMapStateToProps = () => { } return { + isLoading: state.getIn(['statuses', props.params.statusId, 'isLoading']), status, ancestorsIds, descendantsIds, @@ -178,6 +180,7 @@ class Status extends ImmutablePureComponent { params: PropTypes.object.isRequired, dispatch: PropTypes.func.isRequired, status: ImmutablePropTypes.map, + isLoading: PropTypes.bool, settings: ImmutablePropTypes.map.isRequired, ancestorsIds: ImmutablePropTypes.list, descendantsIds: ImmutablePropTypes.list, @@ -589,9 +592,17 @@ class Status extends ImmutablePureComponent { render () { let ancestors, descendants; - const { status, settings, ancestorsIds, descendantsIds, intl, domain, multiColumn, usingPiP } = this.props; + const { isLoading, status, settings, ancestorsIds, descendantsIds, intl, domain, multiColumn, usingPiP } = this.props; const { fullscreen } = this.state; + if (isLoading) { + return ( + <Column> + <LoadingIndicator /> + </Column> + ); + } + if (status === null) { return ( <Column> @@ -611,6 +622,9 @@ class Status extends ImmutablePureComponent { descendants = <div>{this.renderChildren(descendantsIds)}</div>; } + const isLocal = status.getIn(['account', 'acct'], '').indexOf('@') === -1; + const isIndexable = !status.getIn(['account', 'noindex']); + const handlers = { moveUp: this.handleHotkeyMoveUp, moveDown: this.handleHotkeyMoveDown, @@ -684,7 +698,8 @@ class Status extends ImmutablePureComponent { </ScrollContainer> <Helmet> - <title>{titleFromStatus(status)} - {title}</title> + <title>{titleFromStatus(status)}</title> + <meta name='robots' content={(isLocal && isIndexable) ? 'all' : 'noindex'} /> </Helmet> </Column> ); diff --git a/app/javascript/flavours/glitch/features/ui/components/bundle_column_error.js b/app/javascript/flavours/glitch/features/ui/components/bundle_column_error.js index 3e979a250..7cbe1413d 100644 --- a/app/javascript/flavours/glitch/features/ui/components/bundle_column_error.js +++ b/app/javascript/flavours/glitch/features/ui/components/bundle_column_error.js @@ -1,44 +1,162 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { defineMessages, injectIntl } from 'react-intl'; +import { injectIntl, FormattedMessage } from 'react-intl'; +import Column from 'flavours/glitch/components/column'; +import Button from 'flavours/glitch/components/button'; +import { Helmet } from 'react-helmet'; +import { Link } from 'react-router-dom'; +import classNames from 'classnames'; +import { autoPlayGif } from 'flavours/glitch/initial_state'; -import Column from './column'; -import ColumnHeader from './column_header'; -import ColumnBackButtonSlim from 'flavours/glitch/components/column_back_button_slim'; -import IconButton from 'flavours/glitch/components/icon_button'; +class GIF extends React.PureComponent { -const messages = defineMessages({ - title: { id: 'bundle_column_error.title', defaultMessage: 'Network error' }, - body: { id: 'bundle_column_error.body', defaultMessage: 'Something went wrong while loading this component.' }, - retry: { id: 'bundle_column_error.retry', defaultMessage: 'Try again' }, -}); + static propTypes = { + src: PropTypes.string.isRequired, + staticSrc: PropTypes.string.isRequired, + className: PropTypes.string, + animate: PropTypes.bool, + }; + + static defaultProps = { + animate: autoPlayGif, + }; + + state = { + hovering: false, + }; + + handleMouseEnter = () => { + const { animate } = this.props; + + if (!animate) { + this.setState({ hovering: true }); + } + } -class BundleColumnError extends React.Component { + handleMouseLeave = () => { + const { animate } = this.props; + + if (!animate) { + this.setState({ hovering: false }); + } + } + + render () { + const { src, staticSrc, className, animate } = this.props; + const { hovering } = this.state; + + return ( + <img + className={className} + src={(hovering || animate) ? src : staticSrc} + alt='' + role='presentation' + onMouseEnter={this.handleMouseEnter} + onMouseLeave={this.handleMouseLeave} + /> + ); + } + +} + +class CopyButton extends React.PureComponent { static propTypes = { - onRetry: PropTypes.func.isRequired, - intl: PropTypes.object.isRequired, + children: PropTypes.node.isRequired, + value: PropTypes.string.isRequired, + }; + + state = { + copied: false, + }; + + handleClick = () => { + const { value } = this.props; + navigator.clipboard.writeText(value); + this.setState({ copied: true }); + this.timeout = setTimeout(() => this.setState({ copied: false }), 700); + } + + componentWillUnmount () { + if (this.timeout) clearTimeout(this.timeout); } + render () { + const { children } = this.props; + const { copied } = this.state; + + return ( + <Button onClick={this.handleClick} className={copied ? 'copied' : 'copyable'}>{copied ? <FormattedMessage id='copypaste.copied' defaultMessage='Copied' /> : children}</Button> + ); + } + +} + +export default @injectIntl +class BundleColumnError extends React.PureComponent { + + static propTypes = { + errorType: PropTypes.oneOf(['routing', 'network', 'error']), + onRetry: PropTypes.func, + intl: PropTypes.object.isRequired, + multiColumn: PropTypes.bool, + stacktrace: PropTypes.string, + }; + + static defaultProps = { + errorType: 'routing', + }; + handleRetry = () => { - this.props.onRetry(); + const { onRetry } = this.props; + + if (onRetry) { + onRetry(); + } } render () { - const { intl: { formatMessage } } = this.props; + const { errorType, multiColumn, stacktrace } = this.props; + + let title, body; + + switch(errorType) { + case 'routing': + title = <FormattedMessage id='bundle_column_error.routing.title' defaultMessage='404' />; + body = <FormattedMessage id='bundle_column_error.routing.body' defaultMessage='The requested page could not be found. Are you sure the URL in the address bar is correct?' />; + break; + case 'network': + title = <FormattedMessage id='bundle_column_error.network.title' defaultMessage='Network error' />; + body = <FormattedMessage id='bundle_column_error.network.body' defaultMessage='There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.' />; + break; + case 'error': + title = <FormattedMessage id='bundle_column_error.error.title' defaultMessage='Oh, no!' />; + body = <FormattedMessage id='bundle_column_error.error.body' defaultMessage='The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.' />; + break; + } return ( - <Column> - <ColumnHeader icon='exclamation-circle' type={formatMessage(messages.title)} /> - <ColumnBackButtonSlim /> + <Column bindToDocument={!multiColumn}> <div className='error-column'> - <IconButton title={formatMessage(messages.retry)} icon='refresh' onClick={this.handleRetry} size={64} /> - {formatMessage(messages.body)} + <GIF src='/oops.gif' staticSrc='/oops.png' className='error-column__image' /> + + <div className='error-column__message'> + <h1>{title}</h1> + <p>{body}</p> + + <div className='error-column__message__actions'> + {errorType === 'network' && <Button onClick={this.handleRetry}><FormattedMessage id='bundle_column_error.retry' defaultMessage='Try again' /></Button>} + {errorType === 'error' && <CopyButton value={stacktrace}><FormattedMessage id='bundle_column_error.copy_stacktrace' defaultMessage='Copy error report' /></CopyButton>} + <Link to='/' className={classNames('button', { 'button-tertiary': errorType !== 'routing' })}><FormattedMessage id='bundle_column_error.return' defaultMessage='Go back home' /></Link> + </div> + </div> </div> + + <Helmet> + <meta name='robots' content='noindex' /> + </Helmet> </Column> ); } } - -export default injectIntl(BundleColumnError); diff --git a/app/javascript/flavours/glitch/features/ui/components/column_link.js b/app/javascript/flavours/glitch/features/ui/components/column_link.js index d04b869b6..4f04fdba2 100644 --- a/app/javascript/flavours/glitch/features/ui/components/column_link.js +++ b/app/javascript/flavours/glitch/features/ui/components/column_link.js @@ -1,26 +1,29 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { Link } from 'react-router-dom'; +import { NavLink } from 'react-router-dom'; import Icon from 'flavours/glitch/components/icon'; +import classNames from 'classnames'; -const ColumnLink = ({ icon, text, to, onClick, href, method, badge }) => { +const ColumnLink = ({ icon, text, to, onClick, href, method, badge, transparent, ...other }) => { + const className = classNames('column-link', { 'column-link--transparent': transparent }); const badgeElement = typeof badge !== 'undefined' ? <span className='column-link__badge'>{badge}</span> : null; + const iconElement = typeof icon === 'string' ? <Icon id={icon} fixedWidth className='column-link__icon' /> : icon; if (href) { return ( - <a href={href} className='column-link' data-method={method}> - <Icon id={icon} fixedWidth className='column-link__icon' /> - {text} + <a href={href} className={className} data-method={method} title={text} {...other}> + {iconElement} + <span>{text}</span> {badgeElement} </a> ); } else if (to) { return ( - <Link to={to} className='column-link'> - <Icon id={icon} fixedWidth className='column-link__icon' /> - {text} + <NavLink to={to} className={className} title={text} {...other}> + {iconElement} + <span>{text}</span> {badgeElement} - </Link> + </NavLink> ); } else { const handleOnClick = (e) => { @@ -29,8 +32,8 @@ const ColumnLink = ({ icon, text, to, onClick, href, method, badge }) => { return onClick(e); } return ( - <a href='#' onClick={onClick && handleOnClick} className='column-link' tabIndex='0'> - <Icon id={icon} fixedWidth className='column-link__icon' /> + <a href='#' onClick={onClick && handleOnClick} className={className} title={text} {...other} tabIndex='0'> + {iconElement} {text} {badgeElement} </a> @@ -39,13 +42,14 @@ const ColumnLink = ({ icon, text, to, onClick, href, method, badge }) => { }; ColumnLink.propTypes = { - icon: PropTypes.string.isRequired, + icon: PropTypes.oneOfType([PropTypes.string, PropTypes.node]).isRequired, text: PropTypes.string.isRequired, to: PropTypes.string, onClick: PropTypes.func, href: PropTypes.string, method: PropTypes.string, badge: PropTypes.node, + transparent: PropTypes.bool, }; export default ColumnLink; diff --git a/app/javascript/flavours/glitch/features/ui/components/column_loading.js b/app/javascript/flavours/glitch/features/ui/components/column_loading.js index 22c00c915..b07385397 100644 --- a/app/javascript/flavours/glitch/features/ui/components/column_loading.js +++ b/app/javascript/flavours/glitch/features/ui/components/column_loading.js @@ -10,6 +10,7 @@ export default class ColumnLoading extends ImmutablePureComponent { static propTypes = { title: PropTypes.oneOfType([PropTypes.node, PropTypes.string]), icon: PropTypes.string, + multiColumn: PropTypes.bool, }; static defaultProps = { @@ -18,10 +19,11 @@ export default class ColumnLoading extends ImmutablePureComponent { }; render() { - let { title, icon } = this.props; + let { title, icon, multiColumn } = this.props; + return ( <Column> - <ColumnHeader icon={icon} title={title} multiColumn={false} focusable={false} placeholder /> + <ColumnHeader icon={icon} title={title} multiColumn={multiColumn} focusable={false} placeholder /> <div className='scrollable' /> </Column> ); diff --git a/app/javascript/flavours/glitch/features/ui/components/columns_area.js b/app/javascript/flavours/glitch/features/ui/components/columns_area.js index 718b4a27f..bf3e79c24 100644 --- a/app/javascript/flavours/glitch/features/ui/components/columns_area.js +++ b/app/javascript/flavours/glitch/features/ui/components/columns_area.js @@ -1,15 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { defineMessages, injectIntl } from 'react-intl'; import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePureComponent from 'react-immutable-pure-component'; - -import ReactSwipeableViews from 'react-swipeable-views'; -import TabsBar, { links, getIndex, getLink } from './tabs_bar'; -import { Link } from 'react-router-dom'; - -import { disableSwiping } from 'flavours/glitch/initial_state'; - import BundleContainer from '../containers/bundle_container'; import ColumnLoading from './column_loading'; import DrawerLoading from './drawer_loading'; @@ -27,7 +19,6 @@ import { ListTimeline, Directory, } from '../../ui/util/async-components'; -import Icon from 'flavours/glitch/components/icon'; import ComposePanel from './compose_panel'; import NavigationPanel from './navigation_panel'; @@ -49,22 +40,13 @@ const componentMap = { 'DIRECTORY': Directory, }; -const shouldHideFAB = path => path.match(/^\/statuses\/|^\/@[^/]+\/\d+|^\/publish|^\/explore|^\/getting-started|^\/start/); - -const messages = defineMessages({ - publish: { id: 'compose_form.publish', defaultMessage: 'Toot' }, -}); - -export default @(component => injectIntl(component, { withRef: true })) -class ColumnsArea extends ImmutablePureComponent { +export default class ColumnsArea extends ImmutablePureComponent { static contextTypes = { router: PropTypes.object.isRequired, - identity: PropTypes.object.isRequired, }; static propTypes = { - intl: PropTypes.object.isRequired, columns: ImmutablePropTypes.list.isRequired, singleColumn: PropTypes.bool, children: PropTypes.node, @@ -72,20 +54,13 @@ class ColumnsArea extends ImmutablePureComponent { openSettings: PropTypes.func, }; - // Corresponds to (max-width: 600px + (285px * 1) + (10px * 1)) in SCSS - mediaQuery = 'matchMedia' in window && window.matchMedia('(max-width: 895px)'); + // Corresponds to (max-width: $no-gap-breakpoint + 285px - 1px) in SCSS + mediaQuery = 'matchMedia' in window && window.matchMedia('(max-width: 1174px)'); state = { - shouldAnimate: false, renderComposePanel: !(this.mediaQuery && this.mediaQuery.matches), } - componentWillReceiveProps() { - if (typeof this.pendingIndex !== 'number' && this.lastIndex !== getIndex(this.context.router.history.location.pathname)) { - this.setState({ shouldAnimate: false }); - } - } - componentDidMount() { if (!this.props.singleColumn) { this.node.addEventListener('wheel', this.handleWheel, supportsPassiveEvents ? { passive: true } : false); @@ -100,10 +75,7 @@ class ColumnsArea extends ImmutablePureComponent { this.setState({ renderComposePanel: !this.mediaQuery.matches }); } - this.lastIndex = getIndex(this.context.router.history.location.pathname); this.isRtlLayout = document.getElementsByTagName('body')[0].classList.contains('rtl'); - - this.setState({ shouldAnimate: true }); } componentWillUpdate(nextProps) { @@ -116,13 +88,6 @@ class ColumnsArea extends ImmutablePureComponent { if (this.props.singleColumn !== prevProps.singleColumn && !this.props.singleColumn) { this.node.addEventListener('wheel', this.handleWheel, supportsPassiveEvents ? { passive: true } : false); } - - const newIndex = getIndex(this.context.router.history.location.pathname); - - if (this.lastIndex !== newIndex) { - this.lastIndex = newIndex; - this.setState({ shouldAnimate: true }); - } } componentWillUnmount () { @@ -150,31 +115,6 @@ class ColumnsArea extends ImmutablePureComponent { this.setState({ renderComposePanel: !e.matches }); } - handleSwipe = (index) => { - this.pendingIndex = index; - - const nextLinkTranslationId = links[index].props['data-preview-title-id']; - const currentLinkSelector = '.tabs-bar__link.active'; - const nextLinkSelector = `.tabs-bar__link[data-preview-title-id="${nextLinkTranslationId}"]`; - - // HACK: Remove the active class from the current link and set it to the next one - // React-router does this for us, but too late, feeling laggy. - document.querySelector(currentLinkSelector).classList.remove('active'); - document.querySelector(nextLinkSelector).classList.add('active'); - - if (!this.state.shouldAnimate && typeof this.pendingIndex === 'number') { - this.context.router.history.push(getLink(this.pendingIndex)); - this.pendingIndex = null; - } - } - - handleAnimationEnd = () => { - if (typeof this.pendingIndex === 'number') { - this.context.router.history.push(getLink(this.pendingIndex)); - this.pendingIndex = null; - } - } - handleWheel = () => { if (typeof this._interruptScrollAnimation !== 'function') { return; @@ -187,48 +127,19 @@ class ColumnsArea extends ImmutablePureComponent { this.node = node; } - renderView = (link, index) => { - const columnIndex = getIndex(this.context.router.history.location.pathname); - const title = this.props.intl.formatMessage({ id: link.props['data-preview-title-id'] }); - const icon = link.props['data-preview-icon']; - - const view = (index === columnIndex) ? - React.cloneElement(this.props.children) : - <ColumnLoading title={title} icon={icon} />; - - return ( - <div className='columns-area columns-area--mobile' key={index}> - {view} - </div> - ); - } - renderLoading = columnId => () => { - return columnId === 'COMPOSE' ? <DrawerLoading /> : <ColumnLoading />; + return columnId === 'COMPOSE' ? <DrawerLoading /> : <ColumnLoading multiColumn />; } renderError = (props) => { - return <BundleColumnError {...props} />; + return <BundleColumnError multiColumn errorType='network' {...props} />; } render () { - const { columns, children, singleColumn, intl, navbarUnder, openSettings } = this.props; - const { shouldAnimate, renderComposePanel } = this.state; - const { signedIn } = this.context.identity; - - const columnIndex = getIndex(this.context.router.history.location.pathname); + const { columns, children, singleColumn, navbarUnder, openSettings } = this.props; + const { renderComposePanel } = this.state; if (singleColumn) { - const floatingActionButton = (!signedIn || shouldHideFAB(this.context.router.history.location.pathname)) ? null : <Link key='floating-action-button' to='/publish' className='floating-action-button' aria-label={intl.formatMessage(messages.publish)}><Icon id='pencil' /></Link>; - - const content = columnIndex !== -1 ? ( - <ReactSwipeableViews key='content' hysteresis={0.2} threshold={15} index={columnIndex} onChangeIndex={this.handleSwipe} onTransitionEnd={this.handleAnimationEnd} animateTransitions={shouldAnimate} springConfig={{ duration: '400ms', delay: '0s', easeFunction: 'ease' }} style={{ height: '100%' }} disabled={disableSwiping}> - {links.map(this.renderView)} - </ReactSwipeableViews> - ) : ( - <div key='content' className='columns-area columns-area--mobile'>{children}</div> - ); - return ( <div className='columns-area__panels'> <div className='columns-area__panels__pane columns-area__panels__pane--compositional'> @@ -237,10 +148,9 @@ class ColumnsArea extends ImmutablePureComponent { </div> </div> - <div className={`columns-area__panels__main ${floatingActionButton && 'with-fab'}`}> - {!navbarUnder && <TabsBar key='tabs' />} - {content} - {navbarUnder && <TabsBar key='tabs' />} + <div className='columns-area__panels__main'> + <div className='tabs-bar__wrapper'><div id='tabs-bar__portal' /></div> + <div className='columns-area columns-area--mobile'>{children}</div> </div> <div className='columns-area__panels__pane columns-area__panels__pane--start columns-area__panels__pane--navigational'> @@ -248,8 +158,6 @@ class ColumnsArea extends ImmutablePureComponent { <NavigationPanel onOpenSettings={openSettings} /> </div> </div> - - {floatingActionButton} </div> ); } diff --git a/app/javascript/flavours/glitch/features/ui/components/compose_panel.js b/app/javascript/flavours/glitch/features/ui/components/compose_panel.js index 6e1c51d74..dde252a61 100644 --- a/app/javascript/flavours/glitch/features/ui/components/compose_panel.js +++ b/app/javascript/flavours/glitch/features/ui/components/compose_panel.js @@ -1,18 +1,34 @@ import React from 'react'; +import { connect } from 'react-redux'; import PropTypes from 'prop-types'; import SearchContainer from 'flavours/glitch/features/compose/containers/search_container'; import ComposeFormContainer from 'flavours/glitch/features/compose/containers/compose_form_container'; import NavigationContainer from 'flavours/glitch/features/compose/containers/navigation_container'; import LinkFooter from './link_footer'; import ServerBanner from 'flavours/glitch/components/server_banner'; +import { mountCompose, unmountCompose } from 'flavours/glitch/actions/compose'; -export default +export default @connect() class ComposePanel extends React.PureComponent { static contextTypes = { identity: PropTypes.object.isRequired, }; + static propTypes = { + dispatch: PropTypes.func.isRequired, + }; + + componentDidMount () { + const { dispatch } = this.props; + dispatch(mountCompose()); + } + + componentWillUnmount () { + const { dispatch } = this.props; + dispatch(unmountCompose()); + } + render() { const { signedIn } = this.context.identity; @@ -34,7 +50,7 @@ class ComposePanel extends React.PureComponent { </React.Fragment> )} - <LinkFooter withHotkeys /> + <LinkFooter /> </div> ); } diff --git a/app/javascript/flavours/glitch/features/ui/components/follow_requests_nav_link.js b/app/javascript/flavours/glitch/features/ui/components/follow_requests_column_link.js index c30427896..301392a52 100644 --- a/app/javascript/flavours/glitch/features/ui/components/follow_requests_nav_link.js +++ b/app/javascript/flavours/glitch/features/ui/components/follow_requests_column_link.js @@ -2,22 +2,27 @@ import React from 'react'; import PropTypes from 'prop-types'; import { fetchFollowRequests } from 'flavours/glitch/actions/accounts'; import { connect } from 'react-redux'; -import { NavLink, withRouter } from 'react-router-dom'; +import ColumnLink from 'flavours/glitch/features/ui/components/column_link'; import IconWithBadge from 'flavours/glitch/components/icon_with_badge'; import { List as ImmutableList } from 'immutable'; -import { FormattedMessage } from 'react-intl'; +import { injectIntl, defineMessages } from 'react-intl'; + +const messages = defineMessages({ + text: { id: 'navigation_bar.follow_requests', defaultMessage: 'Follow requests' }, +}); const mapStateToProps = state => ({ count: state.getIn(['user_lists', 'follow_requests', 'items'], ImmutableList()).size, }); -export default @withRouter +export default @injectIntl @connect(mapStateToProps) -class FollowRequestsNavLink extends React.Component { +class FollowRequestsColumnLink extends React.Component { static propTypes = { dispatch: PropTypes.func.isRequired, count: PropTypes.number.isRequired, + intl: PropTypes.object.isRequired, }; componentDidMount () { @@ -27,13 +32,20 @@ class FollowRequestsNavLink extends React.Component { } render () { - const { count } = this.props; + const { count, intl } = this.props; if (count === 0) { return null; } - return <NavLink className='column-link column-link--transparent' to='/follow_requests'><IconWithBadge className='column-link__icon' id='user-plus' count={count} /><FormattedMessage id='navigation_bar.follow_requests' defaultMessage='Follow requests' /></NavLink>; + return ( + <ColumnLink + transparent + to='/follow_requests' + icon={<IconWithBadge className='column-link__icon' id='user-plus' count={count} />} + text={intl.formatMessage(messages.text)} + /> + ); } } diff --git a/app/javascript/flavours/glitch/features/ui/components/header.js b/app/javascript/flavours/glitch/features/ui/components/header.js new file mode 100644 index 000000000..6c2fb40ba --- /dev/null +++ b/app/javascript/flavours/glitch/features/ui/components/header.js @@ -0,0 +1,63 @@ +import React from 'react'; +import Logo from 'flavours/glitch/components/logo'; +import { Link, withRouter } from 'react-router-dom'; +import { FormattedMessage } from 'react-intl'; +import { registrationsOpen, me } from 'flavours/glitch/initial_state'; +import Avatar from 'flavours/glitch/components/avatar'; +import Permalink from 'flavours/glitch/components/permalink'; +import PropTypes from 'prop-types'; +import { connect } from 'react-redux'; + +const Account = connect(state => ({ + account: state.getIn(['accounts', me]), +}))(({ account }) => ( + <Permalink href={account.get('url')} to={`/@${account.get('acct')}`} title={account.get('acct')}> + <Avatar account={account} size={35} /> + </Permalink> +)); + +export default @withRouter +class Header extends React.PureComponent { + + static contextTypes = { + identity: PropTypes.object, + }; + + static propTypes = { + location: PropTypes.object, + }; + + render () { + const { signedIn } = this.context.identity; + const { location } = this.props; + + let content; + + if (signedIn) { + content = ( + <> + {location.pathname !== '/publish' && <Link to='/publish' className='button'><FormattedMessage id='compose_form.publish' defaultMessage='Publish' /></Link>} + <Account /> + </> + ); + } else { + content = ( + <> + <a href='/auth/sign_in' className='button'><FormattedMessage id='sign_in_banner.sign_in' defaultMessage='Sign in' /></a> + <a href={registrationsOpen ? '/auth/sign_up' : 'https://joinmastodon.org/servers'} className='button button-tertiary'><FormattedMessage id='sign_in_banner.create_account' defaultMessage='Create account' /></a> + </> + ); + } + + return ( + <div className='ui__header'> + <Link to='/' className='ui__header__logo'><Logo /></Link> + + <div className='ui__header__links'> + {content} + </div> + </div> + ); + } + +} diff --git a/app/javascript/flavours/glitch/features/ui/components/link_footer.js b/app/javascript/flavours/glitch/features/ui/components/link_footer.js index 39576f17b..2e061f760 100644 --- a/app/javascript/flavours/glitch/features/ui/components/link_footer.js +++ b/app/javascript/flavours/glitch/features/ui/components/link_footer.js @@ -3,8 +3,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { FormattedMessage, defineMessages, injectIntl } from 'react-intl'; import { Link } from 'react-router-dom'; -import { limitedFederationMode, version, repository, source_url, profile_directory as profileDirectory } from 'flavours/glitch/initial_state'; -import { signOutLink, securityLink, privacyPolicyLink } from 'flavours/glitch/utils/backend_links'; +import { version, repository, source_url, profile_directory as profileDirectory } from 'flavours/glitch/initial_state'; import { logOut } from 'flavours/glitch/utils/log_out'; import { openModal } from 'flavours/glitch/actions/modal'; import { PERMISSION_INVITE_USERS } from 'flavours/glitch/permissions'; @@ -34,7 +33,6 @@ class LinkFooter extends React.PureComponent { }; static propTypes = { - withHotkeys: PropTypes.bool, onLogout: PropTypes.func.isRequired, intl: PropTypes.object.isRequired, }; @@ -49,44 +47,26 @@ class LinkFooter extends React.PureComponent { } render () { - const { withHotkeys } = this.props; const { signedIn, permissions } = this.context.identity; - const items = []; - if ((this.context.identity.permissions & PERMISSION_INVITE_USERS) === PERMISSION_INVITE_USERS) { - items.push(<a key='invites' href='/invites' target='_blank'><FormattedMessage id='getting_started.invite' defaultMessage='Invite people' /></a>); - } - - if (signedIn && withHotkeys) { - items.push(<Link key='hotkeys' to='/keyboard-shortcuts'><FormattedMessage id='navigation_bar.keyboard_shortcuts' defaultMessage='Hotkeys' /></Link>); - } - - if (signedIn && securityLink) { - items.push(<a key='security' href='/auth/edit'><FormattedMessage id='getting_started.security' defaultMessage='Security' /></a>); - } - - if (!limitedFederationMode) { - items.push(<a key='about' href='/about/more' target='_blank'><FormattedMessage id='navigation_bar.info' defaultMessage='About this server' /></a>); - } + items.push(<a key='apps' href='https://joinmastodon.org/apps' target='_blank'><FormattedMessage id='navigation_bar.apps' defaultMessage='Get the app' /></a>); + items.push(<Link key='about' to='/about'><FormattedMessage id='navigation_bar.info' defaultMessage='About' /></Link>); + items.push(<a key='mastodon' href='https://joinmastodon.org' target='_blank'><FormattedMessage id='getting_started.what_is_mastodon' defaultMessage='About Mastodon' /></a>); + items.push(<a key='docs' href='https://docs.joinmastodon.org' target='_blank'><FormattedMessage id='getting_started.documentation' defaultMessage='Documentation' /></a>); + items.push(<Link key='privacy-policy' to='/privacy-policy'><FormattedMessage id='getting_started.privacy_policy' defaultMessage='Privacy Policy' /></Link>); + items.push(<Link key='hotkeys' to='/keyboard-shortcuts'><FormattedMessage id='navigation_bar.keyboard_shortcuts' defaultMessage='Hotkeys' /></Link>); if (profileDirectory) { - items.push(<Link key='directory' to='/directory'><FormattedMessage id='getting_started.directory' defaultMessage='Profile directory' /></Link>); - } - - items.push(<a key='apps' href='https://joinmastodon.org/apps' target='_blank'><FormattedMessage id='navigation_bar.apps' defaultMessage='Mobile apps' /></a>); - - if (privacyPolicyLink) { - items.push(<a key='terms' href={privacyPolicyLink} target='_blank'><FormattedMessage id='getting_started.privacy_policy' defaultMessage='Privacy Policy' /></a>); + items.push(<Link key='directory' to='/directory'><FormattedMessage id='getting_started.directory' defaultMessage='Directory' /></Link>); } if (signedIn) { - items.push(<a key='developers' href='/settings/applications' target='_blank'><FormattedMessage id='getting_started.developers' defaultMessage='Developers' /></a>); - } + if ((permissions & PERMISSION_INVITE_USERS) === PERMISSION_INVITE_USERS) { + items.push(<a key='invites' href='/invites' target='_blank'><FormattedMessage id='getting_started.invite' defaultMessage='Invite people' /></a>); + } - items.push(<a key='docs' href='https://docs.joinmastodon.org' target='_blank'><FormattedMessage id='getting_started.documentation' defaultMessage='Documentation' /></a>); - - if (signedIn) { + items.push(<a key='security' href='/auth/edit'><FormattedMessage id='getting_started.security' defaultMessage='Security' /></a>); items.push(<a key='logout' href='/auth/sign_out' onClick={this.handleLogoutClick}><FormattedMessage id='navigation_bar.logout' defaultMessage='Logout' /></a>); } diff --git a/app/javascript/flavours/glitch/features/ui/components/list_panel.js b/app/javascript/flavours/glitch/features/ui/components/list_panel.js index e61234283..dff830065 100644 --- a/app/javascript/flavours/glitch/features/ui/components/list_panel.js +++ b/app/javascript/flavours/glitch/features/ui/components/list_panel.js @@ -1,12 +1,12 @@ import React from 'react'; import PropTypes from 'prop-types'; +import { createSelector } from 'reselect'; import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePureComponent from 'react-immutable-pure-component'; -import { fetchLists } from 'flavours/glitch/actions/lists'; import { connect } from 'react-redux'; -import { createSelector } from 'reselect'; -import { NavLink, withRouter } from 'react-router-dom'; -import Icon from 'flavours/glitch/components/icon'; +import { withRouter } from 'react-router-dom'; +import { fetchLists } from 'flavours/glitch/actions/lists'; +import ColumnLink from './column_link'; const getOrderedLists = createSelector([state => state.get('lists')], lists => { if (!lists) { @@ -42,11 +42,11 @@ class ListPanel extends ImmutablePureComponent { } return ( - <div> + <div className='list-panel'> <hr /> {lists.map(list => ( - <NavLink key={list.get('id')} className='column-link column-link--transparent' strict to={`/lists/${list.get('id')}`}><Icon className='column-link__icon' id='list-ul' fixedWidth />{list.get('title')}</NavLink> + <ColumnLink icon='list-ul' key={list.get('id')} strict text={list.get('title')} to={`/lists/${list.get('id')}`} transparent /> ))} </div> ); diff --git a/app/javascript/flavours/glitch/features/ui/components/modal_root.js b/app/javascript/flavours/glitch/features/ui/components/modal_root.js index cedfabe03..93834f60e 100644 --- a/app/javascript/flavours/glitch/features/ui/components/modal_root.js +++ b/app/javascript/flavours/glitch/features/ui/components/modal_root.js @@ -13,10 +13,8 @@ import FavouriteModal from './favourite_modal'; import AudioModal from './audio_modal'; import DoodleModal from './doodle_modal'; import ConfirmationModal from './confirmation_modal'; -import SubscribedLanguagesModal from 'flavours/glitch/features/subscribed_languages_modal'; import FocalPointModal from './focal_point_modal'; import DeprecatedSettingsModal from './deprecated_settings_modal'; -import InteractionModal from 'flavours/glitch/features/interaction_modal'; import { OnboardingModal, MuteModal, @@ -29,7 +27,11 @@ import { PinnedAccountsEditor, CompareHistoryModal, FilterModal, + InteractionModal, + SubscribedLanguagesModal, + ClosedRegistrationsModal, } from 'flavours/glitch/features/ui/util/async-components'; +import { Helmet } from 'react-helmet'; const MODAL_COMPONENTS = { 'MEDIA': () => Promise.resolve({ default: MediaModal }), @@ -53,8 +55,9 @@ const MODAL_COMPONENTS = { 'PINNED_ACCOUNTS_EDITOR': PinnedAccountsEditor, 'COMPARE_HISTORY': CompareHistoryModal, 'FILTER': FilterModal, - 'SUBSCRIBED_LANGUAGES': () => Promise.resolve({ default: SubscribedLanguagesModal }), - 'INTERACTION': () => Promise.resolve({ default: InteractionModal }), + 'SUBSCRIBED_LANGUAGES': SubscribedLanguagesModal, + 'INTERACTION': InteractionModal, + 'CLOSED_REGISTRATIONS': ClosedRegistrationsModal, }; export default class ModalRoot extends React.PureComponent { @@ -119,9 +122,15 @@ export default class ModalRoot extends React.PureComponent { return ( <Base backgroundColor={backgroundColor} onClose={this.handleClose} noEsc={props ? props.noEsc : false} ignoreFocus={ignoreFocus}> {visible && ( - <BundleContainer fetchComponent={MODAL_COMPONENTS[type]} loading={this.renderLoading(type)} error={this.renderError} renderDelay={200}> - {(SpecificComponent) => <SpecificComponent {...props} onChangeBackgroundColor={this.setBackgroundColor} onClose={this.handleClose} ref={this.setModalRef} />} - </BundleContainer> + <> + <BundleContainer fetchComponent={MODAL_COMPONENTS[type]} loading={this.renderLoading(type)} error={this.renderError} renderDelay={200}> + {(SpecificComponent) => <SpecificComponent {...props} onChangeBackgroundColor={this.setBackgroundColor} onClose={this.handleClose} ref={this.setModalRef} />} + </BundleContainer> + + <Helmet> + <meta name='robots' content='noindex' /> + </Helmet> + </> )} </Base> ); diff --git a/app/javascript/flavours/glitch/features/ui/components/navigation_panel.js b/app/javascript/flavours/glitch/features/ui/components/navigation_panel.js index 57fbfb285..c3f14ac72 100644 --- a/app/javascript/flavours/glitch/features/ui/components/navigation_panel.js +++ b/app/javascript/flavours/glitch/features/ui/components/navigation_panel.js @@ -1,17 +1,35 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { NavLink, Link } from 'react-router-dom'; -import { FormattedMessage } from 'react-intl'; -import Icon from 'flavours/glitch/components/icon'; -import { showTrends } from 'flavours/glitch/initial_state'; -import { preferencesLink, relationshipsLink } from 'flavours/glitch/utils/backend_links'; -import NotificationsCounterIcon from './notifications_counter_icon'; -import FollowRequestsNavLink from './follow_requests_nav_link'; +import { defineMessages, injectIntl } from 'react-intl'; +import { Link } from 'react-router-dom'; +import { timelinePreview, showTrends } from 'flavours/glitch/initial_state'; +import ColumnLink from 'flavours/glitch/features/ui/components/column_link'; +import FollowRequestsColumnLink from './follow_requests_column_link'; import ListPanel from './list_panel'; -import TrendsContainer from 'flavours/glitch/features/getting_started/containers/trends_container'; +import NotificationsCounterIcon from './notifications_counter_icon'; import SignInBanner from './sign_in_banner'; +import { preferencesLink, relationshipsLink } from 'flavours/glitch/utils/backend_links'; +import NavigationPortal from 'flavours/glitch/components/navigation_portal'; + +const messages = defineMessages({ + home: { id: 'tabs_bar.home', defaultMessage: 'Home' }, + notifications: { id: 'tabs_bar.notifications', defaultMessage: 'Notifications' }, + explore: { id: 'explore.title', defaultMessage: 'Explore' }, + local: { id: 'tabs_bar.local_timeline', defaultMessage: 'Local' }, + federated: { id: 'tabs_bar.federated_timeline', defaultMessage: 'Federated' }, + direct: { id: 'navigation_bar.direct', defaultMessage: 'Direct messages' }, + favourites: { id: 'navigation_bar.favourites', defaultMessage: 'Favourites' }, + bookmarks: { id: 'navigation_bar.bookmarks', defaultMessage: 'Bookmarks' }, + lists: { id: 'navigation_bar.lists', defaultMessage: 'Lists' }, + preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' }, + followsAndFollowers: { id: 'navigation_bar.follows_and_followers', defaultMessage: 'Follows and followers' }, + about: { id: 'navigation_bar.about', defaultMessage: 'About' }, + search: { id: 'navigation_bar.search', defaultMessage: 'Search' }, + app_settings: { id: 'navigation_bar.app_settings', defaultMessage: 'App settings' }, +}); -export default class NavigationPanel extends React.Component { +export default @injectIntl +class NavigationPanel extends React.Component { static contextTypes = { router: PropTypes.object.isRequired, @@ -23,54 +41,61 @@ export default class NavigationPanel extends React.Component { }; render() { + const { intl, onOpenSettings } = this.props; const { signedIn } = this.context.identity; - const { onOpenSettings } = this.props; return ( <div className='navigation-panel'> {signedIn && ( <React.Fragment> - <NavLink className='column-link column-link--transparent' to='/home' data-preview-title-id='column.home' data-preview-icon='home' ><Icon className='column-link__icon' id='home' fixedWidth /><FormattedMessage id='tabs_bar.home' defaultMessage='Home' /></NavLink> - <NavLink className='column-link column-link--transparent' to='/notifications' data-preview-title-id='column.notifications' data-preview-icon='bell' ><NotificationsCounterIcon className='column-link__icon' /><FormattedMessage id='tabs_bar.notifications' defaultMessage='Notifications' /></NavLink> - <FollowRequestsNavLink /> + <ColumnLink transparent to='/home' icon='home' text={intl.formatMessage(messages.home)} /> + <ColumnLink transparent to='/notifications' icon={<NotificationsCounterIcon className='column-link__icon' />} text={intl.formatMessage(messages.notifications)} /> + <FollowRequestsColumnLink /> </React.Fragment> )} - { showTrends && <NavLink className='column-link column-link--transparent' to='/explore' data-preview-title-id='explore.title' data-preview-icon='hashtag'><Icon className='column-link__icon' id='hashtag' fixedWidth /><FormattedMessage id='explore.title' defaultMessage='Explore' /></NavLink> } + {showTrends ? ( + <ColumnLink transparent to='/explore' icon='hashtag' text={intl.formatMessage(messages.explore)} /> + ) : ( + <ColumnLink transparent to='/search' icon='search' text={intl.formatMessage(messages.search)} /> + )} - <NavLink className='column-link column-link--transparent' to='/public/local' data-preview-title-id='column.community' data-preview-icon='users' ><Icon className='column-link__icon' id='users' fixedWidth /><FormattedMessage id='tabs_bar.local_timeline' defaultMessage='Local' /></NavLink> - <NavLink className='column-link column-link--transparent' exact to='/public' data-preview-title-id='column.public' data-preview-icon='globe' ><Icon className='column-link__icon' id='globe' fixedWidth /><FormattedMessage id='tabs_bar.federated_timeline' defaultMessage='Federated' /></NavLink> + {(signedIn || timelinePreview) && ( + <> + <ColumnLink transparent to='/public/local' icon='users' text={intl.formatMessage(messages.local)} /> + <ColumnLink transparent exact to='/public' icon='globe' text={intl.formatMessage(messages.federated)} /> + </> + )} {!signedIn && ( - <React.Fragment> + <div className='navigation-panel__sign-in-banner'> <hr /> <SignInBanner /> - </React.Fragment> + </div> )} {signedIn && ( <React.Fragment> - <NavLink className='column-link column-link--transparent' to='/conversations'><Icon className='column-link__icon' id='envelope' fixedWidth /><FormattedMessage id='navigation_bar.direct' defaultMessage='Direct messages' /></NavLink> - <NavLink className='column-link column-link--transparent' to='/bookmarks'><Icon className='column-link__icon' id='bookmark' fixedWidth /><FormattedMessage id='navigation_bar.bookmarks' defaultMessage='Bookmarks' /></NavLink> - <NavLink className='column-link column-link--transparent' to='/lists'><Icon className='column-link__icon' id='list-ul' fixedWidth /><FormattedMessage id='navigation_bar.lists' defaultMessage='Lists' /></NavLink> + <ColumnLink transparent to='/conversations' icon='at' text={intl.formatMessage(messages.direct)} /> + <ColumnLink transparent to='/favourites' icon='star' text={intl.formatMessage(messages.favourites)} /> + <ColumnLink transparent to='/bookmarks' icon='bookmark' text={intl.formatMessage(messages.bookmarks)} /> + <ColumnLink transparent to='/lists' icon='list-ul' text={intl.formatMessage(messages.lists)} /> <ListPanel /> <hr /> - {!!preferencesLink && <a className='column-link column-link--transparent' href={preferencesLink} target='_blank'><Icon className='column-link__icon' id='cog' fixedWidth /><FormattedMessage id='navigation_bar.preferences' defaultMessage='Preferences' /></a>} - <a className='column-link column-link--transparent' href='#' onClick={onOpenSettings}><Icon className='column-link__icon' id='cogs' fixedWidth /><FormattedMessage id='navigation_bar.app_settings' defaultMessage='App settings' /></a> - {!!relationshipsLink && <a className='column-link column-link--transparent' href={relationshipsLink} target='_blank'><Icon className='column-link__icon' id='users' fixedWidth /><FormattedMessage id='navigation_bar.follows_and_followers' defaultMessage='Follows and followers' /></a>} + {!!preferencesLink && <ColumnLink transparent href={preferencesLink} icon='cog' text={intl.formatMessage(messages.preferences)} />} + <ColumnLink transparent href='#' onClick={onOpenSettings} icon='cogs' text={intl.formatMessage(messages.app_settings)} /> </React.Fragment> )} - {showTrends && ( - <React.Fragment> - <div className='flex-spacer' /> - <TrendsContainer /> - </React.Fragment> - )} + <div className='navigation-panel__legal'> + <hr /> + <ColumnLink transparent to='/about' icon='ellipsis-h' text={intl.formatMessage(messages.about)} /> + </div> + <NavigationPortal /> </div> ); } diff --git a/app/javascript/flavours/glitch/features/ui/components/sign_in_banner.js b/app/javascript/flavours/glitch/features/ui/components/sign_in_banner.js index a935d7422..e8023803f 100644 --- a/app/javascript/flavours/glitch/features/ui/components/sign_in_banner.js +++ b/app/javascript/flavours/glitch/features/ui/components/sign_in_banner.js @@ -1,13 +1,40 @@ -import React from 'react'; +import React, { useCallback } from 'react'; import { FormattedMessage } from 'react-intl'; +import { useDispatch } from 'react-redux'; import { registrationsOpen } from 'flavours/glitch/initial_state'; +import { openModal } from 'flavours/glitch/actions/modal'; -const SignInBanner = () => ( - <div className='sign-in-banner'> - <p><FormattedMessage id='sign_in_banner.text' defaultMessage='Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.' /></p> - <a href='/auth/sign_in' className='button button--block'><FormattedMessage id='sign_in_banner.sign_in' defaultMessage='Sign in' /></a> - <a href={registrationsOpen ? '/auth/sign_up' : 'https://joinmastodon.org/servers'} className='button button--block button-tertiary'><FormattedMessage id='sign_in_banner.create_account' defaultMessage='Create account' /></a> - </div> -); +const SignInBanner = () => { + const dispatch = useDispatch(); + + const openClosedRegistrationsModal = useCallback( + () => dispatch(openModal('CLOSED_REGISTRATIONS')), + [dispatch], + ); + + let signupButton; + + if (registrationsOpen) { + signupButton = ( + <a href='/auth/sign_up' className='button button--block button-tertiary'> + <FormattedMessage id='sign_in_banner.create_account' defaultMessage='Create account' /> + </a> + ); + } else { + signupButton = ( + <button className='button button--block button-tertiary' onClick={openClosedRegistrationsModal}> + <FormattedMessage id='sign_in_banner.create_account' defaultMessage='Create account' /> + </button> + ); + } + + return ( + <div className='sign-in-banner'> + <p><FormattedMessage id='sign_in_banner.text' defaultMessage='Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.' /></p> + <a href='/auth/sign_in' className='button button--block'><FormattedMessage id='sign_in_banner.sign_in' defaultMessage='Sign in' /></a> + {signupButton} + </div> + ); +}; export default SignInBanner; diff --git a/app/javascript/flavours/glitch/features/ui/components/tabs_bar.js b/app/javascript/flavours/glitch/features/ui/components/tabs_bar.js deleted file mode 100644 index 9c82fc91d..000000000 --- a/app/javascript/flavours/glitch/features/ui/components/tabs_bar.js +++ /dev/null @@ -1,86 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import { NavLink, withRouter } from 'react-router-dom'; -import { FormattedMessage, injectIntl } from 'react-intl'; -import { debounce } from 'lodash'; -import { isUserTouching } from 'flavours/glitch/is_mobile'; -import Icon from 'flavours/glitch/components/icon'; -import NotificationsCounterIcon from './notifications_counter_icon'; - -export const links = [ - <NavLink className='tabs-bar__link' to='/home' data-preview-title-id='column.home' data-preview-icon='home' ><Icon id='home' fixedWidth /><FormattedMessage id='tabs_bar.home' defaultMessage='Home' /></NavLink>, - <NavLink className='tabs-bar__link' to='/notifications' data-preview-title-id='column.notifications' data-preview-icon='bell' ><NotificationsCounterIcon /><FormattedMessage id='tabs_bar.notifications' defaultMessage='Notifications' /></NavLink>, - <NavLink className='tabs-bar__link' to='/public/local' data-preview-title-id='column.community' data-preview-icon='users' ><Icon id='users' fixedWidth /><FormattedMessage id='tabs_bar.local_timeline' defaultMessage='Local' /></NavLink>, - <NavLink className='tabs-bar__link' exact to='/public' data-preview-title-id='column.public' data-preview-icon='globe' ><Icon id='globe' fixedWidth /><FormattedMessage id='tabs_bar.federated_timeline' defaultMessage='Federated' /></NavLink>, - <NavLink className='tabs-bar__link optional' to='/search' data-preview-title-id='tabs_bar.search' data-preview-icon='search' ><Icon id='search' fixedWidth /><FormattedMessage id='tabs_bar.search' defaultMessage='Search' /></NavLink>, - <NavLink className='tabs-bar__link' style={{ flexGrow: '0', flexBasis: '30px' }} to='/getting-started' data-preview-title-id='getting_started.heading' data-preview-icon='bars' ><Icon id='bars' fixedWidth /></NavLink>, -]; - -export function getIndex (path) { - return links.findIndex(link => link.props.to === path); -} - -export function getLink (index) { - return links[index].props.to; -} - -export default @injectIntl -@withRouter -class TabsBar extends React.PureComponent { - - static propTypes = { - intl: PropTypes.object.isRequired, - history: PropTypes.object.isRequired, - } - - setRef = ref => { - this.node = ref; - } - - handleClick = (e) => { - // Only apply optimization for touch devices, which we assume are slower - // We thus avoid the 250ms delay for non-touch devices and the lag for touch devices - if (isUserTouching()) { - e.preventDefault(); - e.persist(); - - requestAnimationFrame(() => { - const tabs = Array(...this.node.querySelectorAll('.tabs-bar__link')); - const currentTab = tabs.find(tab => tab.classList.contains('active')); - const nextTab = tabs.find(tab => tab.contains(e.target)); - const { props: { to } } = links[Array(...this.node.childNodes).indexOf(nextTab)]; - - - if (currentTab !== nextTab) { - if (currentTab) { - currentTab.classList.remove('active'); - } - - const listener = debounce(() => { - nextTab.removeEventListener('transitionend', listener); - this.props.history.push(to); - }, 50); - - nextTab.addEventListener('transitionend', listener); - nextTab.classList.add('active'); - } - }); - } - - } - - render () { - const { intl: { formatMessage } } = this.props; - - return ( - <div className='tabs-bar__wrapper'> - <nav className='tabs-bar' ref={this.setRef}> - {links.map(link => React.cloneElement(link, { key: link.props.to, onClick: this.handleClick, 'aria-label': formatMessage({ id: link.props['data-preview-title-id'] }) }))} - </nav> - - <div id='tabs-bar__portal' /> - </div> - ); - } - -} diff --git a/app/javascript/flavours/glitch/features/ui/index.js b/app/javascript/flavours/glitch/features/ui/index.js index c8cc905e7..3d385eee2 100644 --- a/app/javascript/flavours/glitch/features/ui/index.js +++ b/app/javascript/flavours/glitch/features/ui/index.js @@ -4,7 +4,7 @@ import PropTypes from 'prop-types'; import LoadingBarContainer from './containers/loading_bar_container'; import ModalContainer from './containers/modal_container'; import { connect } from 'react-redux'; -import { Redirect, withRouter } from 'react-router-dom'; +import { Redirect, Route, withRouter } from 'react-router-dom'; import { layoutFromWindow } from 'flavours/glitch/is_mobile'; import { debounce } from 'lodash'; import { uploadCompose, resetCompose, changeComposeSpoilerness } from 'flavours/glitch/actions/compose'; @@ -15,6 +15,7 @@ import { clearHeight } from 'flavours/glitch/actions/height_cache'; import { changeLayout } from 'flavours/glitch/actions/app'; import { synchronouslySubmitMarkers, submitMarkers, fetchMarkers } from 'flavours/glitch/actions/markers'; import { WrappedSwitch, WrappedRoute } from './util/react_router_helpers'; +import BundleColumnError from './components/bundle_column_error'; import UploadArea from './components/upload_area'; import PermaLink from 'flavours/glitch/components/permalink'; import ColumnsAreaContainer from './containers/columns_area_container'; @@ -39,7 +40,6 @@ import { HashtagTimeline, Notifications, FollowRequests, - GenericNotFound, FavouritedStatuses, BookmarkedStatuses, ListTimeline, @@ -52,12 +52,15 @@ import { Directory, Explore, FollowRecommendations, + About, + PrivacyPolicy, } from './util/async-components'; import { HotKeys } from 'react-hotkeys'; -import { me, title } from 'flavours/glitch/initial_state'; +import initialState, { me, owner, singleUserMode, showTrends } from '../../initial_state'; import { closeOnboarding, INTRODUCTION_VERSION } from 'flavours/glitch/actions/onboarding'; import { defineMessages, FormattedMessage, injectIntl } from 'react-intl'; import { Helmet } from 'react-helmet'; +import Header from './components/header'; // Dummy import, to make sure that <Status /> ends up in the application bundle. // Without this it ends up in ~8 very commonly used bundles. @@ -156,7 +159,7 @@ class SwitchingColumnsArea extends React.PureComponent { setRef = c => { if (c) { - this.node = c.getWrappedInstance(); + this.node = c; } } @@ -172,8 +175,12 @@ class SwitchingColumnsArea extends React.PureComponent { } else { redirect = <Redirect from='/' to='/getting-started' exact />; } - } else { + } else if (singleUserMode && owner && initialState?.accounts[owner]) { + redirect = <Redirect from='/' to={`/@${initialState.accounts[owner].username}`} exact />; + } else if (showTrends) { redirect = <Redirect from='/' to='/explore' exact />; + } else { + redirect = <Redirect from='/' to='/about' exact />; } return ( @@ -183,6 +190,8 @@ class SwitchingColumnsArea extends React.PureComponent { <WrappedRoute path='/getting-started' component={GettingStarted} content={children} /> <WrappedRoute path='/keyboard-shortcuts' component={KeyboardShortcuts} content={children} /> + <WrappedRoute path='/about' component={About} content={children} /> + <WrappedRoute path='/privacy-policy' component={PrivacyPolicy} content={children} /> <WrappedRoute path={['/home', '/timelines/home']} component={HomeTimeline} content={children} /> <WrappedRoute path={['/public', '/timelines/public']} exact component={PublicTimeline} content={children} /> @@ -202,9 +211,10 @@ class SwitchingColumnsArea extends React.PureComponent { <WrappedRoute path={['/publish', '/statuses/new']} component={Compose} content={children} /> <WrappedRoute path={['/@:acct', '/accounts/:id']} exact component={AccountTimeline} content={children} /> + <WrappedRoute path='/@:acct/tagged/:tagged?' exact component={AccountTimeline} content={children} /> <WrappedRoute path={['/@:acct/with_replies', '/accounts/:id/with_replies']} component={AccountTimeline} content={children} componentParams={{ withReplies: true }} /> - <WrappedRoute path={['/@:acct/followers', '/accounts/:id/followers']} component={Followers} content={children} /> - <WrappedRoute path={['/@:acct/following', '/accounts/:id/following']} component={Following} content={children} /> + <WrappedRoute path={['/accounts/:id/followers', '/users/:acct/followers', '/@:acct/followers']} component={Followers} content={children} /> + <WrappedRoute path={['/accounts/:id/following', '/users/:acct/following', '/@:acct/following']} component={Following} content={children} /> <WrappedRoute path={['/@:acct/media', '/accounts/:id/media']} component={AccountGallery} content={children} /> <WrappedRoute path='/@:acct/:statusId' exact component={Status} content={children} /> <WrappedRoute path='/@:acct/:statusId/reblogs' component={Reblogs} content={children} /> @@ -224,7 +234,7 @@ class SwitchingColumnsArea extends React.PureComponent { <WrappedRoute path='/lists' component={Lists} content={children} /> <WrappedRoute path='/getting-started-misc' component={GettingStartedMisc} content={children} /> - <WrappedRoute component={GenericNotFound} content={children} /> + <Route component={BundleColumnError} /> </WrappedSwitch> </ColumnsAreaContainer> ); @@ -652,6 +662,9 @@ class UI extends React.Component { )}} /> </div>)} + + <Header /> + <SwitchingColumnsArea location={location} mobile={layout === 'mobile' || layout === 'single-column'} navbarUnder={navbarUnder}> {children} </SwitchingColumnsArea> @@ -661,10 +674,6 @@ class UI extends React.Component { <LoadingBarContainer className='loading-bar' /> <ModalContainer /> <UploadArea active={draggingOver} onClose={this.closeUploadModal} /> - - <Helmet> - <title>{title}</title> - </Helmet> </div> </HotKeys> ); diff --git a/app/javascript/flavours/glitch/features/ui/util/async-components.js b/app/javascript/flavours/glitch/features/ui/util/async-components.js index eef3a941d..025b22e61 100644 --- a/app/javascript/flavours/glitch/features/ui/util/async-components.js +++ b/app/javascript/flavours/glitch/features/ui/util/async-components.js @@ -181,3 +181,23 @@ export function FilterModal () { export function Explore () { return import(/* webpackChunkName: "flavours/glitch/async/explore" */'flavours/glitch/features/explore'); } + +export function InteractionModal () { + return import(/*webpackChunkName: "flavours/glitch/async/modals/interaction_modal" */'flavours/glitch/features/interaction_modal'); +} + +export function SubscribedLanguagesModal () { + return import(/*webpackChunkName: "flavours/glitch/async/modals/subscribed_languages_modal" */'flavours/glitch/features/subscribed_languages_modal'); +} + +export function ClosedRegistrationsModal () { + return import(/*webpackChunkName: "flavours/glitch/async/modals/closed_registrations_modal" */'flavours/glitch/features/closed_registrations_modal'); +} + +export function About () { + return import(/*webpackChunkName: "features/glitch/async/about" */'flavours/glitch/features/about'); +} + +export function PrivacyPolicy () { + return import(/*webpackChunkName: "features/glitch/async/privacy_policy" */'flavours/glitch/features/privacy_policy'); +} diff --git a/app/javascript/flavours/glitch/features/ui/util/react_router_helpers.js b/app/javascript/flavours/glitch/features/ui/util/react_router_helpers.js index e36c512f3..8946c8252 100644 --- a/app/javascript/flavours/glitch/features/ui/util/react_router_helpers.js +++ b/app/javascript/flavours/glitch/features/ui/util/react_router_helpers.js @@ -1,7 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { Switch, Route } from 'react-router-dom'; - +import StackTrace from 'stacktrace-js'; import ColumnLoading from 'flavours/glitch/features/ui/components/column_loading'; import BundleColumnError from 'flavours/glitch/features/ui/components/bundle_column_error'; import BundleContainer from 'flavours/glitch/features/ui/containers/bundle_container'; @@ -42,8 +42,38 @@ export class WrappedRoute extends React.Component { componentParams: {}, }; + static getDerivedStateFromError () { + return { + hasError: true, + }; + }; + + state = { + hasError: false, + stacktrace: '', + }; + + componentDidCatch (error) { + StackTrace.fromError(error).then(stackframes => { + this.setState({ stacktrace: error.toString() + '\n' + stackframes.map(frame => frame.toString()).join('\n') }); + }).catch(err => { + console.error(err); + }); + } + renderComponent = ({ match }) => { const { component, content, multiColumn, componentParams } = this.props; + const { hasError, stacktrace } = this.state; + + if (hasError) { + return ( + <BundleColumnError + stacktrace={stacktrace} + multiColumn={multiColumn} + errorType='error' + /> + ); + } return ( <BundleContainer fetchComponent={component} loading={this.renderLoading} error={this.renderError}> @@ -53,11 +83,13 @@ export class WrappedRoute extends React.Component { } renderLoading = () => { - return <ColumnLoading />; + const { multiColumn } = this.props; + + return <ColumnLoading multiColumn={multiColumn} />; } renderError = (props) => { - return <BundleColumnError {...props} />; + return <BundleColumnError {...props} errorType='network' />; } render () { diff --git a/app/javascript/flavours/glitch/initial_state.js b/app/javascript/flavours/glitch/initial_state.js index 0f2484ba3..ce6bf920c 100644 --- a/app/javascript/flavours/glitch/initial_state.js +++ b/app/javascript/flavours/glitch/initial_state.js @@ -1,5 +1,95 @@ +// @ts-check + +/** + * @typedef Emoji + * @property {string} shortcode + * @property {string} static_url + * @property {string} url + */ + +/** + * @typedef AccountField + * @property {string} name + * @property {string} value + * @property {string} verified_at + */ + +/** + * @typedef Account + * @property {string} acct + * @property {string} avatar + * @property {string} avatar_static + * @property {boolean} bot + * @property {string} created_at + * @property {boolean=} discoverable + * @property {string} display_name + * @property {Emoji[]} emojis + * @property {AccountField[]} fields + * @property {number} followers_count + * @property {number} following_count + * @property {boolean} group + * @property {string} header + * @property {string} header_static + * @property {string} id + * @property {string=} last_status_at + * @property {boolean} locked + * @property {string} note + * @property {number} statuses_count + * @property {string} url + * @property {string} username + */ + +/** + * @typedef {[code: string, name: string, localName: string]} InitialStateLanguage + */ + +/** + * @typedef InitialStateMeta + * @property {string} access_token + * @property {boolean=} advanced_layout + * @property {boolean} auto_play_gif + * @property {boolean} activity_api_enabled + * @property {string} admin + * @property {boolean=} boost_modal + * @property {boolean} crop_images + * @property {boolean=} delete_modal + * @property {boolean=} disable_swiping + * @property {boolean} display_media + * @property {string} domain + * @property {boolean=} expand_spoilers + * @property {boolean} limited_federation_mode + * @property {string} locale + * @property {string | null} mascot + * @property {string=} me + * @property {string=} owner + * @property {boolean} profile_directory + * @property {boolean} registrations_open + * @property {boolean} reduce_motion + * @property {string} repository + * @property {boolean} search_enabled + * @property {boolean} single_user_mode + * @property {string} source_url + * @property {string} streaming_api_base_url + * @property {boolean} timeline_preview + * @property {string} title + * @property {boolean} trends + * @property {boolean} unfollow_modal + * @property {boolean} use_blurhash + * @property {boolean=} use_pending_items + * @property {string} version + * @property {object} local_settings + */ + +/** + * @typedef InitialState + * @property {Record<string, Account>} accounts + * @property {InitialStateLanguage[]} languages + * @property {InitialStateMeta} meta + */ + const element = document.getElementById('initial-state'); -const initialState = element && JSON.parse(element.textContent); +/** @type {InitialState | undefined} */ +const initialState = element?.textContent && JSON.parse(element.textContent); // Glitch-soc-specific “local settings” try { @@ -8,35 +98,45 @@ try { initialState.local_settings = {}; } -const getMeta = (prop) => initialState && initialState.meta && initialState.meta[prop]; +/** + * @template {keyof InitialStateMeta} K + * @param {K} prop + * @returns {InitialStateMeta[K] | undefined} + */ +const getMeta = (prop) => initialState?.meta && initialState.meta[prop]; -export const domain = getMeta('domain'); -export const reduceMotion = getMeta('reduce_motion'); +export const activityApiEnabled = getMeta('activity_api_enabled'); export const autoPlayGif = getMeta('auto_play_gif'); -export const displayMedia = getMeta('display_media'); -export const expandSpoilers = getMeta('expand_spoilers'); -export const unfollowModal = getMeta('unfollow_modal'); export const boostModal = getMeta('boost_modal'); +export const cropImages = getMeta('crop_images'); export const deleteModal = getMeta('delete_modal'); -export const me = getMeta('me'); -export const searchEnabled = getMeta('search_enabled'); -export const maxChars = (initialState && initialState.max_toot_chars) || 500; +export const disableSwiping = getMeta('disable_swiping'); +export const displayMedia = getMeta('display_media'); +export const domain = getMeta('domain'); +export const expandSpoilers = getMeta('expand_spoilers'); +export const forceSingleColumn = !getMeta('advanced_layout'); export const limitedFederationMode = getMeta('limited_federation_mode'); +export const mascot = getMeta('mascot'); +export const me = getMeta('me'); +export const owner = getMeta('owner'); +export const profile_directory = getMeta('profile_directory'); +export const reduceMotion = getMeta('reduce_motion'); export const registrationsOpen = getMeta('registrations_open'); export const repository = getMeta('repository'); +export const searchEnabled = getMeta('search_enabled'); +export const showTrends = getMeta('trends'); +export const singleUserMode = getMeta('single_user_mode'); export const source_url = getMeta('source_url'); -export const version = getMeta('version'); -export const mascot = getMeta('mascot'); -export const profile_directory = getMeta('profile_directory'); -export const forceSingleColumn = !getMeta('advanced_layout'); +export const timelinePreview = getMeta('timeline_preview'); +export const title = getMeta('title'); +export const unfollowModal = getMeta('unfollow_modal'); export const useBlurhash = getMeta('use_blurhash'); export const usePendingItems = getMeta('use_pending_items'); -export const showTrends = getMeta('trends'); -export const title = getMeta('title'); -export const disableSwiping = getMeta('disable_swiping'); -export const languages = initialState && initialState.languages; +export const version = getMeta('version'); +export const languages = initialState?.languages; // Glitch-soc-specific settings +export const maxChars = (initialState && initialState.max_toot_chars) || 500; export const favouriteModal = getMeta('favourite_modal'); export const pollLimits = (initialState && initialState.poll_limits); export const defaultContentType = getMeta('default_content_type'); diff --git a/app/javascript/flavours/glitch/is_mobile.js b/app/javascript/flavours/glitch/is_mobile.js index 0d5663098..31944d89b 100644 --- a/app/javascript/flavours/glitch/is_mobile.js +++ b/app/javascript/flavours/glitch/is_mobile.js @@ -1,10 +1,20 @@ +// @ts-check + import { supportsPassiveEvents } from 'detect-passive-events'; import { forceSingleColumn } from 'flavours/glitch/initial_state'; const LAYOUT_BREAKPOINT = 630; +/** + * @param {number} width + * @returns {boolean} + */ export const isMobile = width => width <= LAYOUT_BREAKPOINT; +/** + * @param {string} layout_local_setting + * @returns {string} + */ export const layoutFromWindow = (layout_local_setting) => { switch (layout_local_setting) { case 'multiple': @@ -28,11 +38,13 @@ export const layoutFromWindow = (layout_local_setting) => { const iOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream; +const listenerOptions = supportsPassiveEvents ? { passive: true } : false; + let userTouching = false; -let listenerOptions = supportsPassiveEvents ? { passive: true } : false; const touchListener = () => { userTouching = true; + window.removeEventListener('touchstart', touchListener, listenerOptions); }; diff --git a/app/javascript/flavours/glitch/load_polyfills.js b/app/javascript/flavours/glitch/load_polyfills.js index 73eedc9dc..cc5bcd18f 100644 --- a/app/javascript/flavours/glitch/load_polyfills.js +++ b/app/javascript/flavours/glitch/load_polyfills.js @@ -26,6 +26,7 @@ function loadPolyfills() { // Edge does not have requestIdleCallback and object-fit CSS property. // This avoids shipping them all the polyfills. const needsExtraPolyfills = !( + window.AbortController && window.IntersectionObserver && window.IntersectionObserverEntry && 'isIntersecting' in IntersectionObserverEntry.prototype && diff --git a/app/javascript/flavours/glitch/locales/ja.js b/app/javascript/flavours/glitch/locales/ja.js index 0ca5e5fc7..52aeed3d6 100644 --- a/app/javascript/flavours/glitch/locales/ja.js +++ b/app/javascript/flavours/glitch/locales/ja.js @@ -8,6 +8,7 @@ const messages = { 'layout.single': 'モバイル', 'navigation_bar.app_settings': 'アプリ設定', 'navigation_bar.featured_users': '紹介しているアカウント', + 'navigation_bar.misc': 'その他', 'getting_started.onboarding': '解説を表示', 'onboarding.page_one.federation': '{domain}はMastodonのインスタンスです。Mastodonとは、独立したサーバが連携して作るソーシャルネットワークです。これらのサーバーをインスタンスと呼びます。', 'onboarding.page_one.welcome': '{domain}へようこそ!', diff --git a/app/javascript/flavours/glitch/main.js b/app/javascript/flavours/glitch/main.js index ecb19ef54..f1e10df34 100644 --- a/app/javascript/flavours/glitch/main.js +++ b/app/javascript/flavours/glitch/main.js @@ -12,14 +12,6 @@ const perf = require('flavours/glitch/performance'); function main() { perf.start('main()'); - if (window.history && history.replaceState) { - const { pathname, search, hash } = window.location; - const path = pathname + search + hash; - if (!(/^\/web($|\/)/).test(path)) { - history.replaceState(null, document.title, `/web${path}`); - } - } - return ready(async () => { const mountNode = document.getElementById('mastodon'); const props = JSON.parse(mountNode.getAttribute('data-props')); diff --git a/app/javascript/flavours/glitch/packs/about.js b/app/javascript/flavours/glitch/packs/about.js deleted file mode 100644 index ef17fdea4..000000000 --- a/app/javascript/flavours/glitch/packs/about.js +++ /dev/null @@ -1,23 +0,0 @@ -import 'packs/public-path'; -import loadPolyfills from 'flavours/glitch/load_polyfills'; - -function loaded() { - const TimelineContainer = require('flavours/glitch/containers/timeline_container').default; - const React = require('react'); - const ReactDOM = require('react-dom'); - const mountNode = document.getElementById('mastodon-timeline'); - - if (mountNode !== null) { - const props = JSON.parse(mountNode.getAttribute('data-props')); - ReactDOM.render(<TimelineContainer {...props} />, mountNode); - } -} - -function main() { - const ready = require('flavours/glitch/ready').default; - ready(loaded); -} - -loadPolyfills().then(main).catch(error => { - console.error(error); -}); diff --git a/app/javascript/flavours/glitch/packs/public.js b/app/javascript/flavours/glitch/packs/public.js index ae1899638..843fd5163 100644 --- a/app/javascript/flavours/glitch/packs/public.js +++ b/app/javascript/flavours/glitch/packs/public.js @@ -12,7 +12,6 @@ function main() { const { messages } = getLocale(); const React = require('react'); const ReactDOM = require('react-dom'); - const Rellax = require('rellax'); const { createBrowserHistory } = require('history'); const scrollToDetailedStatus = () => { @@ -90,12 +89,6 @@ function main() { scrollToDetailedStatus(); } - const parallaxComponents = document.querySelectorAll('.parallax'); - - if (parallaxComponents.length > 0 ) { - new Rellax('.parallax', { speed: -1 }); - } - delegate(document, '#registration_user_password_confirmation,#registration_user_password', 'input', () => { const password = document.getElementById('registration_user_password'); const confirmation = document.getElementById('registration_user_password_confirmation'); @@ -146,8 +139,31 @@ function main() { }); }); + const toggleSidebar = () => { + const sidebar = document.querySelector('.sidebar ul'); + const toggleButton = document.querySelector('.sidebar__toggle__icon'); + + if (sidebar.classList.contains('visible')) { + document.body.style.overflow = null; + toggleButton.setAttribute('aria-expanded', false); + } else { + document.body.style.overflow = 'hidden'; + toggleButton.setAttribute('aria-expanded', true); + } + + toggleButton.classList.toggle('active'); + sidebar.classList.toggle('visible'); + }; + delegate(document, '.sidebar__toggle__icon', 'click', () => { - document.querySelector('.sidebar ul').classList.toggle('visible'); + toggleSidebar(); + }); + + delegate(document, '.sidebar__toggle__icon', 'keydown', e => { + if (e.key === ' ' || e.key === 'Enter') { + e.preventDefault(); + toggleSidebar(); + } }); // Empty the honeypot fields in JS in case something like an extension diff --git a/app/javascript/flavours/glitch/packs/settings.js b/app/javascript/flavours/glitch/packs/settings.js index 4c85f6556..31c88b2b5 100644 --- a/app/javascript/flavours/glitch/packs/settings.js +++ b/app/javascript/flavours/glitch/packs/settings.js @@ -7,8 +7,31 @@ import 'cocoon-js-vanilla'; function main() { const { delegate } = require('@rails/ujs'); + const toggleSidebar = () => { + const sidebar = document.querySelector('.sidebar ul'); + const toggleButton = document.querySelector('.sidebar__toggle__icon'); + + if (sidebar.classList.contains('visible')) { + document.body.style.overflow = null; + toggleButton.setAttribute('aria-expanded', false); + } else { + document.body.style.overflow = 'hidden'; + toggleButton.setAttribute('aria-expanded', true); + } + + toggleButton.classList.toggle('active'); + sidebar.classList.toggle('visible'); + }; + delegate(document, '.sidebar__toggle__icon', 'click', () => { - document.querySelector('.sidebar ul').classList.toggle('visible'); + toggleSidebar(); + }); + + delegate(document, '.sidebar__toggle__icon', 'keydown', e => { + if (e.key === ' ' || e.key === 'Enter') { + e.preventDefault(); + toggleSidebar(); + } }); } diff --git a/app/javascript/flavours/glitch/reducers/accounts_map.js b/app/javascript/flavours/glitch/reducers/accounts_map.js index e0d42e9cd..53e08c8fb 100644 --- a/app/javascript/flavours/glitch/reducers/accounts_map.js +++ b/app/javascript/flavours/glitch/reducers/accounts_map.js @@ -1,14 +1,16 @@ import { ACCOUNT_IMPORT, ACCOUNTS_IMPORT } from '../actions/importer'; import { Map as ImmutableMap } from 'immutable'; +export const normalizeForLookup = str => str.toLowerCase(); + const initialState = ImmutableMap(); export default function accountsMap(state = initialState, action) { switch(action.type) { case ACCOUNT_IMPORT: - return state.set(action.account.acct, action.account.id); + return state.set(normalizeForLookup(action.account.acct), action.account.id); case ACCOUNTS_IMPORT: - return state.withMutations(map => action.accounts.forEach(account => map.set(account.acct, account.id))); + return state.withMutations(map => action.accounts.forEach(account => map.set(normalizeForLookup(account.acct), account.id))); default: return state; } diff --git a/app/javascript/flavours/glitch/reducers/compose.js b/app/javascript/flavours/glitch/reducers/compose.js index 035e9f564..b739456da 100644 --- a/app/javascript/flavours/glitch/reducers/compose.js +++ b/app/javascript/flavours/glitch/reducers/compose.js @@ -15,6 +15,7 @@ import { COMPOSE_UPLOAD_FAIL, COMPOSE_UPLOAD_UNDO, COMPOSE_UPLOAD_PROGRESS, + COMPOSE_UPLOAD_PROCESSING, THUMBNAIL_UPLOAD_REQUEST, THUMBNAIL_UPLOAD_SUCCESS, THUMBNAIL_UPLOAD_FAIL, @@ -223,6 +224,7 @@ function appendMedia(state, media, file) { } map.update('media_attachments', list => list.push(media)); map.set('is_uploading', false); + map.set('is_processing', false); map.set('resetFileKey', Math.floor((Math.random() * 0x10000))); map.set('idempotencyKey', uuid()); map.update('pending_media_attachments', n => n - 1); @@ -465,10 +467,12 @@ export default function compose(state = initialState, action) { return state.set('is_changing_upload', false); case COMPOSE_UPLOAD_REQUEST: return state.set('is_uploading', true).update('pending_media_attachments', n => n + 1); + case COMPOSE_UPLOAD_PROCESSING: + return state.set('is_processing', true); case COMPOSE_UPLOAD_SUCCESS: return appendMedia(state, fromJS(action.media), action.file); case COMPOSE_UPLOAD_FAIL: - return state.set('is_uploading', false).update('pending_media_attachments', n => n - 1); + return state.set('is_uploading', false).set('is_processing', false).update('pending_media_attachments', n => n - 1); case COMPOSE_UPLOAD_UNDO: return removeMedia(state, action.media_id); case COMPOSE_UPLOAD_PROGRESS: diff --git a/app/javascript/flavours/glitch/reducers/server.js b/app/javascript/flavours/glitch/reducers/server.js index 977574148..cc5798fb3 100644 --- a/app/javascript/flavours/glitch/reducers/server.js +++ b/app/javascript/flavours/glitch/reducers/server.js @@ -1,18 +1,52 @@ -import { SERVER_FETCH_REQUEST, SERVER_FETCH_SUCCESS, SERVER_FETCH_FAIL } from 'flavours/glitch/actions/server'; -import { Map as ImmutableMap, fromJS } from 'immutable'; +import { + SERVER_FETCH_REQUEST, + SERVER_FETCH_SUCCESS, + SERVER_FETCH_FAIL, + EXTENDED_DESCRIPTION_REQUEST, + EXTENDED_DESCRIPTION_SUCCESS, + EXTENDED_DESCRIPTION_FAIL, + SERVER_DOMAIN_BLOCKS_FETCH_REQUEST, + SERVER_DOMAIN_BLOCKS_FETCH_SUCCESS, + SERVER_DOMAIN_BLOCKS_FETCH_FAIL, +} from 'flavours/glitch/actions/server'; +import { Map as ImmutableMap, List as ImmutableList, fromJS } from 'immutable'; const initialState = ImmutableMap({ - isLoading: true, + server: ImmutableMap({ + isLoading: true, + }), + + extendedDescription: ImmutableMap({ + isLoading: true, + }), + + domainBlocks: ImmutableMap({ + isLoading: true, + isAvailable: true, + items: ImmutableList(), + }), }); export default function server(state = initialState, action) { switch (action.type) { case SERVER_FETCH_REQUEST: - return state.set('isLoading', true); + return state.setIn(['server', 'isLoading'], true); case SERVER_FETCH_SUCCESS: - return fromJS(action.server).set('isLoading', false); + return state.set('server', fromJS(action.server)).setIn(['server', 'isLoading'], false); case SERVER_FETCH_FAIL: - return state.set('isLoading', false); + return state.setIn(['server', 'isLoading'], false); + case EXTENDED_DESCRIPTION_REQUEST: + return state.setIn(['extendedDescription', 'isLoading'], true); + case EXTENDED_DESCRIPTION_SUCCESS: + return state.set('extendedDescription', fromJS(action.description)).setIn(['extendedDescription', 'isLoading'], false); + case EXTENDED_DESCRIPTION_FAIL: + return state.setIn(['extendedDescription', 'isLoading'], false); + case SERVER_DOMAIN_BLOCKS_FETCH_REQUEST: + return state.setIn(['domainBlocks', 'isLoading'], true); + case SERVER_DOMAIN_BLOCKS_FETCH_SUCCESS: + return state.setIn(['domainBlocks', 'items'], fromJS(action.blocks)).setIn(['domainBlocks', 'isLoading'], false).setIn(['domainBlocks', 'isAvailable'], action.isAvailable); + case SERVER_DOMAIN_BLOCKS_FETCH_FAIL: + return state.setIn(['domainBlocks', 'isLoading'], false); default: return state; } diff --git a/app/javascript/flavours/glitch/reducers/statuses.js b/app/javascript/flavours/glitch/reducers/statuses.js index 333e4b45c..b47155c5f 100644 --- a/app/javascript/flavours/glitch/reducers/statuses.js +++ b/app/javascript/flavours/glitch/reducers/statuses.js @@ -13,6 +13,8 @@ import { STATUS_REVEAL, STATUS_HIDE, STATUS_COLLAPSE, + STATUS_FETCH_REQUEST, + STATUS_FETCH_FAIL, } from 'flavours/glitch/actions/statuses'; import { TIMELINE_DELETE, @@ -37,6 +39,10 @@ const initialState = ImmutableMap(); export default function statuses(state = initialState, action) { switch(action.type) { + case STATUS_FETCH_REQUEST: + return state.setIn([action.id, 'isLoading'], true); + case STATUS_FETCH_FAIL: + return state.delete(action.id); case STATUS_IMPORT: return importStatus(state, action.status); case STATUSES_IMPORT: diff --git a/app/javascript/flavours/glitch/reducers/user_lists.js b/app/javascript/flavours/glitch/reducers/user_lists.js index bfddbd246..0a75e85c1 100644 --- a/app/javascript/flavours/glitch/reducers/user_lists.js +++ b/app/javascript/flavours/glitch/reducers/user_lists.js @@ -51,7 +51,12 @@ import { DIRECTORY_EXPAND_SUCCESS, DIRECTORY_EXPAND_FAIL, } from 'flavours/glitch/actions/directory'; -import { Map as ImmutableMap, List as ImmutableList } from 'immutable'; +import { + FEATURED_TAGS_FETCH_REQUEST, + FEATURED_TAGS_FETCH_SUCCESS, + FEATURED_TAGS_FETCH_FAIL, +} from 'flavours/glitch/actions/featured_tags'; +import { Map as ImmutableMap, List as ImmutableList, fromJS } from 'immutable'; const initialListState = ImmutableMap({ next: null, @@ -67,6 +72,7 @@ const initialState = ImmutableMap({ follow_requests: initialListState, blocks: initialListState, mutes: initialListState, + featured_tags: initialListState, }); const normalizeList = (state, path, accounts, next) => { @@ -89,6 +95,18 @@ const normalizeFollowRequest = (state, notification) => { }); }; +const normalizeFeaturedTag = (featuredTags, accountId) => { + const normalizeFeaturedTag = { ...featuredTags, accountId: accountId }; + return fromJS(normalizeFeaturedTag); +}; + +const normalizeFeaturedTags = (state, path, featuredTags, accountId) => { + return state.setIn(path, ImmutableMap({ + items: ImmutableList(featuredTags.map(featuredTag => normalizeFeaturedTag(featuredTag, accountId)).sort((a, b) => b.get('statuses_count') - a.get('statuses_count'))), + isLoading: false, + })); +}; + export default function userLists(state = initialState, action) { switch(action.type) { case FOLLOWERS_FETCH_SUCCESS: @@ -160,6 +178,12 @@ export default function userLists(state = initialState, action) { case DIRECTORY_FETCH_FAIL: case DIRECTORY_EXPAND_FAIL: return state.setIn(['directory', 'isLoading'], false); + case FEATURED_TAGS_FETCH_SUCCESS: + return normalizeFeaturedTags(state, ['featured_tags', action.id], action.tags, action.id); + case FEATURED_TAGS_FETCH_REQUEST: + return state.setIn(['featured_tags', action.id, 'isLoading'], true); + case FEATURED_TAGS_FETCH_FAIL: + return state.setIn(['featured_tags', action.id, 'isLoading'], false); default: return state; } diff --git a/app/javascript/flavours/glitch/selectors/index.js b/app/javascript/flavours/glitch/selectors/index.js index 8e6e40d24..df46b58a8 100644 --- a/app/javascript/flavours/glitch/selectors/index.js +++ b/app/javascript/flavours/glitch/selectors/index.js @@ -42,7 +42,7 @@ export const makeGetStatus = () => { ], (statusBase, statusReblog, accountBase, accountReblog, filters) => { - if (!statusBase) { + if (!statusBase || statusBase.get('isLoading')) { return null; } diff --git a/app/javascript/flavours/glitch/settings.js b/app/javascript/flavours/glitch/settings.js index 7643a508e..46cfadfa3 100644 --- a/app/javascript/flavours/glitch/settings.js +++ b/app/javascript/flavours/glitch/settings.js @@ -45,3 +45,4 @@ export default class Settings { export const pushNotificationsSetting = new Settings('mastodon_push_notification_data'); export const tagHistory = new Settings('mastodon_tag_history'); +export const bannerSettings = new Settings('mastodon_banner_settings'); diff --git a/app/javascript/flavours/glitch/styles/about.scss b/app/javascript/flavours/glitch/styles/about.scss index 1843129a0..0183c43d5 100644 --- a/app/javascript/flavours/glitch/styles/about.scss +++ b/app/javascript/flavours/glitch/styles/about.scss @@ -1,7 +1,5 @@ $maximum-width: 1235px; $fluid-breakpoint: $maximum-width + 20px; -$column-breakpoint: 700px; -$small-breakpoint: 960px; .container { box-sizing: border-box; @@ -15,894 +13,44 @@ $small-breakpoint: 960px; } } -.rich-formatting { - font-family: $font-sans-serif, sans-serif; - font-size: 14px; - font-weight: 400; - line-height: 1.7; - word-wrap: break-word; - color: $darker-text-color; - - a { - color: $highlight-text-color; - text-decoration: underline; - - &:hover, - &:focus, - &:active { - text-decoration: none; - } - } - - p, - li { - color: $darker-text-color; - } - - p { - margin-top: 0; - margin-bottom: .85em; - - &:last-child { - margin-bottom: 0; - } - } - - strong { - font-weight: 700; - color: $secondary-text-color; - } - - em { - font-style: italic; - color: $secondary-text-color; - } - - code { - font-size: 0.85em; - background: darken($ui-base-color, 8%); - border-radius: 4px; - padding: 0.2em 0.3em; - } - - h1, - h2, - h3, - h4, - h5, - h6 { - font-family: $font-display, sans-serif; - margin-top: 1.275em; - margin-bottom: .85em; - font-weight: 500; - color: $secondary-text-color; - } - - h1 { - font-size: 2em; - } - - h2 { - font-size: 1.75em; - } - - h3 { - font-size: 1.5em; - } - - h4 { - font-size: 1.25em; - } - - h5, - h6 { - font-size: 1em; - } - - ul { - list-style: disc; - } - - ol { - list-style: decimal; - } - - ul, - ol { - margin: 0; - padding: 0; - padding-left: 2em; - margin-bottom: 0.85em; - - &[type='a'] { - list-style-type: lower-alpha; - } - - &[type='i'] { - list-style-type: lower-roman; - } - } - - hr { - width: 100%; - height: 0; - border: 0; - border-bottom: 1px solid lighten($ui-base-color, 4%); - margin: 1.7em 0; - - &.spacer { - height: 1px; - border: 0; - } - } - - table { - width: 100%; - border-collapse: collapse; - break-inside: auto; - margin-top: 24px; - margin-bottom: 32px; - - thead tr, - tbody tr { - border-bottom: 1px solid lighten($ui-base-color, 4%); - font-size: 1em; - line-height: 1.625; - font-weight: 400; - text-align: left; - color: $darker-text-color; - } - - thead tr { - border-bottom-width: 2px; - line-height: 1.5; - font-weight: 500; - color: $dark-text-color; - } - - th, - td { - padding: 8px; - align-self: start; - align-items: start; - word-break: break-all; - - &.nowrap { - width: 25%; - position: relative; - - &::before { - content: ' '; - visibility: hidden; - } - - span { - position: absolute; - left: 8px; - right: 8px; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - } - } - } - } - - & > :first-child { - margin-top: 0; - } +.brand { + position: relative; + text-decoration: none; } -.information-board { - background: darken($ui-base-color, 4%); - padding: 20px 0; - - .container-alt { - position: relative; - padding-right: 280px + 15px; - } - - &__sections { - display: flex; - justify-content: space-between; - flex-wrap: wrap; - } - - &__section { - flex: 1 0 0; - font-family: $font-sans-serif, sans-serif; - font-size: 16px; - line-height: 28px; - color: $primary-text-color; - text-align: right; - padding: 10px 15px; - - span, - strong { - display: block; - } - - span { - &:last-child { - color: $secondary-text-color; - } - } - - strong { - font-family: $font-display, sans-serif; - font-weight: 500; - font-size: 32px; - line-height: 48px; - } - - @media screen and (max-width: $column-breakpoint) { - text-align: center; - } - } - - .panel { - position: absolute; - width: 280px; - box-sizing: border-box; - background: darken($ui-base-color, 8%); - padding: 20px; - padding-top: 10px; - border-radius: 4px 4px 0 0; - right: 0; - bottom: -40px; - - .panel-header { - font-family: $font-display, sans-serif; - font-size: 14px; - line-height: 24px; - font-weight: 500; - color: $darker-text-color; - padding-bottom: 5px; - margin-bottom: 15px; - border-bottom: 1px solid lighten($ui-base-color, 4%); - text-overflow: ellipsis; - white-space: nowrap; - overflow: hidden; - - a, - span { - font-weight: 400; - color: darken($darker-text-color, 10%); - } - - a { - text-decoration: none; - } - } - } - - .owner { - text-align: center; - - .avatar { - width: 80px; - height: 80px; - @include avatar-size(80px); - margin: 0 auto; - margin-bottom: 15px; - - img { - display: block; - width: 80px; - height: 80px; - border-radius: 48px; - @include avatar-radius(); - } - } - - .name { - font-size: 14px; - - a { - display: block; - color: $primary-text-color; - text-decoration: none; - - &:hover { - .display_name { - text-decoration: underline; - } - } - } - - .username { - display: block; - color: $darker-text-color; - } - } - } -} +.rules-list { + font-size: 15px; + line-height: 22px; + color: $primary-text-color; + counter-reset: list-counter; -.landing-page { - p, li { - font-family: $font-sans-serif, sans-serif; - font-size: 16px; - font-weight: 400; - line-height: 30px; - margin-bottom: 12px; - color: $darker-text-color; - - a { - color: $highlight-text-color; - text-decoration: underline; - } - } - - em { - display: inline; - margin: 0; - padding: 0; - font-weight: 700; - background: transparent; - font-family: inherit; - font-size: inherit; - line-height: inherit; - color: lighten($darker-text-color, 10%); - } - - h1 { - font-family: $font-display, sans-serif; - font-size: 26px; - line-height: 30px; - font-weight: 500; - margin-bottom: 20px; - color: $secondary-text-color; - - small { - font-family: $font-sans-serif, sans-serif; - display: block; - font-size: 18px; - font-weight: 400; - color: lighten($darker-text-color, 10%); - } - } - - h2 { - font-family: $font-display, sans-serif; - font-size: 22px; - line-height: 26px; - font-weight: 500; - margin-bottom: 20px; - color: $secondary-text-color; - } - - h3 { - font-family: $font-display, sans-serif; - font-size: 18px; - line-height: 24px; - font-weight: 500; - margin-bottom: 20px; - color: $secondary-text-color; - } - - h4 { - font-family: $font-display, sans-serif; - font-size: 16px; - line-height: 24px; - font-weight: 500; - margin-bottom: 20px; - color: $secondary-text-color; - } - - h5 { - font-family: $font-display, sans-serif; - font-size: 14px; - line-height: 24px; - font-weight: 500; - margin-bottom: 20px; - color: $secondary-text-color; - } - - h6 { - font-family: $font-display, sans-serif; - font-size: 12px; - line-height: 24px; + position: relative; + border-bottom: 1px solid lighten($ui-base-color, 8%); + padding: 1em 1.75em; + padding-left: 3em; font-weight: 500; - margin-bottom: 20px; - color: $secondary-text-color; - } - - ul, - ol { - margin-left: 20px; - - &[type='a'] { - list-style-type: lower-alpha; - } - - &[type='i'] { - list-style-type: lower-roman; - } - } - - ul { - list-style: disc; - } - - ol { - list-style: decimal; - } - - li > ol, - li > ul { - margin-top: 6px; - } - - hr { - width: 100%; - height: 0; - border: 0; - border-bottom: 1px solid rgba($ui-base-lighter-color, .6); - margin: 20px 0; - - &.spacer { - height: 1px; - border: 0; - } - } - - &__information, - &__forms { - padding: 20px; - } - - &__call-to-action { - background: $ui-base-color; - border-radius: 4px; - padding: 25px 40px; - overflow: hidden; - box-sizing: border-box; - - .row { - width: 100%; - display: flex; - flex-direction: row-reverse; - flex-wrap: nowrap; - justify-content: space-between; - align-items: center; - } - - .row__information-board { - display: flex; - justify-content: flex-end; - align-items: flex-end; - - .information-board__section { - flex: 1 0 auto; - padding: 0 10px; - } - - @media screen and (max-width: $no-gap-breakpoint) { - width: 100%; - justify-content: space-between; - } - } - - .row__mascot { - flex: 1; - margin: 10px -50px 0 0; - - @media screen and (max-width: $no-gap-breakpoint) { - display: none; - } - } - } - - &__logo { - margin-right: 20px; - - img { - height: 50px; - width: auto; - mix-blend-mode: lighten; - } - } - - &__information { - padding: 45px 40px; - margin-bottom: 10px; - - &:last-child { - margin-bottom: 0; - } - - strong { + counter-increment: list-counter; + + &::before { + content: counter(list-counter); + position: absolute; + left: 0; + top: 50%; + transform: translateY(-50%); + background: $highlight-text-color; + color: $ui-base-color; + border-radius: 50%; + width: 4ch; + height: 4ch; font-weight: 500; - color: lighten($darker-text-color, 10%); - } - - .account { - border-bottom: 0; - padding: 0; - - &__display-name { - align-items: center; - display: flex; - margin-right: 5px; - } - - div.account__display-name { - &:hover { - .display-name strong { - text-decoration: none; - } - } - - .account__avatar { - cursor: default; - } - } - - &__avatar-wrapper { - margin-left: 0; - flex: 0 0 auto; - } - - .display-name { - font-size: 15px; - - &__account { - font-size: 14px; - } - } - } - - @media screen and (max-width: $small-breakpoint) { - .contact { - margin-top: 30px; - } - } - - @media screen and (max-width: $column-breakpoint) { - padding: 25px 20px; - } - } - - &__information, - &__forms, - #mastodon-timeline { - box-sizing: border-box; - background: $ui-base-color; - border-radius: 4px; - box-shadow: 0 0 6px rgba($black, 0.1); - } - - &__mascot { - height: 104px; - position: relative; - left: -40px; - bottom: 25px; - - img { - height: 190px; - width: auto; - } - } - - &__short-description { - .row { display: flex; - flex-wrap: wrap; + justify-content: center; align-items: center; - margin-bottom: 40px; - } - - @media screen and (max-width: $column-breakpoint) { - .row { - margin-bottom: 20px; - } - } - - p a { - color: $secondary-text-color; - } - - h1 { - font-weight: 500; - color: $primary-text-color; - margin-bottom: 0; - - small { - color: $darker-text-color; - - span { - color: $secondary-text-color; - } - } - } - - p:last-child { - margin-bottom: 0; - } - } - - &__hero { - margin-bottom: 10px; - - img { - display: block; - margin: 0; - max-width: 100%; - height: auto; - border-radius: 4px; - } - } - - @media screen and (max-width: 840px) { - .information-board { - .container-alt { - padding-right: 20px; - } - - .panel { - position: static; - margin-top: 20px; - width: 100%; - border-radius: 4px; - - .panel-header { - text-align: center; - } - } - } - } - - @media screen and (max-width: 675px) { - .header-wrapper { - padding-top: 0; - - &.compact { - padding-bottom: 0; - } - - &.compact .hero .heading { - text-align: initial; - } } - .header .container-alt, - .features .container-alt { - display: block; - } - } - - .cta { - margin: 20px; - } -} - -.landing { - margin-bottom: 100px; - - @media screen and (max-width: 738px) { - margin-bottom: 0; - } - - &__brand { - display: flex; - justify-content: center; - align-items: center; - padding: 50px; - - .logo { - fill: $primary-text-color; - height: 52px; - } - - @media screen and (max-width: $no-gap-breakpoint) { - padding: 0; - margin-bottom: 30px; - } - } - - .directory { - margin-top: 30px; - background: transparent; - box-shadow: none; - border-radius: 0; - } - - .hero-widget { - margin-top: 30px; - margin-bottom: 0; - - h4 { - padding: 10px; - text-transform: uppercase; - font-weight: 700; - font-size: 13px; - color: $darker-text-color; - } - - &__text { - border-radius: 0; - padding-bottom: 0; - } - - &__footer { - background: $ui-base-color; - padding: 10px; - border-radius: 0 0 4px 4px; - display: flex; - - &__column { - flex: 1 1 50%; - overflow-x: hidden; - } - } - - .account { - padding: 10px 0; - border-bottom: 0; - - .account__display-name { - display: flex; - align-items: center; - } - } - - &__counters__wrapper { - display: flex; - } - - &__counter { - padding: 10px; - width: 50%; - - strong { - font-family: $font-display, sans-serif; - font-size: 15px; - font-weight: 700; - display: block; - } - - span { - font-size: 14px; - color: $darker-text-color; - } - } - } - - .simple_form .user_agreement .label_input > label { - font-weight: 400; - color: $darker-text-color; - } - - .simple_form p.lead { - color: $darker-text-color; - font-size: 15px; - line-height: 20px; - font-weight: 400; - margin-bottom: 25px; - } - - &__grid { - max-width: 960px; - margin: 0 auto; - display: grid; - grid-template-columns: minmax(0, 50%) minmax(0, 50%); - grid-gap: 30px; - - @media screen and (max-width: 738px) { - grid-template-columns: minmax(0, 100%); - grid-gap: 10px; - - &__column-login { - grid-row: 1; - display: flex; - flex-direction: column; - - .box-widget { - order: 2; - flex: 0 0 auto; - } - - .hero-widget { - margin-top: 0; - margin-bottom: 10px; - order: 1; - flex: 0 0 auto; - } - } - - &__column-registration { - grid-row: 2; - } - - .directory { - margin-top: 10px; - } - } - - @media screen and (max-width: $no-gap-breakpoint) { - grid-gap: 0; - - .hero-widget { - display: block; - margin-bottom: 0; - box-shadow: none; - - &__img, - &__img img, - &__footer { - border-radius: 0; - } - } - - .hero-widget, - .box-widget, - .directory__tag { - border-bottom: 1px solid lighten($ui-base-color, 8%); - } - - .directory { - margin-top: 0; - - &__tag { - margin-bottom: 0; - - & > a, - & > div { - border-radius: 0; - box-shadow: none; - } - - &:last-child { - border-bottom: 0; - } - } - } - } - } -} - -.brand { - position: relative; - text-decoration: none; -} - -.brand__tagline { - display: block; - position: absolute; - bottom: -10px; - left: 50px; - width: 300px; - color: $ui-primary-color; - text-decoration: none; - font-size: 14px; - - @media screen and (max-width: $no-gap-breakpoint) { - position: static; - width: auto; - margin-top: 20px; - color: $dark-text-color; - } -} - -.rules-list { - background: darken($ui-base-color, 2%); - border: 1px solid darken($ui-base-color, 8%); - border-radius: 4px; - padding: 0.5em 2.5em !important; - margin-top: 1.85em !important; - - li { - border-bottom: 1px solid lighten($ui-base-color, 4%); - color: $dark-text-color; - padding: 1em; - &:last-child { border-bottom: 0; } } - - &__text { - color: $primary-text-color; - } } diff --git a/app/javascript/flavours/glitch/styles/admin.scss b/app/javascript/flavours/glitch/styles/admin.scss index 77890c467..c2426944b 100644 --- a/app/javascript/flavours/glitch/styles/admin.scss +++ b/app/javascript/flavours/glitch/styles/admin.scss @@ -31,23 +31,17 @@ $content-width: 840px; &__toggle { display: none; - background: lighten($ui-base-color, 8%); - height: 48px; + background: darken($ui-base-color, 4%); + border-bottom: 1px solid lighten($ui-base-color, 4%); + align-items: center; &__logo { flex: 1 1 auto; a { - display: inline-block; + display: block; padding: 15px; } - - svg { - fill: $primary-text-color; - height: 20px; - position: relative; - bottom: -2px; - } } &__icon { @@ -55,15 +49,27 @@ $content-width: 840px; color: $darker-text-color; text-decoration: none; flex: 0 0 auto; - font-size: 20px; - padding: 15px; - } + font-size: 18px; + padding: 10px; + margin: 5px 10px; + border-radius: 4px; - a { - &:hover, - &:focus, - &:active { - background: lighten($ui-base-color, 12%); + &:focus { + background: $ui-base-color; + } + + .fa-times { + display: none; + } + + &.active { + .fa-times { + display: block; + } + + .fa-bars { + display: none; + } } } } @@ -79,7 +85,7 @@ $content-width: 840px; display: inherit; margin: inherit; width: inherit; - height: 20px; + height: 25px; } @media screen and (max-width: $no-columns-breakpoint) { @@ -188,24 +194,65 @@ $content-width: 840px; padding-top: 30px; } - &-heading { - display: flex; + &__heading { + margin-bottom: 45px; - padding-bottom: 36px; - border-bottom: 1px solid lighten($ui-base-color, 8%); + &__row { + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: space-between; + margin: -15px -15px 0 0; + + & > * { + margin-top: 15px; + margin-right: 15px; + } + } - margin: -15px -15px 40px 0; + &__tabs { + margin-top: 30px; + width: 100%; - flex-wrap: wrap; - align-items: center; - justify-content: space-between; + & > div { + display: flex; + flex-wrap: wrap; + gap: 5px; + } - & > * { - margin-top: 15px; - margin-right: 15px; + a { + font-size: 14px; + display: inline-flex; + align-items: center; + padding: 7px 10px; + border-radius: 4px; + color: $darker-text-color; + text-decoration: none; + font-weight: 500; + gap: 5px; + white-space: nowrap; + + &:hover, + &:focus, + &:active { + background: lighten($ui-base-color, 4%); + } + + &.selected { + font-weight: 700; + color: $primary-text-color; + background: $ui-highlight-color; + + &:hover, + &:focus, + &:active { + background: lighten($ui-highlight-color, 4%); + } + } + } } - &-actions { + &__actions { display: inline-flex; & > :not(:first-child) { @@ -231,11 +278,7 @@ $content-width: 840px; color: $secondary-text-color; font-size: 24px; line-height: 36px; - font-weight: 400; - - @media screen and (max-width: $no-columns-breakpoint) { - font-weight: 700; - } + font-weight: 700; } h3 { @@ -340,6 +383,14 @@ $content-width: 840px; &.visible { display: block; + position: fixed; + z-index: 10; + width: 100%; + height: calc(100vh - 56px); + left: 0; + bottom: 0; + overflow-y: auto; + background: $ui-base-color; } } @@ -440,6 +491,11 @@ body, } } + & > div { + display: flex; + gap: 5px; + } + strong { font-weight: 500; text-transform: uppercase; @@ -1162,7 +1218,7 @@ a.name-tag, path:first-child { fill: rgba($highlight-text-color, 0.25) !important; - fill-opacity: 1 !important; + fill-opacity: 100% !important; } path:last-child { @@ -1721,3 +1777,67 @@ a.sparkline { } } } + +.history { + counter-reset: step 0; + font-size: 15px; + line-height: 22px; + + li { + counter-increment: step 1; + padding-left: 2.5rem; + padding-bottom: 8px; + position: relative; + margin-bottom: 8px; + + &::before { + position: absolute; + content: counter(step); + font-size: 0.625rem; + font-weight: 500; + left: 0; + display: flex; + justify-content: center; + align-items: center; + width: calc(1.375rem + 1px); + height: calc(1.375rem + 1px); + background: $ui-base-color; + border: 1px solid $highlight-text-color; + color: $highlight-text-color; + border-radius: 8px; + } + + &::after { + position: absolute; + content: ""; + width: 1px; + background: $highlight-text-color; + bottom: 0; + top: calc(1.875rem + 1px); + left: 0.6875rem; + } + + &:last-child { + margin-bottom: 0; + + &::after { + display: none; + } + } + } + + &__entry { + h5 { + font-weight: 500; + color: $primary-text-color; + line-height: 25px; + margin-bottom: 16px; + } + + .status { + border: 1px solid lighten($ui-base-color, 4%); + background: $ui-base-color; + border-radius: 4px; + } + } +} diff --git a/app/javascript/flavours/glitch/styles/compact_header.scss b/app/javascript/flavours/glitch/styles/compact_header.scss deleted file mode 100644 index 4980ab5f1..000000000 --- a/app/javascript/flavours/glitch/styles/compact_header.scss +++ /dev/null @@ -1,34 +0,0 @@ -.compact-header { - h1 { - font-size: 24px; - line-height: 28px; - color: $darker-text-color; - font-weight: 500; - margin-bottom: 20px; - padding: 0 10px; - word-wrap: break-word; - - @media screen and (max-width: 740px) { - text-align: center; - padding: 20px 10px 0; - } - - a { - color: inherit; - text-decoration: none; - } - - small { - font-weight: 400; - color: $secondary-text-color; - } - - img { - display: inline-block; - margin-bottom: -5px; - margin-right: 15px; - width: 36px; - height: 36px; - } - } -} diff --git a/app/javascript/flavours/glitch/styles/components/about.scss b/app/javascript/flavours/glitch/styles/components/about.scss new file mode 100644 index 000000000..ca9ba3ebf --- /dev/null +++ b/app/javascript/flavours/glitch/styles/components/about.scss @@ -0,0 +1,238 @@ +.image { + position: relative; + overflow: hidden; + + &__preview { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + object-fit: cover; + } + + &.loaded &__preview { + display: none; + } + + img { + display: block; + width: 100%; + height: 100%; + object-fit: cover; + border: 0; + background: transparent; + opacity: 0; + } + + &.loaded img { + opacity: 1; + } +} + +.about { + padding: 20px; + + @media screen and (min-width: $no-gap-breakpoint) { + border-radius: 4px; + } + + &__header { + margin-bottom: 30px; + + &__hero { + width: 100%; + height: auto; + aspect-ratio: 1.9; + background: lighten($ui-base-color, 4%); + border-radius: 8px; + margin-bottom: 30px; + } + + h1, + p { + text-align: center; + } + + h1 { + font-size: 24px; + line-height: 1.5; + font-weight: 700; + margin-bottom: 10px; + } + + p { + font-size: 16px; + line-height: 24px; + font-weight: 400; + color: $darker-text-color; + } + } + + &__meta { + background: lighten($ui-base-color, 4%); + border-radius: 4px; + display: flex; + margin-bottom: 30px; + font-size: 15px; + + &__column { + box-sizing: border-box; + width: 50%; + padding: 20px; + } + + &__divider { + width: 0; + border: 0; + border-style: solid; + border-color: lighten($ui-base-color, 8%); + border-left-width: 1px; + min-height: calc(100% - 60px); + flex: 0 0 auto; + } + + h4 { + font-size: 15px; + text-transform: uppercase; + color: $darker-text-color; + font-weight: 500; + margin-bottom: 20px; + } + + @media screen and (max-width: 600px) { + display: block; + + h4 { + text-align: center; + } + + &__column { + width: 100%; + display: flex; + flex-direction: column; + align-items: center; + } + + &__divider { + min-height: 0; + width: 100%; + border-left-width: 0; + border-top-width: 1px; + } + } + + .layout-multiple-columns & { + display: block; + + h4 { + text-align: center; + } + + &__column { + width: 100%; + display: flex; + flex-direction: column; + align-items: center; + } + + &__divider { + min-height: 0; + width: 100%; + border-left-width: 0; + border-top-width: 1px; + } + } + } + + &__mail { + color: $primary-text-color; + text-decoration: none; + font-weight: 500; + + &:hover, + &:focus, + &:active { + text-decoration: underline; + } + } + + .getting-started__footer { + padding: 0; + margin-top: 60px; + text-align: center; + font-size: 15px; + line-height: 22px; + + @media screen and (min-width: $no-gap-breakpoint) { + display: none; + } + } + + .account { + padding: 0; + border: 0; + } + + .account__avatar-wrapper { + margin-left: 0; + } + + .account__relationship { + display: none; + } + + &__section { + margin-bottom: 10px; + + &__title { + font-size: 17px; + font-weight: 600; + line-height: 22px; + padding: 20px; + border-radius: 4px; + background: lighten($ui-base-color, 4%); + color: $highlight-text-color; + cursor: pointer; + } + + &.active &__title { + border-radius: 4px 4px 0 0; + } + + &__body { + border: 1px solid lighten($ui-base-color, 4%); + border-top: 0; + padding: 20px; + font-size: 15px; + line-height: 22px; + } + } + + &__domain-blocks { + margin-top: 30px; + width: 100%; + border-collapse: collapse; + break-inside: auto; + + th { + text-align: left; + font-weight: 500; + color: $darker-text-color; + } + + thead tr, + tbody tr { + border-bottom: 1px solid lighten($ui-base-color, 8%); + } + + tbody tr:last-child { + border-bottom: 0; + } + + th, + td { + padding: 8px; + } + } +} diff --git a/app/javascript/flavours/glitch/styles/components/accounts.scss b/app/javascript/flavours/glitch/styles/components/accounts.scss index 4e912b18b..00519adf1 100644 --- a/app/javascript/flavours/glitch/styles/components/accounts.scss +++ b/app/javascript/flavours/glitch/styles/components/accounts.scss @@ -541,6 +541,7 @@ &__buttons { display: flex; align-items: center; + gap: 8px; padding-top: 55px; overflow: hidden; @@ -550,14 +551,6 @@ box-sizing: content-box; padding: 2px; } - - & > .icon-button { - margin-right: 8px; - } - - .button { - margin: 0 8px; - } } &__name { diff --git a/app/javascript/flavours/glitch/styles/components/columns.scss b/app/javascript/flavours/glitch/styles/components/columns.scss index 762e5dbb9..c61815e07 100644 --- a/app/javascript/flavours/glitch/styles/components/columns.scss +++ b/app/javascript/flavours/glitch/styles/components/columns.scss @@ -42,27 +42,62 @@ &__main { box-sizing: border-box; width: 100%; - max-width: 600px; flex: 0 0 auto; display: flex; flex-direction: column; @media screen and (min-width: $no-gap-breakpoint) { padding: 0 10px; + max-width: 600px; } } } } +$ui-header-height: 55px; + +.ui__header { + display: none; + box-sizing: border-box; + height: $ui-header-height; + position: sticky; + top: 0; + z-index: 2; + justify-content: space-between; + align-items: center; + + &__logo { + display: inline-flex; + padding: 15px; + + .logo { + height: $ui-header-height - 30px; + width: auto; + } + } + + &__links { + display: flex; + align-items: center; + gap: 10px; + padding: 0 10px; + + .button { + flex: 0 0 auto; + } + } +} + .tabs-bar__wrapper { background: darken($ui-base-color, 8%); position: sticky; - top: 0; + top: $ui-header-height; z-index: 2; padding-top: 0; @media screen and (min-width: $no-gap-breakpoint) { padding-top: 10px; + top: 0; } .tabs-bar { @@ -179,6 +214,8 @@ font-size: 16px; padding: 15px; text-decoration: none; + overflow: hidden; + white-space: nowrap; &:hover, &:focus, @@ -322,7 +359,8 @@ > .scrollable { background: $ui-base-color; - border-radius: 0 0 4px 4px; + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; } } @@ -589,7 +627,6 @@ } .empty-column-indicator, -.error-column, .follow_requests-unlocked_explanation { color: $dark-text-color; background: $ui-base-color; @@ -626,7 +663,48 @@ } .error-column { + padding: 20px; + background: $ui-base-color; + border-radius: 4px; + display: flex; + flex: 1 1 auto; + align-items: center; + justify-content: center; flex-direction: column; + cursor: default; + + &__image { + width: 70%; + max-width: 350px; + margin-top: -50px; + } + + &__message { + text-align: center; + color: $darker-text-color; + font-size: 15px; + line-height: 22px; + + h1 { + font-size: 28px; + line-height: 33px; + font-weight: 700; + margin-bottom: 15px; + color: $primary-text-color; + } + + p { + max-width: 48ch; + } + + &__actions { + margin-top: 30px; + display: flex; + gap: 10px; + align-items: center; + justify-content: center; + } + } } // more fixes for the navbar-under mode @@ -868,7 +946,7 @@ .column-actions { display: flex; - align-items: start; + align-items: flex-start; justify-content: center; padding: 40px; padding-top: 40px; @@ -900,3 +978,28 @@ color: $darker-text-color; } } + +.dismissable-banner { + background: $ui-base-color; + border-bottom: 1px solid lighten($ui-base-color, 8%); + display: flex; + align-items: center; + gap: 30px; + + &__message { + flex: 1 1 auto; + padding: 20px 15px; + cursor: default; + font-size: 14px; + line-height: 18px; + color: $primary-text-color; + } + + &__action { + padding: 15px; + flex: 0 0 auto; + display: flex; + align-items: center; + justify-content: center; + } +} diff --git a/app/javascript/flavours/glitch/styles/components/emoji_picker.scss b/app/javascript/flavours/glitch/styles/components/emoji_picker.scss index 0089445e1..bad6949c2 100644 --- a/app/javascript/flavours/glitch/styles/components/emoji_picker.scss +++ b/app/javascript/flavours/glitch/styles/components/emoji_picker.scss @@ -111,7 +111,7 @@ position: relative; input { - font-size: 14px; + font-size: 16px; font-weight: 400; padding: 7px 9px; padding-right: 25px; diff --git a/app/javascript/flavours/glitch/styles/components/explore.scss b/app/javascript/flavours/glitch/styles/components/explore.scss index 05df34eff..bad77fc1c 100644 --- a/app/javascript/flavours/glitch/styles/components/explore.scss +++ b/app/javascript/flavours/glitch/styles/components/explore.scss @@ -3,10 +3,9 @@ } .explore__search-header { - background: $ui-base-color; - display: flex; - align-items: flex-start; + background: darken($ui-base-color, 4%); justify-content: center; + align-items: center; padding: 15px; .search { @@ -15,14 +14,8 @@ } .search__input { - border-radius: 4px; - color: $inverted-text-color; - background: $simple-background-color; + border: 1px solid lighten($ui-base-color, 8%); padding: 10px; - - &::placeholder { - color: $dark-text-color; - } } .search .fa { diff --git a/app/javascript/flavours/glitch/styles/components/index.scss b/app/javascript/flavours/glitch/styles/components/index.scss index 1c3540b33..28f93018d 100644 --- a/app/javascript/flavours/glitch/styles/components/index.scss +++ b/app/javascript/flavours/glitch/styles/components/index.scss @@ -20,6 +20,11 @@ background: transparent; padding: 0; cursor: pointer; + text-decoration: none; + + &--destructive { + color: $error-value-color; + } &:hover, &:active { @@ -189,6 +194,15 @@ color: $highlight-text-color; } + &.copyable { + transition: background 300ms linear; + } + + &.copied { + background: $valid-value-color; + transition: none; + } + &::-moz-focus-inner { border: 0; } @@ -243,11 +257,12 @@ display: inline-flex; align-items: center; width: auto !important; + padding: 0 4px 0 2px; } &__counter { display: inline-block; - width: 14px; + width: auto; margin-left: 4px; font-size: 12px; font-weight: 500; @@ -1034,6 +1049,7 @@ padding: 10px; padding-top: 20px; z-index: 1; + font-size: 13px; ul { margin-bottom: 10px; @@ -1045,7 +1061,6 @@ p { color: $dark-text-color; - font-size: 13px; margin-bottom: 20px; a { @@ -1778,3 +1793,5 @@ noscript { @import 'announcements'; @import 'explore'; @import 'signed_out'; +@import 'privacy_policy'; +@import 'about'; diff --git a/app/javascript/flavours/glitch/styles/components/privacy_policy.scss b/app/javascript/flavours/glitch/styles/components/privacy_policy.scss new file mode 100644 index 000000000..96cf06742 --- /dev/null +++ b/app/javascript/flavours/glitch/styles/components/privacy_policy.scss @@ -0,0 +1,207 @@ +.privacy-policy { + background: $ui-base-color; + padding: 20px; + + @media screen and (min-width: $no-gap-breakpoint) { + border-radius: 4px; + } + + &__body { + margin-top: 20px; + } +} + +.prose { + color: $secondary-text-color; + font-size: 15px; + line-height: 22px; + + p, + ul, + ol { + margin-top: 1.25em; + margin-bottom: 1.25em; + } + + img { + margin-top: 2em; + margin-bottom: 2em; + } + + video { + margin-top: 2em; + margin-bottom: 2em; + } + + figure { + margin-top: 2em; + margin-bottom: 2em; + + figcaption { + font-size: 0.875em; + line-height: 1.4285714; + margin-top: 0.8571429em; + } + } + + figure > * { + margin-top: 0; + margin-bottom: 0; + } + + h1 { + font-size: 1.5em; + margin-top: 0; + margin-bottom: 1em; + line-height: 1.33; + } + + h2 { + font-size: 1.25em; + margin-top: 1.6em; + margin-bottom: 0.6em; + line-height: 1.6; + } + + h3, + h4, + h5, + h6 { + margin-top: 1.5em; + margin-bottom: 0.5em; + line-height: 1.5; + } + + ol { + counter-reset: list-counter; + } + + li { + margin-top: 0.5em; + margin-bottom: 0.5em; + } + + ol > li { + counter-increment: list-counter; + + &::before { + content: counter(list-counter) "."; + position: absolute; + left: 0; + } + } + + ul > li::before { + content: ""; + position: absolute; + background-color: $darker-text-color; + border-radius: 50%; + width: 0.375em; + height: 0.375em; + top: 0.5em; + left: 0.25em; + } + + ul > li, + ol > li { + position: relative; + padding-left: 1.75em; + } + + & > ul > li p { + margin-top: 0.75em; + margin-bottom: 0.75em; + } + + & > ul > li > *:first-child { + margin-top: 1.25em; + } + + & > ul > li > *:last-child { + margin-bottom: 1.25em; + } + + & > ol > li > *:first-child { + margin-top: 1.25em; + } + + & > ol > li > *:last-child { + margin-bottom: 1.25em; + } + + ul ul, + ul ol, + ol ul, + ol ol { + margin-top: 0.75em; + margin-bottom: 0.75em; + } + + h1, + h2, + h3, + h4, + h5, + h6, + strong, + b { + color: $primary-text-color; + font-weight: 700; + } + + em, + i { + font-style: italic; + } + + a { + color: $highlight-text-color; + text-decoration: underline; + + &:focus, + &:hover, + &:active { + text-decoration: none; + } + } + + code { + font-size: 0.875em; + background: darken($ui-base-color, 8%); + border-radius: 4px; + padding: 0.2em 0.3em; + } + + hr { + border: 0; + border-top: 1px solid lighten($ui-base-color, 4%); + margin-top: 3em; + margin-bottom: 3em; + } + + hr + * { + margin-top: 0; + } + + h2 + * { + margin-top: 0; + } + + h3 + * { + margin-top: 0; + } + + h4 + *, + h5 + *, + h6 + * { + margin-top: 0; + } + + & > :first-child { + margin-top: 0; + } + + & > :last-child { + margin-bottom: 0; + } +} diff --git a/app/javascript/flavours/glitch/styles/components/search.scss b/app/javascript/flavours/glitch/styles/components/search.scss index 17a34db62..70af0f651 100644 --- a/app/javascript/flavours/glitch/styles/components/search.scss +++ b/app/javascript/flavours/glitch/styles/components/search.scss @@ -28,10 +28,6 @@ &:focus { background: lighten($ui-base-color, 4%); } - - @media screen and (max-width: 600px) { - font-size: 16px; - } } .search__icon { @@ -132,6 +128,7 @@ align-items: center; padding: 15px; border-bottom: 1px solid lighten($ui-base-color, 8%); + gap: 15px; &:last-child { border-bottom: 0; @@ -173,16 +170,8 @@ font-size: 24px; font-weight: 500; text-align: right; - padding-right: 15px; - margin-left: 5px; color: $secondary-text-color; text-decoration: none; - - &__asterisk { - color: $darker-text-color; - font-size: 18px; - vertical-align: super; - } } &__sparkline { @@ -191,7 +180,7 @@ path:first-child { fill: rgba($highlight-text-color, 0.25) !important; - fill-opacity: 1 !important; + fill-opacity: 100% !important; } path:last-child { diff --git a/app/javascript/flavours/glitch/styles/components/single_column.scss b/app/javascript/flavours/glitch/styles/components/single_column.scss index bbb8b456c..1f1d7d68d 100644 --- a/app/javascript/flavours/glitch/styles/components/single_column.scss +++ b/app/javascript/flavours/glitch/styles/components/single_column.scss @@ -154,97 +154,71 @@ padding-top: 0; } - @media screen and (min-width: 630px) { - .detailed-status { - padding: 15px; + .detailed-status { + padding: 15px; - .media-gallery, - .video-player, - .audio-player { - margin-top: 15px; - } + .media-gallery, + .video-player, + .audio-player { + margin-top: 15px; } + } - .account__header__bar { - padding: 5px 10px; - } + .account__header__bar { + padding: 5px 10px; + } - .navigation-bar, - .compose-form { - padding: 15px; - } + .navigation-bar, + .compose-form { + padding: 15px; + } - .compose-form .compose-form__publish .compose-form__publish-button-wrapper { - padding-top: 15px; - } + .compose-form .compose-form__publish .compose-form__publish-button-wrapper { + padding-top: 15px; + } - .notification__report { - padding: 15px 15px 15px (48px + 15px * 2); - min-height: 48px + 2px; + .notification__report { + padding: 15px 15px 15px (48px + 15px * 2); + min-height: 48px + 2px; - &__avatar { - left: 15px; - top: 17px; - } + &__avatar { + left: 15px; + top: 17px; } + } - .status { - padding: 15px; - min-height: 48px + 2px; + .status { + padding: 15px; + min-height: 48px + 2px; - .media-gallery, - &__action-bar, - .video-player, - .audio-player { - margin-top: 10px; - } + .media-gallery, + &__action-bar, + .video-player, + .audio-player { + margin-top: 10px; } + } - .account { - padding: 15px 10px; + .account { + padding: 15px 10px; - &__header__bio { - margin: 0 -10px; - } + &__header__bio { + margin: 0 -10px; } + } - .notification { - &__message { - padding-top: 15px; - } - - .status { - padding-top: 8px; - } + .notification { + &__message { + padding-top: 15px; + } - .account { - padding-top: 8px; - } + .status { + padding-top: 8px; } - } -} -.floating-action-button { - position: fixed; - display: flex; - justify-content: center; - align-items: center; - width: 3.9375rem; - height: 3.9375rem; - bottom: 1.3125rem; - right: 1.3125rem; - background: darken($ui-highlight-color, 2%); - color: $white; - border-radius: 50%; - font-size: 21px; - line-height: 21px; - text-decoration: none; - box-shadow: 2px 3px 9px rgba($base-shadow-color, 0.4); - - &:hover, - &:focus, - &:active { - background: $ui-highlight-color; + .account { + padding-top: 8px; + } } } @@ -261,37 +235,104 @@ .search { margin-bottom: 10px; } -} -@media screen and (max-width: 600px + (285px * 1) + (10px * 1)) { - .columns-area__panels__pane--compositional { + .tabs-bar__link.optional { display: none; } - .with-fab .scrollable .item-list:last-child { - padding-bottom: 5.25rem; + .search-page .search { + display: none; } -} -@media screen and (min-width: 600px + (285px * 1) + (10px * 1)) { - .floating-action-button, - .tabs-bar__link.optional { + .navigation-panel__legal { display: none; } +} - .search-page .search { - display: none; +@media screen and (max-width: $no-gap-breakpoint - 1px) { + $sidebar-width: 285px; + + .columns-area__panels__main { + width: calc(100% - $sidebar-width); + } + + .columns-area__panels { + min-height: calc(100vh - $ui-header-height); + } + + .columns-area__panels__pane--navigational { + min-width: $sidebar-width; + + .columns-area__panels__pane__inner { + width: $sidebar-width; + } + + .navigation-panel { + margin: 0; + background: $ui-base-color; + border-left: 1px solid lighten($ui-base-color, 8%); + height: 100vh; + } + + .navigation-panel__sign-in-banner, + .navigation-panel__logo, + .getting-started__trends { + display: none; + } + + .column-link__icon { + font-size: 18px; + } + } + + .ui__header { + display: flex; + background: $ui-base-color; + border-bottom: 1px solid lighten($ui-base-color, 8%); + } + + .column-header, + .column-back-button, + .scrollable, + .error-column { + border-radius: 0 !important; } } -@media screen and (max-width: 600px + (285px * 2) + (10px * 2)) { +@media screen and (max-width: $no-gap-breakpoint - 285px - 1px) { + $sidebar-width: 55px; + + .columns-area__panels__main { + width: calc(100% - $sidebar-width); + } + .columns-area__panels__pane--navigational { - display: none; + min-width: $sidebar-width; + + .columns-area__panels__pane__inner { + width: $sidebar-width; + } + + .column-link span { + display: none; + } + + .list-panel { + display: none; + } } } -@media screen and (min-width: 600px + (285px * 2) + (10px * 2)) { - .tabs-bar { +.explore__search-header { + display: none; +} + +@media screen and (max-width: $no-gap-breakpoint - 1px) { + .columns-area__panels__pane--compositional { display: none; } + + .explore__search-header { + display: flex; + } } diff --git a/app/javascript/flavours/glitch/styles/containers.scss b/app/javascript/flavours/glitch/styles/containers.scss index b8d0fdad2..75472646e 100644 --- a/app/javascript/flavours/glitch/styles/containers.scss +++ b/app/javascript/flavours/glitch/styles/containers.scss @@ -9,11 +9,7 @@ } .logo-container { - margin: 100px auto 50px; - - @media screen and (max-width: 500px) { - margin: 40px auto 0; - } + margin: 50px auto; h1 { display: flex; @@ -34,7 +30,6 @@ outline: 0; padding: 12px 16px; line-height: 32px; - font-family: $font-display, sans-serif; font-weight: 500; font-size: 14px; } @@ -111,789 +106,3 @@ margin-left: 10px; } } - -.grid-3 { - display: grid; - grid-gap: 10px; - grid-template-columns: 3fr 1fr; - grid-auto-columns: 25%; - grid-auto-rows: max-content; - - .column-0 { - grid-column: 1/3; - grid-row: 1; - } - - .column-1 { - grid-column: 1; - grid-row: 2; - } - - .column-2 { - grid-column: 2; - grid-row: 2; - } - - .column-3 { - grid-column: 1/3; - grid-row: 3; - } - - @media screen and (max-width: $no-gap-breakpoint) { - grid-gap: 0; - grid-template-columns: minmax(0, 100%); - - .column-0 { - grid-column: 1; - } - - .column-1 { - grid-column: 1; - grid-row: 3; - } - - .column-2 { - grid-column: 1; - grid-row: 2; - } - - .column-3 { - grid-column: 1; - grid-row: 4; - } - } -} - -.grid-4 { - display: grid; - grid-gap: 10px; - grid-template-columns: repeat(4, minmax(0, 1fr)); - grid-auto-columns: 25%; - grid-auto-rows: max-content; - - .column-0 { - grid-column: 1 / 5; - grid-row: 1; - } - - .column-1 { - grid-column: 1 / 4; - grid-row: 2; - } - - .column-2 { - grid-column: 4; - grid-row: 2; - } - - .column-3 { - grid-column: 2 / 5; - grid-row: 3; - } - - .column-4 { - grid-column: 1; - grid-row: 3; - } - - .landing-page__call-to-action { - min-height: 100%; - } - - .flash-message { - margin-bottom: 10px; - } - - @media screen and (max-width: 738px) { - grid-template-columns: minmax(0, 50%) minmax(0, 50%); - - .landing-page__call-to-action { - padding: 20px; - display: flex; - align-items: center; - justify-content: center; - } - - .row__information-board { - width: 100%; - justify-content: center; - align-items: center; - } - - .row__mascot { - display: none; - } - } - - @media screen and (max-width: $no-gap-breakpoint) { - grid-gap: 0; - grid-template-columns: minmax(0, 100%); - - .column-0 { - grid-column: 1; - } - - .column-1 { - grid-column: 1; - grid-row: 3; - } - - .column-2 { - grid-column: 1; - grid-row: 2; - } - - .column-3 { - grid-column: 1; - grid-row: 5; - } - - .column-4 { - grid-column: 1; - grid-row: 4; - } - } -} - -.public-layout { - @media screen and (max-width: $no-gap-breakpoint) { - padding-top: 48px; - } - - .container { - max-width: 960px; - - @media screen and (max-width: $no-gap-breakpoint) { - padding: 0; - } - } - - .header { - background: lighten($ui-base-color, 8%); - box-shadow: 0 0 15px rgba($base-shadow-color, 0.2); - border-radius: 4px; - height: 48px; - margin: 10px 0; - display: flex; - align-items: stretch; - justify-content: center; - flex-wrap: nowrap; - overflow: hidden; - - @media screen and (max-width: $no-gap-breakpoint) { - position: fixed; - width: 100%; - top: 0; - left: 0; - margin: 0; - border-radius: 0; - box-shadow: none; - z-index: 110; - } - - & > div { - flex: 1 1 33.3%; - min-height: 1px; - } - - .nav-left { - display: flex; - align-items: stretch; - justify-content: flex-start; - flex-wrap: nowrap; - } - - .nav-center { - display: flex; - align-items: stretch; - justify-content: center; - flex-wrap: nowrap; - } - - .nav-right { - display: flex; - align-items: stretch; - justify-content: flex-end; - flex-wrap: nowrap; - } - - .brand { - display: block; - padding: 15px; - - .logo { - display: block; - height: 18px; - width: auto; - position: relative; - bottom: -2px; - fill: $primary-text-color; - - @media screen and (max-width: $no-gap-breakpoint) { - height: 20px; - } - } - - &:hover, - &:focus, - &:active { - background: lighten($ui-base-color, 12%); - } - } - - .nav-link { - display: flex; - align-items: center; - padding: 0 1rem; - font-size: 12px; - font-weight: 500; - text-decoration: none; - color: $darker-text-color; - white-space: nowrap; - text-align: center; - - &:hover, - &:focus, - &:active { - text-decoration: underline; - color: $primary-text-color; - } - - @media screen and (max-width: 550px) { - &.optional { - display: none; - } - } - } - - .nav-button { - background: lighten($ui-base-color, 16%); - margin: 8px; - margin-left: 0; - border-radius: 4px; - - &:hover, - &:focus, - &:active { - text-decoration: none; - background: lighten($ui-base-color, 20%); - } - } - } - - $no-columns-breakpoint: 600px; - - .grid { - display: grid; - grid-gap: 10px; - grid-template-columns: minmax(300px, 3fr) minmax(298px, 1fr); - grid-auto-columns: 25%; - grid-auto-rows: max-content; - - .column-0 { - grid-row: 1; - grid-column: 1; - } - - .column-1 { - grid-row: 1; - grid-column: 2; - } - - @media screen and (max-width: $no-columns-breakpoint) { - grid-template-columns: 100%; - grid-gap: 0; - - .column-1 { - display: none; - } - } - } - - .page-header { - @media screen and (max-width: $no-gap-breakpoint) { - border-bottom: 0; - } - } - - .public-account-header { - overflow: hidden; - margin-bottom: 10px; - box-shadow: 0 0 15px rgba($base-shadow-color, 0.2); - - &.inactive { - opacity: 0.5; - - .public-account-header__image, - .avatar { - filter: grayscale(100%); - } - - .logo-button { - background-color: $secondary-text-color; - } - } - - .logo-button { - padding: 3px 15px; - } - - &__image { - border-radius: 4px 4px 0 0; - overflow: hidden; - height: 300px; - position: relative; - background: darken($ui-base-color, 12%); - - &::after { - content: ""; - display: block; - position: absolute; - width: 100%; - height: 100%; - box-shadow: inset 0 -1px 1px 1px rgba($base-shadow-color, 0.15); - top: 0; - left: 0; - } - - img { - object-fit: cover; - display: block; - width: 100%; - height: 100%; - margin: 0; - border-radius: 4px 4px 0 0; - } - - @media screen and (max-width: 600px) { - height: 200px; - } - } - - &--no-bar { - margin-bottom: 0; - - .public-account-header__image, - .public-account-header__image img { - border-radius: 4px; - - @media screen and (max-width: $no-gap-breakpoint) { - border-radius: 0; - } - } - } - - @media screen and (max-width: $no-gap-breakpoint) { - margin-bottom: 0; - box-shadow: none; - - &__image::after { - display: none; - } - - &__image, - &__image img { - border-radius: 0; - } - } - - &__bar { - position: relative; - margin-top: -80px; - display: flex; - justify-content: flex-start; - - &::before { - content: ""; - display: block; - background: lighten($ui-base-color, 4%); - position: absolute; - bottom: 0; - left: 0; - right: 0; - height: 60px; - border-radius: 0 0 4px 4px; - z-index: -1; - } - - .avatar { - display: block; - width: 120px; - height: 120px; - @include avatar-size(120px); - padding-left: 20px - 4px; - flex: 0 0 auto; - - img { - display: block; - width: 100%; - height: 100%; - margin: 0; - border-radius: 50%; - border: 4px solid lighten($ui-base-color, 4%); - background: darken($ui-base-color, 8%); - @include avatar-radius(); - } - } - - @media screen and (max-width: 600px) { - margin-top: 0; - background: lighten($ui-base-color, 4%); - border-radius: 0 0 4px 4px; - padding: 5px; - - &::before { - display: none; - } - - .avatar { - width: 48px; - height: 48px; - @include avatar-size(48px); - padding: 7px 0; - padding-left: 10px; - - img { - border: 0; - border-radius: 4px; - @include avatar-radius(); - } - - @media screen and (max-width: 360px) { - display: none; - } - } - } - - @media screen and (max-width: $no-gap-breakpoint) { - border-radius: 0; - } - - @media screen and (max-width: $no-columns-breakpoint) { - flex-wrap: wrap; - } - } - - &__tabs { - flex: 1 1 auto; - margin-left: 20px; - - &__name { - padding-top: 20px; - padding-bottom: 8px; - - h1 { - font-size: 20px; - line-height: 18px * 1.5; - color: $primary-text-color; - font-weight: 500; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - text-shadow: 1px 1px 1px $base-shadow-color; - - small { - display: block; - font-size: 14px; - color: $primary-text-color; - font-weight: 400; - overflow: hidden; - text-overflow: ellipsis; - } - } - } - - @media screen and (max-width: 600px) { - margin-left: 15px; - display: flex; - justify-content: space-between; - align-items: center; - - &__name { - padding-top: 0; - padding-bottom: 0; - - h1 { - font-size: 16px; - line-height: 24px; - text-shadow: none; - - small { - color: $darker-text-color; - } - } - } - } - - &__tabs { - display: flex; - justify-content: flex-start; - align-items: stretch; - height: 58px; - - .details-counters { - display: flex; - flex-direction: row; - min-width: 300px; - } - - @media screen and (max-width: $no-columns-breakpoint) { - .details-counters { - display: none; - } - } - - .counter { - min-width: 33.3%; - box-sizing: border-box; - flex: 0 0 auto; - color: $darker-text-color; - padding: 10px; - border-right: 1px solid lighten($ui-base-color, 4%); - cursor: default; - text-align: center; - position: relative; - - a { - display: block; - } - - &:last-child { - border-right: 0; - } - - &::after { - display: block; - content: ""; - position: absolute; - bottom: 0; - left: 0; - width: 100%; - border-bottom: 4px solid $ui-primary-color; - opacity: 0.5; - transition: all 400ms ease; - } - - &.active { - &::after { - border-bottom: 4px solid $highlight-text-color; - opacity: 1; - } - - &.inactive::after { - border-bottom-color: $secondary-text-color; - } - } - - &:hover { - &::after { - opacity: 1; - transition-duration: 100ms; - } - } - - a { - text-decoration: none; - color: inherit; - } - - .counter-label { - font-size: 12px; - display: block; - } - - .counter-number { - font-weight: 500; - font-size: 18px; - margin-bottom: 5px; - color: $primary-text-color; - font-family: $font-display, sans-serif; - } - } - - .spacer { - flex: 1 1 auto; - height: 1px; - } - - &__buttons { - padding: 7px 8px; - } - } - } - - &__extra { - display: none; - margin-top: 4px; - - .public-account-bio { - border-radius: 0; - box-shadow: none; - background: transparent; - margin: 0 -5px; - - .account__header__fields { - border-top: 1px solid lighten($ui-base-color, 12%); - } - - .roles { - display: none; - } - } - - &__links { - margin-top: -15px; - font-size: 14px; - color: $darker-text-color; - - a { - display: inline-block; - color: $darker-text-color; - text-decoration: none; - padding: 15px; - font-weight: 500; - - strong { - font-weight: 700; - color: $primary-text-color; - } - } - } - - @media screen and (max-width: $no-columns-breakpoint) { - display: block; - flex: 100%; - } - } - } - - .account__section-headline { - border-radius: 4px 4px 0 0; - - @media screen and (max-width: $no-gap-breakpoint) { - border-radius: 0; - } - } - - .detailed-status__meta { - margin-top: 25px; - } - - .public-account-bio { - background: lighten($ui-base-color, 8%); - box-shadow: 0 0 15px rgba($base-shadow-color, 0.2); - border-radius: 4px; - overflow: hidden; - margin-bottom: 10px; - - @media screen and (max-width: $no-gap-breakpoint) { - box-shadow: none; - margin-bottom: 0; - border-radius: 0; - } - - .account__header__fields { - margin: 0; - border-top: 0; - - a { - color: $highlight-text-color; - } - - dl:first-child .verified { - border-radius: 0 4px 0 0; - } - - .verified a { - color: $valid-value-color; - } - } - - .account__header__content { - padding: 20px; - padding-bottom: 0; - color: $primary-text-color; - } - - &__extra, - .roles { - padding: 20px; - font-size: 14px; - color: $darker-text-color; - } - - .roles { - padding-bottom: 0; - } - } - - .directory__list { - display: grid; - grid-gap: 10px; - grid-template-columns: minmax(0, 50%) minmax(0, 50%); - - .account-card { - display: flex; - flex-direction: column; - } - - @media screen and (max-width: $no-gap-breakpoint) { - display: block; - - .account-card { - margin-bottom: 10px; - display: block; - } - } - } - - .card-grid { - display: flex; - flex-wrap: wrap; - min-width: 100%; - margin: 0 -5px; - - & > div { - box-sizing: border-box; - flex: 1 0 auto; - width: 300px; - padding: 0 5px; - margin-bottom: 10px; - max-width: 33.333%; - - @media screen and (max-width: 900px) { - max-width: 50%; - } - - @media screen and (max-width: 600px) { - max-width: 100%; - } - } - - @media screen and (max-width: $no-gap-breakpoint) { - margin: 0; - border-top: 1px solid lighten($ui-base-color, 8%); - - & > div { - width: 100%; - padding: 0; - margin-bottom: 0; - border-bottom: 1px solid lighten($ui-base-color, 8%); - - &:last-child { - border-bottom: 0; - } - - .card__bar { - background: $ui-base-color; - - &:hover, - &:active, - &:focus { - background: lighten($ui-base-color, 4%); - } - } - } - } - } -} diff --git a/app/javascript/flavours/glitch/styles/contrast/diff.scss b/app/javascript/flavours/glitch/styles/contrast/diff.scss index 9bd31cd7e..a9a203960 100644 --- a/app/javascript/flavours/glitch/styles/contrast/diff.scss +++ b/app/javascript/flavours/glitch/styles/contrast/diff.scss @@ -1,9 +1,5 @@ // components.scss -.rich-formatting a, -.rich-formatting p a, -.rich-formatting li a, -.landing-page__short-description p a, .status__content a, .reply-indicator__content a { color: lighten($ui-highlight-color, 12%); diff --git a/app/javascript/flavours/glitch/styles/dashboard.scss b/app/javascript/flavours/glitch/styles/dashboard.scss index 9b06b44d6..bb103e9ce 100644 --- a/app/javascript/flavours/glitch/styles/dashboard.scss +++ b/app/javascript/flavours/glitch/styles/dashboard.scss @@ -39,7 +39,6 @@ font-size: 24px; line-height: 21px; color: $primary-text-color; - font-family: $font-display, sans-serif; margin-bottom: 20px; line-height: 30px; } diff --git a/app/javascript/flavours/glitch/styles/footer.scss b/app/javascript/flavours/glitch/styles/footer.scss deleted file mode 100644 index 0c3e42033..000000000 --- a/app/javascript/flavours/glitch/styles/footer.scss +++ /dev/null @@ -1,152 +0,0 @@ -.public-layout { - .footer { - text-align: left; - padding-top: 20px; - padding-bottom: 60px; - font-size: 12px; - color: lighten($ui-base-color, 34%); - - @media screen and (max-width: $no-gap-breakpoint) { - padding-left: 20px; - padding-right: 20px; - } - - .grid { - display: grid; - grid-gap: 10px; - grid-template-columns: 1fr 1fr 2fr 1fr 1fr; - - .column-0 { - grid-column: 1; - grid-row: 1; - min-width: 0; - } - - .column-1 { - grid-column: 2; - grid-row: 1; - min-width: 0; - } - - .column-2 { - grid-column: 3; - grid-row: 1; - min-width: 0; - text-align: center; - - h4 a { - color: lighten($ui-base-color, 34%); - } - } - - .column-3 { - grid-column: 4; - grid-row: 1; - min-width: 0; - } - - .column-4 { - grid-column: 5; - grid-row: 1; - min-width: 0; - } - - @media screen and (max-width: 690px) { - grid-template-columns: 1fr 2fr 1fr; - - .column-0, - .column-1 { - grid-column: 1; - } - - .column-1 { - grid-row: 2; - } - - .column-2 { - grid-column: 2; - } - - .column-3, - .column-4 { - grid-column: 3; - } - - .column-4 { - grid-row: 2; - } - } - - @media screen and (max-width: 600px) { - .column-1 { - display: block; - } - } - - @media screen and (max-width: $no-gap-breakpoint) { - .column-0, - .column-1, - .column-3, - .column-4 { - display: none; - } - - .column-2 h4 { - display: none; - } - } - } - - .legal-xs { - display: none; - text-align: center; - padding-top: 20px; - - @media screen and (max-width: $no-gap-breakpoint) { - display: block; - } - } - - h4 { - text-transform: uppercase; - font-weight: 700; - margin-bottom: 8px; - color: $darker-text-color; - - a { - color: inherit; - text-decoration: none; - } - } - - ul a, - .legal-xs a { - text-decoration: none; - color: lighten($ui-base-color, 34%); - - &:hover, - &:active, - &:focus { - text-decoration: underline; - } - } - - .brand { - .logo { - display: block; - height: 36px; - width: auto; - margin: 0 auto; - color: lighten($ui-base-color, 34%); - } - - &:hover, - &:focus, - &:active { - .logo { - color: lighten($ui-base-color, 38%); - } - } - } - } -} diff --git a/app/javascript/flavours/glitch/styles/forms.scss b/app/javascript/flavours/glitch/styles/forms.scss index 8ae2b5bd8..ef0ca1fcd 100644 --- a/app/javascript/flavours/glitch/styles/forms.scss +++ b/app/javascript/flavours/glitch/styles/forms.scss @@ -6,9 +6,10 @@ code { } .form-container { - max-width: 400px; + max-width: 450px; padding: 20px; - margin: 0 auto; + padding-bottom: 50px; + margin: 50px auto; } .indicator-icon { @@ -123,10 +124,22 @@ code { } .title { - color: #d9e1e8; - font-size: 20px; - line-height: 28px; - font-weight: 400; + font-size: 28px; + line-height: 33px; + font-weight: 700; + margin-bottom: 15px; + } + + .lead { + font-size: 17px; + line-height: 22px; + color: $secondary-text-color; + margin-bottom: 30px; + } + + .rules-list { + font-size: 17px; + line-height: 22px; margin-bottom: 30px; } @@ -231,7 +244,7 @@ code { & > label { font-family: inherit; - font-size: 16px; + font-size: 14px; color: $primary-text-color; display: block; font-weight: 500; @@ -268,6 +281,20 @@ code { .input:last-child { margin-bottom: 0; } + + &__thumbnail { + display: block; + margin: 0; + margin-bottom: 10px; + max-width: 100%; + height: auto; + border-radius: 4px; + background: url("images/void.png"); + + &:last-child { + margin-bottom: 0; + } + } } .fields-row { @@ -368,6 +395,7 @@ code { input[type=email], input[type=password], input[type=url], + input[type=datetime-local], textarea { box-sizing: border-box; font-size: 16px; @@ -408,7 +436,8 @@ code { input[type=text], input[type=number], input[type=email], - input[type=password] { + input[type=password], + input[type=datetime-local] { &:focus:invalid:not(:placeholder-shown), &:required:invalid:not(:placeholder-shown) { border-color: lighten($error-red, 12%); @@ -424,6 +453,7 @@ code { input[type=number], input[type=email], input[type=password], + input[type=datetime-local], textarea, select { border-color: lighten($error-red, 12%); @@ -451,6 +481,11 @@ code { } } + .stacked-actions { + margin-top: 30px; + margin-bottom: 15px; + } + button, .button, .block-button { @@ -502,6 +537,16 @@ code { } } + .button.button-tertiary { + padding: 9px; + + &:hover, + &:focus, + &:active { + padding: 10px; + } + } + select { appearance: none; box-sizing: border-box; @@ -556,41 +601,6 @@ code { } } } - - &__overlay-area { - position: relative; - - &__blurred form { - filter: blur(2px); - } - - &__overlay { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - display: flex; - justify-content: center; - align-items: center; - background: rgba($ui-base-color, 0.65); - border-radius: 4px; - margin-left: -4px; - margin-top: -4px; - padding: 4px; - - &__content { - text-align: center; - - &.rich-formatting { - &, - p { - color: $primary-text-color; - } - } - } - } - } } .block-icon { @@ -861,24 +871,7 @@ code { } } -.table-form { - p { - margin-bottom: 15px; - - strong { - font-weight: 500; - - @each $lang in $cjk-langs { - &:lang(#{$lang}) { - font-weight: 700; - } - } - } - } -} - -.simple_form, -.table-form { +.simple_form { .warning { box-sizing: border-box; background: rgba($error-value-color, 0.5); diff --git a/app/javascript/flavours/glitch/styles/index.scss b/app/javascript/flavours/glitch/styles/index.scss index f808773f3..fbb02c788 100644 --- a/app/javascript/flavours/glitch/styles/index.scss +++ b/app/javascript/flavours/glitch/styles/index.scss @@ -2,7 +2,6 @@ @import 'variables'; @import 'styles/fonts/roboto'; @import 'styles/fonts/roboto-mono'; -@import 'styles/fonts/montserrat'; @import 'reset'; @import 'basics'; @@ -10,8 +9,6 @@ @import 'containers'; @import 'lists'; @import 'modal'; -@import 'footer'; -@import 'compact_header'; @import 'widgets'; @import 'forms'; @import 'accounts'; diff --git a/app/javascript/flavours/glitch/styles/mastodon-light/diff.scss b/app/javascript/flavours/glitch/styles/mastodon-light/diff.scss index d16f23aed..d4ac55847 100644 --- a/app/javascript/flavours/glitch/styles/mastodon-light/diff.scss +++ b/app/javascript/flavours/glitch/styles/mastodon-light/diff.scss @@ -354,45 +354,11 @@ } } -.public-layout { - .header, - .public-account-header, - .public-account-bio { - box-shadow: none; - } - - .header { - background: lighten($ui-base-color, 12%); - } - - .public-account-header { - &__image { - background: lighten($ui-base-color, 12%); - - &::after { - box-shadow: none; - } - } - - &__tabs { - &__name { - h1, - h1 small { - color: $white; - } - } - } - } -} - .account__section-headline a.active::after { border-color: transparent transparent $white; } .hero-widget, -.box-widget, -.contact-widget, -.landing-page__information.contact-widget, .moved-account-widget, .memoriam-widget, .activity-stream, diff --git a/app/javascript/flavours/glitch/styles/rtl.scss b/app/javascript/flavours/glitch/styles/rtl.scss index d0153c9f9..31d1de376 100644 --- a/app/javascript/flavours/glitch/styles/rtl.scss +++ b/app/javascript/flavours/glitch/styles/rtl.scss @@ -30,16 +30,6 @@ body.rtl { right: -26px; } - .landing-page__logo { - margin-right: 0; - margin-left: 20px; - } - - .landing-page .features-list .features-list__row .visual { - margin-left: 0; - margin-right: 15px; - } - .column-link__icon, .column-header__icon { margin-right: 0; @@ -327,44 +317,6 @@ body.rtl { margin-left: 45px; } - .landing-page .header-wrapper .mascot { - right: 60px; - left: auto; - } - - .landing-page__call-to-action .row__information-board { - direction: rtl; - } - - .landing-page .header .hero .floats .float-1 { - left: -120px; - right: auto; - } - - .landing-page .header .hero .floats .float-2 { - left: 210px; - right: auto; - } - - .landing-page .header .hero .floats .float-3 { - left: 110px; - right: auto; - } - - .landing-page .header .links .brand img { - left: 0; - } - - .landing-page .fa-external-link { - padding-right: 5px; - padding-left: 0 !important; - } - - .landing-page .features #mastodon-timeline { - margin-right: 0; - margin-left: 30px; - } - @media screen and (min-width: 631px) { .column, .drawer { @@ -392,32 +344,6 @@ body.rtl { padding-right: 0; } - .public-layout { - .header { - .nav-button { - margin-left: 8px; - margin-right: 0; - } - } - - .public-account-header__tabs { - margin-left: 0; - margin-right: 20px; - } - } - - .landing-page__information { - .account__display-name { - margin-right: 0; - margin-left: 5px; - } - - .account__avatar-wrapper { - margin-left: 12px; - margin-right: 0; - } - } - .card__bar .display-name { margin-left: 0; margin-right: 15px; diff --git a/app/javascript/flavours/glitch/styles/statuses.scss b/app/javascript/flavours/glitch/styles/statuses.scss index c302fc0d0..947a5d3ae 100644 --- a/app/javascript/flavours/glitch/styles/statuses.scss +++ b/app/javascript/flavours/glitch/styles/statuses.scss @@ -133,8 +133,7 @@ a.button.logo-button { justify-content: center; } -.embed, -.public-layout { +.embed { .status__content[data-spoiler=folded] { .e-content { display: none; @@ -204,8 +203,7 @@ a.button.logo-button { } // Styling from upstream's WebUI, as public pages use the same layout -.embed, -.public-layout { +.embed { .status { .status__info { font-size: 15px; @@ -244,8 +242,7 @@ a.button.logo-button { } .rtl { - .embed, - .public-layout { + .embed { .status { padding-left: 10px; padding-right: 68px; diff --git a/app/javascript/flavours/glitch/styles/variables.scss b/app/javascript/flavours/glitch/styles/variables.scss index 65758e6e0..b865b5a2d 100644 --- a/app/javascript/flavours/glitch/styles/variables.scss +++ b/app/javascript/flavours/glitch/styles/variables.scss @@ -51,7 +51,7 @@ $media-modal-media-max-width: 100%; // put margins on top and bottom of image to avoid the screen covered by image. $media-modal-media-max-height: 80%; -$no-gap-breakpoint: 415px; +$no-gap-breakpoint: 1175px; $font-sans-serif: 'mastodon-font-sans-serif' !default; $font-display: 'mastodon-font-display' !default; diff --git a/app/javascript/flavours/glitch/styles/widgets.scss b/app/javascript/flavours/glitch/styles/widgets.scss index a88f3b2c7..fd091ee89 100644 --- a/app/javascript/flavours/glitch/styles/widgets.scss +++ b/app/javascript/flavours/glitch/styles/widgets.scss @@ -108,13 +108,6 @@ } } -.box-widget { - padding: 20px; - border-radius: 4px; - background: $ui-base-color; - box-shadow: 0 0 15px rgba($base-shadow-color, 0.2); -} - .placeholder-widget { padding: 16px; border-radius: 4px; @@ -124,47 +117,6 @@ margin-bottom: 10px; } -.contact-widget { - min-height: 100%; - font-size: 15px; - color: $darker-text-color; - line-height: 20px; - word-wrap: break-word; - font-weight: 400; - padding: 0; - - h4 { - padding: 10px; - text-transform: uppercase; - font-weight: 700; - font-size: 13px; - color: $darker-text-color; - } - - .account { - border-bottom: 0; - padding: 10px 0; - padding-top: 5px; - } - - & > a { - display: inline-block; - padding: 10px; - padding-top: 0; - color: $darker-text-color; - text-decoration: none; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - - &:hover, - &:focus, - &:active { - text-decoration: underline; - } - } -} - .moved-account-widget { padding: 15px; padding-bottom: 20px; @@ -245,37 +197,6 @@ margin-bottom: 10px; } -.page-header { - background: lighten($ui-base-color, 8%); - box-shadow: 0 0 15px rgba($base-shadow-color, 0.2); - border-radius: 4px; - padding: 60px 15px; - text-align: center; - margin: 10px 0; - - h1 { - color: $primary-text-color; - font-size: 36px; - line-height: 1.1; - font-weight: 700; - margin-bottom: 10px; - } - - p { - font-size: 15px; - color: $darker-text-color; - } - - @media screen and (max-width: $no-gap-breakpoint) { - margin-top: 0; - background: lighten($ui-base-color, 4%); - - h1 { - font-size: 24px; - } - } -} - .directory { background: $ui-base-color; border-radius: 4px; @@ -357,34 +278,6 @@ } } -.avatar-stack { - display: flex; - justify-content: flex-end; - - .account__avatar { - flex: 0 0 auto; - width: 36px; - height: 36px; - border-radius: 50%; - position: relative; - margin-left: -10px; - background: darken($ui-base-color, 8%); - border: 2px solid $ui-base-color; - - &:nth-child(1) { - z-index: 1; - } - - &:nth-child(2) { - z-index: 2; - } - - &:nth-child(3) { - z-index: 3; - } - } -} - .accounts-table { width: 100%; @@ -486,11 +379,7 @@ .moved-account-widget, .memoriam-widget, -.box-widget, -.contact-widget, -.landing-page__information.contact-widget, -.directory, -.page-header { +.directory { @media screen and (max-width: $no-gap-breakpoint) { margin-bottom: 0; box-shadow: none; @@ -498,88 +387,6 @@ } } -$maximum-width: 1235px; -$fluid-breakpoint: $maximum-width + 20px; - -.statuses-grid { - min-height: 600px; - - @media screen and (max-width: 640px) { - width: 100% !important; // Masonry layout is unnecessary at this width - } - - &__item { - width: math.div(960px - 20px, 3); - - @media screen and (max-width: $fluid-breakpoint) { - width: math.div(940px - 20px, 3); - } - - @media screen and (max-width: 640px) { - width: 100%; - } - - @media screen and (max-width: $no-gap-breakpoint) { - width: 100vw; - } - } - - .detailed-status { - border-radius: 4px; - - @media screen and (max-width: $no-gap-breakpoint) { - border-top: 1px solid lighten($ui-base-color, 16%); - } - - &.compact { - .detailed-status__meta { - margin-top: 15px; - } - - .status__content { - font-size: 15px; - line-height: 20px; - - .emojione { - width: 20px; - height: 20px; - margin: -3px 0 0; - } - - .status__content__spoiler-link { - line-height: 20px; - margin: 0; - } - } - - .media-gallery, - .status-card, - .video-player { - margin-top: 15px; - } - } - } -} - -.notice-widget { - margin-bottom: 10px; - color: $darker-text-color; - - p { - margin-bottom: 10px; - - &:last-child { - margin-bottom: 0; - } - } - - a { - font-size: 14px; - line-height: 20px; - } -} - -.notice-widget, .placeholder-widget { a { text-decoration: none; @@ -593,37 +400,3 @@ $fluid-breakpoint: $maximum-width + 20px; } } } - -.table-of-contents { - background: darken($ui-base-color, 4%); - min-height: 100%; - font-size: 14px; - border-radius: 4px; - - li a { - display: block; - font-weight: 500; - padding: 15px; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - text-decoration: none; - color: $primary-text-color; - border-bottom: 1px solid lighten($ui-base-color, 4%); - - &:hover, - &:focus, - &:active { - text-decoration: underline; - } - } - - li:last-child a { - border-bottom: 0; - } - - li ul { - padding-left: 20px; - border-bottom: 1px solid lighten($ui-base-color, 4%); - } -} diff --git a/app/javascript/flavours/glitch/theme.yml b/app/javascript/flavours/glitch/theme.yml index f3c7fac7e..e85dd74e1 100644 --- a/app/javascript/flavours/glitch/theme.yml +++ b/app/javascript/flavours/glitch/theme.yml @@ -1,6 +1,5 @@ # (REQUIRED) The location of the pack files. pack: - about: packs/about.js admin: - packs/admin.js - packs/public.js diff --git a/app/javascript/flavours/glitch/utils/backend_links.js b/app/javascript/flavours/glitch/utils/backend_links.js index d0ae63419..2028a1e60 100644 --- a/app/javascript/flavours/glitch/utils/backend_links.js +++ b/app/javascript/flavours/glitch/utils/backend_links.js @@ -3,7 +3,7 @@ export const profileLink = '/settings/profile'; export const signOutLink = '/auth/sign_out'; export const privacyPolicyLink = '/privacy-policy'; export const accountAdminLink = (id) => `/admin/accounts/${id}`; -export const statusAdminLink = (account_id, status_id) => `/admin/accounts/${account_id}/statuses?id=${status_id}`; +export const statusAdminLink = (account_id, status_id) => `/admin/accounts/${account_id}/statuses/${status_id}`; export const filterEditLink = (id) => `/filters/${id}/edit`; export const relationshipsLink = '/relationships'; export const securityLink = '/auth/edit'; diff --git a/app/javascript/flavours/vanilla/theme.yml b/app/javascript/flavours/vanilla/theme.yml index 9173d4ec9..5cb76b721 100644 --- a/app/javascript/flavours/vanilla/theme.yml +++ b/app/javascript/flavours/vanilla/theme.yml @@ -1,6 +1,5 @@ # (REQUIRED) The location of the pack files inside `pack_directory`. pack: - about: about.js admin: - admin.js - public.js diff --git a/app/javascript/fonts/montserrat/Montserrat-Medium.ttf b/app/javascript/fonts/montserrat/Montserrat-Medium.ttf deleted file mode 100644 index 88d70b89c..000000000 --- a/app/javascript/fonts/montserrat/Montserrat-Medium.ttf +++ /dev/null Binary files differdiff --git a/app/javascript/fonts/montserrat/Montserrat-Regular.ttf b/app/javascript/fonts/montserrat/Montserrat-Regular.ttf deleted file mode 100644 index 29ca85d4a..000000000 --- a/app/javascript/fonts/montserrat/Montserrat-Regular.ttf +++ /dev/null Binary files differdiff --git a/app/javascript/fonts/montserrat/Montserrat-Regular.woff b/app/javascript/fonts/montserrat/Montserrat-Regular.woff deleted file mode 100644 index af3b5ec44..000000000 --- a/app/javascript/fonts/montserrat/Montserrat-Regular.woff +++ /dev/null Binary files differdiff --git a/app/javascript/fonts/montserrat/Montserrat-Regular.woff2 b/app/javascript/fonts/montserrat/Montserrat-Regular.woff2 deleted file mode 100644 index 3d75434dd..000000000 --- a/app/javascript/fonts/montserrat/Montserrat-Regular.woff2 +++ /dev/null Binary files differdiff --git a/app/javascript/mastodon/actions/compose.js b/app/javascript/mastodon/actions/compose.js index cffd032b3..317383ec1 100644 --- a/app/javascript/mastodon/actions/compose.js +++ b/app/javascript/mastodon/actions/compose.js @@ -1,18 +1,20 @@ -import api from '../api'; -import { CancelToken, isCancel } from 'axios'; +import axios from 'axios'; import { throttle } from 'lodash'; -import { search as emojiSearch } from '../features/emoji/emoji_mart_search_light'; -import { tagHistory } from '../settings'; +import { defineMessages } from 'react-intl'; +import api from 'mastodon/api'; +import { search as emojiSearch } from 'mastodon/features/emoji/emoji_mart_search_light'; +import { tagHistory } from 'mastodon/settings'; +import resizeImage from 'mastodon/utils/resize_image'; +import { showAlert, showAlertForError } from './alerts'; import { useEmoji } from './emojis'; -import resizeImage from '../utils/resize_image'; import { importFetchedAccounts } from './importer'; -import { updateTimeline } from './timelines'; -import { showAlertForError } from './alerts'; -import { showAlert } from './alerts'; import { openModal } from './modal'; -import { defineMessages } from 'react-intl'; +import { updateTimeline } from './timelines'; -let cancelFetchComposeSuggestionsAccounts, cancelFetchComposeSuggestionsTags; +/** @type {AbortController | undefined} */ +let fetchComposeSuggestionsAccountsController; +/** @type {AbortController | undefined} */ +let fetchComposeSuggestionsTagsController; export const COMPOSE_CHANGE = 'COMPOSE_CHANGE'; export const COMPOSE_SUBMIT_REQUEST = 'COMPOSE_SUBMIT_REQUEST'; @@ -23,11 +25,13 @@ export const COMPOSE_REPLY_CANCEL = 'COMPOSE_REPLY_CANCEL'; export const COMPOSE_DIRECT = 'COMPOSE_DIRECT'; export const COMPOSE_MENTION = 'COMPOSE_MENTION'; export const COMPOSE_RESET = 'COMPOSE_RESET'; -export const COMPOSE_UPLOAD_REQUEST = 'COMPOSE_UPLOAD_REQUEST'; -export const COMPOSE_UPLOAD_SUCCESS = 'COMPOSE_UPLOAD_SUCCESS'; -export const COMPOSE_UPLOAD_FAIL = 'COMPOSE_UPLOAD_FAIL'; -export const COMPOSE_UPLOAD_PROGRESS = 'COMPOSE_UPLOAD_PROGRESS'; -export const COMPOSE_UPLOAD_UNDO = 'COMPOSE_UPLOAD_UNDO'; + +export const COMPOSE_UPLOAD_REQUEST = 'COMPOSE_UPLOAD_REQUEST'; +export const COMPOSE_UPLOAD_SUCCESS = 'COMPOSE_UPLOAD_SUCCESS'; +export const COMPOSE_UPLOAD_FAIL = 'COMPOSE_UPLOAD_FAIL'; +export const COMPOSE_UPLOAD_PROGRESS = 'COMPOSE_UPLOAD_PROGRESS'; +export const COMPOSE_UPLOAD_PROCESSING = 'COMPOSE_UPLOAD_PROCESSING'; +export const COMPOSE_UPLOAD_UNDO = 'COMPOSE_UPLOAD_UNDO'; export const THUMBNAIL_UPLOAD_REQUEST = 'THUMBNAIL_UPLOAD_REQUEST'; export const THUMBNAIL_UPLOAD_SUCCESS = 'THUMBNAIL_UPLOAD_SUCCESS'; @@ -77,10 +81,8 @@ const messages = defineMessages({ uploadErrorPoll: { id: 'upload_error.poll', defaultMessage: 'File upload not allowed with polls.' }, }); -const COMPOSE_PANEL_BREAKPOINT = 600 + (285 * 1) + (10 * 1); - export const ensureComposeIsVisible = (getState, routerHistory) => { - if (!getState().getIn(['compose', 'mounted']) && window.innerWidth < COMPOSE_PANEL_BREAKPOINT) { + if (!getState().getIn(['compose', 'mounted'])) { routerHistory.push('/publish'); } }; @@ -270,13 +272,16 @@ export function uploadCompose(files) { if (status === 200) { dispatch(uploadComposeSuccess(data, f)); } else if (status === 202) { + dispatch(uploadComposeProcessing()); + let tryCount = 1; + const poll = () => { api(getState).get(`/api/v1/media/${data.id}`).then(response => { if (response.status === 200) { dispatch(uploadComposeSuccess(response.data, f)); } else if (response.status === 206) { - let retryAfter = (Math.log2(tryCount) || 1) * 1000; + const retryAfter = (Math.log2(tryCount) || 1) * 1000; tryCount += 1; setTimeout(() => poll(), retryAfter); } @@ -291,6 +296,10 @@ export function uploadCompose(files) { }; }; +export const uploadComposeProcessing = () => ({ + type: COMPOSE_UPLOAD_PROCESSING, +}); + export const uploadThumbnail = (id, file) => (dispatch, getState) => { dispatch(uploadThumbnailRequest()); @@ -435,8 +444,8 @@ export function undoUploadCompose(media_id) { }; export function clearComposeSuggestions() { - if (cancelFetchComposeSuggestionsAccounts) { - cancelFetchComposeSuggestionsAccounts(); + if (fetchComposeSuggestionsAccountsController) { + fetchComposeSuggestionsAccountsController.abort(); } return { type: COMPOSE_SUGGESTIONS_CLEAR, @@ -444,14 +453,14 @@ export function clearComposeSuggestions() { }; const fetchComposeSuggestionsAccounts = throttle((dispatch, getState, token) => { - if (cancelFetchComposeSuggestionsAccounts) { - cancelFetchComposeSuggestionsAccounts(); + if (fetchComposeSuggestionsAccountsController) { + fetchComposeSuggestionsAccountsController.abort(); } + fetchComposeSuggestionsAccountsController = new AbortController(); + api(getState).get('/api/v1/accounts/search', { - cancelToken: new CancelToken(cancel => { - cancelFetchComposeSuggestionsAccounts = cancel; - }), + signal: fetchComposeSuggestionsAccountsController.signal, params: { q: token.slice(1), @@ -462,9 +471,11 @@ const fetchComposeSuggestionsAccounts = throttle((dispatch, getState, token) => dispatch(importFetchedAccounts(response.data)); dispatch(readyComposeSuggestionsAccounts(token, response.data)); }).catch(error => { - if (!isCancel(error)) { + if (!axios.isCancel(error)) { dispatch(showAlertForError(error)); } + }).finally(() => { + fetchComposeSuggestionsAccountsController = undefined; }); }, 200, { leading: true, trailing: true }); @@ -474,16 +485,16 @@ const fetchComposeSuggestionsEmojis = (dispatch, getState, token) => { }; const fetchComposeSuggestionsTags = throttle((dispatch, getState, token) => { - if (cancelFetchComposeSuggestionsTags) { - cancelFetchComposeSuggestionsTags(); + if (fetchComposeSuggestionsTagsController) { + fetchComposeSuggestionsTagsController.abort(); } dispatch(updateSuggestionTags(token)); + fetchComposeSuggestionsTagsController = new AbortController(); + api(getState).get('/api/v2/search', { - cancelToken: new CancelToken(cancel => { - cancelFetchComposeSuggestionsTags = cancel; - }), + signal: fetchComposeSuggestionsTagsController.signal, params: { type: 'hashtags', @@ -495,9 +506,11 @@ const fetchComposeSuggestionsTags = throttle((dispatch, getState, token) => { }).then(({ data }) => { dispatch(readyComposeSuggestionsTags(token, data.hashtags)); }).catch(error => { - if (!isCancel(error)) { + if (!axios.isCancel(error)) { dispatch(showAlertForError(error)); } + }).finally(() => { + fetchComposeSuggestionsTagsController = undefined; }); }, 200, { leading: true, trailing: true }); diff --git a/app/javascript/mastodon/actions/featured_tags.js b/app/javascript/mastodon/actions/featured_tags.js new file mode 100644 index 000000000..18bb61539 --- /dev/null +++ b/app/javascript/mastodon/actions/featured_tags.js @@ -0,0 +1,34 @@ +import api from '../api'; + +export const FEATURED_TAGS_FETCH_REQUEST = 'FEATURED_TAGS_FETCH_REQUEST'; +export const FEATURED_TAGS_FETCH_SUCCESS = 'FEATURED_TAGS_FETCH_SUCCESS'; +export const FEATURED_TAGS_FETCH_FAIL = 'FEATURED_TAGS_FETCH_FAIL'; + +export const fetchFeaturedTags = (id) => (dispatch, getState) => { + if (getState().getIn(['user_lists', 'featured_tags', id, 'items'])) { + return; + } + + dispatch(fetchFeaturedTagsRequest(id)); + + api(getState).get(`/api/v1/accounts/${id}/featured_tags`) + .then(({ data }) => dispatch(fetchFeaturedTagsSuccess(id, data))) + .catch(err => dispatch(fetchFeaturedTagsFail(id, err))); +}; + +export const fetchFeaturedTagsRequest = (id) => ({ + type: FEATURED_TAGS_FETCH_REQUEST, + id, +}); + +export const fetchFeaturedTagsSuccess = (id, tags) => ({ + type: FEATURED_TAGS_FETCH_SUCCESS, + id, + tags, +}); + +export const fetchFeaturedTagsFail = (id, error) => ({ + type: FEATURED_TAGS_FETCH_FAIL, + id, + error, +}); diff --git a/app/javascript/mastodon/actions/search.js b/app/javascript/mastodon/actions/search.js index 37560a74c..e333c0ea7 100644 --- a/app/javascript/mastodon/actions/search.js +++ b/app/javascript/mastodon/actions/search.js @@ -29,7 +29,8 @@ export function clearSearch() { export function submitSearch() { return (dispatch, getState) => { - const value = getState().getIn(['search', 'value']); + const value = getState().getIn(['search', 'value']); + const signedIn = !!getState().getIn(['meta', 'me']); if (value.length === 0) { dispatch(fetchSearchSuccess({ accounts: [], statuses: [], hashtags: [] }, '')); @@ -41,7 +42,7 @@ export function submitSearch() { api(getState).get('/api/v2/search', { params: { q: value, - resolve: true, + resolve: signedIn, limit: 5, }, }).then(response => { diff --git a/app/javascript/mastodon/actions/server.js b/app/javascript/mastodon/actions/server.js index af8fef780..31d4aea10 100644 --- a/app/javascript/mastodon/actions/server.js +++ b/app/javascript/mastodon/actions/server.js @@ -5,6 +5,14 @@ export const SERVER_FETCH_REQUEST = 'Server_FETCH_REQUEST'; export const SERVER_FETCH_SUCCESS = 'Server_FETCH_SUCCESS'; export const SERVER_FETCH_FAIL = 'Server_FETCH_FAIL'; +export const EXTENDED_DESCRIPTION_REQUEST = 'EXTENDED_DESCRIPTION_REQUEST'; +export const EXTENDED_DESCRIPTION_SUCCESS = 'EXTENDED_DESCRIPTION_SUCCESS'; +export const EXTENDED_DESCRIPTION_FAIL = 'EXTENDED_DESCRIPTION_FAIL'; + +export const SERVER_DOMAIN_BLOCKS_FETCH_REQUEST = 'SERVER_DOMAIN_BLOCKS_FETCH_REQUEST'; +export const SERVER_DOMAIN_BLOCKS_FETCH_SUCCESS = 'SERVER_DOMAIN_BLOCKS_FETCH_SUCCESS'; +export const SERVER_DOMAIN_BLOCKS_FETCH_FAIL = 'SERVER_DOMAIN_BLOCKS_FETCH_FAIL'; + export const fetchServer = () => (dispatch, getState) => { dispatch(fetchServerRequest()); @@ -28,3 +36,56 @@ const fetchServerFail = error => ({ type: SERVER_FETCH_FAIL, error, }); + +export const fetchExtendedDescription = () => (dispatch, getState) => { + dispatch(fetchExtendedDescriptionRequest()); + + api(getState) + .get('/api/v1/instance/extended_description') + .then(({ data }) => dispatch(fetchExtendedDescriptionSuccess(data))) + .catch(err => dispatch(fetchExtendedDescriptionFail(err))); +}; + +const fetchExtendedDescriptionRequest = () => ({ + type: EXTENDED_DESCRIPTION_REQUEST, +}); + +const fetchExtendedDescriptionSuccess = description => ({ + type: EXTENDED_DESCRIPTION_SUCCESS, + description, +}); + +const fetchExtendedDescriptionFail = error => ({ + type: EXTENDED_DESCRIPTION_FAIL, + error, +}); + +export const fetchDomainBlocks = () => (dispatch, getState) => { + dispatch(fetchDomainBlocksRequest()); + + api(getState) + .get('/api/v1/instance/domain_blocks') + .then(({ data }) => dispatch(fetchDomainBlocksSuccess(true, data))) + .catch(err => { + if (err.response.status === 404) { + dispatch(fetchDomainBlocksSuccess(false, [])); + } else { + dispatch(fetchDomainBlocksFail(err)); + } + }); +}; + +const fetchDomainBlocksRequest = () => ({ + type: SERVER_DOMAIN_BLOCKS_FETCH_REQUEST, +}); + +const fetchDomainBlocksSuccess = (isAvailable, blocks) => ({ + type: SERVER_DOMAIN_BLOCKS_FETCH_SUCCESS, + isAvailable, + blocks, +}); + +const fetchDomainBlocksFail = error => ({ + type: SERVER_DOMAIN_BLOCKS_FETCH_FAIL, + error, +}); diff --git a/app/javascript/mastodon/actions/timelines.js b/app/javascript/mastodon/actions/timelines.js index 44fedd5c2..a3434908f 100644 --- a/app/javascript/mastodon/actions/timelines.js +++ b/app/javascript/mastodon/actions/timelines.js @@ -143,8 +143,8 @@ export function fillTimelineGaps(timelineId, path, params = {}, done = noOp) { export const expandHomeTimeline = ({ maxId } = {}, done = noOp) => expandTimeline('home', '/api/v1/timelines/home', { max_id: maxId }, done); export const expandPublicTimeline = ({ maxId, onlyMedia, onlyRemote } = {}, done = noOp) => expandTimeline(`public${onlyRemote ? ':remote' : ''}${onlyMedia ? ':media' : ''}`, '/api/v1/timelines/public', { remote: !!onlyRemote, max_id: maxId, only_media: !!onlyMedia }, done); export const expandCommunityTimeline = ({ maxId, onlyMedia } = {}, done = noOp) => expandTimeline(`community${onlyMedia ? ':media' : ''}`, '/api/v1/timelines/public', { local: true, max_id: maxId, only_media: !!onlyMedia }, done); -export const expandAccountTimeline = (accountId, { maxId, withReplies } = {}) => expandTimeline(`account:${accountId}${withReplies ? ':with_replies' : ''}`, `/api/v1/accounts/${accountId}/statuses`, { exclude_replies: !withReplies, max_id: maxId }); -export const expandAccountFeaturedTimeline = accountId => expandTimeline(`account:${accountId}:pinned`, `/api/v1/accounts/${accountId}/statuses`, { pinned: true }); +export const expandAccountTimeline = (accountId, { maxId, withReplies, tagged } = {}) => expandTimeline(`account:${accountId}${withReplies ? ':with_replies' : ''}${tagged ? `:${tagged}` : ''}`, `/api/v1/accounts/${accountId}/statuses`, { exclude_replies: !withReplies, tagged, max_id: maxId }); +export const expandAccountFeaturedTimeline = (accountId, { tagged } = {}) => expandTimeline(`account:${accountId}:pinned${tagged ? `:${tagged}` : ''}`, `/api/v1/accounts/${accountId}/statuses`, { pinned: true, tagged }); export const expandAccountMediaTimeline = (accountId, { maxId } = {}) => expandTimeline(`account:${accountId}:media`, `/api/v1/accounts/${accountId}/statuses`, { max_id: maxId, only_media: true, limit: 40 }); export const expandListTimeline = (id, { maxId } = {}, done = noOp) => expandTimeline(`list:${id}`, `/api/v1/timelines/list/${id}`, { max_id: maxId }, done); export const expandHashtagTimeline = (hashtag, { maxId, tags, local } = {}, done = noOp) => { diff --git a/app/javascript/mastodon/api.js b/app/javascript/mastodon/api.js index 645ef6500..6bbddbef6 100644 --- a/app/javascript/mastodon/api.js +++ b/app/javascript/mastodon/api.js @@ -1,20 +1,31 @@ +// @ts-check + import axios from 'axios'; import LinkHeader from 'http-link-header'; import ready from './ready'; +/** + * @param {import('axios').AxiosResponse} response + * @returns {LinkHeader} + */ export const getLinks = response => { const value = response.headers.link; if (!value) { - return { refs: [] }; + return new LinkHeader(); } return LinkHeader.parse(value); }; +/** @type {import('axios').RawAxiosRequestHeaders} */ const csrfHeader = {}; +/** + * @returns {void} + */ const setCSRFHeader = () => { + /** @type {HTMLMetaElement | null} */ const csrfToken = document.querySelector('meta[name=csrf-token]'); if (csrfToken) { @@ -24,6 +35,10 @@ const setCSRFHeader = () => { ready(setCSRFHeader); +/** + * @param {() => import('immutable').Map} getState + * @returns {import('axios').RawAxiosRequestHeaders} + */ const authorizationHeaderFromState = getState => { const accessToken = getState && getState().getIn(['meta', 'access_token'], ''); @@ -36,17 +51,25 @@ const authorizationHeaderFromState = getState => { }; }; -export default getState => axios.create({ - headers: { - ...csrfHeader, - ...authorizationHeaderFromState(getState), - }, - - transformResponse: [function (data) { - try { - return JSON.parse(data); - } catch(Exception) { - return data; - } - }], -}); +/** + * @param {() => import('immutable').Map} getState + * @returns {import('axios').AxiosInstance} + */ +export default function api(getState) { + return axios.create({ + headers: { + ...csrfHeader, + ...authorizationHeaderFromState(getState), + }, + + transformResponse: [ + function (data) { + try { + return JSON.parse(data); + } catch { + return data; + } + }, + ], + }); +} diff --git a/app/javascript/mastodon/components/__tests__/__snapshots__/avatar-test.js.snap b/app/javascript/mastodon/components/__tests__/__snapshots__/avatar-test.js.snap index 1c200b184..7fbdedeb2 100644 --- a/app/javascript/mastodon/components/__tests__/__snapshots__/avatar-test.js.snap +++ b/app/javascript/mastodon/components/__tests__/__snapshots__/avatar-test.js.snap @@ -7,13 +7,16 @@ exports[`<Avatar /> Autoplay renders a animated avatar 1`] = ` onMouseLeave={[Function]} style={ { - "backgroundImage": "url(/animated/alice.gif)", - "backgroundSize": "100px 100px", "height": "100px", "width": "100px", } } -/> +> + <img + alt="alice" + src="/animated/alice.gif" + /> +</div> `; exports[`<Avatar /> Still renders a still avatar 1`] = ` @@ -23,11 +26,14 @@ exports[`<Avatar /> Still renders a still avatar 1`] = ` onMouseLeave={[Function]} style={ { - "backgroundImage": "url(/static/alice.jpg)", - "backgroundSize": "100px 100px", "height": "100px", "width": "100px", } } -/> +> + <img + alt="alice" + src="/static/alice.jpg" + /> +</div> `; diff --git a/app/javascript/mastodon/components/__tests__/__snapshots__/avatar_overlay-test.js.snap b/app/javascript/mastodon/components/__tests__/__snapshots__/avatar_overlay-test.js.snap index 58f27a321..f8385357a 100644 --- a/app/javascript/mastodon/components/__tests__/__snapshots__/avatar_overlay-test.js.snap +++ b/app/javascript/mastodon/components/__tests__/__snapshots__/avatar_overlay-test.js.snap @@ -3,22 +3,52 @@ exports[`<AvatarOverlay renders a overlay avatar 1`] = ` <div className="account__avatar-overlay" + style={ + { + "height": 46, + "width": 46, + } + } > <div className="account__avatar-overlay-base" - style={ - { - "backgroundImage": "url(/static/alice.jpg)", + > + <div + className="account__avatar" + onMouseEnter={[Function]} + onMouseLeave={[Function]} + style={ + { + "height": "36px", + "width": "36px", + } } - } - /> + > + <img + alt="alice" + src="/static/alice.jpg" + /> + </div> + </div> <div className="account__avatar-overlay-overlay" - style={ - { - "backgroundImage": "url(/static/eve.jpg)", + > + <div + className="account__avatar" + onMouseEnter={[Function]} + onMouseLeave={[Function]} + style={ + { + "height": "24px", + "width": "24px", + } } - } - /> + > + <img + alt="eve@blackhat.lair" + src="/static/eve.jpg" + /> + </div> + </div> </div> `; diff --git a/app/javascript/mastodon/components/account.js b/app/javascript/mastodon/components/account.js index 36429e647..92d14da8b 100644 --- a/app/javascript/mastodon/components/account.js +++ b/app/javascript/mastodon/components/account.js @@ -136,7 +136,7 @@ class Account extends ImmutablePureComponent { <div className='account'> <div className='account__wrapper'> <Permalink key={account.get('id')} className='account__display-name' title={account.get('acct')} href={account.get('url')} to={`/@${account.get('acct')}`}> - <div className='account__avatar-wrapper'><Avatar account={account} size={36} /></div> + <div className='account__avatar-wrapper'><Avatar account={account} size={46} /></div> {mute_expires_at} <DisplayName account={account} /> </Permalink> diff --git a/app/javascript/mastodon/components/avatar.js b/app/javascript/mastodon/components/avatar.js index 12ab7d2df..207b26691 100644 --- a/app/javascript/mastodon/components/avatar.js +++ b/app/javascript/mastodon/components/avatar.js @@ -42,28 +42,20 @@ export default class Avatar extends React.PureComponent { ...this.props.style, width: `${size}px`, height: `${size}px`, - backgroundSize: `${size}px ${size}px`, }; - if (account) { - const src = account.get('avatar'); - const staticSrc = account.get('avatar_static'); + let src; - if (hovering || animate) { - style.backgroundImage = `url(${src})`; - } else { - style.backgroundImage = `url(${staticSrc})`; - } + if (hovering || animate) { + src = account?.get('avatar'); + } else { + src = account?.get('avatar_static'); } - return ( - <div - className={classNames('account__avatar', { 'account__avatar-inline': inline })} - onMouseEnter={this.handleMouseEnter} - onMouseLeave={this.handleMouseLeave} - style={style} - /> + <div className={classNames('account__avatar', { 'account__avatar-inline': inline })} onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave} style={style}> + <img src={src} alt={account?.get('acct')} /> + </div> ); } diff --git a/app/javascript/mastodon/components/avatar_composite.js b/app/javascript/mastodon/components/avatar_composite.js index 5d5b89749..220bf5b4f 100644 --- a/app/javascript/mastodon/components/avatar_composite.js +++ b/app/javascript/mastodon/components/avatar_composite.js @@ -2,6 +2,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import ImmutablePropTypes from 'react-immutable-proptypes'; import { autoPlayGif } from '../initial_state'; +import Avatar from './avatar'; export default class AvatarComposite extends React.PureComponent { @@ -74,12 +75,12 @@ export default class AvatarComposite extends React.PureComponent { bottom: bottom, width: `${width}%`, height: `${height}%`, - backgroundSize: 'cover', - backgroundImage: `url(${account.get(animate ? 'avatar' : 'avatar_static')})`, }; return ( - <div key={account.get('id')} style={style} /> + <div key={account.get('id')} style={style}> + <Avatar account={account} animate={animate} /> + </div> ); } diff --git a/app/javascript/mastodon/components/avatar_overlay.js b/app/javascript/mastodon/components/avatar_overlay.js index 3ec1d7730..8d5d44ea5 100644 --- a/app/javascript/mastodon/components/avatar_overlay.js +++ b/app/javascript/mastodon/components/avatar_overlay.js @@ -2,6 +2,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import ImmutablePropTypes from 'react-immutable-proptypes'; import { autoPlayGif } from '../initial_state'; +import Avatar from './avatar'; export default class AvatarOverlay extends React.PureComponent { @@ -9,27 +10,40 @@ export default class AvatarOverlay extends React.PureComponent { account: ImmutablePropTypes.map.isRequired, friend: ImmutablePropTypes.map.isRequired, animate: PropTypes.bool, + size: PropTypes.number, + baseSize: PropTypes.number, + overlaySize: PropTypes.number, }; static defaultProps = { animate: autoPlayGif, + size: 46, + baseSize: 36, + overlaySize: 24, }; - render() { - const { account, friend, animate } = this.props; + state = { + hovering: false, + }; + + handleMouseEnter = () => { + if (this.props.animate) return; + this.setState({ hovering: true }); + } - const baseStyle = { - backgroundImage: `url(${account.get(animate ? 'avatar' : 'avatar_static')})`, - }; + handleMouseLeave = () => { + if (this.props.animate) return; + this.setState({ hovering: false }); + } - const overlayStyle = { - backgroundImage: `url(${friend.get(animate ? 'avatar' : 'avatar_static')})`, - }; + render() { + const { account, friend, animate, size, baseSize, overlaySize } = this.props; + const { hovering } = this.state; return ( - <div className='account__avatar-overlay'> - <div className='account__avatar-overlay-base' style={baseStyle} /> - <div className='account__avatar-overlay-overlay' style={overlayStyle} /> + <div className='account__avatar-overlay' style={{ width: size, height: size }}> + <div className='account__avatar-overlay-base'><Avatar animate={hovering || animate} account={account} size={baseSize} /></div> + <div className='account__avatar-overlay-overlay'><Avatar animate={hovering || animate} account={friend} size={overlaySize} /></div> </div> ); } diff --git a/app/javascript/mastodon/components/dismissable_banner.js b/app/javascript/mastodon/components/dismissable_banner.js new file mode 100644 index 000000000..1ee032056 --- /dev/null +++ b/app/javascript/mastodon/components/dismissable_banner.js @@ -0,0 +1,51 @@ +import React from 'react'; +import IconButton from './icon_button'; +import PropTypes from 'prop-types'; +import { injectIntl, defineMessages } from 'react-intl'; +import { bannerSettings } from 'mastodon/settings'; + +const messages = defineMessages({ + dismiss: { id: 'dismissable_banner.dismiss', defaultMessage: 'Dismiss' }, +}); + +export default @injectIntl +class DismissableBanner extends React.PureComponent { + + static propTypes = { + id: PropTypes.string.isRequired, + children: PropTypes.node, + intl: PropTypes.object.isRequired, + }; + + state = { + visible: !bannerSettings.get(this.props.id), + }; + + handleDismiss = () => { + const { id } = this.props; + this.setState({ visible: false }, () => bannerSettings.set(id, true)); + } + + render () { + const { visible } = this.state; + + if (!visible) { + return null; + } + + const { children, intl } = this.props; + + return ( + <div className='dismissable-banner'> + <div className='dismissable-banner__message'> + {children} + </div> + + <div className='dismissable-banner__action'> + <IconButton icon='times' title={intl.formatMessage(messages.dismiss)} onClick={this.handleDismiss} /> + </div> + </div> + ); + } + +} diff --git a/app/javascript/mastodon/components/error_boundary.js b/app/javascript/mastodon/components/error_boundary.js index ca4a2cfe1..02d5616d6 100644 --- a/app/javascript/mastodon/components/error_boundary.js +++ b/app/javascript/mastodon/components/error_boundary.js @@ -3,6 +3,7 @@ import PropTypes from 'prop-types'; import { FormattedMessage } from 'react-intl'; import { version, source_url } from 'mastodon/initial_state'; import StackTrace from 'stacktrace-js'; +import { Helmet } from 'react-helmet'; export default class ErrorBoundary extends React.PureComponent { @@ -84,6 +85,7 @@ export default class ErrorBoundary extends React.PureComponent { <FormattedMessage id='error.unexpected_crash.explanation' defaultMessage='Due to a bug in our code or a browser compatibility issue, this page could not be displayed correctly.' /> )} </p> + <p> { likelyBrowserAddonIssue ? ( <FormattedMessage id='error.unexpected_crash.next_steps_addons' defaultMessage='Try disabling them and refreshing the page. If that does not help, you may still be able to use Mastodon through a different browser or native app.' /> @@ -91,8 +93,13 @@ export default class ErrorBoundary extends React.PureComponent { <FormattedMessage id='error.unexpected_crash.next_steps' defaultMessage='Try refreshing the page. If that does not help, you may still be able to use Mastodon through a different browser or native app.' /> )} </p> + <p className='error-boundary__footer'>Mastodon v{version} · <a href={source_url} rel='noopener noreferrer' target='_blank'><FormattedMessage id='errors.unexpected_crash.report_issue' defaultMessage='Report issue' /></a> · <button onClick={this.handleCopyStackTrace} className={copied ? 'copied' : ''}><FormattedMessage id='errors.unexpected_crash.copy_stacktrace' defaultMessage='Copy stacktrace to clipboard' /></button></p> </div> + + <Helmet> + <meta name='robots' content='noindex' /> + </Helmet> </div> ); } diff --git a/app/javascript/mastodon/components/hashtag.js b/app/javascript/mastodon/components/hashtag.js index 4a5a4bb57..75220211e 100644 --- a/app/javascript/mastodon/components/hashtag.js +++ b/app/javascript/mastodon/components/hashtag.js @@ -56,7 +56,6 @@ export const ImmutableHashtag = ({ hashtag }) => ( href={hashtag.get('url')} to={`/tags/${hashtag.get('name')}`} people={hashtag.getIn(['history', 0, 'accounts']) * 1 + hashtag.getIn(['history', 1, 'accounts']) * 1} - uses={hashtag.getIn(['history', 0, 'uses']) * 1 + hashtag.getIn(['history', 1, 'uses']) * 1} history={hashtag.get('history').reverse().map((day) => day.get('uses')).toArray()} /> ); @@ -65,23 +64,35 @@ ImmutableHashtag.propTypes = { hashtag: ImmutablePropTypes.map.isRequired, }; -const Hashtag = ({ name, href, to, people, history, className }) => ( +const Hashtag = ({ name, href, to, people, uses, history, className, description, withGraph }) => ( <div className={classNames('trends__item', className)}> <div className='trends__item__name'> <Permalink href={href} to={to}> {name ? <React.Fragment>#<span>{name}</span></React.Fragment> : <Skeleton width={50} />} </Permalink> - {typeof people !== 'undefined' ? <ShortNumber value={people} renderer={accountsCountRenderer} /> : <Skeleton width={100} />} + {description ? ( + <span>{description}</span> + ) : ( + typeof people !== 'undefined' ? <ShortNumber value={people} renderer={accountsCountRenderer} /> : <Skeleton width={100} /> + )} </div> - <div className='trends__item__sparkline'> - <SilentErrorBoundary> - <Sparklines width={50} height={28} data={history ? history : Array.from(Array(7)).map(() => 0)}> - <SparklinesCurve style={{ fill: 'none' }} /> - </Sparklines> - </SilentErrorBoundary> - </div> + {typeof uses !== 'undefined' && ( + <div className='trends__item__current'> + <ShortNumber value={uses} /> + </div> + )} + + {withGraph && ( + <div className='trends__item__sparkline'> + <SilentErrorBoundary> + <Sparklines width={50} height={28} data={history ? history : Array.from(Array(7)).map(() => 0)}> + <SparklinesCurve style={{ fill: 'none' }} /> + </Sparklines> + </SilentErrorBoundary> + </div> + )} </div> ); @@ -90,9 +101,15 @@ Hashtag.propTypes = { href: PropTypes.string, to: PropTypes.string, people: PropTypes.number, + description: PropTypes.node, uses: PropTypes.number, history: PropTypes.arrayOf(PropTypes.number), className: PropTypes.string, + withGraph: PropTypes.bool, +}; + +Hashtag.defaultProps = { + withGraph: true, }; export default Hashtag; diff --git a/app/javascript/mastodon/components/image.js b/app/javascript/mastodon/components/image.js new file mode 100644 index 000000000..6e81ddf08 --- /dev/null +++ b/app/javascript/mastodon/components/image.js @@ -0,0 +1,33 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import Blurhash from './blurhash'; +import classNames from 'classnames'; + +export default class Image extends React.PureComponent { + + static propTypes = { + src: PropTypes.string, + srcSet: PropTypes.string, + blurhash: PropTypes.string, + className: PropTypes.string, + }; + + state = { + loaded: false, + }; + + handleLoad = () => this.setState({ loaded: true }); + + render () { + const { src, srcSet, blurhash, className } = this.props; + const { loaded } = this.state; + + return ( + <div className={classNames('image', { loaded }, className)} role='presentation'> + {blurhash && <Blurhash hash={blurhash} className='image__preview' />} + <img src={src} srcSet={srcSet} alt='' onLoad={this.handleLoad} /> + </div> + ); + } + +} diff --git a/app/javascript/mastodon/components/logo.js b/app/javascript/mastodon/components/logo.js index 3570b3644..ee5c22496 100644 --- a/app/javascript/mastodon/components/logo.js +++ b/app/javascript/mastodon/components/logo.js @@ -1,7 +1,8 @@ import React from 'react'; const Logo = () => ( - <svg viewBox='0 0 261 66' className='logo'> + <svg viewBox='0 0 261 66' className='logo' role='img'> + <title>Mastodon</title> <use xlinkHref='#logo-symbol-wordmark' /> </svg> ); diff --git a/app/javascript/mastodon/components/missing_indicator.js b/app/javascript/mastodon/components/missing_indicator.js index 7b0101bab..05e0d653d 100644 --- a/app/javascript/mastodon/components/missing_indicator.js +++ b/app/javascript/mastodon/components/missing_indicator.js @@ -3,6 +3,7 @@ import PropTypes from 'prop-types'; import { FormattedMessage } from 'react-intl'; import illustration from 'mastodon/../images/elephant_ui_disappointed.svg'; import classNames from 'classnames'; +import { Helmet } from 'react-helmet'; const MissingIndicator = ({ fullPage }) => ( <div className={classNames('regeneration-indicator', { 'regeneration-indicator--without-header': fullPage })}> @@ -14,6 +15,10 @@ const MissingIndicator = ({ fullPage }) => ( <FormattedMessage id='missing_indicator.label' tagName='strong' defaultMessage='Not found' /> <FormattedMessage id='missing_indicator.sublabel' defaultMessage='This resource could not be found' /> </div> + + <Helmet> + <meta name='robots' content='noindex' /> + </Helmet> </div> ); diff --git a/app/javascript/mastodon/components/navigation_portal.js b/app/javascript/mastodon/components/navigation_portal.js new file mode 100644 index 000000000..b2d054a3b --- /dev/null +++ b/app/javascript/mastodon/components/navigation_portal.js @@ -0,0 +1,30 @@ +import React from 'react'; +import { Switch, Route, withRouter } from 'react-router-dom'; +import { showTrends } from 'mastodon/initial_state'; +import Trends from 'mastodon/features/getting_started/containers/trends_container'; +import AccountNavigation from 'mastodon/features/account/navigation'; + +const DefaultNavigation = () => ( + <> + {showTrends && ( + <> + <div className='flex-spacer' /> + <Trends /> + </> + )} + </> +); + +export default @withRouter +class NavigationPortal extends React.PureComponent { + + render () { + return ( + <Switch> + <Route path='/@:acct/(tagged/:tagged?)?' component={AccountNavigation} /> + <Route component={DefaultNavigation} /> + </Switch> + ); + } + +} diff --git a/app/javascript/mastodon/components/not_signed_in_indicator.js b/app/javascript/mastodon/components/not_signed_in_indicator.js new file mode 100644 index 000000000..b440c6be2 --- /dev/null +++ b/app/javascript/mastodon/components/not_signed_in_indicator.js @@ -0,0 +1,12 @@ +import React from 'react'; +import { FormattedMessage } from 'react-intl'; + +const NotSignedInIndicator = () => ( + <div className='scrollable scrollable--flex'> + <div className='empty-column-indicator'> + <FormattedMessage id='not_signed_in_indicator.not_signed_in' defaultMessage='You need to sign in to access this resource.' /> + </div> + </div> +); + +export default NotSignedInIndicator; diff --git a/app/javascript/mastodon/components/server_banner.js b/app/javascript/mastodon/components/server_banner.js index bdd7f7380..c2336e43d 100644 --- a/app/javascript/mastodon/components/server_banner.js +++ b/app/javascript/mastodon/components/server_banner.js @@ -1,19 +1,21 @@ -import React from 'react'; import PropTypes from 'prop-types'; -import { domain } from 'mastodon/initial_state'; -import { fetchServer } from 'mastodon/actions/server'; +import React from 'react'; +import { FormattedMessage, defineMessages, injectIntl } from 'react-intl'; import { connect } from 'react-redux'; -import Account from 'mastodon/containers/account_container'; +import { fetchServer } from 'mastodon/actions/server'; import ShortNumber from 'mastodon/components/short_number'; import Skeleton from 'mastodon/components/skeleton'; -import { FormattedMessage, injectIntl, defineMessages } from 'react-intl'; +import Account from 'mastodon/containers/account_container'; +import { domain } from 'mastodon/initial_state'; +import Image from 'mastodon/components/image'; +import { Link } from 'react-router-dom'; const messages = defineMessages({ aboutActiveUsers: { id: 'server_banner.about_active_users', defaultMessage: 'People using this server during the last 30 days (Monthly Active Users)' }, }); const mapStateToProps = state => ({ - server: state.get('server'), + server: state.getIn(['server', 'server']), }); export default @connect(mapStateToProps) @@ -41,7 +43,7 @@ class ServerBanner extends React.PureComponent { <FormattedMessage id='server_banner.introduction' defaultMessage='{domain} is part of the decentralized social network powered by {mastodon}.' values={{ domain: <strong>{domain}</strong>, mastodon: <a href='https://joinmastodon.org' target='_blank'>Mastodon</a> }} /> </div> - <img src={server.get('thumbnail')} alt={server.get('title')} className='server-banner__hero' /> + <Image blurhash={server.getIn(['thumbnail', 'blurhash'])} src={server.getIn(['thumbnail', 'url'])} className='server-banner__hero' /> <div className='server-banner__description'> {isLoading ? ( @@ -83,7 +85,7 @@ class ServerBanner extends React.PureComponent { <hr className='spacer' /> - <a className='button button--block button-secondary' href='/about/more' target='_blank'><FormattedMessage id='server_banner.learn_more' defaultMessage='Learn more' /></a> + <Link className='button button--block button-secondary' to='/about'><FormattedMessage id='server_banner.learn_more' defaultMessage='Learn more' /></Link> </div> ); } diff --git a/app/javascript/mastodon/components/skeleton.js b/app/javascript/mastodon/components/skeleton.js index 09093e99c..6a17ffb26 100644 --- a/app/javascript/mastodon/components/skeleton.js +++ b/app/javascript/mastodon/components/skeleton.js @@ -4,8 +4,8 @@ import PropTypes from 'prop-types'; const Skeleton = ({ width, height }) => <span className='skeleton' style={{ width, height }}>‌</span>; Skeleton.propTypes = { - width: PropTypes.number, - height: PropTypes.number, + width: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), + height: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), }; export default Skeleton; diff --git a/app/javascript/mastodon/components/status.js b/app/javascript/mastodon/components/status.js index 0d3b51f07..3106a3ecd 100644 --- a/app/javascript/mastodon/components/status.js +++ b/app/javascript/mastodon/components/status.js @@ -86,6 +86,7 @@ class Status extends ImmutablePureComponent { onToggleHidden: PropTypes.func, onToggleCollapsed: PropTypes.func, onTranslate: PropTypes.func, + onInteractionModal: PropTypes.func, muted: PropTypes.bool, hidden: PropTypes.bool, unread: PropTypes.bool, @@ -385,6 +386,15 @@ class Status extends ImmutablePureComponent { account = status.get('account'); status = status.get('reblog'); + } else if (showThread && status.get('in_reply_to_id') && status.get('in_reply_to_account_id') === status.getIn(['account', 'id'])) { + const display_name_html = { __html: status.getIn(['account', 'display_name_html']) }; + + prepend = ( + <div className='status__prepend'> + <div className='status__prepend-icon-wrapper'><Icon id='reply' className='status__prepend-icon' fixedWidth /></div> + <FormattedMessage id='status.replied_to' defaultMessage='Replied to {name}' values={{ name: <a onClick={this.handlePrependAccountClick} data-id={status.getIn(['account', 'id'])} href={status.getIn(['account', 'url'])} className='status__display-name muted'><bdi><strong dangerouslySetInnerHTML={display_name_html} /></bdi></a> }} /> + </div> + ); } if (pictureInPicture.get('inUse')) { @@ -480,7 +490,7 @@ class Status extends ImmutablePureComponent { } if (account === undefined || account === null) { - statusAvatar = <Avatar account={status.get('account')} size={48} />; + statusAvatar = <Avatar account={status.get('account')} size={46} />; } else { statusAvatar = <AvatarOverlay account={status.get('account')} friend={account} />; } @@ -500,8 +510,6 @@ class Status extends ImmutablePureComponent { {prepend} <div className={classNames('status', `status-${status.get('visibility')}`, { 'status-reply': !!status.get('in_reply_to_id'), muted: this.props.muted })} data-id={status.get('id')}> - <div className='status__expand' onClick={this.handleClick} role='presentation' /> - <div className='status__info'> <a onClick={this.handleClick} href={status.get('url')} className='status__relative-time' target='_blank' rel='noopener noreferrer'> <span className='status__visibility-icon'><Icon id={visibilityIcon.icon} title={visibilityIcon.text} /></span> @@ -521,7 +529,6 @@ class Status extends ImmutablePureComponent { status={status} onClick={this.handleClick} expanded={!status.get('hidden')} - showThread={showThread} onExpandedToggle={this.handleExpandedToggle} onTranslate={this.handleTranslate} collapsable diff --git a/app/javascript/mastodon/components/status_action_bar.js b/app/javascript/mastodon/components/status_action_bar.js index 4b384e6e5..2e0c5e081 100644 --- a/app/javascript/mastodon/components/status_action_bar.js +++ b/app/javascript/mastodon/components/status_action_bar.js @@ -82,6 +82,7 @@ class StatusActionBar extends ImmutablePureComponent { onBookmark: PropTypes.func, onFilter: PropTypes.func, onAddFilter: PropTypes.func, + onInteractionModal: PropTypes.func, withDismiss: PropTypes.bool, withCounters: PropTypes.bool, scrollKey: PropTypes.string, @@ -97,10 +98,12 @@ class StatusActionBar extends ImmutablePureComponent { ] handleReplyClick = () => { - if (me) { + const { signedIn } = this.context.identity; + + if (signedIn) { this.props.onReply(this.props.status, this.context.router.history); } else { - this._openInteractionDialog('reply'); + this.props.onInteractionModal('reply', this.props.status); } } @@ -114,25 +117,25 @@ class StatusActionBar extends ImmutablePureComponent { } handleFavouriteClick = () => { - if (me) { + const { signedIn } = this.context.identity; + + if (signedIn) { this.props.onFavourite(this.props.status); } else { - this._openInteractionDialog('favourite'); + this.props.onInteractionModal('favourite', this.props.status); } } handleReblogClick = e => { - if (me) { + const { signedIn } = this.context.identity; + + if (signedIn) { this.props.onReblog(this.props.status, e); } else { - this._openInteractionDialog('reblog'); + this.props.onInteractionModal('reblog', this.props.status); } } - _openInteractionDialog = type => { - window.open(`/interact/${this.props.status.get('id')}?type=${type}`, 'mastodon-intent', 'width=445,height=600,resizable=no,menubar=no,status=no,scrollbars=yes'); - } - handleBookmarkClick = () => { this.props.onBookmark(this.props.status); } @@ -243,8 +246,9 @@ class StatusActionBar extends ImmutablePureComponent { render () { const { status, relationship, intl, withDismiss, withCounters, scrollKey } = this.props; + const { signedIn } = this.context.identity; - const anonymousAccess = !me; + const anonymousAccess = !signedIn; const publicStatus = ['public', 'unlisted'].includes(status.get('visibility')); const pinnableStatus = ['public', 'unlisted', 'private'].includes(status.get('visibility')); const mutingConversation = status.get('muted'); @@ -276,7 +280,7 @@ class StatusActionBar extends ImmutablePureComponent { } if (writtenByMe) { - // menu.push({ text: intl.formatMessage(messages.edit), action: this.handleEditClick }); + menu.push({ text: intl.formatMessage(messages.edit), action: this.handleEditClick }); menu.push({ text: intl.formatMessage(messages.delete), action: this.handleDeleteClick }); menu.push({ text: intl.formatMessage(messages.redraft), action: this.handleRedraftClick }); } else { @@ -319,7 +323,7 @@ class StatusActionBar extends ImmutablePureComponent { if ((this.context.identity.permissions & PERMISSION_MANAGE_USERS) === PERMISSION_MANAGE_USERS) { menu.push(null); menu.push({ text: intl.formatMessage(messages.admin_account, { name: account.get('username') }), href: `/admin/accounts/${status.getIn(['account', 'id'])}` }); - menu.push({ text: intl.formatMessage(messages.admin_status), href: `/admin/accounts/${status.getIn(['account', 'id'])}/statuses?id=${status.get('id')}` }); + menu.push({ text: intl.formatMessage(messages.admin_status), href: `/admin/accounts/${status.getIn(['account', 'id'])}/statuses/${status.get('id')}` }); } } @@ -347,24 +351,25 @@ class StatusActionBar extends ImmutablePureComponent { } const shareButton = ('share' in navigator) && publicStatus && ( - <IconButton className='status__action-bar-button' title={intl.formatMessage(messages.share)} icon='share-alt' onClick={this.handleShareClick} /> + <IconButton className='status__action-bar__button' title={intl.formatMessage(messages.share)} icon='share-alt' onClick={this.handleShareClick} /> ); const filterButton = this.props.onFilter && ( - <IconButton className='status__action-bar-button' title={intl.formatMessage(messages.hide)} icon='eye' onClick={this.handleHideClick} /> + <IconButton className='status__action-bar__button' title={intl.formatMessage(messages.hide)} icon='eye' onClick={this.handleHideClick} /> ); return ( <div className='status__action-bar'> - <IconButton className='status__action-bar-button' title={replyTitle} icon={status.get('in_reply_to_account_id') === status.getIn(['account', 'id']) ? 'reply' : replyIcon} onClick={this.handleReplyClick} counter={status.get('replies_count')} obfuscateCount /> - <IconButton className={classNames('status__action-bar-button', { reblogPrivate })} disabled={!publicStatus && !reblogPrivate} active={status.get('reblogged')} pressed={status.get('reblogged')} title={reblogTitle} icon='retweet' onClick={this.handleReblogClick} counter={withCounters ? status.get('reblogs_count') : undefined} /> - <IconButton className='status__action-bar-button star-icon' animate active={status.get('favourited')} pressed={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' onClick={this.handleFavouriteClick} counter={withCounters ? status.get('favourites_count') : undefined} /> + <IconButton className='status__action-bar__button' title={replyTitle} icon={status.get('in_reply_to_account_id') === status.getIn(['account', 'id']) ? 'reply' : replyIcon} onClick={this.handleReplyClick} counter={status.get('replies_count')} obfuscateCount /> + <IconButton className={classNames('status__action-bar__button', { reblogPrivate })} disabled={!publicStatus && !reblogPrivate} active={status.get('reblogged')} pressed={status.get('reblogged')} title={reblogTitle} icon='retweet' onClick={this.handleReblogClick} counter={withCounters ? status.get('reblogs_count') : undefined} /> + <IconButton className='status__action-bar__button star-icon' animate active={status.get('favourited')} pressed={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' onClick={this.handleFavouriteClick} counter={withCounters ? status.get('favourites_count') : undefined} /> + <IconButton className='status__action-bar__button bookmark-icon' disabled={!signedIn} active={status.get('bookmarked')} title={intl.formatMessage(messages.bookmark)} icon='bookmark' onClick={this.handleBookmarkClick} /> {shareButton} {filterButton} - <div className='status__action-bar-dropdown'> + <div className='status__action-bar__dropdown'> <DropdownMenuContainer scrollKey={scrollKey} disabled={anonymousAccess} diff --git a/app/javascript/mastodon/components/status_content.js b/app/javascript/mastodon/components/status_content.js index a88c5f084..3e3ba7d0f 100644 --- a/app/javascript/mastodon/components/status_content.js +++ b/app/javascript/mastodon/components/status_content.js @@ -6,10 +6,47 @@ import Permalink from './permalink'; import classnames from 'classnames'; import PollContainer from 'mastodon/containers/poll_container'; import Icon from 'mastodon/components/icon'; -import { autoPlayGif, languages as preloadedLanguages } from 'mastodon/initial_state'; +import { autoPlayGif, languages as preloadedLanguages, translationEnabled } from 'mastodon/initial_state'; const MAX_HEIGHT = 642; // 20px * 32 (+ 2px padding at the top) +class TranslateButton extends React.PureComponent { + + static propTypes = { + translation: ImmutablePropTypes.map, + onClick: PropTypes.func, + }; + + render () { + const { translation, onClick } = this.props; + + if (translation) { + const language = preloadedLanguages.find(lang => lang[0] === translation.get('detected_source_language')); + const languageName = language ? language[2] : translation.get('detected_source_language'); + const provider = translation.get('provider'); + + return ( + <div className='translate-button'> + <div className='translate-button__meta'> + <FormattedMessage id='status.translated_from_with' defaultMessage='Translated from {lang} using {provider}' values={{ lang: languageName, provider }} /> + </div> + + <button className='link-button' onClick={onClick}> + <FormattedMessage id='status.show_original' defaultMessage='Show original' /> + </button> + </div> + ); + } + + return ( + <button className='status__content__read-more-button' onClick={onClick}> + <FormattedMessage id='status.translate' defaultMessage='Translate' /> + </button> + ); + } + +} + export default @injectIntl class StatusContent extends React.PureComponent { @@ -21,7 +58,6 @@ class StatusContent extends React.PureComponent { static propTypes = { status: ImmutablePropTypes.map.isRequired, expanded: PropTypes.bool, - showThread: PropTypes.bool, onExpandedToggle: PropTypes.func, onTranslate: PropTypes.func, onClick: PropTypes.func, @@ -61,9 +97,6 @@ class StatusContent extends React.PureComponent { link.setAttribute('title', link.href); link.classList.add('unhandled-link'); } - - link.setAttribute('target', '_blank'); - link.setAttribute('rel', 'noopener noreferrer'); } if (this.props.status.get('collapsed', null) === null) { @@ -180,10 +213,7 @@ class StatusContent extends React.PureComponent { const hidden = this.props.onExpandedToggle ? !this.props.expanded : this.state.hidden; const renderReadMore = this.props.onClick && status.get('collapsed'); - const renderViewThread = this.props.showThread && status.get('in_reply_to_id') && status.get('in_reply_to_account_id') === status.getIn(['account', 'id']); - const renderTranslate = this.context.identity.signedIn && this.props.onTranslate && ['public', 'unlisted'].includes(status.get('visibility')) && status.get('contentHtml').length > 0 && intl.locale !== status.get('language'); - const language = preloadedLanguages.find(lang => lang[0] === status.get('language')); - const languageName = language ? language[2] : status.get('language'); + const renderTranslate = translationEnabled && this.context.identity.signedIn && this.props.onTranslate && ['public', 'unlisted'].includes(status.get('visibility')) && status.get('contentHtml').length > 0 && status.get('language') !== null && intl.locale !== status.get('language'); const content = { __html: status.get('translation') ? status.getIn(['translation', 'content']) : status.get('contentHtml') }; const spoilerContent = { __html: status.get('spoilerHtml') }; @@ -194,22 +224,18 @@ class StatusContent extends React.PureComponent { 'status__content--collapsed': renderReadMore, }); - const showThreadButton = ( - <button className='status__content__read-more-button' onClick={this.props.onClick}> - <FormattedMessage id='status.show_thread' defaultMessage='Show thread' /> - </button> - ); - - const readMoreButton = ( + const readMoreButton = renderReadMore && ( <button className='status__content__read-more-button' onClick={this.props.onClick} key='read-more'> <FormattedMessage id='status.read_more' defaultMessage='Read more' /><Icon id='angle-right' fixedWidth /> </button> ); - const translateButton = ( - <button className='status__content__read-more-button' onClick={this.handleTranslate}> - {status.get('translation') ? <span><FormattedMessage id='status.translated_from' defaultMessage='Translated from {lang}' values={{ lang: languageName }} /> · <FormattedMessage id='status.show_original' defaultMessage='Show original' /></span> : <FormattedMessage id='status.translate' defaultMessage='Translate' />} - </button> + const translateButton = renderTranslate && ( + <TranslateButton onClick={this.handleTranslate} translation={status.get('translation')} /> + ); + + const poll = !!status.get('poll') && ( + <PollContainer pollId={status.get('poll')} /> ); if (status.get('spoiler_text').length > 0) { @@ -239,35 +265,30 @@ class StatusContent extends React.PureComponent { <div tabIndex={!hidden ? 0 : null} className={`status__content__text ${!hidden ? 'status__content__text--visible' : ''} translate`} lang={lang} dangerouslySetInnerHTML={content} /> - {!hidden && !!status.get('poll') && <PollContainer pollId={status.get('poll')} />} - {!hidden && renderTranslate && translateButton} - {renderViewThread && showThreadButton} + {!hidden && poll} + {!hidden && translateButton} </div> ); } else if (this.props.onClick) { - const output = [ - <div className={classNames} ref={this.setRef} tabIndex='0' onMouseDown={this.handleMouseDown} onMouseUp={this.handleMouseUp} key='status-content' onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave}> - <div className='status__content__text status__content__text--visible translate' lang={lang} dangerouslySetInnerHTML={content} /> - - {!!status.get('poll') && <PollContainer pollId={status.get('poll')} />} - {renderTranslate && translateButton} - {renderViewThread && showThreadButton} - </div>, - ]; + return ( + <> + <div className={classNames} ref={this.setRef} tabIndex='0' onMouseDown={this.handleMouseDown} onMouseUp={this.handleMouseUp} key='status-content' onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave}> + <div className='status__content__text status__content__text--visible translate' lang={lang} dangerouslySetInnerHTML={content} /> - if (renderReadMore) { - output.push(readMoreButton); - } + {poll} + {translateButton} + </div> - return output; + {readMoreButton} + </> + ); } else { return ( <div className={classNames} ref={this.setRef} tabIndex='0' onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave}> <div className='status__content__text status__content__text--visible translate' lang={lang} dangerouslySetInnerHTML={content} /> - {!!status.get('poll') && <PollContainer pollId={status.get('poll')} />} - {renderTranslate && translateButton} - {renderViewThread && showThreadButton} + {poll} + {translateButton} </div> ); } diff --git a/app/javascript/mastodon/containers/mastodon.js b/app/javascript/mastodon/containers/mastodon.js index 08241522c..730695c49 100644 --- a/app/javascript/mastodon/containers/mastodon.js +++ b/app/javascript/mastodon/containers/mastodon.js @@ -1,21 +1,24 @@ -import React from 'react'; -import { Provider } from 'react-redux'; import PropTypes from 'prop-types'; -import configureStore from '../store/configureStore'; +import React from 'react'; +import { Helmet } from 'react-helmet'; +import { IntlProvider, addLocaleData } from 'react-intl'; +import { Provider as ReduxProvider } from 'react-redux'; import { BrowserRouter, Route } from 'react-router-dom'; import { ScrollContext } from 'react-router-scroll-4'; -import UI from '../features/ui'; -import { fetchCustomEmojis } from '../actions/custom_emojis'; -import { hydrateStore } from '../actions/store'; -import { connectUserStream } from '../actions/streaming'; -import { IntlProvider, addLocaleData } from 'react-intl'; -import { getLocale } from '../locales'; -import initialState from '../initial_state'; -import ErrorBoundary from '../components/error_boundary'; +import configureStore from 'mastodon/store/configureStore'; +import UI from 'mastodon/features/ui'; +import { fetchCustomEmojis } from 'mastodon/actions/custom_emojis'; +import { hydrateStore } from 'mastodon/actions/store'; +import { connectUserStream } from 'mastodon/actions/streaming'; +import ErrorBoundary from 'mastodon/components/error_boundary'; +import initialState, { title as siteTitle } from 'mastodon/initial_state'; +import { getLocale } from 'mastodon/locales'; const { localeData, messages } = getLocale(); addLocaleData(localeData); +const title = process.env.NODE_ENV === 'production' ? siteTitle : `${siteTitle} (Dev)`; + export const store = configureStore(); const hydrateAction = hydrateStore(initialState); @@ -73,15 +76,17 @@ export default class Mastodon extends React.PureComponent { return ( <IntlProvider locale={locale} messages={messages}> - <Provider store={store}> + <ReduxProvider store={store}> <ErrorBoundary> - <BrowserRouter basename='/web'> + <BrowserRouter> <ScrollContext shouldUpdateScroll={this.shouldUpdateScroll}> <Route path='/' component={UI} /> </ScrollContext> </BrowserRouter> + + <Helmet defaultTitle={title} titleTemplate={`%s - ${title}`} /> </ErrorBoundary> - </Provider> + </ReduxProvider> </IntlProvider> ); } diff --git a/app/javascript/mastodon/containers/status_container.js b/app/javascript/mastodon/containers/status_container.js index 9280a6ee3..294105f25 100644 --- a/app/javascript/mastodon/containers/status_container.js +++ b/app/javascript/mastodon/containers/status_container.js @@ -237,6 +237,14 @@ const mapDispatchToProps = (dispatch, { intl, contextType }) => ({ dispatch(deployPictureInPicture(status.get('id'), status.getIn(['account', 'id']), type, mediaProps)); }, + onInteractionModal (type, status) { + dispatch(openModal('INTERACTION', { + type, + accountId: status.getIn(['account', 'id']), + url: status.get('url'), + })); + }, + }); export default injectIntl(connect(makeMapStateToProps, mapDispatchToProps)(Status)); diff --git a/app/javascript/mastodon/extra_polyfills.js b/app/javascript/mastodon/extra_polyfills.js index 13c4f6da9..395f1ed05 100644 --- a/app/javascript/mastodon/extra_polyfills.js +++ b/app/javascript/mastodon/extra_polyfills.js @@ -1,3 +1,4 @@ +import 'abortcontroller-polyfill/dist/abortcontroller-polyfill-only'; import 'intersection-observer'; import 'requestidlecallback'; import objectFitImages from 'object-fit-images'; diff --git a/app/javascript/mastodon/features/about/index.js b/app/javascript/mastodon/features/about/index.js new file mode 100644 index 000000000..75fed9b95 --- /dev/null +++ b/app/javascript/mastodon/features/about/index.js @@ -0,0 +1,222 @@ +import React from 'react'; +import ImmutablePropTypes from 'react-immutable-proptypes'; +import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; +import { connect } from 'react-redux'; +import PropTypes from 'prop-types'; +import Column from 'mastodon/components/column'; +import LinkFooter from 'mastodon/features/ui/components/link_footer'; +import { Helmet } from 'react-helmet'; +import { fetchServer, fetchExtendedDescription, fetchDomainBlocks } from 'mastodon/actions/server'; +import Account from 'mastodon/containers/account_container'; +import Skeleton from 'mastodon/components/skeleton'; +import Icon from 'mastodon/components/icon'; +import classNames from 'classnames'; +import Image from 'mastodon/components/image'; + +const messages = defineMessages({ + title: { id: 'column.about', defaultMessage: 'About' }, + rules: { id: 'about.rules', defaultMessage: 'Server rules' }, + blocks: { id: 'about.blocks', defaultMessage: 'Moderated servers' }, + silenced: { id: 'about.domain_blocks.silenced.title', defaultMessage: 'Limited' }, + silencedExplanation: { id: 'about.domain_blocks.silenced.explanation', defaultMessage: 'You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.' }, + suspended: { id: 'about.domain_blocks.suspended.title', defaultMessage: 'Suspended' }, + suspendedExplanation: { id: 'about.domain_blocks.suspended.explanation', defaultMessage: 'No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.' }, +}); + +const severityMessages = { + silence: { + title: messages.silenced, + explanation: messages.silencedExplanation, + }, + + suspend: { + title: messages.suspended, + explanation: messages.suspendedExplanation, + }, +}; + +const mapStateToProps = state => ({ + server: state.getIn(['server', 'server']), + extendedDescription: state.getIn(['server', 'extendedDescription']), + domainBlocks: state.getIn(['server', 'domainBlocks']), +}); + +class Section extends React.PureComponent { + + static propTypes = { + title: PropTypes.string, + children: PropTypes.node, + open: PropTypes.bool, + onOpen: PropTypes.func, + }; + + state = { + collapsed: !this.props.open, + }; + + handleClick = () => { + const { onOpen } = this.props; + const { collapsed } = this.state; + + this.setState({ collapsed: !collapsed }, () => onOpen && onOpen()); + } + + render () { + const { title, children } = this.props; + const { collapsed } = this.state; + + return ( + <div className={classNames('about__section', { active: !collapsed })}> + <div className='about__section__title' role='button' tabIndex='0' onClick={this.handleClick}> + <Icon id={collapsed ? 'chevron-right' : 'chevron-down'} fixedWidth /> {title} + </div> + + {!collapsed && ( + <div className='about__section__body'>{children}</div> + )} + </div> + ); + } + +} + +export default @connect(mapStateToProps) +@injectIntl +class About extends React.PureComponent { + + static propTypes = { + server: ImmutablePropTypes.map, + extendedDescription: ImmutablePropTypes.map, + domainBlocks: ImmutablePropTypes.contains({ + isLoading: PropTypes.bool, + isAvailable: PropTypes.bool, + items: ImmutablePropTypes.list, + }), + dispatch: PropTypes.func.isRequired, + intl: PropTypes.object.isRequired, + multiColumn: PropTypes.bool, + }; + + componentDidMount () { + const { dispatch } = this.props; + dispatch(fetchServer()); + dispatch(fetchExtendedDescription()); + } + + handleDomainBlocksOpen = () => { + const { dispatch } = this.props; + dispatch(fetchDomainBlocks()); + } + + render () { + const { multiColumn, intl, server, extendedDescription, domainBlocks } = this.props; + const isLoading = server.get('isLoading'); + + return ( + <Column bindToDocument={!multiColumn} label={intl.formatMessage(messages.title)}> + <div className='scrollable about'> + <div className='about__header'> + <Image blurhash={server.getIn(['thumbnail', 'blurhash'])} src={server.getIn(['thumbnail', 'url'])} srcSet={server.getIn(['thumbnail', 'versions'])?.map((value, key) => `${value} ${key.replace('@', '')}`).join(', ')} className='about__header__hero' /> + <h1>{isLoading ? <Skeleton width='10ch' /> : server.get('domain')}</h1> + <p><FormattedMessage id='about.powered_by' defaultMessage='Decentralized social media powered by {mastodon}' values={{ mastodon: <a href='https://joinmastodon.org' className='about__mail' target='_blank'>Mastodon</a> }} /></p> + </div> + + <div className='about__meta'> + <div className='about__meta__column'> + <h4><FormattedMessage id='server_banner.administered_by' defaultMessage='Administered by:' /></h4> + + <Account id={server.getIn(['contact', 'account', 'id'])} /> + </div> + + <hr className='about__meta__divider' /> + + <div className='about__meta__column'> + <h4><FormattedMessage id='about.contact' defaultMessage='Contact:' /></h4> + + {isLoading ? <Skeleton width='10ch' /> : <a className='about__mail' href={`mailto:${server.getIn(['contact', 'email'])}`}>{server.getIn(['contact', 'email'])}</a>} + </div> + </div> + + <Section open title={intl.formatMessage(messages.title)}> + {extendedDescription.get('isLoading') ? ( + <> + <Skeleton width='100%' /> + <br /> + <Skeleton width='100%' /> + <br /> + <Skeleton width='100%' /> + <br /> + <Skeleton width='70%' /> + </> + ) : (extendedDescription.get('content')?.length > 0 ? ( + <div + className='prose' + dangerouslySetInnerHTML={{ __html: extendedDescription.get('content') }} + /> + ) : ( + <p><FormattedMessage id='about.not_available' defaultMessage='This information has not been made available on this server.' /></p> + ))} + </Section> + + <Section title={intl.formatMessage(messages.rules)}> + {!isLoading && (server.get('rules').isEmpty() ? ( + <p><FormattedMessage id='about.not_available' defaultMessage='This information has not been made available on this server.' /></p> + ) : ( + <ol className='rules-list'> + {server.get('rules').map(rule => ( + <li key={rule.get('id')}> + <span className='rules-list__text'>{rule.get('text')}</span> + </li> + ))} + </ol> + ))} + </Section> + + <Section title={intl.formatMessage(messages.blocks)} onOpen={this.handleDomainBlocksOpen}> + {domainBlocks.get('isLoading') ? ( + <> + <Skeleton width='100%' /> + <br /> + <Skeleton width='70%' /> + </> + ) : (domainBlocks.get('isAvailable') ? ( + <> + <p><FormattedMessage id='about.domain_blocks.preamble' defaultMessage='Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.' /></p> + + <table className='about__domain-blocks'> + <thead> + <tr> + <th><FormattedMessage id='about.domain_blocks.domain' defaultMessage='Domain' /></th> + <th><FormattedMessage id='about.domain_blocks.severity' defaultMessage='Severity' /></th> + <th><FormattedMessage id='about.domain_blocks.comment' defaultMessage='Reason' /></th> + </tr> + </thead> + + <tbody> + {domainBlocks.get('items').map(block => ( + <tr key={block.get('domain')}> + <td><span title={`SHA-256: ${block.get('digest')}`}>{block.get('domain')}</span></td> + <td><span title={intl.formatMessage(severityMessages[block.get('severity')].explanation)}>{intl.formatMessage(severityMessages[block.get('severity')].title)}</span></td> + <td>{block.get('comment')}</td> + </tr> + ))} + </tbody> + </table> + </> + ) : ( + <p><FormattedMessage id='about.not_available' defaultMessage='This information has not been made available on this server.' /></p> + ))} + </Section> + + <LinkFooter /> + </div> + + <Helmet> + <title>{intl.formatMessage(messages.title)}</title> + <meta name='robots' content='all' /> + </Helmet> + </Column> + ); + } + +} diff --git a/app/javascript/mastodon/features/account/components/featured_tags.js b/app/javascript/mastodon/features/account/components/featured_tags.js new file mode 100644 index 000000000..8194c063a --- /dev/null +++ b/app/javascript/mastodon/features/account/components/featured_tags.js @@ -0,0 +1,53 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import ImmutablePropTypes from 'react-immutable-proptypes'; +import ImmutablePureComponent from 'react-immutable-pure-component'; +import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; +import Hashtag from 'mastodon/components/hashtag'; + +const messages = defineMessages({ + lastStatusAt: { id: 'account.featured_tags.last_status_at', defaultMessage: 'Last post on {date}' }, + empty: { id: 'account.featured_tags.last_status_never', defaultMessage: 'No posts' }, +}); + +export default @injectIntl +class FeaturedTags extends ImmutablePureComponent { + + static contextTypes = { + router: PropTypes.object, + }; + + static propTypes = { + account: ImmutablePropTypes.map, + featuredTags: ImmutablePropTypes.list, + tagged: PropTypes.string, + intl: PropTypes.object.isRequired, + }; + + render () { + const { account, featuredTags, intl } = this.props; + + if (!account || account.get('suspended') || featuredTags.isEmpty()) { + return null; + } + + return ( + <div className='getting-started__trends'> + <h4><FormattedMessage id='account.featured_tags.title' defaultMessage="{name}'s featured hashtags" values={{ name: <bdi dangerouslySetInnerHTML={{ __html: account.get('display_name_html') }} /> }} /></h4> + + {featuredTags.take(3).map(featuredTag => ( + <Hashtag + key={featuredTag.get('name')} + name={featuredTag.get('name')} + href={featuredTag.get('url')} + to={`/@${account.get('acct')}/tagged/${featuredTag.get('name')}`} + uses={featuredTag.get('statuses_count') * 1} + withGraph={false} + description={((featuredTag.get('statuses_count') * 1) > 0) ? intl.formatMessage(messages.lastStatusAt, { date: intl.formatDate(featuredTag.get('last_status_at'), { month: 'short', day: '2-digit' }) }) : intl.formatMessage(messages.empty)} + /> + ))} + </div> + ); + } + +} diff --git a/app/javascript/mastodon/features/account/components/header.js b/app/javascript/mastodon/features/account/components/header.js index e407a0d55..e39f0158e 100644 --- a/app/javascript/mastodon/features/account/components/header.js +++ b/app/javascript/mastodon/features/account/components/header.js @@ -4,7 +4,7 @@ import PropTypes from 'prop-types'; import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import Button from 'mastodon/components/button'; import ImmutablePureComponent from 'react-immutable-pure-component'; -import { autoPlayGif, me, title, domain } from 'mastodon/initial_state'; +import { autoPlayGif, me, domain } from 'mastodon/initial_state'; import classNames from 'classnames'; import Icon from 'mastodon/components/icon'; import IconButton from 'mastodon/components/icon_button'; @@ -20,7 +20,7 @@ import { Helmet } from 'react-helmet'; const messages = defineMessages({ unfollow: { id: 'account.unfollow', defaultMessage: 'Unfollow' }, follow: { id: 'account.follow', defaultMessage: 'Follow' }, - cancel_follow_request: { id: 'account.cancel_follow_request', defaultMessage: 'Cancel follow request' }, + cancel_follow_request: { id: 'account.cancel_follow_request', defaultMessage: 'Withdraw follow request' }, requested: { id: 'account.requested', defaultMessage: 'Awaiting approval. Click to cancel follow request' }, unblock: { id: 'account.unblock', defaultMessage: 'Unblock @{name}' }, edit_profile: { id: 'account.edit_profile', defaultMessage: 'Edit profile' }, @@ -96,6 +96,7 @@ class Header extends ImmutablePureComponent { onAddToList: PropTypes.func.isRequired, onEditAccountNote: PropTypes.func.isRequired, onChangeLanguages: PropTypes.func.isRequired, + onInteractionModal: PropTypes.func.isRequired, intl: PropTypes.object.isRequired, domain: PropTypes.string.isRequired, hidden: PropTypes.bool, @@ -177,7 +178,7 @@ class Header extends ImmutablePureComponent { } else if (account.getIn(['relationship', 'requested'])) { actionBtn = <Button className={classNames('logo-button', { 'button--with-bell': bellBtn !== '' })} text={intl.formatMessage(messages.cancel_follow_request)} title={intl.formatMessage(messages.requested)} onClick={this.props.onFollow} />; } else if (!account.getIn(['relationship', 'blocking'])) { - actionBtn = <Button disabled={account.getIn(['relationship', 'blocked_by'])} className={classNames('logo-button', { 'button--destructive': account.getIn(['relationship', 'following']), 'button--with-bell': bellBtn !== '' })} text={intl.formatMessage(account.getIn(['relationship', 'following']) ? messages.unfollow : messages.follow)} onClick={signedIn ? this.props.onFollow : undefined} />; + actionBtn = <Button disabled={account.getIn(['relationship', 'blocked_by'])} className={classNames('logo-button', { 'button--destructive': account.getIn(['relationship', 'following']), 'button--with-bell': bellBtn !== '' })} text={intl.formatMessage(account.getIn(['relationship', 'following']) ? messages.unfollow : messages.follow)} onClick={signedIn ? this.props.onFollow : this.props.onInteractionModal} />; } else if (account.getIn(['relationship', 'blocking'])) { actionBtn = <Button className='logo-button' text={intl.formatMessage(messages.unblock, { name: account.get('username') })} onClick={this.props.onBlock} />; } @@ -269,7 +270,9 @@ class Header extends ImmutablePureComponent { const content = { __html: account.get('note_emojified') }; const displayNameHtml = { __html: account.get('display_name_html') }; const fields = account.get('fields'); - const acct = account.get('acct').indexOf('@') === -1 && domain ? `${account.get('acct')}@${domain}` : account.get('acct'); + const isLocal = account.get('acct').indexOf('@') === -1; + const acct = isLocal && domain ? `${account.get('acct')}@${domain}` : account.get('acct'); + const isIndexable = !account.get('noindex'); let badge; @@ -323,25 +326,26 @@ class Header extends ImmutablePureComponent { {!(suspended || hidden) && ( <div className='account__header__extra'> <div className='account__header__bio'> - {fields.size > 0 && ( - <div className='account__header__fields'> - {fields.map((pair, i) => ( - <dl key={i}> - <dt dangerouslySetInnerHTML={{ __html: pair.get('name_emojified') }} title={pair.get('name')} className='translate' /> - - <dd className={`${pair.get('verified_at') ? 'verified' : ''} translate`} title={pair.get('value_plain')}> - {pair.get('verified_at') && <span title={intl.formatMessage(messages.linkVerifiedOn, { date: intl.formatDate(pair.get('verified_at'), dateFormatOptions) })}><Icon id='check' className='verified__mark' /></span>} <span dangerouslySetInnerHTML={{ __html: pair.get('value_emojified') }} /> - </dd> - </dl> - ))} - </div> - )} - {(account.get('id') !== me && signedIn) && <AccountNoteContainer account={account} />} {account.get('note').length > 0 && account.get('note') !== '<p></p>' && <div className='account__header__content translate' dangerouslySetInnerHTML={content} />} - <div className='account__header__joined'><FormattedMessage id='account.joined' defaultMessage='Joined {date}' values={{ date: intl.formatDate(account.get('created_at'), { year: 'numeric', month: 'short', day: '2-digit' }) }} /></div> + <div className='account__header__fields'> + <dl> + <dt><FormattedMessage id='account.joined_short' defaultMessage='Joined' /></dt> + <dd>{intl.formatDate(account.get('created_at'), { year: 'numeric', month: 'short', day: '2-digit' })}</dd> + </dl> + + {fields.map((pair, i) => ( + <dl key={i}> + <dt dangerouslySetInnerHTML={{ __html: pair.get('name_emojified') }} title={pair.get('name')} className='translate' /> + + <dd className={`${pair.get('verified_at') ? 'verified' : ''} translate`} title={pair.get('value_plain')}> + {pair.get('verified_at') && <span title={intl.formatMessage(messages.linkVerifiedOn, { date: intl.formatDate(pair.get('verified_at'), dateFormatOptions) })}><Icon id='check' className='verified__mark' /></span>} <span dangerouslySetInnerHTML={{ __html: pair.get('value_emojified') }} /> + </dd> + </dl> + ))} + </div> </div> <div className='account__header__extra__links'> @@ -371,7 +375,8 @@ class Header extends ImmutablePureComponent { </div> <Helmet> - <title>{titleFromAccount(account)} - {title}</title> + <title>{titleFromAccount(account)}</title> + <meta name='robots' content={(isLocal && isIndexable) ? 'all' : 'noindex'} /> </Helmet> </div> ); diff --git a/app/javascript/mastodon/features/account/containers/featured_tags_container.js b/app/javascript/mastodon/features/account/containers/featured_tags_container.js new file mode 100644 index 000000000..7e206567f --- /dev/null +++ b/app/javascript/mastodon/features/account/containers/featured_tags_container.js @@ -0,0 +1,15 @@ +import { connect } from 'react-redux'; +import FeaturedTags from '../components/featured_tags'; +import { makeGetAccount } from 'mastodon/selectors'; +import { List as ImmutableList } from 'immutable'; + +const mapStateToProps = () => { + const getAccount = makeGetAccount(); + + return (state, { accountId }) => ({ + account: getAccount(state, accountId), + featuredTags: state.getIn(['user_lists', 'featured_tags', accountId, 'items'], ImmutableList()), + }); +}; + +export default connect(mapStateToProps)(FeaturedTags); diff --git a/app/javascript/mastodon/features/account/navigation.js b/app/javascript/mastodon/features/account/navigation.js new file mode 100644 index 000000000..eb9ff9a95 --- /dev/null +++ b/app/javascript/mastodon/features/account/navigation.js @@ -0,0 +1,52 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { connect } from 'react-redux'; +import FeaturedTags from 'mastodon/features/account/containers/featured_tags_container'; +import { normalizeForLookup } from 'mastodon/reducers/accounts_map'; + +const mapStateToProps = (state, { match: { params: { acct } } }) => { + const accountId = state.getIn(['accounts_map', normalizeForLookup(acct)]); + + if (!accountId) { + return { + isLoading: true, + }; + } + + return { + accountId, + isLoading: false, + }; +}; + +export default @connect(mapStateToProps) +class AccountNavigation extends React.PureComponent { + + static propTypes = { + match: PropTypes.shape({ + params: PropTypes.shape({ + acct: PropTypes.string, + tagged: PropTypes.string, + }).isRequired, + }).isRequired, + + accountId: PropTypes.string, + isLoading: PropTypes.bool, + }; + + render () { + const { accountId, isLoading, match: { params: { tagged } } } = this.props; + + if (isLoading) { + return null; + } + + return ( + <> + <div className='flex-spacer' /> + <FeaturedTags accountId={accountId} tagged={tagged} /> + </> + ); + } + +} diff --git a/app/javascript/mastodon/features/account_gallery/index.js b/app/javascript/mastodon/features/account_gallery/index.js index cc0bfa9ba..dc7556a9a 100644 --- a/app/javascript/mastodon/features/account_gallery/index.js +++ b/app/javascript/mastodon/features/account_gallery/index.js @@ -16,9 +16,10 @@ import LoadMore from 'mastodon/components/load_more'; import MissingIndicator from 'mastodon/components/missing_indicator'; import { openModal } from 'mastodon/actions/modal'; import { FormattedMessage } from 'react-intl'; +import { normalizeForLookup } from 'mastodon/reducers/accounts_map'; const mapStateToProps = (state, { params: { acct, id } }) => { - const accountId = id || state.getIn(['accounts_map', acct]); + const accountId = id || state.getIn(['accounts_map', normalizeForLookup(acct)]); if (!accountId) { return { diff --git a/app/javascript/mastodon/features/account_timeline/components/header.js b/app/javascript/mastodon/features/account_timeline/components/header.js index f9838442f..f31848f41 100644 --- a/app/javascript/mastodon/features/account_timeline/components/header.js +++ b/app/javascript/mastodon/features/account_timeline/components/header.js @@ -23,6 +23,7 @@ export default class Header extends ImmutablePureComponent { onEndorseToggle: PropTypes.func.isRequired, onAddToList: PropTypes.func.isRequired, onChangeLanguages: PropTypes.func.isRequired, + onInteractionModal: PropTypes.func.isRequired, hideTabs: PropTypes.bool, domain: PropTypes.string.isRequired, hidden: PropTypes.bool, @@ -96,6 +97,10 @@ export default class Header extends ImmutablePureComponent { this.props.onChangeLanguages(this.props.account); } + handleInteractionModal = () => { + this.props.onInteractionModal(this.props.account); + } + render () { const { account, hidden, hideTabs } = this.props; @@ -123,6 +128,7 @@ export default class Header extends ImmutablePureComponent { onAddToList={this.handleAddToList} onEditAccountNote={this.handleEditAccountNote} onChangeLanguages={this.handleChangeLanguages} + onInteractionModal={this.handleInteractionModal} domain={this.props.domain} hidden={hidden} /> diff --git a/app/javascript/mastodon/features/account_timeline/containers/header_container.js b/app/javascript/mastodon/features/account_timeline/containers/header_container.js index 3d6eb487d..62e59939c 100644 --- a/app/javascript/mastodon/features/account_timeline/containers/header_container.js +++ b/app/javascript/mastodon/features/account_timeline/containers/header_container.js @@ -23,6 +23,7 @@ import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import { unfollowModal } from '../../../initial_state'; const messages = defineMessages({ + cancelFollowRequestConfirm: { id: 'confirmations.cancel_follow_request.confirm', defaultMessage: 'Withdraw request' }, unfollowConfirm: { id: 'confirmations.unfollow.confirm', defaultMessage: 'Unfollow' }, blockDomainConfirm: { id: 'confirmations.domain_block.confirm', defaultMessage: 'Hide entire domain' }, }); @@ -42,7 +43,7 @@ const makeMapStateToProps = () => { const mapDispatchToProps = (dispatch, { intl }) => ({ onFollow (account) { - if (account.getIn(['relationship', 'following']) || account.getIn(['relationship', 'requested'])) { + if (account.getIn(['relationship', 'following'])) { if (unfollowModal) { dispatch(openModal('CONFIRM', { message: <FormattedMessage id='confirmations.unfollow.message' defaultMessage='Are you sure you want to unfollow {name}?' values={{ name: <strong>@{account.get('acct')}</strong> }} />, @@ -52,11 +53,27 @@ const mapDispatchToProps = (dispatch, { intl }) => ({ } else { dispatch(unfollowAccount(account.get('id'))); } + } else if (account.getIn(['relationship', 'requested'])) { + if (unfollowModal) { + dispatch(openModal('CONFIRM', { + message: <FormattedMessage id='confirmations.cancel_follow_request.message' defaultMessage='Are you sure you want to withdraw your request to follow {name}?' values={{ name: <strong>@{account.get('acct')}</strong> }} />, + confirm: intl.formatMessage(messages.cancelFollowRequestConfirm), + onConfirm: () => dispatch(unfollowAccount(account.get('id'))), + })); + } } else { dispatch(followAccount(account.get('id'))); } }, + onInteractionModal (account) { + dispatch(openModal('INTERACTION', { + type: 'follow', + accountId: account.get('id'), + url: account.get('url'), + })); + }, + onBlock (account) { if (account.getIn(['relationship', 'blocking'])) { dispatch(unblockAccount(account.get('id'))); diff --git a/app/javascript/mastodon/features/account_timeline/index.js b/app/javascript/mastodon/features/account_timeline/index.js index 5b592c5a7..525837c72 100644 --- a/app/javascript/mastodon/features/account_timeline/index.js +++ b/app/javascript/mastodon/features/account_timeline/index.js @@ -18,19 +18,22 @@ import { me } from 'mastodon/initial_state'; import { connectTimeline, disconnectTimeline } from 'mastodon/actions/timelines'; import LimitedAccountHint from './components/limited_account_hint'; import { getAccountHidden } from 'mastodon/selectors'; +import { fetchFeaturedTags } from '../../actions/featured_tags'; +import { normalizeForLookup } from 'mastodon/reducers/accounts_map'; const emptyList = ImmutableList(); -const mapStateToProps = (state, { params: { acct, id }, withReplies = false }) => { - const accountId = id || state.getIn(['accounts_map', acct]); +const mapStateToProps = (state, { params: { acct, id, tagged }, withReplies = false }) => { + const accountId = id || state.getIn(['accounts_map', normalizeForLookup(acct)]); if (!accountId) { return { isLoading: true, + statusIds: emptyList, }; } - const path = withReplies ? `${accountId}:with_replies` : accountId; + const path = withReplies ? `${accountId}:with_replies` : `${accountId}${tagged ? `:${tagged}` : ''}`; return { accountId, @@ -38,7 +41,7 @@ const mapStateToProps = (state, { params: { acct, id }, withReplies = false }) = remoteUrl: state.getIn(['accounts', accountId, 'url']), isAccount: !!state.getIn(['accounts', accountId]), statusIds: state.getIn(['timelines', `account:${path}`, 'items'], emptyList), - featuredStatusIds: withReplies ? ImmutableList() : state.getIn(['timelines', `account:${accountId}:pinned`, 'items'], emptyList), + featuredStatusIds: withReplies ? ImmutableList() : state.getIn(['timelines', `account:${accountId}:pinned${tagged ? `:${tagged}` : ''}`, 'items'], emptyList), isLoading: state.getIn(['timelines', `account:${path}`, 'isLoading']), hasMore: state.getIn(['timelines', `account:${path}`, 'hasMore']), suspended: state.getIn(['accounts', accountId, 'suspended'], false), @@ -62,6 +65,7 @@ class AccountTimeline extends ImmutablePureComponent { params: PropTypes.shape({ acct: PropTypes.string, id: PropTypes.string, + tagged: PropTypes.string, }).isRequired, accountId: PropTypes.string, dispatch: PropTypes.func.isRequired, @@ -80,15 +84,16 @@ class AccountTimeline extends ImmutablePureComponent { }; _load () { - const { accountId, withReplies, dispatch } = this.props; + const { accountId, withReplies, params: { tagged }, dispatch } = this.props; dispatch(fetchAccount(accountId)); if (!withReplies) { - dispatch(expandAccountFeaturedTimeline(accountId)); + dispatch(expandAccountFeaturedTimeline(accountId, { tagged })); } - dispatch(expandAccountTimeline(accountId, { withReplies })); + dispatch(fetchFeaturedTags(accountId)); + dispatch(expandAccountTimeline(accountId, { withReplies, tagged })); if (accountId === me) { dispatch(connectTimeline(`account:${me}`)); @@ -106,12 +111,17 @@ class AccountTimeline extends ImmutablePureComponent { } componentDidUpdate (prevProps) { - const { params: { acct }, accountId, dispatch } = this.props; + const { params: { acct, tagged }, accountId, withReplies, dispatch } = this.props; if (prevProps.accountId !== accountId && accountId) { this._load(); } else if (prevProps.params.acct !== acct) { dispatch(lookupAccount(acct)); + } else if (prevProps.params.tagged !== tagged) { + if (!withReplies) { + dispatch(expandAccountFeaturedTimeline(accountId, { tagged })); + } + dispatch(expandAccountTimeline(accountId, { withReplies, tagged })); } if (prevProps.accountId === me && accountId !== me) { @@ -128,25 +138,23 @@ class AccountTimeline extends ImmutablePureComponent { } handleLoadMore = maxId => { - this.props.dispatch(expandAccountTimeline(this.props.accountId, { maxId, withReplies: this.props.withReplies })); + this.props.dispatch(expandAccountTimeline(this.props.accountId, { maxId, withReplies: this.props.withReplies, tagged: this.props.params.tagged })); } render () { const { accountId, statusIds, featuredStatusIds, isLoading, hasMore, blockedBy, suspended, isAccount, hidden, multiColumn, remote, remoteUrl } = this.props; - if (!isAccount) { + if (isLoading && statusIds.isEmpty()) { return ( <Column> - <ColumnBackButton multiColumn={multiColumn} /> - <MissingIndicator /> + <LoadingIndicator /> </Column> ); - } - - if (!statusIds && isLoading) { + } else if (!isLoading && !isAccount) { return ( <Column> - <LoadingIndicator /> + <ColumnBackButton multiColumn={multiColumn} /> + <MissingIndicator /> </Column> ); } @@ -174,7 +182,7 @@ class AccountTimeline extends ImmutablePureComponent { <ColumnBackButton multiColumn={multiColumn} /> <StatusList - prepend={<HeaderContainer accountId={this.props.accountId} hideTabs={forceEmptyState} />} + prepend={<HeaderContainer accountId={this.props.accountId} hideTabs={forceEmptyState} tagged={this.props.params.tagged} />} alwaysPrepend append={remoteMessage} scrollKey='account_timeline' diff --git a/app/javascript/mastodon/features/bookmarked_statuses/index.js b/app/javascript/mastodon/features/bookmarked_statuses/index.js index 8f41b0f95..097be17c9 100644 --- a/app/javascript/mastodon/features/bookmarked_statuses/index.js +++ b/app/javascript/mastodon/features/bookmarked_statuses/index.js @@ -1,15 +1,16 @@ -import React from 'react'; -import { connect } from 'react-redux'; +import { debounce } from 'lodash'; import PropTypes from 'prop-types'; -import ImmutablePropTypes from 'react-immutable-proptypes'; -import { fetchBookmarkedStatuses, expandBookmarkedStatuses } from '../../actions/bookmarks'; -import Column from '../ui/components/column'; -import ColumnHeader from '../../components/column_header'; -import { addColumn, removeColumn, moveColumn } from '../../actions/columns'; -import StatusList from '../../components/status_list'; +import React from 'react'; +import { Helmet } from 'react-helmet'; import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; +import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePureComponent from 'react-immutable-pure-component'; -import { debounce } from 'lodash'; +import { connect } from 'react-redux'; +import { fetchBookmarkedStatuses, expandBookmarkedStatuses } from 'mastodon/actions/bookmarks'; +import { addColumn, removeColumn, moveColumn } from 'mastodon/actions/columns'; +import ColumnHeader from 'mastodon/components/column_header'; +import StatusList from 'mastodon/components/status_list'; +import Column from 'mastodon/features/ui/components/column'; const messages = defineMessages({ heading: { id: 'column.bookmarks', defaultMessage: 'Bookmarks' }, @@ -95,6 +96,11 @@ class Bookmarks extends ImmutablePureComponent { emptyMessage={emptyMessage} bindToDocument={!multiColumn} /> + + <Helmet> + <title>{intl.formatMessage(messages.heading)}</title> + <meta name='robots' content='noindex' /> + </Helmet> </Column> ); } diff --git a/app/javascript/mastodon/features/closed_registrations_modal/index.js b/app/javascript/mastodon/features/closed_registrations_modal/index.js new file mode 100644 index 000000000..275bd50aa --- /dev/null +++ b/app/javascript/mastodon/features/closed_registrations_modal/index.js @@ -0,0 +1,75 @@ +import React from 'react'; +import { connect } from 'react-redux'; +import { FormattedMessage } from 'react-intl'; +import ImmutablePureComponent from 'react-immutable-pure-component'; +import { domain } from 'mastodon/initial_state'; +import { fetchServer } from 'mastodon/actions/server'; + +const mapStateToProps = state => ({ + message: state.getIn(['server', 'server', 'registrations', 'message']), +}); + +export default @connect(mapStateToProps) +class ClosedRegistrationsModal extends ImmutablePureComponent { + + componentDidMount () { + const { dispatch } = this.props; + dispatch(fetchServer()); + } + + render () { + let closedRegistrationsMessage; + + if (this.props.message) { + closedRegistrationsMessage = ( + <p + className='prose' + dangerouslySetInnerHTML={{ __html: this.props.message }} + /> + ); + } else { + closedRegistrationsMessage = ( + <p className='prose'> + <FormattedMessage + id='closed_registrations_modal.description' + defaultMessage='Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.' + values={{ domain: <strong>{domain}</strong> }} + /> + </p> + ); + } + + return ( + <div className='modal-root__modal interaction-modal'> + <div className='interaction-modal__lead'> + <h3><FormattedMessage id='closed_registrations_modal.title' defaultMessage='Signing up on Mastodon' /></h3> + <p> + <FormattedMessage + id='closed_registrations_modal.preamble' + defaultMessage='Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!' + /> + </p> + </div> + + <div className='interaction-modal__choices'> + <div className='interaction-modal__choices__choice'> + <h3><FormattedMessage id='interaction_modal.on_this_server' defaultMessage='On this server' /></h3> + {closedRegistrationsMessage} + </div> + + <div className='interaction-modal__choices__choice'> + <h3><FormattedMessage id='interaction_modal.on_another_server' defaultMessage='On a different server' /></h3> + <p className='prose'> + <FormattedMessage + id='closed_registrations.other_server_instructions' + defaultMessage='Since Mastodon is decentralized, you can create an account on another server and still interact with this one.' + /> + </p> + <a href='https://joinmastodon.org/servers' className='button button--block'><FormattedMessage id='closed_registrations_modal.find_another_server' defaultMessage='Find another server' /></a> + </div> + </div> + </div> + ); + } + +}; diff --git a/app/javascript/mastodon/features/community_timeline/index.js b/app/javascript/mastodon/features/community_timeline/index.js index f9d50e64c..7b3f8845f 100644 --- a/app/javascript/mastodon/features/community_timeline/index.js +++ b/app/javascript/mastodon/features/community_timeline/index.js @@ -10,7 +10,8 @@ import { addColumn, removeColumn, moveColumn } from '../../actions/columns'; import ColumnSettingsContainer from './containers/column_settings_container'; import { connectCommunityStream } from '../../actions/streaming'; import { Helmet } from 'react-helmet'; -import { title } from 'mastodon/initial_state'; +import { domain } from 'mastodon/initial_state'; +import DismissableBanner from 'mastodon/components/dismissable_banner'; const messages = defineMessages({ title: { id: 'column.community', defaultMessage: 'Local timeline' }, @@ -35,6 +36,7 @@ class CommunityTimeline extends React.PureComponent { static contextTypes = { router: PropTypes.object, + identity: PropTypes.object, }; static defaultProps = { @@ -71,18 +73,30 @@ class CommunityTimeline extends React.PureComponent { componentDidMount () { const { dispatch, onlyMedia } = this.props; + const { signedIn } = this.context.identity; dispatch(expandCommunityTimeline({ onlyMedia })); - this.disconnect = dispatch(connectCommunityStream({ onlyMedia })); + + if (signedIn) { + this.disconnect = dispatch(connectCommunityStream({ onlyMedia })); + } } componentDidUpdate (prevProps) { + const { signedIn } = this.context.identity; + if (prevProps.onlyMedia !== this.props.onlyMedia) { const { dispatch, onlyMedia } = this.props; - this.disconnect(); + if (this.disconnect) { + this.disconnect(); + } + dispatch(expandCommunityTimeline({ onlyMedia })); - this.disconnect = dispatch(connectCommunityStream({ onlyMedia })); + + if (signedIn) { + this.disconnect = dispatch(connectCommunityStream({ onlyMedia })); + } } } @@ -122,6 +136,10 @@ class CommunityTimeline extends React.PureComponent { <ColumnSettingsContainer columnId={columnId} /> </ColumnHeader> + <DismissableBanner id='community_timeline'> + <FormattedMessage id='dismissable_banner.community_timeline' defaultMessage='These are the most recent public posts from people whose accounts are hosted by {domain}.' values={{ domain }} /> + </DismissableBanner> + <StatusListContainer trackScroll={!pinned} scrollKey={`community_timeline-${columnId}`} @@ -132,7 +150,8 @@ class CommunityTimeline extends React.PureComponent { /> <Helmet> - <title>{intl.formatMessage(messages.title)} - {title}</title> + <title>{intl.formatMessage(messages.title)}</title> + <meta name='robots' content='noindex' /> </Helmet> </Column> ); diff --git a/app/javascript/mastodon/features/compose/components/action_bar.js b/app/javascript/mastodon/features/compose/components/action_bar.js index 4ff0b7b94..ceed928bf 100644 --- a/app/javascript/mastodon/features/compose/components/action_bar.js +++ b/app/javascript/mastodon/features/compose/components/action_bar.js @@ -56,7 +56,7 @@ class ActionBar extends React.PureComponent { return ( <div className='compose__action-bar'> <div className='compose__action-bar-dropdown'> - <DropdownMenuContainer items={menu} icon='chevron-down' size={16} direction='right' /> + <DropdownMenuContainer items={menu} icon='ellipsis-v' size={18} direction='right' /> </div> </div> ); diff --git a/app/javascript/mastodon/features/compose/components/navigation_bar.js b/app/javascript/mastodon/features/compose/components/navigation_bar.js index e6ba7d8b7..372765ca4 100644 --- a/app/javascript/mastodon/features/compose/components/navigation_bar.js +++ b/app/javascript/mastodon/features/compose/components/navigation_bar.js @@ -21,7 +21,7 @@ export default class NavigationBar extends ImmutablePureComponent { <div className='navigation-bar'> <Permalink href={this.props.account.get('url')} to={`/@${this.props.account.get('acct')}`}> <span style={{ display: 'none' }}>{this.props.account.get('acct')}</span> - <Avatar account={this.props.account} size={48} /> + <Avatar account={this.props.account} size={46} /> </Permalink> <div className='navigation-bar__profile'> diff --git a/app/javascript/mastodon/features/compose/components/search.js b/app/javascript/mastodon/features/compose/components/search.js index 3e36a922b..ebb23d92f 100644 --- a/app/javascript/mastodon/features/compose/components/search.js +++ b/app/javascript/mastodon/features/compose/components/search.js @@ -9,6 +9,7 @@ import Icon from 'mastodon/components/icon'; const messages = defineMessages({ placeholder: { id: 'search.placeholder', defaultMessage: 'Search' }, + placeholderSignedIn: { id: 'search.search_or_paste', defaultMessage: 'Search or paste URL' }, }); class SearchPopout extends React.PureComponent { @@ -49,6 +50,7 @@ class Search extends React.PureComponent { static contextTypes = { router: PropTypes.object.isRequired, + identity: PropTypes.object.isRequired, }; static propTypes = { @@ -116,6 +118,7 @@ class Search extends React.PureComponent { render () { const { intl, value, submitted } = this.props; const { expanded } = this.state; + const { signedIn } = this.context.identity; const hasValue = value.length > 0 || submitted; return ( @@ -126,7 +129,7 @@ class Search extends React.PureComponent { ref={this.setRef} className='search__input' type='text' - placeholder={intl.formatMessage(messages.placeholder)} + placeholder={intl.formatMessage(signedIn ? messages.placeholderSignedIn : messages.placeholder)} value={value} onChange={this.handleChange} onKeyUp={this.handleKeyUp} diff --git a/app/javascript/mastodon/features/compose/components/search_results.js b/app/javascript/mastodon/features/compose/components/search_results.js index e2493a6c6..44ab43638 100644 --- a/app/javascript/mastodon/features/compose/components/search_results.js +++ b/app/javascript/mastodon/features/compose/components/search_results.js @@ -61,8 +61,8 @@ class SearchResults extends ImmutablePureComponent { <AccountContainer key={suggestion.get('account')} id={suggestion.get('account')} - actionIcon={suggestion.get('source') === 'past_interaction' ? 'times' : null} - actionTitle={suggestion.get('source') === 'past_interaction' ? intl.formatMessage(messages.dismissSuggestion) : null} + actionIcon={suggestion.get('source') === 'past_interactions' ? 'times' : null} + actionTitle={suggestion.get('source') === 'past_interactions' ? intl.formatMessage(messages.dismissSuggestion) : null} onActionClick={dismissSuggestion} /> ))} diff --git a/app/javascript/mastodon/features/compose/components/upload_form.js b/app/javascript/mastodon/features/compose/components/upload_form.js index c6eac554e..9ff2aa0fa 100644 --- a/app/javascript/mastodon/features/compose/components/upload_form.js +++ b/app/javascript/mastodon/features/compose/components/upload_form.js @@ -4,7 +4,6 @@ import UploadProgressContainer from '../containers/upload_progress_container'; import ImmutablePureComponent from 'react-immutable-pure-component'; import UploadContainer from '../containers/upload_container'; import SensitiveButtonContainer from '../containers/sensitive_button_container'; -import { FormattedMessage } from 'react-intl'; export default class UploadForm extends ImmutablePureComponent { @@ -17,7 +16,7 @@ export default class UploadForm extends ImmutablePureComponent { return ( <div className='compose-form__upload-wrapper'> - <UploadProgressContainer icon='upload' message={<FormattedMessage id='upload_progress.label' defaultMessage='Uploading…' />} /> + <UploadProgressContainer /> <div className='compose-form__uploads-wrapper'> {mediaIds.map(id => ( diff --git a/app/javascript/mastodon/features/compose/components/upload_progress.js b/app/javascript/mastodon/features/compose/components/upload_progress.js index b0bfe0c9a..cabf520fd 100644 --- a/app/javascript/mastodon/features/compose/components/upload_progress.js +++ b/app/javascript/mastodon/features/compose/components/upload_progress.js @@ -3,27 +3,35 @@ import PropTypes from 'prop-types'; import Motion from '../../ui/util/optional_motion'; import spring from 'react-motion/lib/spring'; import Icon from 'mastodon/components/icon'; +import { FormattedMessage } from 'react-intl'; export default class UploadProgress extends React.PureComponent { static propTypes = { active: PropTypes.bool, progress: PropTypes.number, - icon: PropTypes.string.isRequired, - message: PropTypes.node.isRequired, + isProcessing: PropTypes.bool, }; render () { - const { active, progress, icon, message } = this.props; + const { active, progress, isProcessing } = this.props; if (!active) { return null; } + let message; + + if (isProcessing) { + message = <FormattedMessage id='upload_progress.processing' defaultMessage='Processing…' />; + } else { + message = <FormattedMessage id='upload_progress.label' defaultMessage='Uploading…' />; + } + return ( <div className='upload-progress'> <div className='upload-progress__icon'> - <Icon id={icon} /> + <Icon id='upload' /> </div> <div className='upload-progress__message'> diff --git a/app/javascript/mastodon/features/compose/containers/upload_progress_container.js b/app/javascript/mastodon/features/compose/containers/upload_progress_container.js index 0cfee96da..b18c76a43 100644 --- a/app/javascript/mastodon/features/compose/containers/upload_progress_container.js +++ b/app/javascript/mastodon/features/compose/containers/upload_progress_container.js @@ -4,6 +4,7 @@ import UploadProgress from '../components/upload_progress'; const mapStateToProps = state => ({ active: state.getIn(['compose', 'is_uploading']), progress: state.getIn(['compose', 'progress']), + isProcessing: state.getIn(['compose', 'is_processing']), }); export default connect(mapStateToProps)(UploadProgress); diff --git a/app/javascript/mastodon/features/compose/index.js b/app/javascript/mastodon/features/compose/index.js index 711a55904..f744fc611 100644 --- a/app/javascript/mastodon/features/compose/index.js +++ b/app/javascript/mastodon/features/compose/index.js @@ -4,19 +4,20 @@ import NavigationContainer from './containers/navigation_container'; import PropTypes from 'prop-types'; import ImmutablePropTypes from 'react-immutable-proptypes'; import { connect } from 'react-redux'; -import { mountCompose, unmountCompose } from '../../actions/compose'; +import { changeComposing, mountCompose, unmountCompose } from '../../actions/compose'; import { Link } from 'react-router-dom'; import { injectIntl, defineMessages } from 'react-intl'; import SearchContainer from './containers/search_container'; import Motion from '../ui/util/optional_motion'; import spring from 'react-motion/lib/spring'; import SearchResultsContainer from './containers/search_results_container'; -import { changeComposing } from '../../actions/compose'; import { openModal } from 'mastodon/actions/modal'; import elephantUIPlane from '../../../images/elephant_ui_plane.svg'; import { mascot } from '../../initial_state'; import Icon from 'mastodon/components/icon'; import { logOut } from 'mastodon/utils/log_out'; +import Column from 'mastodon/components/column'; +import { Helmet } from 'react-helmet'; const messages = defineMessages({ start: { id: 'getting_started.heading', defaultMessage: 'Getting started' }, @@ -33,7 +34,7 @@ const messages = defineMessages({ const mapStateToProps = (state, ownProps) => ({ columns: state.getIn(['settings', 'columns']), - showSearch: ownProps.multiColumn ? state.getIn(['search', 'submitted']) && !state.getIn(['search', 'hidden']) : ownProps.isSearchPage, + showSearch: ownProps.multiColumn ? state.getIn(['search', 'submitted']) && !state.getIn(['search', 'hidden']) : false, }); export default @connect(mapStateToProps) @@ -45,24 +46,17 @@ class Compose extends React.PureComponent { columns: ImmutablePropTypes.list.isRequired, multiColumn: PropTypes.bool, showSearch: PropTypes.bool, - isSearchPage: PropTypes.bool, intl: PropTypes.object.isRequired, }; componentDidMount () { - const { isSearchPage } = this.props; - - if (!isSearchPage) { - this.props.dispatch(mountCompose()); - } + const { dispatch } = this.props; + dispatch(mountCompose()); } componentWillUnmount () { - const { isSearchPage } = this.props; - - if (!isSearchPage) { - this.props.dispatch(unmountCompose()); - } + const { dispatch } = this.props; + dispatch(unmountCompose()); } handleLogoutClick = e => { @@ -90,59 +84,65 @@ class Compose extends React.PureComponent { } render () { - const { multiColumn, showSearch, isSearchPage, intl } = this.props; - - let header = ''; + const { multiColumn, showSearch, intl } = this.props; if (multiColumn) { const { columns } = this.props; - header = ( - <nav className='drawer__header'> - <Link to='/getting-started' className='drawer__tab' title={intl.formatMessage(messages.start)} aria-label={intl.formatMessage(messages.start)}><Icon id='bars' fixedWidth /></Link> - {!columns.some(column => column.get('id') === 'HOME') && ( - <Link to='/home' className='drawer__tab' title={intl.formatMessage(messages.home_timeline)} aria-label={intl.formatMessage(messages.home_timeline)}><Icon id='home' fixedWidth /></Link> - )} - {!columns.some(column => column.get('id') === 'NOTIFICATIONS') && ( - <Link to='/notifications' className='drawer__tab' title={intl.formatMessage(messages.notifications)} aria-label={intl.formatMessage(messages.notifications)}><Icon id='bell' fixedWidth /></Link> - )} - {!columns.some(column => column.get('id') === 'COMMUNITY') && ( - <Link to='/public/local' className='drawer__tab' title={intl.formatMessage(messages.community)} aria-label={intl.formatMessage(messages.community)}><Icon id='users' fixedWidth /></Link> - )} - {!columns.some(column => column.get('id') === 'PUBLIC') && ( - <Link to='/public' className='drawer__tab' title={intl.formatMessage(messages.public)} aria-label={intl.formatMessage(messages.public)}><Icon id='globe' fixedWidth /></Link> - )} - <a href='/settings/preferences' className='drawer__tab' title={intl.formatMessage(messages.preferences)} aria-label={intl.formatMessage(messages.preferences)}><Icon id='cog' fixedWidth /></a> - <a href='/auth/sign_out' className='drawer__tab' title={intl.formatMessage(messages.logout)} aria-label={intl.formatMessage(messages.logout)} onClick={this.handleLogoutClick}><Icon id='sign-out' fixedWidth /></a> - </nav> - ); - } - return ( - <div className='drawer' role='region' aria-label={intl.formatMessage(messages.compose)}> - {header} + return ( + <div className='drawer' role='region' aria-label={intl.formatMessage(messages.compose)}> + <nav className='drawer__header'> + <Link to='/getting-started' className='drawer__tab' title={intl.formatMessage(messages.start)} aria-label={intl.formatMessage(messages.start)}><Icon id='bars' fixedWidth /></Link> + {!columns.some(column => column.get('id') === 'HOME') && ( + <Link to='/home' className='drawer__tab' title={intl.formatMessage(messages.home_timeline)} aria-label={intl.formatMessage(messages.home_timeline)}><Icon id='home' fixedWidth /></Link> + )} + {!columns.some(column => column.get('id') === 'NOTIFICATIONS') && ( + <Link to='/notifications' className='drawer__tab' title={intl.formatMessage(messages.notifications)} aria-label={intl.formatMessage(messages.notifications)}><Icon id='bell' fixedWidth /></Link> + )} + {!columns.some(column => column.get('id') === 'COMMUNITY') && ( + <Link to='/public/local' className='drawer__tab' title={intl.formatMessage(messages.community)} aria-label={intl.formatMessage(messages.community)}><Icon id='users' fixedWidth /></Link> + )} + {!columns.some(column => column.get('id') === 'PUBLIC') && ( + <Link to='/public' className='drawer__tab' title={intl.formatMessage(messages.public)} aria-label={intl.formatMessage(messages.public)}><Icon id='globe' fixedWidth /></Link> + )} + <a href='/settings/preferences' className='drawer__tab' title={intl.formatMessage(messages.preferences)} aria-label={intl.formatMessage(messages.preferences)}><Icon id='cog' fixedWidth /></a> + <a href='/auth/sign_out' className='drawer__tab' title={intl.formatMessage(messages.logout)} aria-label={intl.formatMessage(messages.logout)} onClick={this.handleLogoutClick}><Icon id='sign-out' fixedWidth /></a> + </nav> - {(multiColumn || isSearchPage) && <SearchContainer /> } + {multiColumn && <SearchContainer /> } - <div className='drawer__pager'> - {!isSearchPage && <div className='drawer__inner' onFocus={this.onFocus}> - <NavigationContainer onClose={this.onBlur} /> + <div className='drawer__pager'> + <div className='drawer__inner' onFocus={this.onFocus}> + <NavigationContainer onClose={this.onBlur} /> - <ComposeFormContainer /> + <ComposeFormContainer /> - <div className='drawer__inner__mastodon'> - <img alt='' draggable='false' src={mascot || elephantUIPlane} /> + <div className='drawer__inner__mastodon'> + <img alt='' draggable='false' src={mascot || elephantUIPlane} /> + </div> </div> - </div>} - <Motion defaultStyle={{ x: isSearchPage ? 0 : -100 }} style={{ x: spring(showSearch || isSearchPage ? 0 : -100, { stiffness: 210, damping: 20 }) }}> - {({ x }) => ( - <div className='drawer__inner darker' style={{ transform: `translateX(${x}%)`, visibility: x === -100 ? 'hidden' : 'visible' }}> - <SearchResultsContainer /> - </div> - )} - </Motion> + <Motion defaultStyle={{ x: -100 }} style={{ x: spring(showSearch ? 0 : -100, { stiffness: 210, damping: 20 }) }}> + {({ x }) => ( + <div className='drawer__inner darker' style={{ transform: `translateX(${x}%)`, visibility: x === -100 ? 'hidden' : 'visible' }}> + <SearchResultsContainer /> + </div> + )} + </Motion> + </div> </div> - </div> + ); + } + + return ( + <Column onFocus={this.onFocus}> + <NavigationContainer onClose={this.onBlur} /> + <ComposeFormContainer /> + + <Helmet> + <meta name='robots' content='noindex' /> + </Helmet> + </Column> ); } diff --git a/app/javascript/mastodon/features/direct_timeline/index.js b/app/javascript/mastodon/features/direct_timeline/index.js index debb2d721..8dcc43e28 100644 --- a/app/javascript/mastodon/features/direct_timeline/index.js +++ b/app/javascript/mastodon/features/direct_timeline/index.js @@ -1,12 +1,13 @@ -import React from 'react'; -import { connect } from 'react-redux'; import PropTypes from 'prop-types'; -import Column from '../../components/column'; -import ColumnHeader from '../../components/column_header'; -import { mountConversations, unmountConversations, expandConversations } from '../../actions/conversations'; -import { addColumn, removeColumn, moveColumn } from '../../actions/columns'; +import React from 'react'; +import { Helmet } from 'react-helmet'; import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; -import { connectDirectStream } from '../../actions/streaming'; +import { connect } from 'react-redux'; +import { addColumn, removeColumn, moveColumn } from 'mastodon/actions/columns'; +import { mountConversations, unmountConversations, expandConversations } from 'mastodon/actions/conversations'; +import { connectDirectStream } from 'mastodon/actions/streaming'; +import Column from 'mastodon/components/column'; +import ColumnHeader from 'mastodon/components/column_header'; import ConversationsListContainer from './containers/conversations_list_container'; const messages = defineMessages({ @@ -94,6 +95,11 @@ class DirectTimeline extends React.PureComponent { prepend={<div className='follow_requests-unlocked_explanation'><span><FormattedMessage id='compose_form.encryption_warning' defaultMessage='Posts on Mastodon are not end-to-end encrypted. Do not share any dangerous information over Mastodon.' /> <a href='/terms' target='_blank'><FormattedMessage id='compose_form.direct_message_warning_learn_more' defaultMessage='Learn more' /></a></span></div>} emptyMessage={<FormattedMessage id='empty_column.direct' defaultMessage="You don't have any direct messages yet. When you send or receive one, it will show up here." />} /> + + <Helmet> + <title>{intl.formatMessage(messages.title)}</title> + <meta name='robots' content='noindex' /> + </Helmet> </Column> ); } diff --git a/app/javascript/mastodon/features/directory/components/account_card.js b/app/javascript/mastodon/features/directory/components/account_card.js index 27ba4e7f4..7c675a147 100644 --- a/app/javascript/mastodon/features/directory/components/account_card.js +++ b/app/javascript/mastodon/features/directory/components/account_card.js @@ -23,7 +23,7 @@ import classNames from 'classnames'; const messages = defineMessages({ unfollow: { id: 'account.unfollow', defaultMessage: 'Unfollow' }, follow: { id: 'account.follow', defaultMessage: 'Follow' }, - cancel_follow_request: { id: 'account.cancel_follow_request', defaultMessage: 'Cancel follow request' }, + cancel_follow_request: { id: 'account.cancel_follow_request', defaultMessage: 'Withdraw follow request' }, requested: { id: 'account.requested', defaultMessage: 'Awaiting approval. Click to cancel follow request' }, unblock: { id: 'account.unblock_short', defaultMessage: 'Unblock' }, unmute: { id: 'account.unmute_short', defaultMessage: 'Unmute' }, diff --git a/app/javascript/mastodon/features/directory/index.js b/app/javascript/mastodon/features/directory/index.js index 36f46c510..b45faa049 100644 --- a/app/javascript/mastodon/features/directory/index.js +++ b/app/javascript/mastodon/features/directory/index.js @@ -13,7 +13,6 @@ import RadioButton from 'mastodon/components/radio_button'; import LoadMore from 'mastodon/components/load_more'; import ScrollContainer from 'mastodon/containers/scroll_container'; import LoadingIndicator from 'mastodon/components/loading_indicator'; -import { title } from 'mastodon/initial_state'; import { Helmet } from 'react-helmet'; const messages = defineMessages({ @@ -169,7 +168,8 @@ class Directory extends React.PureComponent { {multiColumn && !pinned ? <ScrollContainer scrollKey='directory'>{scrollableArea}</ScrollContainer> : scrollableArea} <Helmet> - <title>{intl.formatMessage(messages.title)} - {title}</title> + <title>{intl.formatMessage(messages.title)}</title> + <meta name='robots' content='noindex' /> </Helmet> </Column> ); diff --git a/app/javascript/mastodon/features/domain_blocks/index.js b/app/javascript/mastodon/features/domain_blocks/index.js index edb80aef4..43b275c2d 100644 --- a/app/javascript/mastodon/features/domain_blocks/index.js +++ b/app/javascript/mastodon/features/domain_blocks/index.js @@ -11,6 +11,7 @@ import ColumnBackButtonSlim from '../../components/column_back_button_slim'; import DomainContainer from '../../containers/domain_container'; import { fetchDomainBlocks, expandDomainBlocks } from '../../actions/domain_blocks'; import ScrollableList from '../../components/scrollable_list'; +import { Helmet } from 'react-helmet'; const messages = defineMessages({ heading: { id: 'column.domain_blocks', defaultMessage: 'Blocked domains' }, @@ -59,6 +60,7 @@ class Blocks extends ImmutablePureComponent { return ( <Column bindToDocument={!multiColumn} icon='minus-circle' heading={intl.formatMessage(messages.heading)}> <ColumnBackButtonSlim /> + <ScrollableList scrollKey='domain_blocks' onLoadMore={this.handleLoadMore} @@ -70,6 +72,10 @@ class Blocks extends ImmutablePureComponent { <DomainContainer key={domain} domain={domain} />, )} </ScrollableList> + + <Helmet> + <meta name='robots' content='noindex' /> + </Helmet> </Column> ); } diff --git a/app/javascript/mastodon/features/explore/index.js b/app/javascript/mastodon/features/explore/index.js index e1d1eb563..552def142 100644 --- a/app/javascript/mastodon/features/explore/index.js +++ b/app/javascript/mastodon/features/explore/index.js @@ -12,7 +12,7 @@ import Suggestions from './suggestions'; import Search from 'mastodon/features/compose/containers/search_container'; import SearchResults from './results'; import { Helmet } from 'react-helmet'; -import { title } from 'mastodon/initial_state'; +import { showTrends } from 'mastodon/initial_state'; const messages = defineMessages({ title: { id: 'explore.title', defaultMessage: 'Explore' }, @@ -21,7 +21,7 @@ const messages = defineMessages({ const mapStateToProps = state => ({ layout: state.getIn(['meta', 'layout']), - isSearching: state.getIn(['search', 'submitted']), + isSearching: state.getIn(['search', 'submitted']) || !showTrends, }); export default @connect(mapStateToProps) @@ -30,13 +30,13 @@ class Explore extends React.PureComponent { static contextTypes = { router: PropTypes.object, + identity: PropTypes.object, }; static propTypes = { intl: PropTypes.object.isRequired, multiColumn: PropTypes.bool, isSearching: PropTypes.bool, - layout: PropTypes.string, }; handleHeaderClick = () => { @@ -48,22 +48,21 @@ class Explore extends React.PureComponent { } render () { - const { intl, multiColumn, isSearching, layout } = this.props; + const { intl, multiColumn, isSearching } = this.props; + const { signedIn } = this.context.identity; return ( <Column bindToDocument={!multiColumn} ref={this.setRef} label={intl.formatMessage(messages.title)}> - {layout === 'mobile' ? ( - <div className='explore__search-header'> - <Search /> - </div> - ) : ( - <ColumnHeader - icon={isSearching ? 'search' : 'hashtag'} - title={intl.formatMessage(isSearching ? messages.searchResults : messages.title)} - onClick={this.handleHeaderClick} - multiColumn={multiColumn} - /> - )} + <ColumnHeader + icon={isSearching ? 'search' : 'hashtag'} + title={intl.formatMessage(isSearching ? messages.searchResults : messages.title)} + onClick={this.handleHeaderClick} + multiColumn={multiColumn} + /> + + <div className='explore__search-header'> + <Search /> + </div> <div className='scrollable scrollable--flex'> {isSearching ? ( @@ -74,7 +73,7 @@ class Explore extends React.PureComponent { <NavLink exact to='/explore'><FormattedMessage id='explore.trending_statuses' defaultMessage='Posts' /></NavLink> <NavLink exact to='/explore/tags'><FormattedMessage id='explore.trending_tags' defaultMessage='Hashtags' /></NavLink> <NavLink exact to='/explore/links'><FormattedMessage id='explore.trending_links' defaultMessage='News' /></NavLink> - <NavLink exact to='/explore/suggestions'><FormattedMessage id='explore.suggested_follows' defaultMessage='For you' /></NavLink> + {signedIn && <NavLink exact to='/explore/suggestions'><FormattedMessage id='explore.suggested_follows' defaultMessage='For you' /></NavLink>} </div> <Switch> @@ -85,7 +84,8 @@ class Explore extends React.PureComponent { </Switch> <Helmet> - <title>{intl.formatMessage(messages.title)} - {title}</title> + <title>{intl.formatMessage(messages.title)}</title> + <meta name='robots' content={isSearching ? 'noindex' : 'all'} /> </Helmet> </React.Fragment> )} diff --git a/app/javascript/mastodon/features/explore/links.js b/app/javascript/mastodon/features/explore/links.js index d3aaa9cdd..b47fc8fcf 100644 --- a/app/javascript/mastodon/features/explore/links.js +++ b/app/javascript/mastodon/features/explore/links.js @@ -6,6 +6,7 @@ import LoadingIndicator from 'mastodon/components/loading_indicator'; import { connect } from 'react-redux'; import { fetchTrendingLinks } from 'mastodon/actions/trends'; import { FormattedMessage } from 'react-intl'; +import DismissableBanner from 'mastodon/components/dismissable_banner'; const mapStateToProps = state => ({ links: state.getIn(['trends', 'links', 'items']), @@ -29,9 +30,17 @@ class Links extends React.PureComponent { render () { const { isLoading, links } = this.props; + const banner = ( + <DismissableBanner id='explore/links'> + <FormattedMessage id='dismissable_banner.explore_links' defaultMessage='These news stories are being talked about by people on this and other servers of the decentralized network right now.' /> + </DismissableBanner> + ); + if (!isLoading && links.isEmpty()) { return ( <div className='explore__links scrollable scrollable--flex'> + {banner} + <div className='empty-column-indicator'> <FormattedMessage id='empty_column.explore_statuses' defaultMessage='Nothing is trending right now. Check back later!' /> </div> @@ -41,6 +50,8 @@ class Links extends React.PureComponent { return ( <div className='explore__links'> + {banner} + {isLoading ? (<LoadingIndicator />) : links.map(link => ( <Story key={link.get('id')} diff --git a/app/javascript/mastodon/features/explore/results.js b/app/javascript/mastodon/features/explore/results.js index 0dc108918..b2f6c72b7 100644 --- a/app/javascript/mastodon/features/explore/results.js +++ b/app/javascript/mastodon/features/explore/results.js @@ -10,7 +10,6 @@ import { ImmutableHashtag as Hashtag } from 'mastodon/components/hashtag'; import { List as ImmutableList } from 'immutable'; import LoadMore from 'mastodon/components/load_more'; import LoadingIndicator from 'mastodon/components/loading_indicator'; -import { title } from 'mastodon/initial_state'; import { Helmet } from 'react-helmet'; const messages = defineMessages({ @@ -118,7 +117,7 @@ class Results extends React.PureComponent { </div> <Helmet> - <title>{intl.formatMessage(messages.title, { q })} - {title}</title> + <title>{intl.formatMessage(messages.title, { q })}</title> </Helmet> </React.Fragment> ); diff --git a/app/javascript/mastodon/features/explore/statuses.js b/app/javascript/mastodon/features/explore/statuses.js index 33e5b4179..791f11b9f 100644 --- a/app/javascript/mastodon/features/explore/statuses.js +++ b/app/javascript/mastodon/features/explore/statuses.js @@ -6,6 +6,7 @@ import { FormattedMessage } from 'react-intl'; import { connect } from 'react-redux'; import { fetchTrendingStatuses, expandTrendingStatuses } from 'mastodon/actions/trends'; import { debounce } from 'lodash'; +import DismissableBanner from 'mastodon/components/dismissable_banner'; const mapStateToProps = state => ({ statusIds: state.getIn(['status_lists', 'trending', 'items']), @@ -40,17 +41,23 @@ class Statuses extends React.PureComponent { const emptyMessage = <FormattedMessage id='empty_column.explore_statuses' defaultMessage='Nothing is trending right now. Check back later!' />; return ( - <StatusList - trackScroll - statusIds={statusIds} - scrollKey='explore-statuses' - hasMore={hasMore} - isLoading={isLoading} - onLoadMore={this.handleLoadMore} - emptyMessage={emptyMessage} - bindToDocument={!multiColumn} - withCounters - /> + <> + <DismissableBanner id='explore/statuses'> + <FormattedMessage id='dismissable_banner.explore_statuses' defaultMessage='These posts from this and other servers in the decentralized network are gaining traction on this server right now.' /> + </DismissableBanner> + + <StatusList + trackScroll + statusIds={statusIds} + scrollKey='explore-statuses' + hasMore={hasMore} + isLoading={isLoading} + onLoadMore={this.handleLoadMore} + emptyMessage={emptyMessage} + bindToDocument={!multiColumn} + withCounters + /> + </> ); } diff --git a/app/javascript/mastodon/features/explore/tags.js b/app/javascript/mastodon/features/explore/tags.js index 6cd3a6fb1..258dc392f 100644 --- a/app/javascript/mastodon/features/explore/tags.js +++ b/app/javascript/mastodon/features/explore/tags.js @@ -6,6 +6,7 @@ import LoadingIndicator from 'mastodon/components/loading_indicator'; import { connect } from 'react-redux'; import { fetchTrendingHashtags } from 'mastodon/actions/trends'; import { FormattedMessage } from 'react-intl'; +import DismissableBanner from 'mastodon/components/dismissable_banner'; const mapStateToProps = state => ({ hashtags: state.getIn(['trends', 'tags', 'items']), @@ -29,9 +30,17 @@ class Tags extends React.PureComponent { render () { const { isLoading, hashtags } = this.props; + const banner = ( + <DismissableBanner id='explore/tags'> + <FormattedMessage id='dismissable_banner.explore_tags' defaultMessage='These hashtags are gaining traction among people on this and other servers of the decentralized network right now.' /> + </DismissableBanner> + ); + if (!isLoading && hashtags.isEmpty()) { return ( <div className='explore__links scrollable scrollable--flex'> + {banner} + <div className='empty-column-indicator'> <FormattedMessage id='empty_column.explore_statuses' defaultMessage='Nothing is trending right now. Check back later!' /> </div> @@ -41,6 +50,8 @@ class Tags extends React.PureComponent { return ( <div className='explore__links'> + {banner} + {isLoading ? (<LoadingIndicator />) : hashtags.map(hashtag => ( <Hashtag key={hashtag.get('name')} hashtag={hashtag} /> ))} diff --git a/app/javascript/mastodon/features/favourited_statuses/index.js b/app/javascript/mastodon/features/favourited_statuses/index.js index 73631946a..3741f68f6 100644 --- a/app/javascript/mastodon/features/favourited_statuses/index.js +++ b/app/javascript/mastodon/features/favourited_statuses/index.js @@ -1,15 +1,16 @@ -import React from 'react'; -import { connect } from 'react-redux'; +import { debounce } from 'lodash'; import PropTypes from 'prop-types'; +import React from 'react'; +import { Helmet } from 'react-helmet'; import ImmutablePropTypes from 'react-immutable-proptypes'; -import { fetchFavouritedStatuses, expandFavouritedStatuses } from '../../actions/favourites'; -import Column from '../ui/components/column'; -import ColumnHeader from '../../components/column_header'; -import { addColumn, removeColumn, moveColumn } from '../../actions/columns'; -import StatusList from '../../components/status_list'; -import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import ImmutablePureComponent from 'react-immutable-pure-component'; -import { debounce } from 'lodash'; +import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; +import { connect } from 'react-redux'; +import { addColumn, removeColumn, moveColumn } from 'mastodon/actions/columns'; +import { fetchFavouritedStatuses, expandFavouritedStatuses } from 'mastodon/actions/favourites'; +import ColumnHeader from 'mastodon/components/column_header'; +import StatusList from 'mastodon/components/status_list'; +import Column from 'mastodon/features/ui/components/column'; const messages = defineMessages({ heading: { id: 'column.favourites', defaultMessage: 'Favourites' }, @@ -95,6 +96,11 @@ class Favourites extends ImmutablePureComponent { emptyMessage={emptyMessage} bindToDocument={!multiColumn} /> + + <Helmet> + <title>{intl.formatMessage(messages.heading)}</title> + <meta name='robots' content='noindex' /> + </Helmet> </Column> ); } diff --git a/app/javascript/mastodon/features/favourites/index.js b/app/javascript/mastodon/features/favourites/index.js index f060068a4..ad10744da 100644 --- a/app/javascript/mastodon/features/favourites/index.js +++ b/app/javascript/mastodon/features/favourites/index.js @@ -1,16 +1,17 @@ +import PropTypes from 'prop-types'; import React from 'react'; -import { connect } from 'react-redux'; import ImmutablePureComponent from 'react-immutable-pure-component'; -import PropTypes from 'prop-types'; import ImmutablePropTypes from 'react-immutable-proptypes'; -import LoadingIndicator from '../../components/loading_indicator'; -import { fetchFavourites } from '../../actions/interactions'; import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; -import AccountContainer from '../../containers/account_container'; -import Column from '../ui/components/column'; -import ScrollableList from '../../components/scrollable_list'; +import { connect } from 'react-redux'; +import ColumnHeader from 'mastodon/components/column_header'; import Icon from 'mastodon/components/icon'; -import ColumnHeader from '../../components/column_header'; +import { fetchFavourites } from 'mastodon/actions/interactions'; +import LoadingIndicator from 'mastodon/components/loading_indicator'; +import ScrollableList from 'mastodon/components/scrollable_list'; +import AccountContainer from 'mastodon/containers/account_container'; +import Column from 'mastodon/features/ui/components/column'; +import { Helmet } from 'react-helmet'; const messages = defineMessages({ refresh: { id: 'refresh', defaultMessage: 'Refresh' }, @@ -80,6 +81,10 @@ class Favourites extends ImmutablePureComponent { <AccountContainer key={id} id={id} withNote={false} />, )} </ScrollableList> + + <Helmet> + <meta name='robots' content='noindex' /> + </Helmet> </Column> ); } diff --git a/app/javascript/mastodon/features/follow_recommendations/index.js b/app/javascript/mastodon/features/follow_recommendations/index.js index 32b55eeb3..5f7baa64c 100644 --- a/app/javascript/mastodon/features/follow_recommendations/index.js +++ b/app/javascript/mastodon/features/follow_recommendations/index.js @@ -12,6 +12,7 @@ import Column from 'mastodon/features/ui/components/column'; import Account from './components/account'; import imageGreeting from 'mastodon/../images/elephant_ui_greeting.svg'; import Button from 'mastodon/components/button'; +import { Helmet } from 'react-helmet'; const mapStateToProps = state => ({ suggestions: state.getIn(['suggestions', 'items']), @@ -104,6 +105,10 @@ class FollowRecommendations extends ImmutablePureComponent { </React.Fragment> )} </div> + + <Helmet> + <meta name='robots' content='noindex' /> + </Helmet> </Column> ); } diff --git a/app/javascript/mastodon/features/follow_requests/index.js b/app/javascript/mastodon/features/follow_requests/index.js index 1f9b635bb..d16aa7737 100644 --- a/app/javascript/mastodon/features/follow_requests/index.js +++ b/app/javascript/mastodon/features/follow_requests/index.js @@ -12,6 +12,7 @@ import AccountAuthorizeContainer from './containers/account_authorize_container' import { fetchFollowRequests, expandFollowRequests } from '../../actions/accounts'; import ScrollableList from '../../components/scrollable_list'; import { me } from '../../initial_state'; +import { Helmet } from 'react-helmet'; const messages = defineMessages({ heading: { id: 'column.follow_requests', defaultMessage: 'Follow requests' }, @@ -87,6 +88,10 @@ class FollowRequests extends ImmutablePureComponent { <AccountAuthorizeContainer key={id} id={id} />, )} </ScrollableList> + + <Helmet> + <meta name='robots' content='noindex' /> + </Helmet> </Column> ); } diff --git a/app/javascript/mastodon/features/followers/index.js b/app/javascript/mastodon/features/followers/index.js index 5b7f402f8..277eb702f 100644 --- a/app/javascript/mastodon/features/followers/index.js +++ b/app/javascript/mastodon/features/followers/index.js @@ -21,9 +21,10 @@ import MissingIndicator from 'mastodon/components/missing_indicator'; import TimelineHint from 'mastodon/components/timeline_hint'; import LimitedAccountHint from '../account_timeline/components/limited_account_hint'; import { getAccountHidden } from 'mastodon/selectors'; +import { normalizeForLookup } from 'mastodon/reducers/accounts_map'; const mapStateToProps = (state, { params: { acct, id } }) => { - const accountId = id || state.getIn(['accounts_map', acct]); + const accountId = id || state.getIn(['accounts_map', normalizeForLookup(acct)]); if (!accountId) { return { diff --git a/app/javascript/mastodon/features/following/index.js b/app/javascript/mastodon/features/following/index.js index 143082d76..e23d9b35c 100644 --- a/app/javascript/mastodon/features/following/index.js +++ b/app/javascript/mastodon/features/following/index.js @@ -21,9 +21,10 @@ import MissingIndicator from 'mastodon/components/missing_indicator'; import TimelineHint from 'mastodon/components/timeline_hint'; import LimitedAccountHint from '../account_timeline/components/limited_account_hint'; import { getAccountHidden } from 'mastodon/selectors'; +import { normalizeForLookup } from 'mastodon/reducers/accounts_map'; const mapStateToProps = (state, { params: { acct, id } }) => { - const accountId = id || state.getIn(['accounts_map', acct]); + const accountId = id || state.getIn(['accounts_map', normalizeForLookup(acct)]); if (!accountId) { return { diff --git a/app/javascript/mastodon/features/getting_started/index.js b/app/javascript/mastodon/features/getting_started/index.js index 65cee7498..fc91070d1 100644 --- a/app/javascript/mastodon/features/getting_started/index.js +++ b/app/javascript/mastodon/features/getting_started/index.js @@ -1,8 +1,9 @@ import React from 'react'; -import Column from '../ui/components/column'; +import Column from 'mastodon/components/column'; +import ColumnHeader from 'mastodon/components/column_header'; import ColumnLink from '../ui/components/column_link'; import ColumnSubheading from '../ui/components/column_subheading'; -import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; +import { defineMessages, injectIntl } from 'react-intl'; import { connect } from 'react-redux'; import PropTypes from 'prop-types'; import ImmutablePropTypes from 'react-immutable-proptypes'; @@ -11,9 +12,9 @@ import { me, showTrends } from '../../initial_state'; import { fetchFollowRequests } from 'mastodon/actions/accounts'; import { List as ImmutableList } from 'immutable'; import NavigationContainer from '../compose/containers/navigation_container'; -import Icon from 'mastodon/components/icon'; import LinkFooter from 'mastodon/features/ui/components/link_footer'; import TrendsContainer from './containers/trends_container'; +import { Helmet } from 'react-helmet'; const messages = defineMessages({ home_timeline: { id: 'tabs_bar.home', defaultMessage: 'Home' }, @@ -40,7 +41,6 @@ const messages = defineMessages({ const mapStateToProps = state => ({ myAccount: state.getIn(['accounts', me]), - columns: state.getIn(['settings', 'columns']), unreadFollowRequests: state.getIn(['user_lists', 'follow_requests', 'items'], ImmutableList()).size, }); @@ -58,20 +58,18 @@ const badgeDisplay = (number, limit) => { } }; -const NAVIGATION_PANEL_BREAKPOINT = 600 + (285 * 2) + (10 * 2); - export default @connect(mapStateToProps, mapDispatchToProps) @injectIntl class GettingStarted extends ImmutablePureComponent { static contextTypes = { router: PropTypes.object.isRequired, + identity: PropTypes.object, }; static propTypes = { intl: PropTypes.object.isRequired, - myAccount: ImmutablePropTypes.map.isRequired, - columns: ImmutablePropTypes.list, + myAccount: ImmutablePropTypes.map, multiColumn: PropTypes.bool, fetchFollowRequests: PropTypes.func.isRequired, unreadFollowRequests: PropTypes.number, @@ -79,10 +77,10 @@ class GettingStarted extends ImmutablePureComponent { }; componentDidMount () { - const { fetchFollowRequests, multiColumn } = this.props; + const { fetchFollowRequests } = this.props; + const { signedIn } = this.context.identity; - if (!multiColumn && window.innerWidth >= NAVIGATION_PANEL_BREAKPOINT) { - this.context.router.history.replace('/home'); + if (!signedIn) { return; } @@ -90,91 +88,66 @@ class GettingStarted extends ImmutablePureComponent { } render () { - const { intl, myAccount, columns, multiColumn, unreadFollowRequests } = this.props; + const { intl, myAccount, multiColumn, unreadFollowRequests } = this.props; + const { signedIn } = this.context.identity; const navItems = []; - let height = (multiColumn) ? 0 : 60; - - if (multiColumn) { - navItems.push( - <ColumnSubheading key='header-discover' text={intl.formatMessage(messages.discover)} />, - ); - height += 34; - } navItems.push( - <ColumnLink key='explore' icon='hashtag' text={intl.formatMessage(messages.explore)} to='/explore' />, + <ColumnSubheading key='header-discover' text={intl.formatMessage(messages.discover)} />, ); - height += 48; - if (multiColumn) { + if (showTrends) { navItems.push( - <ColumnLink key='community_timeline' icon='users' text={intl.formatMessage(messages.community_timeline)} to='/public/local' />, - <ColumnLink key='public_timeline' icon='globe' text={intl.formatMessage(messages.public_timeline)} to='/public' />, + <ColumnLink key='explore' icon='hashtag' text={intl.formatMessage(messages.explore)} to='/explore' />, ); + } - height += 48*2; + navItems.push( + <ColumnLink key='community_timeline' icon='users' text={intl.formatMessage(messages.community_timeline)} to='/public/local' />, + <ColumnLink key='public_timeline' icon='globe' text={intl.formatMessage(messages.public_timeline)} to='/public' />, + ); + if (signedIn) { navItems.push( <ColumnSubheading key='header-personal' text={intl.formatMessage(messages.personal)} />, - ); - - height += 34; - } - - if (multiColumn && !columns.find(item => item.get('id') === 'HOME')) { - navItems.push( <ColumnLink key='home' icon='home' text={intl.formatMessage(messages.home_timeline)} to='/home' />, + <ColumnLink key='direct' icon='at' text={intl.formatMessage(messages.direct)} to='/conversations' />, + <ColumnLink key='bookmark' icon='bookmark' text={intl.formatMessage(messages.bookmarks)} to='/bookmarks' />, + <ColumnLink key='favourites' icon='star' text={intl.formatMessage(messages.favourites)} to='/favourites' />, + <ColumnLink key='lists' icon='list-ul' text={intl.formatMessage(messages.lists)} to='/lists' />, ); - height += 48; - } - - navItems.push( - <ColumnLink key='direct' icon='at' text={intl.formatMessage(messages.direct)} to='/conversations' />, - <ColumnLink key='bookmark' icon='bookmark' text={intl.formatMessage(messages.bookmarks)} to='/bookmarks' />, - <ColumnLink key='favourites' icon='star' text={intl.formatMessage(messages.favourites)} to='/favourites' />, - <ColumnLink key='lists' icon='list-ul' text={intl.formatMessage(messages.lists)} to='/lists' />, - ); - height += 48*4; + if (myAccount.get('locked') || unreadFollowRequests > 0) { + navItems.push(<ColumnLink key='follow_requests' icon='user-plus' text={intl.formatMessage(messages.follow_requests)} badge={badgeDisplay(unreadFollowRequests, 40)} to='/follow_requests' />); + } - if (myAccount.get('locked') || unreadFollowRequests > 0) { - navItems.push(<ColumnLink key='follow_requests' icon='user-plus' text={intl.formatMessage(messages.follow_requests)} badge={badgeDisplay(unreadFollowRequests, 40)} to='/follow_requests' />); - height += 48; - } - - if (!multiColumn) { navItems.push( <ColumnSubheading key='header-settings' text={intl.formatMessage(messages.settings_subheading)} />, <ColumnLink key='preferences' icon='gears' text={intl.formatMessage(messages.preferences)} href='/settings/preferences' />, ); - - height += 34 + 48; } return ( - <Column bindToDocument={!multiColumn} label={intl.formatMessage(messages.menu)}> - {multiColumn && <div className='column-header__wrapper'> - <h1 className='column-header'> - <button> - <Icon id='bars' className='column-header__icon' fixedWidth /> - <FormattedMessage id='getting_started.heading' defaultMessage='Getting started' /> - </button> - </h1> - </div>} - - <div className='getting-started'> - <div className='getting-started__wrapper' style={{ height }}> - {!multiColumn && <NavigationContainer />} + <Column> + {(signedIn && !multiColumn) ? <NavigationContainer /> : <ColumnHeader title={intl.formatMessage(messages.menu)} icon='bars' multiColumn={multiColumn} />} + + <div className='getting-started scrollable scrollable--flex'> + <div className='getting-started__wrapper'> {navItems} </div> {!multiColumn && <div className='flex-spacer' />} - <LinkFooter withHotkeys={multiColumn} /> + <LinkFooter /> </div> - {multiColumn && showTrends && <TrendsContainer />} + {(multiColumn && showTrends) && <TrendsContainer />} + + <Helmet> + <title>{intl.formatMessage(messages.menu)}</title> + <meta name='robots' content='noindex' /> + </Helmet> </Column> ); } diff --git a/app/javascript/mastodon/features/hashtag_timeline/index.js b/app/javascript/mastodon/features/hashtag_timeline/index.js index 7069e0341..ec524be8f 100644 --- a/app/javascript/mastodon/features/hashtag_timeline/index.js +++ b/app/javascript/mastodon/features/hashtag_timeline/index.js @@ -14,7 +14,6 @@ import { isEqual } from 'lodash'; import { fetchHashtag, followHashtag, unfollowHashtag } from 'mastodon/actions/tags'; import Icon from 'mastodon/components/icon'; import classNames from 'classnames'; -import { title } from 'mastodon/initial_state'; import { Helmet } from 'react-helmet'; const messages = defineMessages({ @@ -96,6 +95,12 @@ class HashtagTimeline extends React.PureComponent { } _subscribe (dispatch, id, tags = {}, local) { + const { signedIn } = this.context.identity; + + if (!signedIn) { + return; + } + let any = (tags.any || []).map(tag => tag.value); let all = (tags.all || []).map(tag => tag.value); let none = (tags.none || []).map(tag => tag.value); @@ -222,7 +227,8 @@ class HashtagTimeline extends React.PureComponent { /> <Helmet> - <title>{`#${id}`} - {title}</title> + <title>#{id}</title> + <meta name='robots' content='noindex' /> </Helmet> </Column> ); diff --git a/app/javascript/mastodon/features/home_timeline/index.js b/app/javascript/mastodon/features/home_timeline/index.js index dc440f2fe..838ed7dd8 100644 --- a/app/javascript/mastodon/features/home_timeline/index.js +++ b/app/javascript/mastodon/features/home_timeline/index.js @@ -13,6 +13,8 @@ import { fetchAnnouncements, toggleShowAnnouncements } from 'mastodon/actions/an import AnnouncementsContainer from 'mastodon/features/getting_started/containers/announcements_container'; import classNames from 'classnames'; import IconWithBadge from 'mastodon/components/icon_with_badge'; +import NotSignedInIndicator from 'mastodon/components/not_signed_in_indicator'; +import { Helmet } from 'react-helmet'; const messages = defineMessages({ title: { id: 'column.home', defaultMessage: 'Home' }, @@ -32,6 +34,10 @@ export default @connect(mapStateToProps) @injectIntl class HomeTimeline extends React.PureComponent { + static contextTypes = { + identity: PropTypes.object, + }; + static propTypes = { dispatch: PropTypes.func.isRequired, intl: PropTypes.object.isRequired, @@ -113,6 +119,7 @@ class HomeTimeline extends React.PureComponent { render () { const { intl, hasUnread, columnId, multiColumn, hasAnnouncements, unreadAnnouncements, showAnnouncements } = this.props; const pinned = !!columnId; + const { signedIn } = this.context.identity; let announcementsButton = null; @@ -147,14 +154,21 @@ class HomeTimeline extends React.PureComponent { <ColumnSettingsContainer /> </ColumnHeader> - <StatusListContainer - trackScroll={!pinned} - scrollKey={`home_timeline-${columnId}`} - onLoadMore={this.handleLoadMore} - timelineId='home' - emptyMessage={<FormattedMessage id='empty_column.home' defaultMessage='Your home timeline is empty! Follow more people to fill it up. {suggestions}' values={{ suggestions: <Link to='/start'><FormattedMessage id='empty_column.home.suggestions' defaultMessage='See some suggestions' /></Link> }} />} - bindToDocument={!multiColumn} - /> + {signedIn ? ( + <StatusListContainer + trackScroll={!pinned} + scrollKey={`home_timeline-${columnId}`} + onLoadMore={this.handleLoadMore} + timelineId='home' + emptyMessage={<FormattedMessage id='empty_column.home' defaultMessage='Your home timeline is empty! Follow more people to fill it up. {suggestions}' values={{ suggestions: <Link to='/start'><FormattedMessage id='empty_column.home.suggestions' defaultMessage='See some suggestions' /></Link> }} />} + bindToDocument={!multiColumn} + /> + ) : <NotSignedInIndicator />} + + <Helmet> + <title>{intl.formatMessage(messages.title)}</title> + <meta name='robots' content='noindex' /> + </Helmet> </Column> ); } diff --git a/app/javascript/mastodon/features/interaction_modal/index.js b/app/javascript/mastodon/features/interaction_modal/index.js new file mode 100644 index 000000000..9f7747903 --- /dev/null +++ b/app/javascript/mastodon/features/interaction_modal/index.js @@ -0,0 +1,161 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { FormattedMessage } from 'react-intl'; +import { registrationsOpen } from 'mastodon/initial_state'; +import { connect } from 'react-redux'; +import Icon from 'mastodon/components/icon'; +import classNames from 'classnames'; +import { openModal, closeModal } from 'mastodon/actions/modal'; + +const mapStateToProps = (state, { accountId }) => ({ + displayNameHtml: state.getIn(['accounts', accountId, 'display_name_html']), +}); + +const mapDispatchToProps = (dispatch) => ({ + onSignupClick() { + dispatch(closeModal()); + dispatch(openModal('CLOSED_REGISTRATIONS')); + }, +}); + +class Copypaste extends React.PureComponent { + + static propTypes = { + value: PropTypes.string, + }; + + state = { + copied: false, + }; + + setRef = c => { + this.input = c; + } + + handleInputClick = () => { + this.setState({ copied: false }); + this.input.focus(); + this.input.select(); + this.input.setSelectionRange(0, this.input.value.length); + } + + handleButtonClick = () => { + const { value } = this.props; + navigator.clipboard.writeText(value); + this.input.blur(); + this.setState({ copied: true }); + this.timeout = setTimeout(() => this.setState({ copied: false }), 700); + } + + componentWillUnmount () { + if (this.timeout) clearTimeout(this.timeout); + } + + render () { + const { value } = this.props; + const { copied } = this.state; + + return ( + <div className={classNames('copypaste', { copied })}> + <input + type='text' + ref={this.setRef} + value={value} + readOnly + onClick={this.handleInputClick} + /> + + <button className='button' onClick={this.handleButtonClick}> + {copied ? <FormattedMessage id='copypaste.copied' defaultMessage='Copied' /> : <FormattedMessage id='copypaste.copy' defaultMessage='Copy' />} + </button> + </div> + ); + } + +} + +export default @connect(mapStateToProps, mapDispatchToProps) +class InteractionModal extends React.PureComponent { + + static propTypes = { + displayNameHtml: PropTypes.string, + url: PropTypes.string, + type: PropTypes.oneOf(['reply', 'reblog', 'favourite', 'follow']), + onSignupClick: PropTypes.func.isRequired, + }; + + handleSignupClick = () => { + this.props.onSignupClick(); + } + + render () { + const { url, type, displayNameHtml } = this.props; + + const name = <bdi dangerouslySetInnerHTML={{ __html: displayNameHtml }} />; + + let title, actionDescription, icon; + + switch(type) { + case 'reply': + icon = <Icon id='reply' />; + title = <FormattedMessage id='interaction_modal.title.reply' defaultMessage="Reply to {name}'s post" values={{ name }} />; + actionDescription = <FormattedMessage id='interaction_modal.description.reply' defaultMessage='With an account on Mastodon, you can respond to this post.' />; + break; + case 'reblog': + icon = <Icon id='retweet' />; + title = <FormattedMessage id='interaction_modal.title.reblog' defaultMessage="Boost {name}'s post" values={{ name }} />; + actionDescription = <FormattedMessage id='interaction_modal.description.reblog' defaultMessage='With an account on Mastodon, you can boost this post to share it with your own followers.' />; + break; + case 'favourite': + icon = <Icon id='star' />; + title = <FormattedMessage id='interaction_modal.title.favourite' defaultMessage="Favourite {name}'s post" values={{ name }} />; + actionDescription = <FormattedMessage id='interaction_modal.description.favourite' defaultMessage='With an account on Mastodon, you can favourite this post to let the author know you appreciate it and save it for later.' />; + break; + case 'follow': + icon = <Icon id='user-plus' />; + title = <FormattedMessage id='interaction_modal.title.follow' defaultMessage='Follow {name}' values={{ name }} />; + actionDescription = <FormattedMessage id='interaction_modal.description.follow' defaultMessage='With an account on Mastodon, you can follow {name} to receive their posts in your home feed.' values={{ name }} />; + break; + } + + let signupButton; + + if (registrationsOpen) { + signupButton = ( + <a href='/auth/sign_up' className='button button--block button-tertiary'> + <FormattedMessage id='sign_in_banner.create_account' defaultMessage='Create account' /> + </a> + ); + } else { + signupButton = ( + <button className='button button--block button-tertiary' onClick={this.handleSignupClick}> + <FormattedMessage id='sign_in_banner.create_account' defaultMessage='Create account' /> + </button> + ); + } + + return ( + <div className='modal-root__modal interaction-modal'> + <div className='interaction-modal__lead'> + <h3><span className='interaction-modal__icon'>{icon}</span> {title}</h3> + <p>{actionDescription} <FormattedMessage id='interaction_modal.preamble' defaultMessage="Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one." /></p> + </div> + + <div className='interaction-modal__choices'> + <div className='interaction-modal__choices__choice'> + <h3><FormattedMessage id='interaction_modal.on_this_server' defaultMessage='On this server' /></h3> + <a href='/auth/sign_in' className='button button--block'><FormattedMessage id='sign_in_banner.sign_in' defaultMessage='Sign in' /></a> + {signupButton} + </div> + + <div className='interaction-modal__choices__choice'> + <h3><FormattedMessage id='interaction_modal.on_another_server' defaultMessage='On a different server' /></h3> + <p><FormattedMessage id='interaction_modal.other_server_instructions' defaultMessage='Simply copy and paste this URL into the search bar of your favourite app or the web interface where you are signed in.' /></p> + <Copypaste value={url} /> + </div> + </div> + </div> + ); + } + +} diff --git a/app/javascript/mastodon/features/keyboard_shortcuts/index.js b/app/javascript/mastodon/features/keyboard_shortcuts/index.js index 8f1631d82..9a870478d 100644 --- a/app/javascript/mastodon/features/keyboard_shortcuts/index.js +++ b/app/javascript/mastodon/features/keyboard_shortcuts/index.js @@ -1,9 +1,10 @@ import React from 'react'; -import Column from '../ui/components/column'; -import ColumnBackButtonSlim from '../../components/column_back_button_slim'; +import Column from 'mastodon/components/column'; import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import PropTypes from 'prop-types'; import ImmutablePureComponent from 'react-immutable-pure-component'; +import ColumnHeader from 'mastodon/components/column_header'; +import { Helmet } from 'react-helmet'; const messages = defineMessages({ heading: { id: 'keyboard_shortcuts.heading', defaultMessage: 'Keyboard Shortcuts' }, @@ -21,8 +22,13 @@ class KeyboardShortcuts extends ImmutablePureComponent { const { intl, multiColumn } = this.props; return ( - <Column bindToDocument={!multiColumn} icon='question' heading={intl.formatMessage(messages.heading)}> - <ColumnBackButtonSlim /> + <Column> + <ColumnHeader + title={intl.formatMessage(messages.heading)} + icon='question' + multiColumn={multiColumn} + /> + <div className='keyboard-shortcuts scrollable optionally-scrollable'> <table> <thead> @@ -159,6 +165,10 @@ class KeyboardShortcuts extends ImmutablePureComponent { </tbody> </table> </div> + + <Helmet> + <meta name='robots' content='noindex' /> + </Helmet> </Column> ); } diff --git a/app/javascript/mastodon/features/list_timeline/index.js b/app/javascript/mastodon/features/list_timeline/index.js index 8010274f8..fd9d33df7 100644 --- a/app/javascript/mastodon/features/list_timeline/index.js +++ b/app/javascript/mastodon/features/list_timeline/index.js @@ -1,21 +1,22 @@ -import React from 'react'; -import { connect } from 'react-redux'; import PropTypes from 'prop-types'; +import React from 'react'; +import { Helmet } from 'react-helmet'; import ImmutablePropTypes from 'react-immutable-proptypes'; -import StatusListContainer from '../ui/containers/status_list_container'; -import Column from '../../components/column'; -import ColumnBackButton from '../../components/column_back_button'; -import ColumnHeader from '../../components/column_header'; -import { addColumn, removeColumn, moveColumn } from '../../actions/columns'; import { FormattedMessage, defineMessages, injectIntl } from 'react-intl'; -import { connectListStream } from '../../actions/streaming'; -import { expandListTimeline } from '../../actions/timelines'; -import { fetchList, deleteList, updateList } from '../../actions/lists'; -import { openModal } from '../../actions/modal'; -import MissingIndicator from '../../components/missing_indicator'; -import LoadingIndicator from '../../components/loading_indicator'; +import { connect } from 'react-redux'; +import { addColumn, removeColumn, moveColumn } from 'mastodon/actions/columns'; +import { fetchList, deleteList, updateList } from 'mastodon/actions/lists'; +import { openModal } from 'mastodon/actions/modal'; +import { connectListStream } from 'mastodon/actions/streaming'; +import { expandListTimeline } from 'mastodon/actions/timelines'; +import Column from 'mastodon/components/column'; +import ColumnBackButton from 'mastodon/components/column_back_button'; +import ColumnHeader from 'mastodon/components/column_header'; import Icon from 'mastodon/components/icon'; +import LoadingIndicator from 'mastodon/components/loading_indicator'; +import MissingIndicator from 'mastodon/components/missing_indicator'; import RadioButton from 'mastodon/components/radio_button'; +import StatusListContainer from 'mastodon/features/ui/containers/status_list_container'; const messages = defineMessages({ deleteMessage: { id: 'confirmations.delete_list.message', defaultMessage: 'Are you sure you want to permanently delete this list?' }, @@ -208,6 +209,11 @@ class ListTimeline extends React.PureComponent { 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.' />} bindToDocument={!multiColumn} /> + + <Helmet> + <title>{title}</title> + <meta name='robots' content='noindex' /> + </Helmet> </Column> ); } diff --git a/app/javascript/mastodon/features/lists/index.js b/app/javascript/mastodon/features/lists/index.js index 809d79d99..017595ba0 100644 --- a/app/javascript/mastodon/features/lists/index.js +++ b/app/javascript/mastodon/features/lists/index.js @@ -1,18 +1,19 @@ -import React from 'react'; -import { connect } from 'react-redux'; import PropTypes from 'prop-types'; +import React from 'react'; +import { Helmet } from 'react-helmet'; import ImmutablePropTypes from 'react-immutable-proptypes'; -import LoadingIndicator from '../../components/loading_indicator'; -import Column from '../ui/components/column'; -import ColumnBackButtonSlim from '../../components/column_back_button_slim'; -import { fetchLists } from '../../actions/lists'; -import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import ImmutablePureComponent from 'react-immutable-pure-component'; -import ColumnLink from '../ui/components/column_link'; -import ColumnSubheading from '../ui/components/column_subheading'; -import NewListForm from './components/new_list_form'; +import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; +import { connect } from 'react-redux'; import { createSelector } from 'reselect'; -import ScrollableList from '../../components/scrollable_list'; +import { fetchLists } from 'mastodon/actions/lists'; +import ColumnBackButtonSlim from 'mastodon/components/column_back_button_slim'; +import LoadingIndicator from 'mastodon/components/loading_indicator'; +import ScrollableList from 'mastodon/components/scrollable_list'; +import Column from 'mastodon/features/ui/components/column'; +import ColumnLink from 'mastodon/features/ui/components/column_link'; +import ColumnSubheading from 'mastodon/features/ui/components/column_subheading'; +import NewListForm from './components/new_list_form'; const messages = defineMessages({ heading: { id: 'column.lists', defaultMessage: 'Lists' }, @@ -76,6 +77,11 @@ class Lists extends ImmutablePureComponent { <ColumnLink key={list.get('id')} to={`/lists/${list.get('id')}`} icon='list-ul' text={list.get('title')} />, )} </ScrollableList> + + <Helmet> + <title>{intl.formatMessage(messages.heading)}</title> + <meta name='robots' content='noindex' /> + </Helmet> </Column> ); } diff --git a/app/javascript/mastodon/features/mutes/index.js b/app/javascript/mastodon/features/mutes/index.js index c21433cc4..65df6149f 100644 --- a/app/javascript/mastodon/features/mutes/index.js +++ b/app/javascript/mastodon/features/mutes/index.js @@ -11,6 +11,7 @@ import ColumnBackButtonSlim from '../../components/column_back_button_slim'; import AccountContainer from '../../containers/account_container'; import { fetchMutes, expandMutes } from '../../actions/mutes'; import ScrollableList from '../../components/scrollable_list'; +import { Helmet } from 'react-helmet'; const messages = defineMessages({ heading: { id: 'column.mutes', defaultMessage: 'Muted users' }, @@ -72,6 +73,10 @@ class Mutes extends ImmutablePureComponent { <AccountContainer key={id} id={id} defaultAction='mute' />, )} </ScrollableList> + + <Helmet> + <meta name='robots' content='noindex' /> + </Helmet> </Column> ); } diff --git a/app/javascript/mastodon/features/notifications/components/column_settings.js b/app/javascript/mastodon/features/notifications/components/column_settings.js index b1618c1b4..d75fa8a02 100644 --- a/app/javascript/mastodon/features/notifications/components/column_settings.js +++ b/app/javascript/mastodon/features/notifications/components/column_settings.js @@ -170,7 +170,7 @@ export default class ColumnSettings extends React.PureComponent { </div> </div> - {(this.context.identity.permissions & PERMISSION_MANAGE_USERS === PERMISSION_MANAGE_USERS) && ( + {((this.context.identity.permissions & PERMISSION_MANAGE_USERS) === PERMISSION_MANAGE_USERS) && ( <div role='group' aria-labelledby='notifications-admin-sign-up'> <span id='notifications-status' className='column-settings__section'><FormattedMessage id='notifications.column_settings.admin.sign_up' defaultMessage='New sign-ups:' /></span> @@ -183,7 +183,7 @@ export default class ColumnSettings extends React.PureComponent { </div> )} - {(this.context.identity.permissions & PERMISSION_MANAGE_REPORTS === PERMISSION_MANAGE_REPORTS) && ( + {((this.context.identity.permissions & PERMISSION_MANAGE_REPORTS) === PERMISSION_MANAGE_REPORTS) && ( <div role='group' aria-labelledby='notifications-admin-report'> <span id='notifications-status' className='column-settings__section'><FormattedMessage id='notifications.column_settings.admin.report' defaultMessage='New reports:' /></span> diff --git a/app/javascript/mastodon/features/notifications/components/notification.js b/app/javascript/mastodon/features/notifications/components/notification.js index 0af71418c..5974e378e 100644 --- a/app/javascript/mastodon/features/notifications/components/notification.js +++ b/app/javascript/mastodon/features/notifications/components/notification.js @@ -372,6 +372,10 @@ class Notification extends ImmutablePureComponent { renderAdminReport (notification, account, link) { const { intl, unread, report } = this.props; + if (!report) { + return null; + } + const targetAccount = report.get('target_account'); const targetDisplayNameHtml = { __html: targetAccount.get('display_name_html') }; const targetLink = <bdi><Permalink className='notification__display-name' href={targetAccount.get('url')} title={targetAccount.get('acct')} to={`/@${targetAccount.get('acct')}`} dangerouslySetInnerHTML={targetDisplayNameHtml} /></bdi>; diff --git a/app/javascript/mastodon/features/notifications/index.js b/app/javascript/mastodon/features/notifications/index.js index a6a277d7e..f1bc5f160 100644 --- a/app/javascript/mastodon/features/notifications/index.js +++ b/app/javascript/mastodon/features/notifications/index.js @@ -26,6 +26,8 @@ import LoadGap from '../../components/load_gap'; import Icon from 'mastodon/components/icon'; import compareId from 'mastodon/compare_id'; import NotificationsPermissionBanner from './components/notifications_permission_banner'; +import NotSignedInIndicator from 'mastodon/components/not_signed_in_indicator'; +import { Helmet } from 'react-helmet'; const messages = defineMessages({ title: { id: 'column.notifications', defaultMessage: 'Notifications' }, @@ -69,6 +71,10 @@ export default @connect(mapStateToProps) @injectIntl class Notifications extends React.PureComponent { + static contextTypes = { + identity: PropTypes.object, + }; + static propTypes = { columnId: PropTypes.string, notifications: ImmutablePropTypes.list.isRequired, @@ -178,10 +184,11 @@ class Notifications extends React.PureComponent { const { intl, notifications, isLoading, isUnread, columnId, multiColumn, hasMore, numPending, showFilterBar, lastReadId, canMarkAsRead, needsNotificationPermission } = this.props; const pinned = !!columnId; const emptyMessage = <FormattedMessage id='empty_column.notifications' defaultMessage="You don't have any notifications yet. When other people interact with you, you will see it here." />; + const { signedIn } = this.context.identity; let scrollableContent = null; - const filterBarContainer = showFilterBar + const filterBarContainer = (signedIn && showFilterBar) ? (<FilterBarContainer />) : null; @@ -211,26 +218,32 @@ class Notifications extends React.PureComponent { this.scrollableContent = scrollableContent; - const scrollContainer = ( - <ScrollableList - scrollKey={`notifications-${columnId}`} - trackScroll={!pinned} - isLoading={isLoading} - showLoading={isLoading && notifications.size === 0} - hasMore={hasMore} - numPending={numPending} - prepend={needsNotificationPermission && <NotificationsPermissionBanner />} - alwaysPrepend - emptyMessage={emptyMessage} - onLoadMore={this.handleLoadOlder} - onLoadPending={this.handleLoadPending} - onScrollToTop={this.handleScrollToTop} - onScroll={this.handleScroll} - bindToDocument={!multiColumn} - > - {scrollableContent} - </ScrollableList> - ); + let scrollContainer; + + if (signedIn) { + scrollContainer = ( + <ScrollableList + scrollKey={`notifications-${columnId}`} + trackScroll={!pinned} + isLoading={isLoading} + showLoading={isLoading && notifications.size === 0} + hasMore={hasMore} + numPending={numPending} + prepend={needsNotificationPermission && <NotificationsPermissionBanner />} + alwaysPrepend + emptyMessage={emptyMessage} + onLoadMore={this.handleLoadOlder} + onLoadPending={this.handleLoadPending} + onScrollToTop={this.handleScrollToTop} + onScroll={this.handleScroll} + bindToDocument={!multiColumn} + > + {scrollableContent} + </ScrollableList> + ); + } else { + scrollContainer = <NotSignedInIndicator />; + } let extraButton = null; @@ -262,8 +275,14 @@ class Notifications extends React.PureComponent { > <ColumnSettingsContainer /> </ColumnHeader> + {filterBarContainer} {scrollContainer} + + <Helmet> + <title>{intl.formatMessage(messages.title)}</title> + <meta name='robots' content='noindex' /> + </Helmet> </Column> ); } diff --git a/app/javascript/mastodon/features/picture_in_picture/components/footer.js b/app/javascript/mastodon/features/picture_in_picture/components/footer.js index 0cb42b25a..0beb2e14d 100644 --- a/app/javascript/mastodon/features/picture_in_picture/components/footer.js +++ b/app/javascript/mastodon/features/picture_in_picture/components/footer.js @@ -43,6 +43,7 @@ class Footer extends ImmutablePureComponent { static contextTypes = { router: PropTypes.object, + identity: PropTypes.object, }; static propTypes = { @@ -67,26 +68,44 @@ class Footer extends ImmutablePureComponent { }; handleReplyClick = () => { - const { dispatch, askReplyConfirmation, intl } = this.props; - - if (askReplyConfirmation) { - dispatch(openModal('CONFIRM', { - message: intl.formatMessage(messages.replyMessage), - confirm: intl.formatMessage(messages.replyConfirm), - onConfirm: this._performReply, - })); + const { dispatch, askReplyConfirmation, status, intl } = this.props; + const { signedIn } = this.context.identity; + + if (signedIn) { + if (askReplyConfirmation) { + dispatch(openModal('CONFIRM', { + message: intl.formatMessage(messages.replyMessage), + confirm: intl.formatMessage(messages.replyConfirm), + onConfirm: this._performReply, + })); + } else { + this._performReply(); + } } else { - this._performReply(); + dispatch(openModal('INTERACTION', { + type: 'reply', + accountId: status.getIn(['account', 'id']), + url: status.get('url'), + })); } }; handleFavouriteClick = () => { const { dispatch, status } = this.props; - - if (status.get('favourited')) { - dispatch(unfavourite(status)); + const { signedIn } = this.context.identity; + + if (signedIn) { + if (status.get('favourited')) { + dispatch(unfavourite(status)); + } else { + dispatch(favourite(status)); + } } else { - dispatch(favourite(status)); + dispatch(openModal('INTERACTION', { + type: 'favourite', + accountId: status.getIn(['account', 'id']), + url: status.get('url'), + })); } }; @@ -97,13 +116,22 @@ class Footer extends ImmutablePureComponent { handleReblogClick = e => { const { dispatch, status } = this.props; - - if (status.get('reblogged')) { - dispatch(unreblog(status)); - } else if ((e && e.shiftKey) || !boostModal) { - this._performReblog(status); + const { signedIn } = this.context.identity; + + if (signedIn) { + if (status.get('reblogged')) { + dispatch(unreblog(status)); + } else if ((e && e.shiftKey) || !boostModal) { + this._performReblog(status); + } else { + dispatch(initBoostModal({ status, onReblog: this._performReblog })); + } } else { - dispatch(initBoostModal({ status, onReblog: this._performReblog })); + dispatch(openModal('INTERACTION', { + type: 'reblog', + accountId: status.getIn(['account', 'id']), + url: status.get('url'), + })); } }; diff --git a/app/javascript/mastodon/features/pinned_statuses/index.js b/app/javascript/mastodon/features/pinned_statuses/index.js index 67b13f10a..c6790ea06 100644 --- a/app/javascript/mastodon/features/pinned_statuses/index.js +++ b/app/javascript/mastodon/features/pinned_statuses/index.js @@ -8,6 +8,7 @@ import ColumnBackButtonSlim from '../../components/column_back_button_slim'; import StatusList from '../../components/status_list'; import { defineMessages, injectIntl } from 'react-intl'; import ImmutablePureComponent from 'react-immutable-pure-component'; +import { Helmet } from 'react-helmet'; const messages = defineMessages({ heading: { id: 'column.pins', defaultMessage: 'Pinned post' }, @@ -54,6 +55,9 @@ class PinnedStatuses extends ImmutablePureComponent { hasMore={hasMore} bindToDocument={!multiColumn} /> + <Helmet> + <meta name='robots' content='noindex' /> + </Helmet> </Column> ); } diff --git a/app/javascript/mastodon/features/privacy_policy/index.js b/app/javascript/mastodon/features/privacy_policy/index.js new file mode 100644 index 000000000..3df487e8f --- /dev/null +++ b/app/javascript/mastodon/features/privacy_policy/index.js @@ -0,0 +1,61 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { Helmet } from 'react-helmet'; +import { FormattedMessage, FormattedDate, injectIntl, defineMessages } from 'react-intl'; +import Column from 'mastodon/components/column'; +import api from 'mastodon/api'; +import Skeleton from 'mastodon/components/skeleton'; + +const messages = defineMessages({ + title: { id: 'privacy_policy.title', defaultMessage: 'Privacy Policy' }, +}); + +export default @injectIntl +class PrivacyPolicy extends React.PureComponent { + + static propTypes = { + intl: PropTypes.object, + multiColumn: PropTypes.bool, + }; + + state = { + content: null, + lastUpdated: null, + isLoading: true, + }; + + componentDidMount () { + api().get('/api/v1/instance/privacy_policy').then(({ data }) => { + this.setState({ content: data.content, lastUpdated: data.updated_at, isLoading: false }); + }).catch(() => { + this.setState({ isLoading: false }); + }); + } + + render () { + const { intl, multiColumn } = this.props; + const { isLoading, content, lastUpdated } = this.state; + + return ( + <Column bindToDocument={!multiColumn} label={intl.formatMessage(messages.title)}> + <div className='scrollable privacy-policy'> + <div className='column-title'> + <h3><FormattedMessage id='privacy_policy.title' defaultMessage='Privacy Policy' /></h3> + <p><FormattedMessage id='privacy_policy.last_updated' defaultMessage='Last updated {date}' values={{ date: isLoading ? <Skeleton width='10ch' /> : <FormattedDate value={lastUpdated} year='numeric' month='short' day='2-digit' /> }} /></p> + </div> + + <div + className='privacy-policy__body prose' + dangerouslySetInnerHTML={{ __html: content }} + /> + </div> + + <Helmet> + <title>{intl.formatMessage(messages.title)}</title> + <meta name='robots' content='all' /> + </Helmet> + </Column> + ); + } + +} diff --git a/app/javascript/mastodon/features/public_timeline/index.js b/app/javascript/mastodon/features/public_timeline/index.js index 2f926678c..a41be07e1 100644 --- a/app/javascript/mastodon/features/public_timeline/index.js +++ b/app/javascript/mastodon/features/public_timeline/index.js @@ -10,7 +10,7 @@ import { addColumn, removeColumn, moveColumn } from '../../actions/columns'; import ColumnSettingsContainer from './containers/column_settings_container'; import { connectPublicStream } from '../../actions/streaming'; import { Helmet } from 'react-helmet'; -import { title } from 'mastodon/initial_state'; +import DismissableBanner from 'mastodon/components/dismissable_banner'; const messages = defineMessages({ title: { id: 'column.public', defaultMessage: 'Federated timeline' }, @@ -37,6 +37,7 @@ class PublicTimeline extends React.PureComponent { static contextTypes = { router: PropTypes.object, + identity: PropTypes.object, }; static defaultProps = { @@ -74,18 +75,30 @@ class PublicTimeline extends React.PureComponent { componentDidMount () { const { dispatch, onlyMedia, onlyRemote } = this.props; + const { signedIn } = this.context.identity; dispatch(expandPublicTimeline({ onlyMedia, onlyRemote })); - this.disconnect = dispatch(connectPublicStream({ onlyMedia, onlyRemote })); + + if (signedIn) { + this.disconnect = dispatch(connectPublicStream({ onlyMedia, onlyRemote })); + } } componentDidUpdate (prevProps) { + const { signedIn } = this.context.identity; + if (prevProps.onlyMedia !== this.props.onlyMedia || prevProps.onlyRemote !== this.props.onlyRemote) { const { dispatch, onlyMedia, onlyRemote } = this.props; - this.disconnect(); + if (this.disconnect) { + this.disconnect(); + } + dispatch(expandPublicTimeline({ onlyMedia, onlyRemote })); - this.disconnect = dispatch(connectPublicStream({ onlyMedia, onlyRemote })); + + if (signedIn) { + this.disconnect = dispatch(connectPublicStream({ onlyMedia, onlyRemote })); + } } } @@ -125,6 +138,10 @@ class PublicTimeline extends React.PureComponent { <ColumnSettingsContainer columnId={columnId} /> </ColumnHeader> + <DismissableBanner id='public_timeline'> + <FormattedMessage id='dismissable_banner.public_timeline' defaultMessage='These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.' /> + </DismissableBanner> + <StatusListContainer timelineId={`public${onlyRemote ? ':remote' : ''}${onlyMedia ? ':media' : ''}`} onLoadMore={this.handleLoadMore} @@ -135,7 +152,8 @@ class PublicTimeline extends React.PureComponent { /> <Helmet> - <title>{intl.formatMessage(messages.title)} - {title}</title> + <title>{intl.formatMessage(messages.title)}</title> + <meta name='robots' content='noindex' /> </Helmet> </Column> ); diff --git a/app/javascript/mastodon/features/reblogs/index.js b/app/javascript/mastodon/features/reblogs/index.js index 7704a049f..70d338ef1 100644 --- a/app/javascript/mastodon/features/reblogs/index.js +++ b/app/javascript/mastodon/features/reblogs/index.js @@ -11,6 +11,7 @@ import Column from '../ui/components/column'; import ScrollableList from '../../components/scrollable_list'; import Icon from 'mastodon/components/icon'; import ColumnHeader from '../../components/column_header'; +import { Helmet } from 'react-helmet'; const messages = defineMessages({ refresh: { id: 'refresh', defaultMessage: 'Refresh' }, @@ -80,6 +81,10 @@ class Reblogs extends ImmutablePureComponent { <AccountContainer key={id} id={id} withNote={false} />, )} </ScrollableList> + + <Helmet> + <meta name='robots' content='noindex' /> + </Helmet> </Column> ); } diff --git a/app/javascript/mastodon/features/report/category.js b/app/javascript/mastodon/features/report/category.js index 9215b3f51..c6c0a506f 100644 --- a/app/javascript/mastodon/features/report/category.js +++ b/app/javascript/mastodon/features/report/category.js @@ -5,6 +5,7 @@ import { connect } from 'react-redux'; import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import Button from 'mastodon/components/button'; import Option from './components/option'; +import { List as ImmutableList } from 'immutable'; const messages = defineMessages({ dislike: { id: 'report.reasons.dislike', defaultMessage: 'I don\'t like it' }, @@ -20,7 +21,7 @@ const messages = defineMessages({ }); const mapStateToProps = state => ({ - rules: state.get('rules'), + rules: state.getIn(['server', 'server', 'rules'], ImmutableList()), }); export default @connect(mapStateToProps) diff --git a/app/javascript/mastodon/features/report/rules.js b/app/javascript/mastodon/features/report/rules.js index 2cb4a95b5..920da68d6 100644 --- a/app/javascript/mastodon/features/report/rules.js +++ b/app/javascript/mastodon/features/report/rules.js @@ -7,7 +7,7 @@ import Button from 'mastodon/components/button'; import Option from './components/option'; const mapStateToProps = state => ({ - rules: state.getIn(['server', 'rules']), + rules: state.getIn(['server', 'server', 'rules']), }); export default @connect(mapStateToProps) diff --git a/app/javascript/mastodon/features/standalone/hashtag_timeline/index.js b/app/javascript/mastodon/features/standalone/hashtag_timeline/index.js deleted file mode 100644 index d3d8a6507..000000000 --- a/app/javascript/mastodon/features/standalone/hashtag_timeline/index.js +++ /dev/null @@ -1,90 +0,0 @@ -import React from 'react'; -import { connect } from 'react-redux'; -import PropTypes from 'prop-types'; -import ImmutablePropTypes from 'react-immutable-proptypes'; -import { expandHashtagTimeline } from 'mastodon/actions/timelines'; -import Masonry from 'react-masonry-infinite'; -import { List as ImmutableList } from 'immutable'; -import DetailedStatusContainer from 'mastodon/features/status/containers/detailed_status_container'; -import { debounce } from 'lodash'; -import LoadingIndicator from 'mastodon/components/loading_indicator'; - -const mapStateToProps = (state, { hashtag }) => ({ - statusIds: state.getIn(['timelines', `hashtag:${hashtag}`, 'items'], ImmutableList()), - isLoading: state.getIn(['timelines', `hashtag:${hashtag}`, 'isLoading'], false), - hasMore: state.getIn(['timelines', `hashtag:${hashtag}`, 'hasMore'], false), -}); - -export default @connect(mapStateToProps) -class HashtagTimeline extends React.PureComponent { - - static propTypes = { - dispatch: PropTypes.func.isRequired, - statusIds: ImmutablePropTypes.list.isRequired, - isLoading: PropTypes.bool.isRequired, - hasMore: PropTypes.bool.isRequired, - hashtag: PropTypes.string.isRequired, - local: PropTypes.bool.isRequired, - }; - - static defaultProps = { - local: false, - }; - - componentDidMount () { - const { dispatch, hashtag, local } = this.props; - - dispatch(expandHashtagTimeline(hashtag, { local })); - } - - handleLoadMore = () => { - const { dispatch, hashtag, local, statusIds } = this.props; - const maxId = statusIds.last(); - - if (maxId) { - dispatch(expandHashtagTimeline(hashtag, { maxId, local })); - } - } - - setRef = c => { - this.masonry = c; - } - - handleHeightChange = debounce(() => { - if (!this.masonry) { - return; - } - - this.masonry.forcePack(); - }, 50) - - render () { - const { statusIds, hasMore, isLoading } = this.props; - - const sizes = [ - { columns: 1, gutter: 0 }, - { mq: '415px', columns: 1, gutter: 10 }, - { mq: '640px', columns: 2, gutter: 10 }, - { mq: '960px', columns: 3, gutter: 10 }, - { mq: '1255px', columns: 3, gutter: 10 }, - ]; - - const loader = (isLoading && statusIds.isEmpty()) ? <LoadingIndicator key={0} /> : undefined; - - return ( - <Masonry ref={this.setRef} className='statuses-grid' hasMore={hasMore} loadMore={this.handleLoadMore} sizes={sizes} loader={loader}> - {statusIds.map(statusId => ( - <div className='statuses-grid__item' key={statusId}> - <DetailedStatusContainer - id={statusId} - compact - measureHeight - onHeightChange={this.handleHeightChange} - /> - </div> - )).toArray()} - </Masonry> - ); - } - -} diff --git a/app/javascript/mastodon/features/standalone/public_timeline/index.js b/app/javascript/mastodon/features/standalone/public_timeline/index.js deleted file mode 100644 index 19b0b14be..000000000 --- a/app/javascript/mastodon/features/standalone/public_timeline/index.js +++ /dev/null @@ -1,99 +0,0 @@ -import React from 'react'; -import { connect } from 'react-redux'; -import PropTypes from 'prop-types'; -import ImmutablePropTypes from 'react-immutable-proptypes'; -import { expandPublicTimeline, expandCommunityTimeline } from 'mastodon/actions/timelines'; -import Masonry from 'react-masonry-infinite'; -import { List as ImmutableList, Map as ImmutableMap } from 'immutable'; -import DetailedStatusContainer from 'mastodon/features/status/containers/detailed_status_container'; -import { debounce } from 'lodash'; -import LoadingIndicator from 'mastodon/components/loading_indicator'; - -const mapStateToProps = (state, { local }) => { - const timeline = state.getIn(['timelines', local ? 'community' : 'public'], ImmutableMap()); - - return { - statusIds: timeline.get('items', ImmutableList()), - isLoading: timeline.get('isLoading', false), - hasMore: timeline.get('hasMore', false), - }; -}; - -export default @connect(mapStateToProps) -class PublicTimeline extends React.PureComponent { - - static propTypes = { - dispatch: PropTypes.func.isRequired, - statusIds: ImmutablePropTypes.list.isRequired, - isLoading: PropTypes.bool.isRequired, - hasMore: PropTypes.bool.isRequired, - local: PropTypes.bool, - }; - - componentDidMount () { - this._connect(); - } - - componentDidUpdate (prevProps) { - if (prevProps.local !== this.props.local) { - this._connect(); - } - } - - _connect () { - const { dispatch, local } = this.props; - - dispatch(local ? expandCommunityTimeline() : expandPublicTimeline()); - } - - handleLoadMore = () => { - const { dispatch, statusIds, local } = this.props; - const maxId = statusIds.last(); - - if (maxId) { - dispatch(local ? expandCommunityTimeline({ maxId }) : expandPublicTimeline({ maxId })); - } - } - - setRef = c => { - this.masonry = c; - } - - handleHeightChange = debounce(() => { - if (!this.masonry) { - return; - } - - this.masonry.forcePack(); - }, 50) - - render () { - const { statusIds, hasMore, isLoading } = this.props; - - const sizes = [ - { columns: 1, gutter: 0 }, - { mq: '415px', columns: 1, gutter: 10 }, - { mq: '640px', columns: 2, gutter: 10 }, - { mq: '960px', columns: 3, gutter: 10 }, - { mq: '1255px', columns: 3, gutter: 10 }, - ]; - - const loader = (isLoading && statusIds.isEmpty()) ? <LoadingIndicator key={0} /> : undefined; - - return ( - <Masonry ref={this.setRef} className='statuses-grid' hasMore={hasMore} loadMore={this.handleLoadMore} sizes={sizes} loader={loader}> - {statusIds.map(statusId => ( - <div className='statuses-grid__item' key={statusId}> - <DetailedStatusContainer - id={statusId} - compact - measureHeight - onHeightChange={this.handleHeightChange} - /> - </div> - )).toArray()} - </Masonry> - ); - } - -} diff --git a/app/javascript/mastodon/features/status/components/action_bar.js b/app/javascript/mastodon/features/status/components/action_bar.js index 50bda69f8..fc82aa9c2 100644 --- a/app/javascript/mastodon/features/status/components/action_bar.js +++ b/app/javascript/mastodon/features/status/components/action_bar.js @@ -194,6 +194,7 @@ class ActionBar extends React.PureComponent { render () { const { status, relationship, intl } = this.props; + const { signedIn, permissions } = this.context.identity; const publicStatus = ['public', 'unlisted'].includes(status.get('visibility')); const pinnableStatus = ['public', 'unlisted', 'private'].includes(status.get('visibility')); @@ -217,7 +218,7 @@ class ActionBar extends React.PureComponent { menu.push({ text: intl.formatMessage(mutingConversation ? messages.unmuteConversation : messages.muteConversation), action: this.handleConversationMuteClick }); menu.push(null); - // menu.push({ text: intl.formatMessage(messages.edit), action: this.handleEditClick }); + menu.push({ text: intl.formatMessage(messages.edit), action: this.handleEditClick }); menu.push({ text: intl.formatMessage(messages.delete), action: this.handleDeleteClick }); menu.push({ text: intl.formatMessage(messages.redraft), action: this.handleRedraftClick }); } else { @@ -250,10 +251,10 @@ class ActionBar extends React.PureComponent { } } - if ((this.context.identity.permissions & PERMISSION_MANAGE_USERS) === PERMISSION_MANAGE_USERS) { + if ((permissions & PERMISSION_MANAGE_USERS) === PERMISSION_MANAGE_USERS) { menu.push(null); menu.push({ text: intl.formatMessage(messages.admin_account, { name: status.getIn(['account', 'username']) }), href: `/admin/accounts/${status.getIn(['account', 'id'])}` }); - menu.push({ text: intl.formatMessage(messages.admin_status), href: `/admin/accounts/${status.getIn(['account', 'id'])}/statuses?id=${status.get('id')}` }); + menu.push({ text: intl.formatMessage(messages.admin_status), href: `/admin/accounts/${status.getIn(['account', 'id'])}/statuses/${status.get('id')}` }); } } @@ -286,11 +287,12 @@ class ActionBar extends React.PureComponent { <div className='detailed-status__button'><IconButton title={intl.formatMessage(messages.reply)} icon={status.get('in_reply_to_account_id') === status.getIn(['account', 'id']) ? 'reply' : replyIcon} onClick={this.handleReplyClick} /></div> <div className='detailed-status__button' ><IconButton className={classNames({ reblogPrivate })} disabled={!publicStatus && !reblogPrivate} active={status.get('reblogged')} title={reblogTitle} icon='retweet' onClick={this.handleReblogClick} /></div> <div className='detailed-status__button'><IconButton className='star-icon' animate active={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' onClick={this.handleFavouriteClick} /></div> + <div className='detailed-status__button'><IconButton className='bookmark-icon' disabled={!signedIn} active={status.get('bookmarked')} title={intl.formatMessage(messages.bookmark)} icon='bookmark' onClick={this.handleBookmarkClick} /></div> + {shareButton} - <div className='detailed-status__button'><IconButton className='bookmark-icon' active={status.get('bookmarked')} title={intl.formatMessage(messages.bookmark)} icon='bookmark' onClick={this.handleBookmarkClick} /></div> <div className='detailed-status__action-bar-dropdown'> - <DropdownMenuContainer size={18} icon='ellipsis-h' status={status} items={menu} direction='left' title={intl.formatMessage(messages.more)} /> + <DropdownMenuContainer size={18} icon='ellipsis-h' disabled={!signedIn} status={status} items={menu} direction='left' title={intl.formatMessage(messages.more)} /> </div> </div> ); diff --git a/app/javascript/mastodon/features/status/components/detailed_status.js b/app/javascript/mastodon/features/status/components/detailed_status.js index 320a847f7..1a2aab819 100644 --- a/app/javascript/mastodon/features/status/components/detailed_status.js +++ b/app/javascript/mastodon/features/status/components/detailed_status.js @@ -262,7 +262,7 @@ class DetailedStatus extends ImmutablePureComponent { <div style={outerStyle}> <div ref={this.setRef} className={classNames('detailed-status', `detailed-status-${status.get('visibility')}`, { compact })}> <a href={status.getIn(['account', 'url'])} onClick={this.handleAccountClick} className='detailed-status__display-name'> - <div className='detailed-status__display-avatar'><Avatar account={status.get('account')} size={48} /></div> + <div className='detailed-status__display-avatar'><Avatar account={status.get('account')} size={46} /></div> <DisplayName account={status.get('account')} localDomain={this.props.domain} /> </a> diff --git a/app/javascript/mastodon/features/status/index.js b/app/javascript/mastodon/features/status/index.js index 748dc7a92..02f390c6a 100644 --- a/app/javascript/mastodon/features/status/index.js +++ b/app/javascript/mastodon/features/status/index.js @@ -7,6 +7,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes'; import { createSelector } from 'reselect'; import { fetchStatus } from '../../actions/statuses'; import MissingIndicator from '../../components/missing_indicator'; +import LoadingIndicator from 'mastodon/components/loading_indicator'; import DetailedStatus from './components/detailed_status'; import ActionBar from './components/action_bar'; import Column from '../ui/components/column'; @@ -56,7 +57,7 @@ import { openModal } from '../../actions/modal'; import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import ImmutablePureComponent from 'react-immutable-pure-component'; import { HotKeys } from 'react-hotkeys'; -import { boostModal, deleteModal, title } from '../../initial_state'; +import { boostModal, deleteModal } from '../../initial_state'; import { attachFullscreenListener, detachFullscreenListener, isFullscreen } from '../ui/util/fullscreen'; import { textForScreenReader, defaultMediaVisibility } from '../../components/status'; import Icon from 'mastodon/components/icon'; @@ -145,6 +146,7 @@ const makeMapStateToProps = () => { } return { + isLoading: state.getIn(['statuses', props.params.statusId, 'isLoading']), status, ancestorsIds, descendantsIds, @@ -180,12 +182,14 @@ class Status extends ImmutablePureComponent { static contextTypes = { router: PropTypes.object, + identity: PropTypes.object, }; static propTypes = { params: PropTypes.object.isRequired, dispatch: PropTypes.func.isRequired, status: ImmutablePropTypes.map, + isLoading: PropTypes.bool, ancestorsIds: ImmutablePropTypes.list, descendantsIds: ImmutablePropTypes.list, intl: PropTypes.object.isRequired, @@ -228,10 +232,21 @@ class Status extends ImmutablePureComponent { } handleFavouriteClick = (status) => { - if (status.get('favourited')) { - this.props.dispatch(unfavourite(status)); + const { dispatch } = this.props; + const { signedIn } = this.context.identity; + + if (signedIn) { + if (status.get('favourited')) { + dispatch(unfavourite(status)); + } else { + dispatch(favourite(status)); + } } else { - this.props.dispatch(favourite(status)); + dispatch(openModal('INTERACTION', { + type: 'favourite', + accountId: status.getIn(['account', 'id']), + url: status.get('url'), + })); } } @@ -244,15 +259,25 @@ class Status extends ImmutablePureComponent { } handleReplyClick = (status) => { - let { askReplyConfirmation, dispatch, intl } = this.props; - if (askReplyConfirmation) { - dispatch(openModal('CONFIRM', { - message: intl.formatMessage(messages.replyMessage), - confirm: intl.formatMessage(messages.replyConfirm), - onConfirm: () => dispatch(replyCompose(status, this.context.router.history)), - })); + const { askReplyConfirmation, dispatch, intl } = this.props; + const { signedIn } = this.context.identity; + + if (signedIn) { + if (askReplyConfirmation) { + dispatch(openModal('CONFIRM', { + message: intl.formatMessage(messages.replyMessage), + confirm: intl.formatMessage(messages.replyConfirm), + onConfirm: () => dispatch(replyCompose(status, this.context.router.history)), + })); + } else { + dispatch(replyCompose(status, this.context.router.history)); + } } else { - dispatch(replyCompose(status, this.context.router.history)); + dispatch(openModal('INTERACTION', { + type: 'reply', + accountId: status.getIn(['account', 'id']), + url: status.get('url'), + })); } } @@ -261,14 +286,25 @@ class Status extends ImmutablePureComponent { } handleReblogClick = (status, e) => { - if (status.get('reblogged')) { - this.props.dispatch(unreblog(status)); - } else { - if ((e && e.shiftKey) || !boostModal) { - this.handleModalReblog(status); + const { dispatch } = this.props; + const { signedIn } = this.context.identity; + + if (signedIn) { + if (status.get('reblogged')) { + dispatch(unreblog(status)); } else { - this.props.dispatch(initBoostModal({ status, onReblog: this.handleModalReblog })); + if ((e && e.shiftKey) || !boostModal) { + this.handleModalReblog(status); + } else { + dispatch(initBoostModal({ status, onReblog: this.handleModalReblog })); + } } + } else { + dispatch(openModal('INTERACTION', { + type: 'reblog', + accountId: status.getIn(['account', 'id']), + url: status.get('url'), + })); } } @@ -533,9 +569,17 @@ class Status extends ImmutablePureComponent { render () { let ancestors, descendants; - const { status, ancestorsIds, descendantsIds, intl, domain, multiColumn, pictureInPicture } = this.props; + const { isLoading, status, ancestorsIds, descendantsIds, intl, domain, multiColumn, pictureInPicture } = this.props; const { fullscreen } = this.state; + if (isLoading) { + return ( + <Column> + <LoadingIndicator /> + </Column> + ); + } + if (status === null) { return ( <Column> @@ -553,6 +597,9 @@ class Status extends ImmutablePureComponent { descendants = <div>{this.renderChildren(descendantsIds)}</div>; } + const isLocal = status.getIn(['account', 'acct'], '').indexOf('@') === -1; + const isIndexable = !status.getIn(['account', 'noindex']); + const handlers = { moveUp: this.handleHotkeyMoveUp, moveDown: this.handleHotkeyMoveDown, @@ -625,7 +672,8 @@ class Status extends ImmutablePureComponent { </ScrollContainer> <Helmet> - <title>{titleFromStatus(status)} - {title}</title> + <title>{titleFromStatus(status)}</title> + <meta name='robots' content={(isLocal && isIndexable) ? 'all' : 'noindex'} /> </Helmet> </Column> ); diff --git a/app/javascript/mastodon/features/ui/components/actions_modal.js b/app/javascript/mastodon/features/ui/components/actions_modal.js index 875b2b75d..67be69d43 100644 --- a/app/javascript/mastodon/features/ui/components/actions_modal.js +++ b/app/javascript/mastodon/features/ui/components/actions_modal.js @@ -2,10 +2,6 @@ import React from 'react'; import PropTypes from 'prop-types'; import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePureComponent from 'react-immutable-pure-component'; -import StatusContent from '../../../components/status_content'; -import Avatar from '../../../components/avatar'; -import RelativeTimestamp from '../../../components/relative_timestamp'; -import DisplayName from '../../../components/display_name'; import IconButton from '../../../components/icon_button'; import classNames from 'classnames'; @@ -38,32 +34,8 @@ export default class ActionsModal extends ImmutablePureComponent { } render () { - const status = this.props.status && ( - <div className='status light'> - <div className='boost-modal__status-header'> - <div className='boost-modal__status-time'> - <a href={this.props.status.get('url')} className='status__relative-time' target='_blank' rel='noopener noreferrer'> - <RelativeTimestamp timestamp={this.props.status.get('created_at')} /> - </a> - </div> - - <a href={this.props.status.getIn(['account', 'url'])} className='status__display-name'> - <div className='status__avatar'> - <Avatar account={this.props.status.get('account')} size={48} /> - </div> - - <DisplayName account={this.props.status.get('account')} /> - </a> - </div> - - <StatusContent status={this.props.status} /> - </div> - ); - return ( <div className='modal-root__modal actions-modal'> - {status} - <ul className={classNames({ 'with-status': !!status })}> {this.props.actions.map(this.renderAction)} </ul> diff --git a/app/javascript/mastodon/features/ui/components/boost_modal.js b/app/javascript/mastodon/features/ui/components/boost_modal.js index ab87ee427..d7a6d711e 100644 --- a/app/javascript/mastodon/features/ui/components/boost_modal.js +++ b/app/javascript/mastodon/features/ui/components/boost_modal.js @@ -97,12 +97,11 @@ class BoostModal extends ImmutablePureComponent { <div className='modal-root__modal boost-modal'> <div className='boost-modal__container'> <div className={classNames('status', `status-${status.get('visibility')}`, 'light')}> - <div className='boost-modal__status-header'> - <div className='boost-modal__status-time'> - <a href={status.get('url')} className='status__relative-time' target='_blank' rel='noopener noreferrer'> - <span className='status__visibility-icon'><Icon id={visibilityIcon.icon} title={visibilityIcon.text} /></span> - <RelativeTimestamp timestamp={status.get('created_at')} /></a> - </div> + <div className='status__info'> + <a href={status.get('url')} className='status__relative-time' target='_blank' rel='noopener noreferrer'> + <span className='status__visibility-icon'><Icon id={visibilityIcon.icon} title={visibilityIcon.text} /></span> + <RelativeTimestamp timestamp={status.get('created_at')} /> + </a> <a onClick={this.handleAccountClick} href={status.getIn(['account', 'url'])} className='status__display-name'> <div className='status__avatar'> diff --git a/app/javascript/mastodon/features/ui/components/bundle_column_error.js b/app/javascript/mastodon/features/ui/components/bundle_column_error.js index f39ebd900..dfe970ad0 100644 --- a/app/javascript/mastodon/features/ui/components/bundle_column_error.js +++ b/app/javascript/mastodon/features/ui/components/bundle_column_error.js @@ -1,44 +1,162 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { defineMessages, injectIntl } from 'react-intl'; +import { injectIntl, FormattedMessage } from 'react-intl'; +import Column from 'mastodon/components/column'; +import Button from 'mastodon/components/button'; +import { Helmet } from 'react-helmet'; +import { Link } from 'react-router-dom'; +import classNames from 'classnames'; +import { autoPlayGif } from 'mastodon/initial_state'; -import Column from './column'; -import ColumnHeader from './column_header'; -import ColumnBackButtonSlim from '../../../components/column_back_button_slim'; -import IconButton from '../../../components/icon_button'; +class GIF extends React.PureComponent { -const messages = defineMessages({ - title: { id: 'bundle_column_error.title', defaultMessage: 'Network error' }, - body: { id: 'bundle_column_error.body', defaultMessage: 'Something went wrong while loading this component.' }, - retry: { id: 'bundle_column_error.retry', defaultMessage: 'Try again' }, -}); + static propTypes = { + src: PropTypes.string.isRequired, + staticSrc: PropTypes.string.isRequired, + className: PropTypes.string, + animate: PropTypes.bool, + }; + + static defaultProps = { + animate: autoPlayGif, + }; + + state = { + hovering: false, + }; + + handleMouseEnter = () => { + const { animate } = this.props; + + if (!animate) { + this.setState({ hovering: true }); + } + } + + handleMouseLeave = () => { + const { animate } = this.props; + + if (!animate) { + this.setState({ hovering: false }); + } + } + + render () { + const { src, staticSrc, className, animate } = this.props; + const { hovering } = this.state; + + return ( + <img + className={className} + src={(hovering || animate) ? src : staticSrc} + alt='' + role='presentation' + onMouseEnter={this.handleMouseEnter} + onMouseLeave={this.handleMouseLeave} + /> + ); + } + +} + +class CopyButton extends React.PureComponent { + + static propTypes = { + children: PropTypes.node.isRequired, + value: PropTypes.string.isRequired, + }; + + state = { + copied: false, + }; + handleClick = () => { + const { value } = this.props; + navigator.clipboard.writeText(value); + this.setState({ copied: true }); + this.timeout = setTimeout(() => this.setState({ copied: false }), 700); + } + + componentWillUnmount () { + if (this.timeout) clearTimeout(this.timeout); + } + + render () { + const { children } = this.props; + const { copied } = this.state; + + return ( + <Button onClick={this.handleClick} className={copied ? 'copied' : 'copyable'}>{copied ? <FormattedMessage id='copypaste.copied' defaultMessage='Copied' /> : children}</Button> + ); + } + +} + +export default @injectIntl class BundleColumnError extends React.PureComponent { static propTypes = { - onRetry: PropTypes.func.isRequired, + errorType: PropTypes.oneOf(['routing', 'network', 'error']), + onRetry: PropTypes.func, intl: PropTypes.object.isRequired, - } + multiColumn: PropTypes.bool, + stacktrace: PropTypes.string, + }; + + static defaultProps = { + errorType: 'routing', + }; handleRetry = () => { - this.props.onRetry(); + const { onRetry } = this.props; + + if (onRetry) { + onRetry(); + } } render () { - const { intl: { formatMessage } } = this.props; + const { errorType, multiColumn, stacktrace } = this.props; + + let title, body; + + switch(errorType) { + case 'routing': + title = <FormattedMessage id='bundle_column_error.routing.title' defaultMessage='404' />; + body = <FormattedMessage id='bundle_column_error.routing.body' defaultMessage='The requested page could not be found. Are you sure the URL in the address bar is correct?' />; + break; + case 'network': + title = <FormattedMessage id='bundle_column_error.network.title' defaultMessage='Network error' />; + body = <FormattedMessage id='bundle_column_error.network.body' defaultMessage='There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.' />; + break; + case 'error': + title = <FormattedMessage id='bundle_column_error.error.title' defaultMessage='Oh, no!' />; + body = <FormattedMessage id='bundle_column_error.error.body' defaultMessage='The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.' />; + break; + } return ( - <Column> - <ColumnHeader icon='exclamation-circle' type={formatMessage(messages.title)} /> - <ColumnBackButtonSlim /> + <Column bindToDocument={!multiColumn}> <div className='error-column'> - <IconButton title={formatMessage(messages.retry)} icon='refresh' onClick={this.handleRetry} size={64} /> - {formatMessage(messages.body)} + <GIF src='/oops.gif' staticSrc='/oops.png' className='error-column__image' /> + + <div className='error-column__message'> + <h1>{title}</h1> + <p>{body}</p> + + <div className='error-column__message__actions'> + {errorType === 'network' && <Button onClick={this.handleRetry}><FormattedMessage id='bundle_column_error.retry' defaultMessage='Try again' /></Button>} + {errorType === 'error' && <CopyButton value={stacktrace}><FormattedMessage id='bundle_column_error.copy_stacktrace' defaultMessage='Copy error report' /></CopyButton>} + <Link to='/' className={classNames('button', { 'button-tertiary': errorType !== 'routing' })}><FormattedMessage id='bundle_column_error.return' defaultMessage='Go back home' /></Link> + </div> + </div> </div> + + <Helmet> + <meta name='robots' content='noindex' /> + </Helmet> </Column> ); } } - -export default injectIntl(BundleColumnError); diff --git a/app/javascript/mastodon/features/ui/components/column_link.js b/app/javascript/mastodon/features/ui/components/column_link.js index 0a25f1ea2..8eebbf526 100644 --- a/app/javascript/mastodon/features/ui/components/column_link.js +++ b/app/javascript/mastodon/features/ui/components/column_link.js @@ -1,37 +1,41 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { Link } from 'react-router-dom'; +import { NavLink } from 'react-router-dom'; import Icon from 'mastodon/components/icon'; +import classNames from 'classnames'; -const ColumnLink = ({ icon, text, to, href, method, badge }) => { +const ColumnLink = ({ icon, text, to, href, method, badge, transparent, ...other }) => { + const className = classNames('column-link', { 'column-link--transparent': transparent }); const badgeElement = typeof badge !== 'undefined' ? <span className='column-link__badge'>{badge}</span> : null; + const iconElement = typeof icon === 'string' ? <Icon id={icon} fixedWidth className='column-link__icon' /> : icon; if (href) { return ( - <a href={href} className='column-link' data-method={method}> - <Icon id={icon} fixedWidth className='column-link__icon' /> - {text} + <a href={href} className={className} data-method={method} title={text} {...other}> + {iconElement} + <span>{text}</span> {badgeElement} </a> ); } else { return ( - <Link to={to} className='column-link'> - <Icon id={icon} fixedWidth className='column-link__icon' /> - {text} + <NavLink to={to} className={className} title={text} {...other}> + {iconElement} + <span>{text}</span> {badgeElement} - </Link> + </NavLink> ); } }; ColumnLink.propTypes = { - icon: PropTypes.string.isRequired, + icon: PropTypes.oneOfType([PropTypes.string, PropTypes.node]).isRequired, text: PropTypes.string.isRequired, to: PropTypes.string, href: PropTypes.string, method: PropTypes.string, badge: PropTypes.node, + transparent: PropTypes.bool, }; export default ColumnLink; diff --git a/app/javascript/mastodon/features/ui/components/column_loading.js b/app/javascript/mastodon/features/ui/components/column_loading.js index 0cdfd05d8..e5ed22584 100644 --- a/app/javascript/mastodon/features/ui/components/column_loading.js +++ b/app/javascript/mastodon/features/ui/components/column_loading.js @@ -10,6 +10,7 @@ export default class ColumnLoading extends ImmutablePureComponent { static propTypes = { title: PropTypes.oneOfType([PropTypes.node, PropTypes.string]), icon: PropTypes.string, + multiColumn: PropTypes.bool, }; static defaultProps = { @@ -18,10 +19,11 @@ export default class ColumnLoading extends ImmutablePureComponent { }; render() { - let { title, icon } = this.props; + let { title, icon, multiColumn } = this.props; + return ( <Column> - <ColumnHeader icon={icon} title={title} multiColumn={false} focusable={false} placeholder /> + <ColumnHeader icon={icon} title={title} multiColumn={multiColumn} focusable={false} placeholder /> <div className='scrollable' /> </Column> ); diff --git a/app/javascript/mastodon/features/ui/components/columns_area.js b/app/javascript/mastodon/features/ui/components/columns_area.js index 83e10e003..f4824f045 100644 --- a/app/javascript/mastodon/features/ui/components/columns_area.js +++ b/app/javascript/mastodon/features/ui/components/columns_area.js @@ -1,15 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { defineMessages, injectIntl } from 'react-intl'; import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePureComponent from 'react-immutable-pure-component'; - -import ReactSwipeableViews from 'react-swipeable-views'; -import TabsBar, { links, getIndex, getLink } from './tabs_bar'; -import { Link } from 'react-router-dom'; - -import { disableSwiping } from 'mastodon/initial_state'; - import BundleContainer from '../containers/bundle_container'; import ColumnLoading from './column_loading'; import DrawerLoading from './drawer_loading'; @@ -27,10 +19,8 @@ import { ListTimeline, Directory, } from '../../ui/util/async-components'; -import Icon from 'mastodon/components/icon'; import ComposePanel from './compose_panel'; import NavigationPanel from './navigation_panel'; - import { supportsPassiveEvents } from 'detect-passive-events'; import { scrollRight } from '../../../scroll'; @@ -49,42 +39,26 @@ const componentMap = { 'DIRECTORY': Directory, }; -const messages = defineMessages({ - publish: { id: 'compose_form.publish', defaultMessage: 'Publish' }, -}); - -const shouldHideFAB = path => path.match(/^\/statuses\/|^\/@[^/]+\/\d+|^\/publish|^\/explore|^\/getting-started|^\/start/); - -export default @(component => injectIntl(component, { withRef: true })) -class ColumnsArea extends ImmutablePureComponent { +export default class ColumnsArea extends ImmutablePureComponent { static contextTypes = { router: PropTypes.object.isRequired, - identity: PropTypes.object.isRequired, }; static propTypes = { - intl: PropTypes.object.isRequired, columns: ImmutablePropTypes.list.isRequired, isModalOpen: PropTypes.bool.isRequired, singleColumn: PropTypes.bool, children: PropTypes.node, }; - // Corresponds to (max-width: 600px + (285px * 1) + (10px * 1)) in SCSS - mediaQuery = 'matchMedia' in window && window.matchMedia('(max-width: 895px)'); + // Corresponds to (max-width: $no-gap-breakpoint + 285px - 1px) in SCSS + mediaQuery = 'matchMedia' in window && window.matchMedia('(max-width: 1174px)'); state = { - shouldAnimate: false, renderComposePanel: !(this.mediaQuery && this.mediaQuery.matches), } - componentWillReceiveProps() { - if (typeof this.pendingIndex !== 'number' && this.lastIndex !== getIndex(this.context.router.history.location.pathname)) { - this.setState({ shouldAnimate: false }); - } - } - componentDidMount() { if (!this.props.singleColumn) { this.node.addEventListener('wheel', this.handleWheel, supportsPassiveEvents ? { passive: true } : false); @@ -99,10 +73,7 @@ class ColumnsArea extends ImmutablePureComponent { this.setState({ renderComposePanel: !this.mediaQuery.matches }); } - this.lastIndex = getIndex(this.context.router.history.location.pathname); this.isRtlLayout = document.getElementsByTagName('body')[0].classList.contains('rtl'); - - this.setState({ shouldAnimate: true }); } componentWillUpdate(nextProps) { @@ -115,13 +86,6 @@ class ColumnsArea extends ImmutablePureComponent { if (this.props.singleColumn !== prevProps.singleColumn && !this.props.singleColumn) { this.node.addEventListener('wheel', this.handleWheel, supportsPassiveEvents ? { passive: true } : false); } - - const newIndex = getIndex(this.context.router.history.location.pathname); - - if (this.lastIndex !== newIndex) { - this.lastIndex = newIndex; - this.setState({ shouldAnimate: true }); - } } componentWillUnmount () { @@ -149,31 +113,6 @@ class ColumnsArea extends ImmutablePureComponent { this.setState({ renderComposePanel: !e.matches }); } - handleSwipe = (index) => { - this.pendingIndex = index; - - const nextLinkTranslationId = links[index].props['data-preview-title-id']; - const currentLinkSelector = '.tabs-bar__link.active'; - const nextLinkSelector = `.tabs-bar__link[data-preview-title-id="${nextLinkTranslationId}"]`; - - // HACK: Remove the active class from the current link and set it to the next one - // React-router does this for us, but too late, feeling laggy. - document.querySelector(currentLinkSelector).classList.remove('active'); - document.querySelector(nextLinkSelector).classList.add('active'); - - if (!this.state.shouldAnimate && typeof this.pendingIndex === 'number') { - this.context.router.history.push(getLink(this.pendingIndex)); - this.pendingIndex = null; - } - } - - handleAnimationEnd = () => { - if (typeof this.pendingIndex === 'number') { - this.context.router.history.push(getLink(this.pendingIndex)); - this.pendingIndex = null; - } - } - handleWheel = () => { if (typeof this._interruptScrollAnimation !== 'function') { return; @@ -186,48 +125,19 @@ class ColumnsArea extends ImmutablePureComponent { this.node = node; } - renderView = (link, index) => { - const columnIndex = getIndex(this.context.router.history.location.pathname); - const title = this.props.intl.formatMessage({ id: link.props['data-preview-title-id'] }); - const icon = link.props['data-preview-icon']; - - const view = (index === columnIndex) ? - React.cloneElement(this.props.children) : - <ColumnLoading title={title} icon={icon} />; - - return ( - <div className='columns-area columns-area--mobile' key={index}> - {view} - </div> - ); - } - renderLoading = columnId => () => { - return columnId === 'COMPOSE' ? <DrawerLoading /> : <ColumnLoading />; + return columnId === 'COMPOSE' ? <DrawerLoading /> : <ColumnLoading multiColumn />; } renderError = (props) => { - return <BundleColumnError {...props} />; + return <BundleColumnError multiColumn errorType='network' {...props} />; } render () { - const { columns, children, singleColumn, isModalOpen, intl } = this.props; - const { shouldAnimate, renderComposePanel } = this.state; - const { signedIn } = this.context.identity; - - const columnIndex = getIndex(this.context.router.history.location.pathname); + const { columns, children, singleColumn, isModalOpen } = this.props; + const { renderComposePanel } = this.state; if (singleColumn) { - const floatingActionButton = (!signedIn || shouldHideFAB(this.context.router.history.location.pathname)) ? null : <Link key='floating-action-button' to='/publish' className='floating-action-button' aria-label={intl.formatMessage(messages.publish)}><Icon id='pencil' /></Link>; - - const content = columnIndex !== -1 ? ( - <ReactSwipeableViews key='content' hysteresis={0.2} threshold={15} index={columnIndex} onChangeIndex={this.handleSwipe} onTransitionEnd={this.handleAnimationEnd} animateTransitions={shouldAnimate} springConfig={{ duration: '400ms', delay: '0s', easeFunction: 'ease' }} style={{ height: '100%' }} disabled={disableSwiping}> - {links.map(this.renderView)} - </ReactSwipeableViews> - ) : ( - <div key='content' className='columns-area columns-area--mobile'>{children}</div> - ); - return ( <div className='columns-area__panels'> <div className='columns-area__panels__pane columns-area__panels__pane--compositional'> @@ -236,9 +146,9 @@ class ColumnsArea extends ImmutablePureComponent { </div> </div> - <div className={`columns-area__panels__main ${floatingActionButton && 'with-fab'}`}> - <TabsBar key='tabs' /> - {content} + <div className='columns-area__panels__main'> + <div className='tabs-bar__wrapper'><div id='tabs-bar__portal' /></div> + <div className='columns-area columns-area--mobile'>{children}</div> </div> <div className='columns-area__panels__pane columns-area__panels__pane--start columns-area__panels__pane--navigational'> @@ -246,8 +156,6 @@ class ColumnsArea extends ImmutablePureComponent { <NavigationPanel /> </div> </div> - - {floatingActionButton} </div> ); } diff --git a/app/javascript/mastodon/features/ui/components/compose_panel.js b/app/javascript/mastodon/features/ui/components/compose_panel.js index c8bc79a67..92d16b5b3 100644 --- a/app/javascript/mastodon/features/ui/components/compose_panel.js +++ b/app/javascript/mastodon/features/ui/components/compose_panel.js @@ -6,7 +6,7 @@ import ComposeFormContainer from 'mastodon/features/compose/containers/compose_f import NavigationContainer from 'mastodon/features/compose/containers/navigation_container'; import LinkFooter from './link_footer'; import ServerBanner from 'mastodon/components/server_banner'; -import { changeComposing } from 'mastodon/actions/compose'; +import { changeComposing, mountCompose, unmountCompose } from 'mastodon/actions/compose'; export default @connect() class ComposePanel extends React.PureComponent { @@ -20,11 +20,23 @@ class ComposePanel extends React.PureComponent { }; onFocus = () => { - this.props.dispatch(changeComposing(true)); + const { dispatch } = this.props; + dispatch(changeComposing(true)); } onBlur = () => { - this.props.dispatch(changeComposing(false)); + const { dispatch } = this.props; + dispatch(changeComposing(false)); + } + + componentDidMount () { + const { dispatch } = this.props; + dispatch(mountCompose()); + } + + componentWillUnmount () { + const { dispatch } = this.props; + dispatch(unmountCompose()); } render() { @@ -48,7 +60,7 @@ class ComposePanel extends React.PureComponent { </React.Fragment> )} - <LinkFooter withHotkeys /> + <LinkFooter /> </div> ); } diff --git a/app/javascript/mastodon/features/ui/components/follow_requests_nav_link.js b/app/javascript/mastodon/features/ui/components/follow_requests_column_link.js index 950ed7b27..8d4057782 100644 --- a/app/javascript/mastodon/features/ui/components/follow_requests_nav_link.js +++ b/app/javascript/mastodon/features/ui/components/follow_requests_column_link.js @@ -2,22 +2,27 @@ import React from 'react'; import PropTypes from 'prop-types'; import { fetchFollowRequests } from 'mastodon/actions/accounts'; import { connect } from 'react-redux'; -import { NavLink, withRouter } from 'react-router-dom'; +import ColumnLink from 'mastodon/features/ui/components/column_link'; import IconWithBadge from 'mastodon/components/icon_with_badge'; import { List as ImmutableList } from 'immutable'; -import { FormattedMessage } from 'react-intl'; +import { injectIntl, defineMessages } from 'react-intl'; + +const messages = defineMessages({ + text: { id: 'navigation_bar.follow_requests', defaultMessage: 'Follow requests' }, +}); const mapStateToProps = state => ({ count: state.getIn(['user_lists', 'follow_requests', 'items'], ImmutableList()).size, }); -export default @withRouter +export default @injectIntl @connect(mapStateToProps) -class FollowRequestsNavLink extends React.Component { +class FollowRequestsColumnLink extends React.Component { static propTypes = { dispatch: PropTypes.func.isRequired, count: PropTypes.number.isRequired, + intl: PropTypes.object.isRequired, }; componentDidMount () { @@ -27,13 +32,20 @@ class FollowRequestsNavLink extends React.Component { } render () { - const { count } = this.props; + const { count, intl } = this.props; if (count === 0) { return null; } - return <NavLink className='column-link column-link--transparent' to='/follow_requests'><IconWithBadge className='column-link__icon' id='user-plus' count={count} /><FormattedMessage id='navigation_bar.follow_requests' defaultMessage='Follow requests' /></NavLink>; + return ( + <ColumnLink + transparent + to='/follow_requests' + icon={<IconWithBadge className='column-link__icon' id='user-plus' count={count} />} + text={intl.formatMessage(messages.text)} + /> + ); } } diff --git a/app/javascript/mastodon/features/ui/components/header.js b/app/javascript/mastodon/features/ui/components/header.js new file mode 100644 index 000000000..a1c281315 --- /dev/null +++ b/app/javascript/mastodon/features/ui/components/header.js @@ -0,0 +1,63 @@ +import React from 'react'; +import Logo from 'mastodon/components/logo'; +import { Link, withRouter } from 'react-router-dom'; +import { FormattedMessage } from 'react-intl'; +import { registrationsOpen, me } from 'mastodon/initial_state'; +import Avatar from 'mastodon/components/avatar'; +import Permalink from 'mastodon/components/permalink'; +import PropTypes from 'prop-types'; +import { connect } from 'react-redux'; + +const Account = connect(state => ({ + account: state.getIn(['accounts', me]), +}))(({ account }) => ( + <Permalink href={account.get('url')} to={`/@${account.get('acct')}`} title={account.get('acct')}> + <Avatar account={account} size={35} /> + </Permalink> +)); + +export default @withRouter +class Header extends React.PureComponent { + + static contextTypes = { + identity: PropTypes.object, + }; + + static propTypes = { + location: PropTypes.object, + }; + + render () { + const { signedIn } = this.context.identity; + const { location } = this.props; + + let content; + + if (signedIn) { + content = ( + <> + {location.pathname !== '/publish' && <Link to='/publish' className='button'><FormattedMessage id='compose_form.publish' defaultMessage='Publish' /></Link>} + <Account /> + </> + ); + } else { + content = ( + <> + <a href='/auth/sign_in' className='button'><FormattedMessage id='sign_in_banner.sign_in' defaultMessage='Sign in' /></a> + <a href={registrationsOpen ? '/auth/sign_up' : 'https://joinmastodon.org/servers'} className='button button-tertiary'><FormattedMessage id='sign_in_banner.create_account' defaultMessage='Create account' /></a> + </> + ); + } + + return ( + <div className='ui__header'> + <Link to='/' className='ui__header__logo'><Logo /></Link> + + <div className='ui__header__links'> + {content} + </div> + </div> + ); + } + +} diff --git a/app/javascript/mastodon/features/ui/components/link_footer.js b/app/javascript/mastodon/features/ui/components/link_footer.js index dd05d03dd..cc3d83572 100644 --- a/app/javascript/mastodon/features/ui/components/link_footer.js +++ b/app/javascript/mastodon/features/ui/components/link_footer.js @@ -3,7 +3,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { FormattedMessage, defineMessages, injectIntl } from 'react-intl'; import { Link } from 'react-router-dom'; -import { limitedFederationMode, version, repository, source_url, profile_directory as profileDirectory } from 'mastodon/initial_state'; +import { version, repository, source_url, profile_directory as profileDirectory } from 'mastodon/initial_state'; import { logOut } from 'mastodon/utils/log_out'; import { openModal } from 'mastodon/actions/modal'; import { PERMISSION_INVITE_USERS } from 'mastodon/permissions'; @@ -33,7 +33,6 @@ class LinkFooter extends React.PureComponent { }; static propTypes = { - withHotkeys: PropTypes.bool, onLogout: PropTypes.func.isRequired, intl: PropTypes.object.isRequired, }; @@ -48,40 +47,26 @@ class LinkFooter extends React.PureComponent { } render () { - const { withHotkeys } = this.props; const { signedIn, permissions } = this.context.identity; const items = []; - if ((permissions & PERMISSION_INVITE_USERS) === PERMISSION_INVITE_USERS) { - items.push(<a key='invites' href='/invites' target='_blank'><FormattedMessage id='getting_started.invite' defaultMessage='Invite people' /></a>); - } - - if (signedIn && withHotkeys) { - items.push(<Link key='hotkeys' to='/keyboard-shortcuts'><FormattedMessage id='navigation_bar.keyboard_shortcuts' defaultMessage='Hotkeys' /></Link>); - } - - if (signedIn) { - items.push(<a key='security' href='/auth/edit'><FormattedMessage id='getting_started.security' defaultMessage='Security' /></a>); - } - - if (!limitedFederationMode) { - items.push(<a key='about' href='/about/more' target='_blank'><FormattedMessage id='navigation_bar.info' defaultMessage='About this server' /></a>); - } + items.push(<a key='apps' href='https://joinmastodon.org/apps' target='_blank'><FormattedMessage id='navigation_bar.apps' defaultMessage='Get the app' /></a>); + items.push(<Link key='about' to='/about'><FormattedMessage id='navigation_bar.info' defaultMessage='About' /></Link>); + items.push(<a key='mastodon' href='https://joinmastodon.org' target='_blank'><FormattedMessage id='getting_started.what_is_mastodon' defaultMessage='About Mastodon' /></a>); + items.push(<a key='docs' href='https://docs.joinmastodon.org' target='_blank'><FormattedMessage id='getting_started.documentation' defaultMessage='Documentation' /></a>); + items.push(<Link key='privacy-policy' to='/privacy-policy'><FormattedMessage id='getting_started.privacy_policy' defaultMessage='Privacy Policy' /></Link>); + items.push(<Link key='hotkeys' to='/keyboard-shortcuts'><FormattedMessage id='navigation_bar.keyboard_shortcuts' defaultMessage='Hotkeys' /></Link>); if (profileDirectory) { - items.push(<Link key='directory' to='/directory'><FormattedMessage id='getting_started.directory' defaultMessage='Profile directory' /></Link>); + items.push(<Link key='directory' to='/directory'><FormattedMessage id='getting_started.directory' defaultMessage='Directory' /></Link>); } - items.push(<a key='apps' href='https://joinmastodon.org/apps' target='_blank'><FormattedMessage id='navigation_bar.apps' defaultMessage='Mobile apps' /></a>); - items.push(<a key='privacy-policy' href='/privacy-policy' target='_blank'><FormattedMessage id='getting_started.privacy_policy' defaultMessage='Privacy Policy' /></a>); - if (signedIn) { - items.push(<a key='developers' href='/settings/applications' target='_blank'><FormattedMessage id='getting_started.developers' defaultMessage='Developers' /></a>); - } + if ((permissions & PERMISSION_INVITE_USERS) === PERMISSION_INVITE_USERS) { + items.push(<a key='invites' href='/invites' target='_blank'><FormattedMessage id='getting_started.invite' defaultMessage='Invite people' /></a>); + } - items.push(<a key='docs' href='https://docs.joinmastodon.org' target='_blank'><FormattedMessage id='getting_started.documentation' defaultMessage='Documentation' /></a>); - - if (signedIn) { + items.push(<a key='security' href='/auth/edit'><FormattedMessage id='getting_started.security' defaultMessage='Security' /></a>); items.push(<a key='logout' href='/auth/sign_out' onClick={this.handleLogoutClick}><FormattedMessage id='navigation_bar.logout' defaultMessage='Logout' /></a>); } @@ -93,9 +78,9 @@ class LinkFooter extends React.PureComponent { <p> <FormattedMessage - id='getting_started.open_source_notice' - defaultMessage='Mastodon is open source software. You can contribute or report issues on GitHub at {github}.' - values={{ github: <span><a href={source_url} rel='noopener noreferrer' target='_blank'>{repository}</a> (v{version})</span> }} + id='getting_started.free_software_notice' + defaultMessage='Mastodon is free, open source software. You can view the source code, contribute or report issues at {repository}.' + values={{ repository: <span><a href={source_url} rel='noopener noreferrer' target='_blank'>{repository}</a> (v{version})</span> }} /> </p> </div> diff --git a/app/javascript/mastodon/features/ui/components/list_panel.js b/app/javascript/mastodon/features/ui/components/list_panel.js index 411f62508..2f92a9254 100644 --- a/app/javascript/mastodon/features/ui/components/list_panel.js +++ b/app/javascript/mastodon/features/ui/components/list_panel.js @@ -1,12 +1,12 @@ import React from 'react'; import PropTypes from 'prop-types'; +import { createSelector } from 'reselect'; import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePureComponent from 'react-immutable-pure-component'; -import { fetchLists } from 'mastodon/actions/lists'; import { connect } from 'react-redux'; -import { createSelector } from 'reselect'; -import { NavLink, withRouter } from 'react-router-dom'; -import Icon from 'mastodon/components/icon'; +import { withRouter } from 'react-router-dom'; +import { fetchLists } from 'mastodon/actions/lists'; +import ColumnLink from './column_link'; const getOrderedLists = createSelector([state => state.get('lists')], lists => { if (!lists) { @@ -42,11 +42,11 @@ class ListPanel extends ImmutablePureComponent { } return ( - <div> + <div className='list-panel'> <hr /> {lists.map(list => ( - <NavLink key={list.get('id')} className='column-link column-link--transparent' strict to={`/lists/${list.get('id')}`}><Icon className='column-link__icon' id='list-ul' fixedWidth />{list.get('title')}</NavLink> + <ColumnLink icon='list-ul' key={list.get('id')} strict text={list.get('title')} to={`/lists/${list.get('id')}`} transparent /> ))} </div> ); diff --git a/app/javascript/mastodon/features/ui/components/modal_root.js b/app/javascript/mastodon/features/ui/components/modal_root.js index dfa89f2ce..484ebbd8b 100644 --- a/app/javascript/mastodon/features/ui/components/modal_root.js +++ b/app/javascript/mastodon/features/ui/components/modal_root.js @@ -11,7 +11,6 @@ import VideoModal from './video_modal'; import BoostModal from './boost_modal'; import AudioModal from './audio_modal'; import ConfirmationModal from './confirmation_modal'; -import SubscribedLanguagesModal from 'mastodon/features/subscribed_languages_modal'; import FocalPointModal from './focal_point_modal'; import { MuteModal, @@ -22,7 +21,11 @@ import { ListAdder, CompareHistoryModal, FilterModal, + InteractionModal, + SubscribedLanguagesModal, + ClosedRegistrationsModal, } from 'mastodon/features/ui/util/async-components'; +import { Helmet } from 'react-helmet'; const MODAL_COMPONENTS = { 'MEDIA': () => Promise.resolve({ default: MediaModal }), @@ -40,7 +43,9 @@ const MODAL_COMPONENTS = { 'LIST_ADDER': ListAdder, 'COMPARE_HISTORY': CompareHistoryModal, 'FILTER': FilterModal, - 'SUBSCRIBED_LANGUAGES': () => Promise.resolve({ default: SubscribedLanguagesModal }), + 'SUBSCRIBED_LANGUAGES': SubscribedLanguagesModal, + 'INTERACTION': InteractionModal, + 'CLOSED_REGISTRATIONS': ClosedRegistrationsModal, }; export default class ModalRoot extends React.PureComponent { @@ -109,9 +114,15 @@ export default class ModalRoot extends React.PureComponent { return ( <Base backgroundColor={backgroundColor} onClose={this.handleClose} ignoreFocus={ignoreFocus}> {visible && ( - <BundleContainer fetchComponent={MODAL_COMPONENTS[type]} loading={this.renderLoading(type)} error={this.renderError} renderDelay={200}> - {(SpecificComponent) => <SpecificComponent {...props} onChangeBackgroundColor={this.setBackgroundColor} onClose={this.handleClose} ref={this.setModalRef} />} - </BundleContainer> + <> + <BundleContainer fetchComponent={MODAL_COMPONENTS[type]} loading={this.renderLoading(type)} error={this.renderError} renderDelay={200}> + {(SpecificComponent) => <SpecificComponent {...props} onChangeBackgroundColor={this.setBackgroundColor} onClose={this.handleClose} ref={this.setModalRef} />} + </BundleContainer> + + <Helmet> + <meta name='robots' content='noindex' /> + </Helmet> + </> )} </Base> ); diff --git a/app/javascript/mastodon/features/ui/components/navigation_panel.js b/app/javascript/mastodon/features/ui/components/navigation_panel.js index 00ae04761..4e9e39e2f 100644 --- a/app/javascript/mastodon/features/ui/components/navigation_panel.js +++ b/app/javascript/mastodon/features/ui/components/navigation_panel.js @@ -1,73 +1,104 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { NavLink, Link } from 'react-router-dom'; -import { FormattedMessage } from 'react-intl'; -import Icon from 'mastodon/components/icon'; -import { showTrends } from 'mastodon/initial_state'; -import NotificationsCounterIcon from './notifications_counter_icon'; -import FollowRequestsNavLink from './follow_requests_nav_link'; -import ListPanel from './list_panel'; -import TrendsContainer from 'mastodon/features/getting_started/containers/trends_container'; +import { defineMessages, injectIntl } from 'react-intl'; +import { Link } from 'react-router-dom'; import Logo from 'mastodon/components/logo'; +import { timelinePreview, showTrends } from 'mastodon/initial_state'; +import ColumnLink from './column_link'; +import FollowRequestsColumnLink from './follow_requests_column_link'; +import ListPanel from './list_panel'; +import NotificationsCounterIcon from './notifications_counter_icon'; import SignInBanner from './sign_in_banner'; +import NavigationPortal from 'mastodon/components/navigation_portal'; + +const messages = defineMessages({ + home: { id: 'tabs_bar.home', defaultMessage: 'Home' }, + notifications: { id: 'tabs_bar.notifications', defaultMessage: 'Notifications' }, + explore: { id: 'explore.title', defaultMessage: 'Explore' }, + local: { id: 'tabs_bar.local_timeline', defaultMessage: 'Local' }, + federated: { id: 'tabs_bar.federated_timeline', defaultMessage: 'Federated' }, + direct: { id: 'navigation_bar.direct', defaultMessage: 'Direct messages' }, + favourites: { id: 'navigation_bar.favourites', defaultMessage: 'Favourites' }, + bookmarks: { id: 'navigation_bar.bookmarks', defaultMessage: 'Bookmarks' }, + lists: { id: 'navigation_bar.lists', defaultMessage: 'Lists' }, + preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' }, + followsAndFollowers: { id: 'navigation_bar.follows_and_followers', defaultMessage: 'Follows and followers' }, + about: { id: 'navigation_bar.about', defaultMessage: 'About' }, + search: { id: 'navigation_bar.search', defaultMessage: 'Search' }, +}); -export default class NavigationPanel extends React.Component { +export default @injectIntl +class NavigationPanel extends React.Component { static contextTypes = { router: PropTypes.object.isRequired, identity: PropTypes.object.isRequired, }; + static propTypes = { + intl: PropTypes.object.isRequired, + }; + render () { + const { intl } = this.props; const { signedIn } = this.context.identity; return ( <div className='navigation-panel'> - <Link to='/' className='column-link column-link--logo'><Logo /></Link> - - <hr /> + <div className='navigation-panel__logo'> + <Link to='/' className='column-link column-link--logo'><Logo /></Link> + <hr /> + </div> {signedIn && ( <React.Fragment> - <NavLink className='column-link column-link--transparent' to='/home' data-preview-title-id='column.home' data-preview-icon='home' ><Icon className='column-link__icon' id='home' fixedWidth /><FormattedMessage id='tabs_bar.home' defaultMessage='Home' /></NavLink> - <NavLink className='column-link column-link--transparent' to='/notifications' data-preview-title-id='column.notifications' data-preview-icon='bell' ><NotificationsCounterIcon className='column-link__icon' /><FormattedMessage id='tabs_bar.notifications' defaultMessage='Notifications' /></NavLink> - <FollowRequestsNavLink /> + <ColumnLink transparent to='/home' icon='home' text={intl.formatMessage(messages.home)} /> + <ColumnLink transparent to='/notifications' icon={<NotificationsCounterIcon className='column-link__icon' />} text={intl.formatMessage(messages.notifications)} /> + <FollowRequestsColumnLink /> </React.Fragment> )} - <NavLink className='column-link column-link--transparent' to='/explore' data-preview-title-id='explore.title' data-preview-icon='hashtag'><Icon className='column-link__icon' id='hashtag' fixedWidth /><FormattedMessage id='explore.title' defaultMessage='Explore' /></NavLink> - <NavLink className='column-link column-link--transparent' to='/public/local' data-preview-title-id='column.community' data-preview-icon='users' ><Icon className='column-link__icon' id='users' fixedWidth /><FormattedMessage id='tabs_bar.local_timeline' defaultMessage='Local' /></NavLink> - <NavLink className='column-link column-link--transparent' exact to='/public' data-preview-title-id='column.public' data-preview-icon='globe' ><Icon className='column-link__icon' id='globe' fixedWidth /><FormattedMessage id='tabs_bar.federated_timeline' defaultMessage='Federated' /></NavLink> + {showTrends ? ( + <ColumnLink transparent to='/explore' icon='hashtag' text={intl.formatMessage(messages.explore)} /> + ) : ( + <ColumnLink transparent to='/search' icon='search' text={intl.formatMessage(messages.search)} /> + )} + + {(signedIn || timelinePreview) && ( + <> + <ColumnLink transparent to='/public/local' icon='users' text={intl.formatMessage(messages.local)} /> + <ColumnLink transparent exact to='/public' icon='globe' text={intl.formatMessage(messages.federated)} /> + </> + )} {!signedIn && ( - <React.Fragment> + <div className='navigation-panel__sign-in-banner'> <hr /> <SignInBanner /> - </React.Fragment> + </div> )} {signedIn && ( <React.Fragment> - <NavLink className='column-link column-link--transparent' to='/conversations'><Icon className='column-link__icon' id='at' fixedWidth /><FormattedMessage id='navigation_bar.direct' defaultMessage='Direct messages' /></NavLink> - <NavLink className='column-link column-link--transparent' to='/favourites'><Icon className='column-link__icon' id='star' fixedWidth /><FormattedMessage id='navigation_bar.favourites' defaultMessage='Favourites' /></NavLink> - <NavLink className='column-link column-link--transparent' to='/bookmarks'><Icon className='column-link__icon' id='bookmark' fixedWidth /><FormattedMessage id='navigation_bar.bookmarks' defaultMessage='Bookmarks' /></NavLink> - <NavLink className='column-link column-link--transparent' to='/lists'><Icon className='column-link__icon' id='list-ul' fixedWidth /><FormattedMessage id='navigation_bar.lists' defaultMessage='Lists' /></NavLink> + <ColumnLink transparent to='/conversations' icon='at' text={intl.formatMessage(messages.direct)} /> + <ColumnLink transparent to='/favourites' icon='star' text={intl.formatMessage(messages.favourites)} /> + <ColumnLink transparent to='/bookmarks' icon='bookmark' text={intl.formatMessage(messages.bookmarks)} /> + <ColumnLink transparent to='/lists' icon='list-ul' text={intl.formatMessage(messages.lists)} /> <ListPanel /> <hr /> - <a className='column-link column-link--transparent' href='/settings/preferences'><Icon className='column-link__icon' id='cog' fixedWidth /><FormattedMessage id='navigation_bar.preferences' defaultMessage='Preferences' /></a> - <a className='column-link column-link--transparent' href='/relationships'><Icon className='column-link__icon' id='users' fixedWidth /><FormattedMessage id='navigation_bar.follows_and_followers' defaultMessage='Follows and followers' /></a> + <ColumnLink transparent href='/settings/preferences' icon='cog' text={intl.formatMessage(messages.preferences)} /> </React.Fragment> )} - {showTrends && ( - <React.Fragment> - <div className='flex-spacer' /> - <TrendsContainer /> - </React.Fragment> - )} + <div className='navigation-panel__legal'> + <hr /> + <ColumnLink transparent to='/about' icon='ellipsis-h' text={intl.formatMessage(messages.about)} /> + </div> + + <NavigationPortal /> </div> ); } diff --git a/app/javascript/mastodon/features/ui/components/sign_in_banner.js b/app/javascript/mastodon/features/ui/components/sign_in_banner.js index 5ff4ee2a8..8bd32edf9 100644 --- a/app/javascript/mastodon/features/ui/components/sign_in_banner.js +++ b/app/javascript/mastodon/features/ui/components/sign_in_banner.js @@ -1,13 +1,40 @@ -import React from 'react'; +import React, { useCallback } from 'react'; import { FormattedMessage } from 'react-intl'; +import { useDispatch } from 'react-redux'; import { registrationsOpen } from 'mastodon/initial_state'; +import { openModal } from 'mastodon/actions/modal'; -const SignInBanner = () => ( - <div className='sign-in-banner'> - <p><FormattedMessage id='sign_in_banner.text' defaultMessage='Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.' /></p> - <a href='/auth/sign_in' className='button button--block'><FormattedMessage id='sign_in_banner.sign_in' defaultMessage='Sign in' /></a> - <a href={registrationsOpen ? '/auth/sign_up' : 'https://joinmastodon.org/servers'} className='button button--block button-tertiary'><FormattedMessage id='sign_in_banner.create_account' defaultMessage='Create account' /></a> - </div> -); +const SignInBanner = () => { + const dispatch = useDispatch(); + + const openClosedRegistrationsModal = useCallback( + () => dispatch(openModal('CLOSED_REGISTRATIONS')), + [dispatch], + ); + + let signupButton; + + if (registrationsOpen) { + signupButton = ( + <a href='/auth/sign_up' className='button button--block button-tertiary'> + <FormattedMessage id='sign_in_banner.create_account' defaultMessage='Create account' /> + </a> + ); + } else { + signupButton = ( + <button className='button button--block button-tertiary' onClick={openClosedRegistrationsModal}> + <FormattedMessage id='sign_in_banner.create_account' defaultMessage='Create account' /> + </button> + ); + } + + return ( + <div className='sign-in-banner'> + <p><FormattedMessage id='sign_in_banner.text' defaultMessage='Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.' /></p> + <a href='/auth/sign_in' className='button button--block'><FormattedMessage id='sign_in_banner.sign_in' defaultMessage='Sign in' /></a> + {signupButton} + </div> + ); +}; export default SignInBanner; diff --git a/app/javascript/mastodon/features/ui/components/tabs_bar.js b/app/javascript/mastodon/features/ui/components/tabs_bar.js deleted file mode 100644 index 55668cab6..000000000 --- a/app/javascript/mastodon/features/ui/components/tabs_bar.js +++ /dev/null @@ -1,86 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import { NavLink, withRouter } from 'react-router-dom'; -import { FormattedMessage, injectIntl } from 'react-intl'; -import { debounce } from 'lodash'; -import { isUserTouching } from '../../../is_mobile'; -import Icon from 'mastodon/components/icon'; -import NotificationsCounterIcon from './notifications_counter_icon'; - -export const links = [ - <NavLink className='tabs-bar__link' to='/home' data-preview-title-id='column.home' data-preview-icon='home' ><Icon id='home' fixedWidth /><FormattedMessage id='tabs_bar.home' defaultMessage='Home' /></NavLink>, - <NavLink className='tabs-bar__link' to='/notifications' data-preview-title-id='column.notifications' data-preview-icon='bell' ><NotificationsCounterIcon /><FormattedMessage id='tabs_bar.notifications' defaultMessage='Notifications' /></NavLink>, - <NavLink className='tabs-bar__link' to='/public/local' data-preview-title-id='column.community' data-preview-icon='users' ><Icon id='users' fixedWidth /><FormattedMessage id='tabs_bar.local_timeline' defaultMessage='Local' /></NavLink>, - <NavLink className='tabs-bar__link' exact to='/public' data-preview-title-id='column.public' data-preview-icon='globe' ><Icon id='globe' fixedWidth /><FormattedMessage id='tabs_bar.federated_timeline' defaultMessage='Federated' /></NavLink>, - <NavLink className='tabs-bar__link optional' to='/explore' data-preview-title-id='tabs_bar.search' data-preview-icon='search' ><Icon id='search' fixedWidth /><FormattedMessage id='tabs_bar.search' defaultMessage='Search' /></NavLink>, - <NavLink className='tabs-bar__link' style={{ flexGrow: '0', flexBasis: '30px' }} to='/getting-started' data-preview-title-id='getting_started.heading' data-preview-icon='bars' ><Icon id='bars' fixedWidth /></NavLink>, -]; - -export function getIndex (path) { - return links.findIndex(link => link.props.to === path); -} - -export function getLink (index) { - return links[index].props.to; -} - -export default @injectIntl -@withRouter -class TabsBar extends React.PureComponent { - - static propTypes = { - intl: PropTypes.object.isRequired, - history: PropTypes.object.isRequired, - } - - setRef = ref => { - this.node = ref; - } - - handleClick = (e) => { - // Only apply optimization for touch devices, which we assume are slower - // We thus avoid the 250ms delay for non-touch devices and the lag for touch devices - if (isUserTouching()) { - e.preventDefault(); - e.persist(); - - requestAnimationFrame(() => { - const tabs = Array(...this.node.querySelectorAll('.tabs-bar__link')); - const currentTab = tabs.find(tab => tab.classList.contains('active')); - const nextTab = tabs.find(tab => tab.contains(e.target)); - const { props: { to } } = links[Array(...this.node.childNodes).indexOf(nextTab)]; - - - if (currentTab !== nextTab) { - if (currentTab) { - currentTab.classList.remove('active'); - } - - const listener = debounce(() => { - nextTab.removeEventListener('transitionend', listener); - this.props.history.push(to); - }, 50); - - nextTab.addEventListener('transitionend', listener); - nextTab.classList.add('active'); - } - }); - } - - } - - render () { - const { intl: { formatMessage } } = this.props; - - return ( - <div className='tabs-bar__wrapper'> - <nav className='tabs-bar' ref={this.setRef}> - {links.map(link => React.cloneElement(link, { key: link.props.to, onClick: this.handleClick, 'aria-label': formatMessage({ id: link.props['data-preview-title-id'] }) }))} - </nav> - - <div id='tabs-bar__portal' /> - </div> - ); - } - -} diff --git a/app/javascript/mastodon/features/ui/index.js b/app/javascript/mastodon/features/ui/index.js index efe460fab..298f2111d 100644 --- a/app/javascript/mastodon/features/ui/index.js +++ b/app/javascript/mastodon/features/ui/index.js @@ -3,7 +3,7 @@ import React from 'react'; import { HotKeys } from 'react-hotkeys'; import { defineMessages, injectIntl } from 'react-intl'; import { connect } from 'react-redux'; -import { Redirect, withRouter } from 'react-router-dom'; +import { Redirect, Route, withRouter } from 'react-router-dom'; import PropTypes from 'prop-types'; import NotificationsContainer from './containers/notifications_container'; import LoadingBarContainer from './containers/loading_bar_container'; @@ -18,6 +18,7 @@ import { clearHeight } from '../../actions/height_cache'; import { focusApp, unfocusApp, changeLayout } from 'mastodon/actions/app'; import { synchronouslySubmitMarkers, submitMarkers, fetchMarkers } from 'mastodon/actions/markers'; import { WrappedSwitch, WrappedRoute } from './util/react_router_helpers'; +import BundleColumnError from './components/bundle_column_error'; import UploadArea from './components/upload_area'; import ColumnsAreaContainer from './containers/columns_area_container'; import PictureInPicture from 'mastodon/features/picture_in_picture'; @@ -39,7 +40,6 @@ import { HashtagTimeline, Notifications, FollowRequests, - GenericNotFound, FavouritedStatuses, BookmarkedStatuses, ListTimeline, @@ -51,10 +51,12 @@ import { Directory, Explore, FollowRecommendations, + About, + PrivacyPolicy, } from './util/async-components'; -import { me, title } from '../../initial_state'; +import initialState, { me, owner, singleUserMode, showTrends } from '../../initial_state'; import { closeOnboarding, INTRODUCTION_VERSION } from 'mastodon/actions/onboarding'; -import { Helmet } from 'react-helmet'; +import Header from './components/header'; // Dummy import, to make sure that <Status /> ends up in the application bundle. // Without this it ends up in ~8 very commonly used bundles. @@ -143,7 +145,7 @@ class SwitchingColumnsArea extends React.PureComponent { setRef = c => { if (c) { - this.node = c.getWrappedInstance(); + this.node = c; } } @@ -159,8 +161,12 @@ class SwitchingColumnsArea extends React.PureComponent { } else { redirect = <Redirect from='/' to='/getting-started' exact />; } - } else { + } else if (singleUserMode && owner && initialState?.accounts[owner]) { + redirect = <Redirect from='/' to={`/@${initialState.accounts[owner].username}`} exact />; + } else if (showTrends) { redirect = <Redirect from='/' to='/explore' exact />; + } else { + redirect = <Redirect from='/' to='/about' exact />; } return ( @@ -170,6 +176,8 @@ class SwitchingColumnsArea extends React.PureComponent { <WrappedRoute path='/getting-started' component={GettingStarted} content={children} /> <WrappedRoute path='/keyboard-shortcuts' component={KeyboardShortcuts} content={children} /> + <WrappedRoute path='/about' component={About} content={children} /> + <WrappedRoute path='/privacy-policy' component={PrivacyPolicy} content={children} /> <WrappedRoute path={['/home', '/timelines/home']} component={HomeTimeline} content={children} /> <WrappedRoute path={['/public', '/timelines/public']} exact component={PublicTimeline} content={children} /> @@ -189,9 +197,10 @@ class SwitchingColumnsArea extends React.PureComponent { <WrappedRoute path={['/publish', '/statuses/new']} component={Compose} content={children} /> <WrappedRoute path={['/@:acct', '/accounts/:id']} exact component={AccountTimeline} content={children} /> + <WrappedRoute path='/@:acct/tagged/:tagged?' exact component={AccountTimeline} content={children} /> <WrappedRoute path={['/@:acct/with_replies', '/accounts/:id/with_replies']} component={AccountTimeline} content={children} componentParams={{ withReplies: true }} /> - <WrappedRoute path={['/@:acct/followers', '/accounts/:id/followers']} component={Followers} content={children} /> - <WrappedRoute path={['/@:acct/following', '/accounts/:id/following']} component={Following} content={children} /> + <WrappedRoute path={['/accounts/:id/followers', '/users/:acct/followers', '/@:acct/followers']} component={Followers} content={children} /> + <WrappedRoute path={['/accounts/:id/following', '/users/:acct/following', '/@:acct/following']} component={Following} content={children} /> <WrappedRoute path={['/@:acct/media', '/accounts/:id/media']} component={AccountGallery} content={children} /> <WrappedRoute path='/@:acct/:statusId' exact component={Status} content={children} /> <WrappedRoute path='/@:acct/:statusId/reblogs' component={Reblogs} content={children} /> @@ -210,7 +219,7 @@ class SwitchingColumnsArea extends React.PureComponent { <WrappedRoute path='/mutes' component={Mutes} content={children} /> <WrappedRoute path='/lists' component={Lists} content={children} /> - <WrappedRoute component={GenericNotFound} content={children} /> + <Route component={BundleColumnError} /> </WrappedSwitch> </ColumnsAreaContainer> ); @@ -559,6 +568,8 @@ class UI extends React.PureComponent { return ( <HotKeys keyMap={keyMap} handlers={handlers} ref={this.setHotkeysRef} attach={window} focused> <div className={classNames('ui', { 'is-composing': isComposing })} ref={this.setRef} style={{ pointerEvents: dropdownMenuIsOpen ? 'none' : null }}> + <Header /> + <SwitchingColumnsArea location={location} mobile={layout === 'mobile' || layout === 'single-column'}> {children} </SwitchingColumnsArea> @@ -568,10 +579,6 @@ class UI extends React.PureComponent { <LoadingBarContainer className='loading-bar' /> <ModalContainer /> <UploadArea active={draggingOver} onClose={this.closeUploadModal} /> - - <Helmet> - <title>{title}</title> - </Helmet> </div> </HotKeys> ); diff --git a/app/javascript/mastodon/features/ui/util/async-components.js b/app/javascript/mastodon/features/ui/util/async-components.js index 29b06206a..6046578de 100644 --- a/app/javascript/mastodon/features/ui/util/async-components.js +++ b/app/javascript/mastodon/features/ui/util/async-components.js @@ -165,3 +165,23 @@ export function Explore () { export function FilterModal () { return import(/*webpackChunkName: "modals/filter_modal" */'../components/filter_modal'); } + +export function InteractionModal () { + return import(/*webpackChunkName: "modals/interaction_modal" */'../../interaction_modal'); +} + +export function SubscribedLanguagesModal () { + return import(/*webpackChunkName: "modals/subscribed_languages_modal" */'../../subscribed_languages_modal'); +} + +export function ClosedRegistrationsModal () { + return import(/*webpackChunkName: "modals/closed_registrations_modal" */'../../closed_registrations_modal'); +} + +export function About () { + return import(/*webpackChunkName: "features/about" */'../../about'); +} + +export function PrivacyPolicy () { + return import(/*webpackChunkName: "features/privacy_policy" */'../../privacy_policy'); +} diff --git a/app/javascript/mastodon/features/ui/util/react_router_helpers.js b/app/javascript/mastodon/features/ui/util/react_router_helpers.js index d452b871f..2ee06c3ff 100644 --- a/app/javascript/mastodon/features/ui/util/react_router_helpers.js +++ b/app/javascript/mastodon/features/ui/util/react_router_helpers.js @@ -1,7 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { Switch, Route } from 'react-router-dom'; - +import StackTrace from 'stacktrace-js'; import ColumnLoading from '../components/column_loading'; import BundleColumnError from '../components/bundle_column_error'; import BundleContainer from '../containers/bundle_container'; @@ -42,8 +42,38 @@ export class WrappedRoute extends React.Component { componentParams: {}, }; + static getDerivedStateFromError () { + return { + hasError: true, + }; + }; + + state = { + hasError: false, + stacktrace: '', + }; + + componentDidCatch (error) { + StackTrace.fromError(error).then(stackframes => { + this.setState({ stacktrace: error.toString() + '\n' + stackframes.map(frame => frame.toString()).join('\n') }); + }).catch(err => { + console.error(err); + }); + } + renderComponent = ({ match }) => { const { component, content, multiColumn, componentParams } = this.props; + const { hasError, stacktrace } = this.state; + + if (hasError) { + return ( + <BundleColumnError + stacktrace={stacktrace} + multiColumn={multiColumn} + errorType='error' + /> + ); + } return ( <BundleContainer fetchComponent={component} loading={this.renderLoading} error={this.renderError}> @@ -53,11 +83,13 @@ export class WrappedRoute extends React.Component { } renderLoading = () => { - return <ColumnLoading />; + const { multiColumn } = this.props; + + return <ColumnLoading multiColumn={multiColumn} />; } renderError = (props) => { - return <BundleColumnError {...props} />; + return <BundleColumnError {...props} errorType='network' />; } render () { diff --git a/app/javascript/mastodon/initial_state.js b/app/javascript/mastodon/initial_state.js index 08121005a..bb05dafdf 100644 --- a/app/javascript/mastodon/initial_state.js +++ b/app/javascript/mastodon/initial_state.js @@ -1,33 +1,132 @@ +// @ts-check + +/** + * @typedef Emoji + * @property {string} shortcode + * @property {string} static_url + * @property {string} url + */ + +/** + * @typedef AccountField + * @property {string} name + * @property {string} value + * @property {string} verified_at + */ + +/** + * @typedef Account + * @property {string} acct + * @property {string} avatar + * @property {string} avatar_static + * @property {boolean} bot + * @property {string} created_at + * @property {boolean=} discoverable + * @property {string} display_name + * @property {Emoji[]} emojis + * @property {AccountField[]} fields + * @property {number} followers_count + * @property {number} following_count + * @property {boolean} group + * @property {string} header + * @property {string} header_static + * @property {string} id + * @property {string=} last_status_at + * @property {boolean} locked + * @property {string} note + * @property {number} statuses_count + * @property {string} url + * @property {string} username + */ + +/** + * @typedef {[code: string, name: string, localName: string]} InitialStateLanguage + */ + +/** + * @typedef InitialStateMeta + * @property {string} access_token + * @property {boolean=} advanced_layout + * @property {boolean} auto_play_gif + * @property {boolean} activity_api_enabled + * @property {string} admin + * @property {boolean=} boost_modal + * @property {boolean} crop_images + * @property {boolean=} delete_modal + * @property {boolean=} disable_swiping + * @property {boolean} display_media + * @property {string} domain + * @property {boolean=} expand_spoilers + * @property {boolean} limited_federation_mode + * @property {string} locale + * @property {string | null} mascot + * @property {string=} me + * @property {string=} owner + * @property {boolean} profile_directory + * @property {boolean} registrations_open + * @property {boolean} reduce_motion + * @property {string} repository + * @property {boolean} search_enabled + * @property {boolean} single_user_mode + * @property {string} source_url + * @property {string} streaming_api_base_url + * @property {boolean} timeline_preview + * @property {string} title + * @property {boolean} trends + * @property {boolean} unfollow_modal + * @property {boolean} use_blurhash + * @property {boolean=} use_pending_items + * @property {string} version + * @property {boolean} translation_enabled + */ + +/** + * @typedef InitialState + * @property {Record<string, Account>} accounts + * @property {InitialStateLanguage[]} languages + * @property {InitialStateMeta} meta + */ + const element = document.getElementById('initial-state'); -const initialState = element && JSON.parse(element.textContent); +/** @type {InitialState | undefined} */ +const initialState = element?.textContent && JSON.parse(element.textContent); -const getMeta = (prop) => initialState && initialState.meta && initialState.meta[prop]; +/** + * @template {keyof InitialStateMeta} K + * @param {K} prop + * @returns {InitialStateMeta[K] | undefined} + */ +const getMeta = (prop) => initialState?.meta && initialState.meta[prop]; -export const domain = getMeta('domain'); -export const reduceMotion = getMeta('reduce_motion'); +export const activityApiEnabled = getMeta('activity_api_enabled'); export const autoPlayGif = getMeta('auto_play_gif'); -export const displayMedia = getMeta('display_media'); -export const expandSpoilers = getMeta('expand_spoilers'); -export const unfollowModal = getMeta('unfollow_modal'); export const boostModal = getMeta('boost_modal'); +export const cropImages = getMeta('crop_images'); export const deleteModal = getMeta('delete_modal'); -export const me = getMeta('me'); -export const searchEnabled = getMeta('search_enabled'); -export const maxChars = (initialState && initialState.max_toot_chars) || 500; +export const disableSwiping = getMeta('disable_swiping'); +export const displayMedia = getMeta('display_media'); +export const domain = getMeta('domain'); +export const expandSpoilers = getMeta('expand_spoilers'); +export const forceSingleColumn = !getMeta('advanced_layout'); export const limitedFederationMode = getMeta('limited_federation_mode'); +export const mascot = getMeta('mascot'); +export const me = getMeta('me'); +export const owner = getMeta('owner'); +export const profile_directory = getMeta('profile_directory'); +export const reduceMotion = getMeta('reduce_motion'); export const registrationsOpen = getMeta('registrations_open'); export const repository = getMeta('repository'); +export const searchEnabled = getMeta('search_enabled'); +export const showTrends = getMeta('trends'); +export const singleUserMode = getMeta('single_user_mode'); export const source_url = getMeta('source_url'); -export const version = getMeta('version'); -export const mascot = getMeta('mascot'); -export const profile_directory = getMeta('profile_directory'); -export const forceSingleColumn = !getMeta('advanced_layout'); +export const timelinePreview = getMeta('timeline_preview'); +export const title = getMeta('title'); +export const unfollowModal = getMeta('unfollow_modal'); export const useBlurhash = getMeta('use_blurhash'); export const usePendingItems = getMeta('use_pending_items'); -export const showTrends = getMeta('trends'); -export const title = getMeta('title'); -export const cropImages = getMeta('crop_images'); -export const disableSwiping = getMeta('disable_swiping'); -export const languages = initialState && initialState.languages; +export const version = getMeta('version'); +export const translationEnabled = getMeta('translation_enabled'); +export const languages = initialState?.languages; export default initialState; diff --git a/app/javascript/mastodon/is_mobile.js b/app/javascript/mastodon/is_mobile.js index 2926eb4b1..3c8ec1545 100644 --- a/app/javascript/mastodon/is_mobile.js +++ b/app/javascript/mastodon/is_mobile.js @@ -1,10 +1,19 @@ +// @ts-check + import { supportsPassiveEvents } from 'detect-passive-events'; import { forceSingleColumn } from 'mastodon/initial_state'; const LAYOUT_BREAKPOINT = 630; +/** + * @param {number} width + * @returns {boolean} + */ export const isMobile = width => width <= LAYOUT_BREAKPOINT; +/** + * @returns {string} + */ export const layoutFromWindow = () => { if (isMobile(window.innerWidth)) { return 'mobile'; @@ -17,11 +26,13 @@ export const layoutFromWindow = () => { const iOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream; +const listenerOptions = supportsPassiveEvents ? { passive: true } : false; + let userTouching = false; -let listenerOptions = supportsPassiveEvents ? { passive: true } : false; const touchListener = () => { userTouching = true; + window.removeEventListener('touchstart', touchListener, listenerOptions); }; diff --git a/app/javascript/mastodon/load_polyfills.js b/app/javascript/mastodon/load_polyfills.js index 73eedc9dc..cc5bcd18f 100644 --- a/app/javascript/mastodon/load_polyfills.js +++ b/app/javascript/mastodon/load_polyfills.js @@ -26,6 +26,7 @@ function loadPolyfills() { // Edge does not have requestIdleCallback and object-fit CSS property. // This avoids shipping them all the polyfills. const needsExtraPolyfills = !( + window.AbortController && window.IntersectionObserver && window.IntersectionObserverEntry && 'isIntersecting' in IntersectionObserverEntry.prototype && diff --git a/app/javascript/mastodon/locales/af.json b/app/javascript/mastodon/locales/af.json index 2d3f2e694..364fa5505 100644 --- a/app/javascript/mastodon/locales/af.json +++ b/app/javascript/mastodon/locales/af.json @@ -1,4 +1,17 @@ { + "about.blocks": "Moderated servers", + "about.contact": "Contact:", + "about.domain_blocks.comment": "Reason", + "about.domain_blocks.domain": "Domain", + "about.domain_blocks.preamble": "Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.", + "about.domain_blocks.severity": "Severity", + "about.domain_blocks.silenced.explanation": "You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.", + "about.domain_blocks.silenced.title": "Limited", + "about.domain_blocks.suspended.explanation": "No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.", + "about.domain_blocks.suspended.title": "Suspended", + "about.not_available": "This information has not been made available on this server.", + "about.powered_by": "Decentralized social media powered by {mastodon}", + "about.rules": "Server rules", "account.account_note_header": "Nota", "account.add_or_remove_from_list": "Voeg by of verwyder van lyste", "account.badges.bot": "Bot", @@ -7,13 +20,16 @@ "account.block_domain": "Blokeer alles van {domain}", "account.blocked": "Geblok", "account.browse_more_on_origin_server": "Snuffel rond op oorspronklike profiel", - "account.cancel_follow_request": "Kanselleer volgversoek", + "account.cancel_follow_request": "Withdraw follow request", "account.direct": "Stuur direkte boodskap aan @{name}", "account.disable_notifications": "Stop notifying me when @{name} posts", "account.domain_blocked": "Domain blocked", "account.edit_profile": "Redigeer profiel", "account.enable_notifications": "Stel my in kennis wanneer @{name} plasings maak", "account.endorse": "Beklemtoon op profiel", + "account.featured_tags.last_status_at": "Last post on {date}", + "account.featured_tags.last_status_never": "No posts", + "account.featured_tags.title": "{name}'s featured hashtags", "account.follow": "Volg", "account.followers": "Volgelinge", "account.followers.empty": "Niemand volg tans hierdie gebruiker nie.", @@ -23,7 +39,7 @@ "account.follows.empty": "Die gebruiker volg nie tans iemand nie.", "account.follows_you": "Volg jou", "account.hide_reblogs": "Versteek hupstoot vanaf @{name}", - "account.joined": "{date} aangesluit", + "account.joined_short": "Joined", "account.languages": "Change subscribed languages", "account.link_verified_on": "Eienaarskap van die skakel was getoets op {date}", "account.locked_info": "Die rekening se privaatheidstatus is gesluit. Die eienaar hersien handmatig wie hom/haar kan volg.", @@ -63,12 +79,24 @@ "audio.hide": "Hide audio", "autosuggest_hashtag.per_week": "{count} per week", "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.copy_stacktrace": "Copy error report", + "bundle_column_error.error.body": "The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.", + "bundle_column_error.error.title": "Oh, no!", + "bundle_column_error.network.body": "There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.", + "bundle_column_error.network.title": "Network error", "bundle_column_error.retry": "Probeer weer", - "bundle_column_error.title": "Netwerk fout", + "bundle_column_error.return": "Go back home", + "bundle_column_error.routing.body": "The requested page could not be found. Are you sure the URL in the address bar is correct?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Close", "bundle_modal_error.message": "Iets het verkeerd gegaan terwyl hierdie komponent besig was om te laai.", "bundle_modal_error.retry": "Probeer weer", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "About", "column.blocks": "Blocked users", "column.bookmarks": "Boekmerke", "column.community": "Plaaslike tydlyn", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "Block & Report", "confirmations.block.confirm": "Block", "confirmations.block.message": "Are you sure you want to block {name}?", + "confirmations.cancel_follow_request.confirm": "Withdraw request", + "confirmations.cancel_follow_request.message": "Are you sure you want to withdraw your request to follow {name}?", "confirmations.delete.confirm": "Delete", "confirmations.delete.message": "Are you sure you want to delete this status?", "confirmations.delete_list.confirm": "Delete", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Mark as read", "conversation.open": "View conversation", "conversation.with": "With {names}", + "copypaste.copied": "Copied", + "copypaste.copy": "Copy", "directory.federated": "From known fediverse", "directory.local": "From {domain} only", "directory.new_arrivals": "New arrivals", "directory.recently_active": "Recently active", + "dismissable_banner.community_timeline": "These are the most recent public posts from people whose accounts are hosted by {domain}.", + "dismissable_banner.dismiss": "Dismiss", + "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", + "dismissable_banner.explore_statuses": "These posts from this and other servers in the decentralized network are gaining traction on this server right now.", + "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", + "dismissable_banner.public_timeline": "These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.", "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", @@ -221,14 +259,14 @@ "follow_request.reject": "Reject", "follow_requests.unlocked_explanation": "Even though your account is not locked, the {domain} staff thought you might want to review follow requests from these accounts manually.", "generic.saved": "Saved", - "getting_started.developers": "Developers", - "getting_started.directory": "Profile directory", + "getting_started.directory": "Directory", "getting_started.documentation": "Documentation", + "getting_started.free_software_notice": "Mastodon is free, open source software. You can view the source code, contribute or report issues at {repository}.", "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.privacy_policy": "Privacy Policy", "getting_started.security": "Security", + "getting_started.what_is_mastodon": "About Mastodon", "hashtag.column_header.tag_mode.all": "and {additional}", "hashtag.column_header.tag_mode.any": "or {additional}", "hashtag.column_header.tag_mode.none": "without {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Show replies", "home.hide_announcements": "Hide announcements", "home.show_announcements": "Show announcements", + "interaction_modal.description.favourite": "With an account on Mastodon, you can favourite this post to let the author know you appreciate it and save it for later.", + "interaction_modal.description.follow": "With an account on Mastodon, you can follow {name} to receive their posts in your home feed.", + "interaction_modal.description.reblog": "With an account on Mastodon, you can boost this post to share it with your own followers.", + "interaction_modal.description.reply": "With an account on Mastodon, you can respond to this post.", + "interaction_modal.on_another_server": "On a different server", + "interaction_modal.on_this_server": "On this server", + "interaction_modal.other_server_instructions": "Simply copy and paste this URL into the search bar of your favourite app or the web interface where you are signed in.", + "interaction_modal.preamble": "Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one.", + "interaction_modal.title.favourite": "Favourite {name}'s post", + "interaction_modal.title.follow": "Follow {name}", + "interaction_modal.title.reblog": "Boost {name}'s post", + "interaction_modal.title.reply": "Reply to {name}'s post", "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}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Duration", "mute_modal.hide_notifications": "Hide notifications from this user?", "mute_modal.indefinite": "Indefinite", - "navigation_bar.apps": "Mobile apps", + "navigation_bar.about": "About", + "navigation_bar.apps": "Get the app", "navigation_bar.blocks": "Blocked users", "navigation_bar.bookmarks": "Bookmarks", "navigation_bar.community_timeline": "Local timeline", @@ -324,7 +375,7 @@ "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.info": "About", "navigation_bar.keyboard_shortcuts": "Hotkeys", "navigation_bar.lists": "Lists", "navigation_bar.logout": "Logout", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Pinned toots", "navigation_bar.preferences": "Preferences", "navigation_bar.public_timeline": "Federated timeline", + "navigation_bar.search": "Search", "navigation_bar.security": "Security", + "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", "notification.admin.report": "{name} reported {target}", "notification.admin.sign_up": "{name} signed up", "notification.favourite": "{name} favourited your status", @@ -401,6 +454,8 @@ "privacy.public.short": "Public", "privacy.unlisted.long": "Visible for all, but opted-out of discovery features", "privacy.unlisted.short": "Unlisted", + "privacy_policy.last_updated": "Last updated {date}", + "privacy_policy.title": "Privacy Policy", "refresh": "Refresh", "regeneration_indicator.label": "Loading…", "regeneration_indicator.sublabel": "Your home feed is being prepared!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.title": "Search for {q}", "search_results.total": "{count, number} {count, plural, one {result} other {results}}", + "server_banner.about_active_users": "People using this server during the last 30 days (Monthly Active Users)", + "server_banner.active_users": "active users", + "server_banner.administered_by": "Administered by:", + "server_banner.introduction": "{domain} is part of the decentralized social network powered by {mastodon}.", + "server_banner.learn_more": "Learn more", + "server_banner.server_stats": "Server stats:", "sign_in_banner.create_account": "Create account", "sign_in_banner.sign_in": "Sign in", "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "No one has boosted this toot yet. When someone does, they will show up here.", "status.redraft": "Delete & re-draft", "status.remove_bookmark": "Remove bookmark", + "status.replied_to": "Replied to {name}", "status.reply": "Reply", "status.replyAll": "Reply to thread", "status.report": "Report @{name}", @@ -523,9 +585,8 @@ "status.show_more": "Show more", "status.show_more_all": "Show more for all", "status.show_original": "Show original", - "status.show_thread": "Show thread", "status.translate": "Translate", - "status.translated_from": "Translated from {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Not available", "status.unmute_conversation": "Unmute conversation", "status.unpin": "Unpin from profile", @@ -538,7 +599,6 @@ "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", diff --git a/app/javascript/mastodon/locales/ar.json b/app/javascript/mastodon/locales/ar.json index 00e91004e..d8113d439 100644 --- a/app/javascript/mastodon/locales/ar.json +++ b/app/javascript/mastodon/locales/ar.json @@ -1,4 +1,17 @@ { + "about.blocks": "خوادم تحت الإشراف", + "about.contact": "اتصل بـ:", + "about.domain_blocks.comment": "السبب", + "about.domain_blocks.domain": "النطاق", + "about.domain_blocks.preamble": "Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.", + "about.domain_blocks.severity": "Severity", + "about.domain_blocks.silenced.explanation": "You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.", + "about.domain_blocks.silenced.title": "Limited", + "about.domain_blocks.suspended.explanation": "No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.", + "about.domain_blocks.suspended.title": "Suspended", + "about.not_available": "This information has not been made available on this server.", + "about.powered_by": "Decentralized social media powered by {mastodon}", + "about.rules": "قواعد الخادم", "account.account_note_header": "مُلاحظة", "account.add_or_remove_from_list": "الإضافة أو الإزالة من القائمة", "account.badges.bot": "روبوت", @@ -7,13 +20,16 @@ "account.block_domain": "حظر اسم النِّطاق {domain}", "account.blocked": "محظور", "account.browse_more_on_origin_server": "تصفح المزيد في الملف الشخصي الأصلي", - "account.cancel_follow_request": "إلغاء طلب المتابَعة", + "account.cancel_follow_request": "Withdraw follow request", "account.direct": "مراسلة @{name} بشكل مباشر", "account.disable_notifications": "توقف عن إشعاري عندما ينشر @{name}", "account.domain_blocked": "اسم النِّطاق محظور", "account.edit_profile": "تعديل الملف الشخصي", "account.enable_notifications": "أشعرني عندما ينشر @{name}", "account.endorse": "أوصِ به على صفحتك الشخصية", + "account.featured_tags.last_status_at": "Last post on {date}", + "account.featured_tags.last_status_never": "No posts", + "account.featured_tags.title": "{name}'s featured hashtags", "account.follow": "متابعة", "account.followers": "مُتابِعون", "account.followers.empty": "لا أحدَ يُتابع هذا المُستخدم إلى حد الآن.", @@ -23,7 +39,7 @@ "account.follows.empty": "لا يُتابع هذا المُستخدمُ أيَّ أحدٍ حتى الآن.", "account.follows_you": "يُتابِعُك", "account.hide_reblogs": "إخفاء مشاركات @{name}", - "account.joined": "انضم في {date}", + "account.joined_short": "Joined", "account.languages": "Change subscribed languages", "account.link_verified_on": "تمَّ التَّحقق مِن مِلْكيّة هذا الرابط بتاريخ {date}", "account.locked_info": "تمَّ تعيين حالة خصوصية هذا الحساب إلى مُقفَل. يُراجع المالك يدويًا من يمكنه متابعته.", @@ -63,12 +79,24 @@ "audio.hide": "إخفاء المقطع الصوتي", "autosuggest_hashtag.per_week": "{count} في الأسبوع", "boost_modal.combo": "يُمكنك الضّغط على {combo} لتخطي هذا في المرة المُقبلة", - "bundle_column_error.body": "لقد حدث خطأ ما أثناء تحميل هذا العنصر.", + "bundle_column_error.copy_stacktrace": "Copy error report", + "bundle_column_error.error.body": "The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.", + "bundle_column_error.error.title": "أوه لا!", + "bundle_column_error.network.body": "There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.", + "bundle_column_error.network.title": "خطأ في الشبكة", "bundle_column_error.retry": "إعادة المُحاولة", - "bundle_column_error.title": "خطأ في الشبكة", + "bundle_column_error.return": "Go back home", + "bundle_column_error.routing.body": "The requested page could not be found. Are you sure the URL in the address bar is correct?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "إغلاق", "bundle_modal_error.message": "لقد حدث خطأ ما أثناء تحميل هذا العنصر.", "bundle_modal_error.retry": "إعادة المُحاولة", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "عن", "column.blocks": "المُستَخدِمون المَحظورون", "column.bookmarks": "الفواصل المرجعية", "column.community": "الخيط الزمني المحلي", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "حظره والإبلاغ عنه", "confirmations.block.confirm": "حظر", "confirmations.block.message": "هل أنتَ مُتأكدٌ أنكَ تُريدُ حَظرَ {name}؟", + "confirmations.cancel_follow_request.confirm": "Withdraw request", + "confirmations.cancel_follow_request.message": "Are you sure you want to withdraw your request to follow {name}?", "confirmations.delete.confirm": "حذف", "confirmations.delete.message": "هل أنتَ مُتأكدٌ أنك تُريدُ حَذفَ هذا المنشور؟", "confirmations.delete_list.confirm": "حذف", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "اعتبرها كمقروءة", "conversation.open": "اعرض المحادثة", "conversation.with": "بـ {names}", + "copypaste.copied": "تم نسخه", + "copypaste.copy": "انسخ", "directory.federated": "مِن الفديفرس المعروف", "directory.local": "مِن {domain} فقط", "directory.new_arrivals": "الوافدون الجُدد", "directory.recently_active": "نشط مؤخرا", + "dismissable_banner.community_timeline": "These are the most recent public posts from people whose accounts are hosted by {domain}.", + "dismissable_banner.dismiss": "Dismiss", + "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", + "dismissable_banner.explore_statuses": "These posts from this and other servers in the decentralized network are gaining traction on this server right now.", + "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", + "dismissable_banner.public_timeline": "These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.", "embed.instructions": "يمكنكم إدماج هذا المنشور على موقعكم الإلكتروني عن طريق نسخ الشفرة أدناه.", "embed.preview": "هكذا ما سوف يبدو عليه:", "emoji_button.activity": "الأنشطة", @@ -209,7 +247,7 @@ "filter_modal.added.title": "Filter added!", "filter_modal.select_filter.context_mismatch": "does not apply to this context", "filter_modal.select_filter.expired": "expired", - "filter_modal.select_filter.prompt_new": "New category: {name}", + "filter_modal.select_filter.prompt_new": "فئة جديدة: {name}", "filter_modal.select_filter.search": "Search or create", "filter_modal.select_filter.subtitle": "Use an existing category or create a new one", "filter_modal.select_filter.title": "Filter this post", @@ -221,14 +259,14 @@ "follow_request.reject": "رفض", "follow_requests.unlocked_explanation": "على الرغم من أن حسابك غير مقفل، فإن موظفين الـ{domain} ظنوا أنك قد ترغب في مراجعة طلبات المتابعة من هذه الحسابات يدوياً.", "generic.saved": "تم الحفظ", - "getting_started.developers": "المُطوِّرون", - "getting_started.directory": "دليل الصفحات التعريفية", + "getting_started.directory": "الدليل", "getting_started.documentation": "الدليل", + "getting_started.free_software_notice": "Mastodon is free, open source software. You can view the source code, contribute or report issues at {repository}.", "getting_started.heading": "استعدّ للبدء", "getting_started.invite": "دعوة أشخاص", - "getting_started.open_source_notice": "ماستدون برنامج مفتوح المصدر. يمكنك المساهمة، أو الإبلاغ عن تقارير الأخطاء، على جيت هب {github}.", - "getting_started.privacy_policy": "Privacy Policy", + "getting_started.privacy_policy": "سياسة الخصوصية", "getting_started.security": "الأمان", + "getting_started.what_is_mastodon": "عن ماستدون", "hashtag.column_header.tag_mode.all": "و {additional}", "hashtag.column_header.tag_mode.any": "أو {additional}", "hashtag.column_header.tag_mode.none": "بدون {additional}", @@ -238,13 +276,25 @@ "hashtag.column_settings.tag_mode.any": "أي كان مِن هذه", "hashtag.column_settings.tag_mode.none": "لا شيء مِن هذه", "hashtag.column_settings.tag_toggle": "إدراج الوسوم الإضافية لهذا العمود", - "hashtag.follow": "Follow hashtag", - "hashtag.unfollow": "Unfollow hashtag", + "hashtag.follow": "اتبع وسم الهاشج", + "hashtag.unfollow": "ألغِ متابعة الوسم", "home.column_settings.basic": "الأساسية", "home.column_settings.show_reblogs": "اعرض الترقيات", "home.column_settings.show_replies": "اعرض الردود", "home.hide_announcements": "إخفاء الإعلانات", "home.show_announcements": "إظهار الإعلانات", + "interaction_modal.description.favourite": "With an account on Mastodon, you can favourite this post to let the author know you appreciate it and save it for later.", + "interaction_modal.description.follow": "With an account on Mastodon, you can follow {name} to receive their posts in your home feed.", + "interaction_modal.description.reblog": "With an account on Mastodon, you can boost this post to share it with your own followers.", + "interaction_modal.description.reply": "With an account on Mastodon, you can respond to this post.", + "interaction_modal.on_another_server": "On a different server", + "interaction_modal.on_this_server": "على هذا الخادم", + "interaction_modal.other_server_instructions": "Simply copy and paste this URL into the search bar of your favourite app or the web interface where you are signed in.", + "interaction_modal.preamble": "Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one.", + "interaction_modal.title.favourite": "Favourite {name}'s post", + "interaction_modal.title.follow": "اتبع {name}", + "interaction_modal.title.reblog": "Boost {name}'s post", + "interaction_modal.title.reply": "Reply to {name}'s post", "intervals.full.days": "{number, plural, one {# يوم} other {# أيام}}", "intervals.full.hours": "{number, plural, one {# ساعة} other {# ساعات}}", "intervals.full.minutes": "{number, plural, one {# دقيقة} other {# دقائق}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "المدة", "mute_modal.hide_notifications": "هل تود إخفاء الإخطارات القادمة من هذا المستخدم ؟", "mute_modal.indefinite": "إلى أجل غير مسمى", - "navigation_bar.apps": "تطبيقات الأجهزة المحمولة", + "navigation_bar.about": "عن", + "navigation_bar.apps": "احصل على التطبيق", "navigation_bar.blocks": "الحسابات المحجوبة", "navigation_bar.bookmarks": "الفواصل المرجعية", "navigation_bar.community_timeline": "الخيط المحلي", @@ -324,7 +375,7 @@ "navigation_bar.filters": "الكلمات المكتومة", "navigation_bar.follow_requests": "طلبات المتابعة", "navigation_bar.follows_and_followers": "المتابِعين والمتابَعون", - "navigation_bar.info": "عن هذا الخادم", + "navigation_bar.info": "عن", "navigation_bar.keyboard_shortcuts": "اختصارات لوحة المفاتيح", "navigation_bar.lists": "القوائم", "navigation_bar.logout": "خروج", @@ -333,7 +384,9 @@ "navigation_bar.pins": "المنشورات المُثَبَّتَة", "navigation_bar.preferences": "التفضيلات", "navigation_bar.public_timeline": "الخيط العام الموحد", + "navigation_bar.search": "Search", "navigation_bar.security": "الأمان", + "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", "notification.admin.report": "{name} reported {target}", "notification.admin.sign_up": "أنشأ {name} حسابًا", "notification.favourite": "أُعجِب {name} بمنشورك", @@ -401,6 +454,8 @@ "privacy.public.short": "للعامة", "privacy.unlisted.long": "مرئي للجميع، ولكن مِن دون ميزات الاكتشاف", "privacy.unlisted.short": "غير مدرج", + "privacy_policy.last_updated": "Last updated {date}", + "privacy_policy.title": "سياسة الخصوصية", "refresh": "أنعِش", "regeneration_indicator.label": "جارٍ التحميل…", "regeneration_indicator.sublabel": "جارٍ تجهيز تغذية صفحتك الرئيسية!", @@ -473,8 +528,14 @@ "search_results.statuses_fts_disabled": "البحث عن المنشورات عن طريق المحتوى ليس مفعل في خادم ماستدون هذا.", "search_results.title": "Search for {q}", "search_results.total": "{count, number} {count, plural, zero {} one {نتيجة} two {نتيجتين} few {نتائج} many {نتائج} other {نتائج}}", - "sign_in_banner.create_account": "Create account", - "sign_in_banner.sign_in": "Sign in", + "server_banner.about_active_users": "People using this server during the last 30 days (Monthly Active Users)", + "server_banner.active_users": "مستخدم نشط", + "server_banner.administered_by": "يُديره:", + "server_banner.introduction": "{domain} is part of the decentralized social network powered by {mastodon}.", + "server_banner.learn_more": "تعلم المزيد", + "server_banner.server_stats": "إحصائيات الخادم:", + "sign_in_banner.create_account": "أنشئ حسابًا", + "sign_in_banner.sign_in": "لِج", "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", "status.admin_account": "افتح الواجهة الإدارية لـ @{name}", "status.admin_status": "افتح هذا المنشور على واجهة الإشراف", @@ -512,6 +573,7 @@ "status.reblogs.empty": "لم يقم أي أحد بمشاركة هذا المنشور بعد. عندما يقوم أحدهم بذلك سوف يظهر هنا.", "status.redraft": "إزالة و إعادة الصياغة", "status.remove_bookmark": "احذفه مِن الفواصل المرجعية", + "status.replied_to": "Replied to {name}", "status.reply": "ردّ", "status.replyAll": "رُد على الخيط", "status.report": "ابلِغ عن @{name}", @@ -522,10 +584,9 @@ "status.show_less_all": "طي الكل", "status.show_more": "أظهر المزيد", "status.show_more_all": "توسيع الكل", - "status.show_original": "Show original", - "status.show_thread": "الكشف عن المحادثة", - "status.translate": "Translate", - "status.translated_from": "Translated from {lang}", + "status.show_original": "إظهار الأصل", + "status.translate": "ترجم", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "غير متوفر", "status.unmute_conversation": "فك الكتم عن المحادثة", "status.unpin": "فك التدبيس من الصفحة التعريفية", @@ -538,7 +599,6 @@ "tabs_bar.home": "الرئيسية", "tabs_bar.local_timeline": "الخيط العام المحلي", "tabs_bar.notifications": "الإخطارات", - "tabs_bar.search": "البحث", "time_remaining.days": "{number, plural, one {# يوم} other {# أيام}} متبقية", "time_remaining.hours": "{number, plural, one {# ساعة} other {# ساعات}} متبقية", "time_remaining.minutes": "{number, plural, one {# دقيقة} other {# دقائق}} متبقية", diff --git a/app/javascript/mastodon/locales/ast.json b/app/javascript/mastodon/locales/ast.json index aabcefaea..60d2008b5 100644 --- a/app/javascript/mastodon/locales/ast.json +++ b/app/javascript/mastodon/locales/ast.json @@ -1,4 +1,17 @@ { + "about.blocks": "Moderated servers", + "about.contact": "Contact:", + "about.domain_blocks.comment": "Reason", + "about.domain_blocks.domain": "Domain", + "about.domain_blocks.preamble": "Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.", + "about.domain_blocks.severity": "Severity", + "about.domain_blocks.silenced.explanation": "You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.", + "about.domain_blocks.silenced.title": "Limited", + "about.domain_blocks.suspended.explanation": "No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.", + "about.domain_blocks.suspended.title": "Suspended", + "about.not_available": "This information has not been made available on this server.", + "about.powered_by": "Decentralized social media powered by {mastodon}", + "about.rules": "Server rules", "account.account_note_header": "Note", "account.add_or_remove_from_list": "Amestar o desaniciar de les llistes", "account.badges.bot": "Robó", @@ -7,13 +20,16 @@ "account.block_domain": "Anubrir tolo de {domain}", "account.blocked": "Bloquiada", "account.browse_more_on_origin_server": "Browse more on the original profile", - "account.cancel_follow_request": "Encaboxar la solicitú de siguimientu", + "account.cancel_follow_request": "Withdraw follow request", "account.direct": "Unviar un mensaxe direutu a @{name}", "account.disable_notifications": "Stop notifying me when @{name} posts", "account.domain_blocked": "Dominiu anubríu", "account.edit_profile": "Editar el perfil", "account.enable_notifications": "Notify me when @{name} posts", "account.endorse": "Destacar nel perfil", + "account.featured_tags.last_status_at": "Last post on {date}", + "account.featured_tags.last_status_never": "No posts", + "account.featured_tags.title": "{name}'s featured hashtags", "account.follow": "Siguir", "account.followers": "Siguidores", "account.followers.empty": "Naide sigue a esti usuariu entá.", @@ -23,7 +39,7 @@ "account.follows.empty": "Esti usuariu entá nun sigue a naide.", "account.follows_you": "Síguete", "account.hide_reblogs": "Anubrir les comparticiones de @{name}", - "account.joined": "Joined {date}", + "account.joined_short": "Joined", "account.languages": "Change subscribed languages", "account.link_verified_on": "La propiedá d'esti enllaz foi comprobada'l {date}", "account.locked_info": "This account privacy status is set to locked. The owner manually reviews who can follow them.", @@ -63,12 +79,24 @@ "audio.hide": "Hide audio", "autosuggest_hashtag.per_week": "{count} per selmana", "boost_modal.combo": "Pues primir {combo} pa saltar esto la próxima vegada", - "bundle_column_error.body": "Asocedió daqué malo mentanto se cargaba esti componente.", + "bundle_column_error.copy_stacktrace": "Copy error report", + "bundle_column_error.error.body": "The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.", + "bundle_column_error.error.title": "Oh, no!", + "bundle_column_error.network.body": "There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.", + "bundle_column_error.network.title": "Network error", "bundle_column_error.retry": "Try again", - "bundle_column_error.title": "Network error", + "bundle_column_error.return": "Go back home", + "bundle_column_error.routing.body": "The requested page could not be found. Are you sure the URL in the address bar is correct?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Close", "bundle_modal_error.message": "Asocedió daqué malo mentanto se cargaba esti componente.", "bundle_modal_error.retry": "Try again", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "About", "column.blocks": "Usuarios bloquiaos", "column.bookmarks": "Marcadores", "column.community": "Llinia temporal llocal", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "Bloquiar ya informar", "confirmations.block.confirm": "Bloquiar", "confirmations.block.message": "¿De xuru que quies bloquiar a {name}?", + "confirmations.cancel_follow_request.confirm": "Withdraw request", + "confirmations.cancel_follow_request.message": "Are you sure you want to withdraw your request to follow {name}?", "confirmations.delete.confirm": "Desaniciar", "confirmations.delete.message": "¿De xuru que quies desaniciar esti estáu?", "confirmations.delete_list.confirm": "Desaniciar", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Mark as read", "conversation.open": "View conversation", "conversation.with": "Con {names}", + "copypaste.copied": "Copied", + "copypaste.copy": "Copy", "directory.federated": "Dende'l fediversu", "directory.local": "Dende {domain} namái", "directory.new_arrivals": "Cuentes nueves", "directory.recently_active": "Actividá recién", + "dismissable_banner.community_timeline": "These are the most recent public posts from people whose accounts are hosted by {domain}.", + "dismissable_banner.dismiss": "Dismiss", + "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", + "dismissable_banner.explore_statuses": "These posts from this and other servers in the decentralized network are gaining traction on this server right now.", + "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", + "dismissable_banner.public_timeline": "These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.", "embed.instructions": "Empotra esti estáu nun sitiu web copiando'l códigu d'embaxo.", "embed.preview": "Asina ye cómo va vese:", "emoji_button.activity": "Actividá", @@ -177,14 +215,14 @@ "empty_column.favourited_statuses": "Entá nun tienes nengún barritu en Favoritos. Cuando amiestes unu, va amosase equí.", "empty_column.favourites": "No one has favourited this post yet. When someone does, they will show up here.", "empty_column.follow_recommendations": "Looks like no suggestions could be generated for you. You can try using search to look for people you might know or explore trending hashtags.", - "empty_column.follow_requests": "Entá nun tienes nenguna solicitú de siguimientu. Cuando recibas una, va amosase equí.", + "empty_column.follow_requests": "Entá nun tienes nenguna solicitú de siguimientu. Cuando recibas una, va apaecer equí.", "empty_column.hashtag": "Entá nun hai nada nesta etiqueta.", "empty_column.home": "¡Tienes la llinia temporal balera! Visita {public} o usa la gueta pa entamar y conocer a otros usuarios.", "empty_column.home.suggestions": "See some suggestions", "empty_column.list": "Entá nun hai nada nesta llista. Cuando los miembros d'esta llista espublicen estaos nuevos, van apaecer equí.", - "empty_column.lists": "Entá nun tienes nenguna llista. Cuando crees una, va amosase equí.", - "empty_column.mutes": "Entá nun silenciesti a nunengún usuariu.", - "empty_column.notifications": "Entá nun tienes nunengún avisu. Interactúa con otros p'aniciar la conversación.", + "empty_column.lists": "Entá nun tienes nenguna llista. Cuando crees una, va apaecer equí.", + "empty_column.mutes": "You haven't muted any users yet.", + "empty_column.notifications": "You don't have any notifications yet. When other people interact with you, you will see it here.", "empty_column.public": "¡Equí nun hai nada! Escribi daqué público o sigui a usuarios d'otros sirvidores pa rellenar esto", "error.unexpected_crash.explanation": "Pola mor d'un fallu nel códigu o un problema de compatibilidá del restolador, esta páxina nun se pudo amosar correutamente.", "error.unexpected_crash.explanation_addons": "Esta páxina nun se pudo amosar correutamente. Ye probable que dalgún complementu del restolador o dalguna ferramienta de traducción automática produxere esti fallu.", @@ -221,14 +259,14 @@ "follow_request.reject": "Refugar", "follow_requests.unlocked_explanation": "Even though your account is not locked, the {domain} staff thought you might want to review follow requests from these accounts manually.", "generic.saved": "Saved", - "getting_started.developers": "Desendolcadores", - "getting_started.directory": "Direutoriu de perfiles", + "getting_started.directory": "Directory", "getting_started.documentation": "Documentación", + "getting_started.free_software_notice": "Mastodon ye software llibre y de códigu abiertu. Pues ver el códigu fonte, collaborar ya informar de fallos en {repository}.", "getting_started.heading": "Entamu", "getting_started.invite": "Convidar a persones", - "getting_started.open_source_notice": "Mastodon ye software de códigu abiertu. Pues collaborar o informar de fallos en GitHub: {github}.", "getting_started.privacy_policy": "Privacy Policy", "getting_started.security": "Axustes de la cuenta", + "getting_started.what_is_mastodon": "About Mastodon", "hashtag.column_header.tag_mode.all": "y {additional}", "hashtag.column_header.tag_mode.any": "o {additional}", "hashtag.column_header.tag_mode.none": "ensin {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Amosar rempuestes", "home.hide_announcements": "Hide announcements", "home.show_announcements": "Show announcements", + "interaction_modal.description.favourite": "With an account on Mastodon, you can favourite this post to let the author know you appreciate it and save it for later.", + "interaction_modal.description.follow": "With an account on Mastodon, you can follow {name} to receive their posts in your home feed.", + "interaction_modal.description.reblog": "Con una cuenta de Mastodon, pues compartir esti artículu colos perfiles que te sigan.", + "interaction_modal.description.reply": "Con una cuenta de Mastodon, pues responder a esti artículu.", + "interaction_modal.on_another_server": "N'otru sirvidor", + "interaction_modal.on_this_server": "Nesti sirvidor", + "interaction_modal.other_server_instructions": "Simply copy and paste this URL into the search bar of your favourite app or the web interface where you are signed in.", + "interaction_modal.preamble": "Darréu que Mastodon ye descentralizáu, pues usar una cuenta agospiada n'otru sirvidor de Mastodon o n'otra plataforma compatible si nun tienes cuenta nesti sirvidor.", + "interaction_modal.title.favourite": "Favourite {name}'s post", + "interaction_modal.title.follow": "Follow {name}", + "interaction_modal.title.reblog": "Boost {name}'s post", + "interaction_modal.title.reply": "Reply to {name}'s post", "intervals.full.days": "{number, plural, one {# día} other {# díes}}", "intervals.full.hours": "{number, plural, one {# hora} other {# hores}}", "intervals.full.minutes": "{number, plural, one {# minutu} other {# minutos}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Duración", "mute_modal.hide_notifications": "¿Anubrir los avisos d'esti usuariu?", "mute_modal.indefinite": "Indefinite", - "navigation_bar.apps": "Aplicaciones pa móviles", + "navigation_bar.about": "About", + "navigation_bar.apps": "Get the app", "navigation_bar.blocks": "Usuarios bloquiaos", "navigation_bar.bookmarks": "Marcadores", "navigation_bar.community_timeline": "Llinia temporal llocal", @@ -324,7 +375,7 @@ "navigation_bar.filters": "Pallabres silenciaes", "navigation_bar.follow_requests": "Solicitúes de siguimientu", "navigation_bar.follows_and_followers": "Follows and followers", - "navigation_bar.info": "Tocante a esta instancia", + "navigation_bar.info": "About", "navigation_bar.keyboard_shortcuts": "Atayos", "navigation_bar.lists": "Llistes", "navigation_bar.logout": "Zarrar sesión", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Barritos fixaos", "navigation_bar.preferences": "Preferencies", "navigation_bar.public_timeline": "Llinia temporal federada", + "navigation_bar.search": "Search", "navigation_bar.security": "Seguranza", + "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", "notification.admin.report": "{name} reported {target}", "notification.admin.sign_up": "{name} signed up", "notification.favourite": "{name} favourited your status", @@ -401,6 +454,8 @@ "privacy.public.short": "Public", "privacy.unlisted.long": "Visible for all, but opted-out of discovery features", "privacy.unlisted.short": "Nun llistar", + "privacy_policy.last_updated": "Last updated {date}", + "privacy_policy.title": "Política de privacidá", "refresh": "Refresh", "regeneration_indicator.label": "Cargando…", "regeneration_indicator.sublabel": "¡Tamos tresnando'l feed d'Aniciu!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "Esti sirvidor de Mastodon tien activada la gueta de barritos pol so conteníu.", "search_results.title": "Search for {q}", "search_results.total": "{count, number} {count, plural, one {resultáu} other {resultaos}}", + "server_banner.about_active_users": "People using this server during the last 30 days (Monthly Active Users)", + "server_banner.active_users": "active users", + "server_banner.administered_by": "Administered by:", + "server_banner.introduction": "{domain} is part of the decentralized social network powered by {mastodon}.", + "server_banner.learn_more": "Saber más", + "server_banner.server_stats": "Estadístiques del sirvidor:", "sign_in_banner.create_account": "Create account", "sign_in_banner.sign_in": "Sign in", "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "Naide nun compartió esti barritu entá. Cuando daquién lo faiga, va amosase equí.", "status.redraft": "Desaniciar y reeditar", "status.remove_bookmark": "Desaniciar de Marcadores", + "status.replied_to": "Replied to {name}", "status.reply": "Responder", "status.replyAll": "Reply to thread", "status.report": "Report @{name}", @@ -523,9 +585,8 @@ "status.show_more": "Amosar más", "status.show_more_all": "Amosar más en too", "status.show_original": "Show original", - "status.show_thread": "Amosar el filu", "status.translate": "Translate", - "status.translated_from": "Translated from {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Non disponible", "status.unmute_conversation": "Unmute conversation", "status.unpin": "Desfixar del perfil", @@ -538,7 +599,6 @@ "tabs_bar.home": "Aniciu", "tabs_bar.local_timeline": "Llocal", "tabs_bar.notifications": "Avisos", - "tabs_bar.search": "Search", "time_remaining.days": "{number, plural, one {Queda # día} other {Queden # díes}}", "time_remaining.hours": "{number, plural, one {Queda # hora} other {Queden # hores}}", "time_remaining.minutes": "{number, plural, one {Queda # minutu} other {Queden # minutos}}", diff --git a/app/javascript/mastodon/locales/bg.json b/app/javascript/mastodon/locales/bg.json index 0bb60d8bd..aa67edfd2 100644 --- a/app/javascript/mastodon/locales/bg.json +++ b/app/javascript/mastodon/locales/bg.json @@ -1,4 +1,17 @@ { + "about.blocks": "Moderated servers", + "about.contact": "Contact:", + "about.domain_blocks.comment": "Reason", + "about.domain_blocks.domain": "Domain", + "about.domain_blocks.preamble": "Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.", + "about.domain_blocks.severity": "Severity", + "about.domain_blocks.silenced.explanation": "You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.", + "about.domain_blocks.silenced.title": "Limited", + "about.domain_blocks.suspended.explanation": "No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.", + "about.domain_blocks.suspended.title": "Suspended", + "about.not_available": "This information has not been made available on this server.", + "about.powered_by": "Decentralized social media powered by {mastodon}", + "about.rules": "Server rules", "account.account_note_header": "Бележка", "account.add_or_remove_from_list": "Добави или премахни от списъците", "account.badges.bot": "Бот", @@ -7,13 +20,16 @@ "account.block_domain": "скрий всичко от (домейн)", "account.blocked": "Блокирани", "account.browse_more_on_origin_server": "Разгледайте повече в оригиналния профил", - "account.cancel_follow_request": "Откажи искането за следване", + "account.cancel_follow_request": "Withdraw follow request", "account.direct": "Direct Message @{name}", "account.disable_notifications": "Спрете да ме уведомявате, когато @{name} публикува", "account.domain_blocked": "Скрит домейн", "account.edit_profile": "Редактирай профила", "account.enable_notifications": "Уведомявайте ме, когато @{name} публикува", "account.endorse": "Характеристика на профила", + "account.featured_tags.last_status_at": "Last post on {date}", + "account.featured_tags.last_status_never": "No posts", + "account.featured_tags.title": "{name}'s featured hashtags", "account.follow": "Последвай", "account.followers": "Последователи", "account.followers.empty": "Все още никой не следва този потребител.", @@ -23,7 +39,7 @@ "account.follows.empty": "Този потребител все още не следва никого.", "account.follows_you": "Твой последовател", "account.hide_reblogs": "Скриване на споделяния от @{name}", - "account.joined": "Присъединил се на {date}", + "account.joined_short": "Joined", "account.languages": "Change subscribed languages", "account.link_verified_on": "Собствеността върху тази връзка е проверена на {date}", "account.locked_info": "Този акаунт е поверително заключен. Собственикът преглежда ръчно кой може да го следва.", @@ -63,12 +79,24 @@ "audio.hide": "Скриване на видеото", "autosuggest_hashtag.per_week": "{count} на седмица", "boost_modal.combo": "Можете да натиснете {combo}, за да пропуснете това следващия път", - "bundle_column_error.body": "Нещо се обърка при зареждането на този компонент.", + "bundle_column_error.copy_stacktrace": "Copy error report", + "bundle_column_error.error.body": "The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.", + "bundle_column_error.error.title": "Oh, no!", + "bundle_column_error.network.body": "There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.", + "bundle_column_error.network.title": "Network error", "bundle_column_error.retry": "Опитай отново", - "bundle_column_error.title": "Мрежова грешка", + "bundle_column_error.return": "Go back home", + "bundle_column_error.routing.body": "The requested page could not be found. Are you sure the URL in the address bar is correct?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Затваряне", "bundle_modal_error.message": "Нещо се обърка при зареждането на този компонент.", "bundle_modal_error.retry": "Опитайте отново", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "About", "column.blocks": "Блокирани потребители", "column.bookmarks": "Отметки", "column.community": "Локална емисия", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "Блокиране и докладване", "confirmations.block.confirm": "Блокиране", "confirmations.block.message": "Сигурни ли сте, че искате да блокирате {name}?", + "confirmations.cancel_follow_request.confirm": "Withdraw request", + "confirmations.cancel_follow_request.message": "Are you sure you want to withdraw your request to follow {name}?", "confirmations.delete.confirm": "Изтриване", "confirmations.delete.message": "Are you sure you want to delete this status?", "confirmations.delete_list.confirm": "Изтриване", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Маркиране като прочетено", "conversation.open": "Преглед на разговор", "conversation.with": "С {names}", + "copypaste.copied": "Copied", + "copypaste.copy": "Copy", "directory.federated": "От познат федивърс", "directory.local": "Само от {domain}", "directory.new_arrivals": "Новодошли", "directory.recently_active": "Наскоро активни", + "dismissable_banner.community_timeline": "These are the most recent public posts from people whose accounts are hosted by {domain}.", + "dismissable_banner.dismiss": "Dismiss", + "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", + "dismissable_banner.explore_statuses": "These posts from this and other servers in the decentralized network are gaining traction on this server right now.", + "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", + "dismissable_banner.public_timeline": "These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.", "embed.instructions": "Embed this status on your website by copying the code below.", "embed.preview": "Ето как ще изглежда:", "emoji_button.activity": "Дейност", @@ -221,14 +259,14 @@ "follow_request.reject": "Отхвърляне", "follow_requests.unlocked_explanation": "Въпреки че акаунтът ви не е заключен, служителите на {domain} помислиха, че може да искате да преглеждате ръчно заявките за последване на тези профили.", "generic.saved": "Запазено", - "getting_started.developers": "Разработчици", - "getting_started.directory": "Профилна директория", + "getting_started.directory": "Directory", "getting_started.documentation": "Документация", + "getting_started.free_software_notice": "Mastodon is free, open source software. You can view the source code, contribute or report issues at {repository}.", "getting_started.heading": "Първи стъпки", "getting_started.invite": "Поканване на хора", - "getting_started.open_source_notice": "Mastodon е софтуер с отворен код. Можеш да помогнеш или да докладваш за проблеми в Github: {github}.", "getting_started.privacy_policy": "Privacy Policy", "getting_started.security": "Security", + "getting_started.what_is_mastodon": "About Mastodon", "hashtag.column_header.tag_mode.all": "и {additional}", "hashtag.column_header.tag_mode.any": "или {additional}", "hashtag.column_header.tag_mode.none": "без {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Показване на отговори", "home.hide_announcements": "Скриване на оповестявания", "home.show_announcements": "Показване на оповестявания", + "interaction_modal.description.favourite": "With an account on Mastodon, you can favourite this post to let the author know you appreciate it and save it for later.", + "interaction_modal.description.follow": "With an account on Mastodon, you can follow {name} to receive their posts in your home feed.", + "interaction_modal.description.reblog": "With an account on Mastodon, you can boost this post to share it with your own followers.", + "interaction_modal.description.reply": "With an account on Mastodon, you can respond to this post.", + "interaction_modal.on_another_server": "On a different server", + "interaction_modal.on_this_server": "On this server", + "interaction_modal.other_server_instructions": "Simply copy and paste this URL into the search bar of your favourite app or the web interface where you are signed in.", + "interaction_modal.preamble": "Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one.", + "interaction_modal.title.favourite": "Favourite {name}'s post", + "interaction_modal.title.follow": "Follow {name}", + "interaction_modal.title.reblog": "Boost {name}'s post", + "interaction_modal.title.reply": "Reply to {name}'s post", "intervals.full.days": "{number, plural, one {# ден} other {# дни}}", "intervals.full.hours": "{number, plural, one {# час} other {# часа}}", "intervals.full.minutes": "{number, plural, one {# минута} other {# минути}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Продължителност", "mute_modal.hide_notifications": "Скриване на известия от този потребител?", "mute_modal.indefinite": "Неопределено", - "navigation_bar.apps": "Мобилни приложения", + "navigation_bar.about": "About", + "navigation_bar.apps": "Get the app", "navigation_bar.blocks": "Блокирани потребители", "navigation_bar.bookmarks": "Отметки", "navigation_bar.community_timeline": "Локална емисия", @@ -324,7 +375,7 @@ "navigation_bar.filters": "Заглушени думи", "navigation_bar.follow_requests": "Заявки за последване", "navigation_bar.follows_and_followers": "Последвания и последователи", - "navigation_bar.info": "Extended information", + "navigation_bar.info": "About", "navigation_bar.keyboard_shortcuts": "Keyboard shortcuts", "navigation_bar.lists": "Списъци", "navigation_bar.logout": "Излизане", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Закачени публикации", "navigation_bar.preferences": "Предпочитания", "navigation_bar.public_timeline": "Публичен канал", + "navigation_bar.search": "Search", "navigation_bar.security": "Сигурност", + "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", "notification.admin.report": "{name} докладва {target}", "notification.admin.sign_up": "{name} се регистрира", "notification.favourite": "{name} хареса твоята публикация", @@ -401,6 +454,8 @@ "privacy.public.short": "Публично", "privacy.unlisted.long": "Visible for all, but opted-out of discovery features", "privacy.unlisted.short": "Скрито", + "privacy_policy.last_updated": "Last updated {date}", + "privacy_policy.title": "Privacy Policy", "refresh": "Опресняване", "regeneration_indicator.label": "Зареждане…", "regeneration_indicator.sublabel": "Вашата начална емисия се подготвя!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "Търсенето на публикации по тяхното съдържание не е активирано за този Mastodon сървър.", "search_results.title": "Search for {q}", "search_results.total": "{count, number} {count, plural, one {резултат} other {резултата}}", + "server_banner.about_active_users": "People using this server during the last 30 days (Monthly Active Users)", + "server_banner.active_users": "active users", + "server_banner.administered_by": "Administered by:", + "server_banner.introduction": "{domain} is part of the decentralized social network powered by {mastodon}.", + "server_banner.learn_more": "Learn more", + "server_banner.server_stats": "Server stats:", "sign_in_banner.create_account": "Create account", "sign_in_banner.sign_in": "Sign in", "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "Все още никой не е споделил тази публикация. Когато някой го направи, ще се покаже тук.", "status.redraft": "Изтриване и преработване", "status.remove_bookmark": "Премахване на отметка", + "status.replied_to": "Replied to {name}", "status.reply": "Отговор", "status.replyAll": "Отговор на тема", "status.report": "Докладване на @{name}", @@ -523,9 +585,8 @@ "status.show_more": "Покажи повече", "status.show_more_all": "Покажи повече за всички", "status.show_original": "Show original", - "status.show_thread": "Показване на тема", "status.translate": "Translate", - "status.translated_from": "Translated from {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Не е налично", "status.unmute_conversation": "Раззаглушаване на разговор", "status.unpin": "Разкачане от профил", @@ -538,7 +599,6 @@ "tabs_bar.home": "Начало", "tabs_bar.local_timeline": "Локално", "tabs_bar.notifications": "Известия", - "tabs_bar.search": "Търсене", "time_remaining.days": "{number, plural, one {# ден} other {# дни}} остава", "time_remaining.hours": "{number, plural, one {# час} other {# часа}} остава", "time_remaining.minutes": "{number, plural, one {# минута} other {# минути}} остава", diff --git a/app/javascript/mastodon/locales/bn.json b/app/javascript/mastodon/locales/bn.json index 87c62cd90..c793cac6f 100644 --- a/app/javascript/mastodon/locales/bn.json +++ b/app/javascript/mastodon/locales/bn.json @@ -1,4 +1,17 @@ { + "about.blocks": "Moderated servers", + "about.contact": "Contact:", + "about.domain_blocks.comment": "Reason", + "about.domain_blocks.domain": "Domain", + "about.domain_blocks.preamble": "Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.", + "about.domain_blocks.severity": "Severity", + "about.domain_blocks.silenced.explanation": "You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.", + "about.domain_blocks.silenced.title": "Limited", + "about.domain_blocks.suspended.explanation": "No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.", + "about.domain_blocks.suspended.title": "Suspended", + "about.not_available": "This information has not been made available on this server.", + "about.powered_by": "Decentralized social media powered by {mastodon}", + "about.rules": "Server rules", "account.account_note_header": "বিজ্ঞপ্তি", "account.add_or_remove_from_list": "তালিকাতে যোগ বা অপসারণ করো", "account.badges.bot": "বট", @@ -7,13 +20,16 @@ "account.block_domain": "{domain} থেকে সব লুকাও", "account.blocked": "অবরুদ্ধ", "account.browse_more_on_origin_server": "মূল প্রোফাইলটিতে আরও ব্রাউজ করুন", - "account.cancel_follow_request": "অনুসরণ অনুরোধ বাতিল করো", + "account.cancel_follow_request": "Withdraw follow request", "account.direct": "@{name} কে সরাসরি বার্তা", "account.disable_notifications": "Stop notifying me when @{name} posts", "account.domain_blocked": "ডোমেন গোপন করুন", "account.edit_profile": "প্রোফাইল পরিবর্তন করুন", "account.enable_notifications": "Notify me when @{name} posts", "account.endorse": "নিজের পাতায় দেখান", + "account.featured_tags.last_status_at": "Last post on {date}", + "account.featured_tags.last_status_never": "No posts", + "account.featured_tags.title": "{name}'s featured hashtags", "account.follow": "অনুসরণ", "account.followers": "অনুসরণকারী", "account.followers.empty": "এই ব্যক্তিকে এখনো কেউ অনুসরণ করে না।", @@ -23,7 +39,7 @@ "account.follows.empty": "এই সদস্য কাওকে এখনো অনুসরণ করেন না.", "account.follows_you": "তোমাকে অনুসরণ করে", "account.hide_reblogs": "@{name}'র সমর্থনগুলি লুকিয়ে ফেলুন", - "account.joined": "Joined {date}", + "account.joined_short": "Joined", "account.languages": "Change subscribed languages", "account.link_verified_on": "এই লিংকের মালিকানা চেক করা হয়েছে {date} তারিখে", "account.locked_info": "এই নিবন্ধনের গোপনীয়তার ক্ষেত্র তালা দেওয়া আছে। নিবন্ধনকারী অনুসরণ করার অনুমতি যাদেরকে দেবেন, শুধু তারাই অনুসরণ করতে পারবেন।", @@ -63,12 +79,24 @@ "audio.hide": "Hide audio", "autosuggest_hashtag.per_week": "প্রতি সপ্তাহে {count}", "boost_modal.combo": "পরেরবার আপনি {combo} টিপলে এটি আর আসবে না", - "bundle_column_error.body": "এই অংশটি দেখতে যেয়ে কোনো সমস্যা হয়েছে।.", + "bundle_column_error.copy_stacktrace": "Copy error report", + "bundle_column_error.error.body": "The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.", + "bundle_column_error.error.title": "Oh, no!", + "bundle_column_error.network.body": "There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.", + "bundle_column_error.network.title": "Network error", "bundle_column_error.retry": "আবার চেষ্টা করুন", - "bundle_column_error.title": "নেটওয়ার্কের সমস্যা", + "bundle_column_error.return": "Go back home", + "bundle_column_error.routing.body": "The requested page could not be found. Are you sure the URL in the address bar is correct?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "বন্ধ করুন", "bundle_modal_error.message": "এই অংশটি দেখাতে যেয়ে কোনো সমস্যা হয়েছে।.", "bundle_modal_error.retry": "আবার চেষ্টা করুন", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "About", "column.blocks": "যাদের ব্লক করা হয়েছে", "column.bookmarks": "বুকমার্ক", "column.community": "স্থানীয় সময়সারি", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "ব্লক করুন এবং রিপোর্ট করুন", "confirmations.block.confirm": "ব্লক করুন", "confirmations.block.message": "আপনি কি নিশ্চিত {name} কে ব্লক করতে চান?", + "confirmations.cancel_follow_request.confirm": "Withdraw request", + "confirmations.cancel_follow_request.message": "Are you sure you want to withdraw your request to follow {name}?", "confirmations.delete.confirm": "মুছে ফেলুন", "confirmations.delete.message": "আপনি কি নিশ্চিত যে এই লেখাটি মুছে ফেলতে চান ?", "confirmations.delete_list.confirm": "মুছে ফেলুন", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "পঠিত হিসেবে চিহ্নিত করুন", "conversation.open": "কথপোকথন দেখান", "conversation.with": "{names} এর সঙ্গে", + "copypaste.copied": "Copied", + "copypaste.copy": "Copy", "directory.federated": "পরিচিত ফেডিভারসের থেকে", "directory.local": "শুধু {domain} থেকে", "directory.new_arrivals": "নতুন আগত", "directory.recently_active": "সম্প্রতি সক্রিয়", + "dismissable_banner.community_timeline": "These are the most recent public posts from people whose accounts are hosted by {domain}.", + "dismissable_banner.dismiss": "Dismiss", + "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", + "dismissable_banner.explore_statuses": "These posts from this and other servers in the decentralized network are gaining traction on this server right now.", + "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", + "dismissable_banner.public_timeline": "These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.", "embed.instructions": "এই লেখাটি আপনার ওয়েবসাইটে যুক্ত করতে নিচের কোডটি বেবহার করুন।", "embed.preview": "সেটা দেখতে এরকম হবে:", "emoji_button.activity": "কার্যকলাপ", @@ -221,14 +259,14 @@ "follow_request.reject": "প্রত্যাখ্যান করুন", "follow_requests.unlocked_explanation": "আপনার অ্যাকাউন্টটি লক না থাকলেও, {domain} কর্মীরা ভেবেছিলেন যে আপনি এই অ্যাকাউন্টগুলি থেকে ম্যানুয়ালি অনুসরণের অনুরোধগুলি পর্যালোচনা করতে চাইতে পারেন।", "generic.saved": "সংরক্ষণ হয়েছে", - "getting_started.developers": "তৈরিকারকদের জন্য", - "getting_started.directory": "নিজস্ব-পাতাগুলির তালিকা", + "getting_started.directory": "Directory", "getting_started.documentation": "নথিপত্র", + "getting_started.free_software_notice": "Mastodon is free, open source software. You can view the source code, contribute or report issues at {repository}.", "getting_started.heading": "শুরু করা", "getting_started.invite": "অন্যদের আমন্ত্রণ করুন", - "getting_started.open_source_notice": "মাস্টাডন একটি মুক্ত সফটওয়্যার। তৈরিতে সাহায্য করতে বা কোনো সমস্যা সম্পর্কে জানাতে আমাদের গিটহাবে যেতে পারেন {github}।", "getting_started.privacy_policy": "Privacy Policy", "getting_started.security": "নিরাপত্তা", + "getting_started.what_is_mastodon": "About Mastodon", "hashtag.column_header.tag_mode.all": "এবং {additional}", "hashtag.column_header.tag_mode.any": "অথবা {additional}", "hashtag.column_header.tag_mode.none": "বাদ দিয়ে {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "মতামত দেখান", "home.hide_announcements": "ঘোষণা লুকান", "home.show_announcements": "ঘোষণা দেখান", + "interaction_modal.description.favourite": "With an account on Mastodon, you can favourite this post to let the author know you appreciate it and save it for later.", + "interaction_modal.description.follow": "With an account on Mastodon, you can follow {name} to receive their posts in your home feed.", + "interaction_modal.description.reblog": "With an account on Mastodon, you can boost this post to share it with your own followers.", + "interaction_modal.description.reply": "With an account on Mastodon, you can respond to this post.", + "interaction_modal.on_another_server": "On a different server", + "interaction_modal.on_this_server": "On this server", + "interaction_modal.other_server_instructions": "Simply copy and paste this URL into the search bar of your favourite app or the web interface where you are signed in.", + "interaction_modal.preamble": "Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one.", + "interaction_modal.title.favourite": "Favourite {name}'s post", + "interaction_modal.title.follow": "Follow {name}", + "interaction_modal.title.reblog": "Boost {name}'s post", + "interaction_modal.title.reply": "Reply to {name}'s post", "intervals.full.days": "{number, plural, one {# day} other {# days}}", "intervals.full.hours": "{number, plural, one {# ঘটা} other {# ঘটা}}", "intervals.full.minutes": "{number, plural, one {# মিনিট} other {# মিনিট}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "সময়কাল", "mute_modal.hide_notifications": "এই ব্যবহারকারীর প্রজ্ঞাপন বন্ধ করবেন ?", "mute_modal.indefinite": "Indefinite", - "navigation_bar.apps": "মোবাইলের আপ্প", + "navigation_bar.about": "About", + "navigation_bar.apps": "Get the app", "navigation_bar.blocks": "বন্ধ করা ব্যবহারকারী", "navigation_bar.bookmarks": "বুকমার্ক", "navigation_bar.community_timeline": "স্থানীয় সময়রেখা", @@ -324,7 +375,7 @@ "navigation_bar.filters": "বন্ধ করা শব্দ", "navigation_bar.follow_requests": "অনুসরণের অনুরোধগুলি", "navigation_bar.follows_and_followers": "অনুসরণ এবং অনুসরণকারী", - "navigation_bar.info": "এই সার্ভার সম্পর্কে", + "navigation_bar.info": "About", "navigation_bar.keyboard_shortcuts": "হটকীগুলি", "navigation_bar.lists": "তালিকাগুলো", "navigation_bar.logout": "বাইরে যান", @@ -333,7 +384,9 @@ "navigation_bar.pins": "পিন দেওয়া টুট", "navigation_bar.preferences": "পছন্দসমূহ", "navigation_bar.public_timeline": "যুক্তবিশ্বের সময়রেখা", + "navigation_bar.search": "Search", "navigation_bar.security": "নিরাপত্তা", + "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", "notification.admin.report": "{name} reported {target}", "notification.admin.sign_up": "{name} signed up", "notification.favourite": "{name} আপনার কার্যক্রম পছন্দ করেছেন", @@ -401,6 +454,8 @@ "privacy.public.short": "সর্বজনীন প্রকাশ্য", "privacy.unlisted.long": "Visible for all, but opted-out of discovery features", "privacy.unlisted.short": "প্রকাশ্য নয়", + "privacy_policy.last_updated": "Last updated {date}", + "privacy_policy.title": "Privacy Policy", "refresh": "সতেজ করা", "regeneration_indicator.label": "আসছে…", "regeneration_indicator.sublabel": "আপনার বাড়ির-সময়রেখা প্রস্তূত করা হচ্ছে!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "তাদের সামগ্রী দ্বারা টুটগুলি অনুসন্ধান এই মস্তোডন সার্ভারে সক্ষম নয়।", "search_results.title": "Search for {q}", "search_results.total": "{count, number} {count, plural, one {ফলাফল} other {ফলাফল}}", + "server_banner.about_active_users": "People using this server during the last 30 days (Monthly Active Users)", + "server_banner.active_users": "active users", + "server_banner.administered_by": "Administered by:", + "server_banner.introduction": "{domain} is part of the decentralized social network powered by {mastodon}.", + "server_banner.learn_more": "Learn more", + "server_banner.server_stats": "Server stats:", "sign_in_banner.create_account": "Create account", "sign_in_banner.sign_in": "Sign in", "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "এখনো কেও এটাতে সমর্থন দেয়নি। যখন কেও দেয়, সেটা তখন এখানে দেখা যাবে।", "status.redraft": "মুছে আবার নতুন করে লিখতে", "status.remove_bookmark": "বুকমার্ক সরান", + "status.replied_to": "Replied to {name}", "status.reply": "মতামত জানাতে", "status.replyAll": "লেখাযুক্ত সবার কাছে মতামত জানাতে", "status.report": "@{name} কে রিপোর্ট করতে", @@ -523,9 +585,8 @@ "status.show_more": "আরো দেখাতে", "status.show_more_all": "সবগুলোতে আরো দেখতে", "status.show_original": "Show original", - "status.show_thread": "আলোচনা দেখতে", "status.translate": "Translate", - "status.translated_from": "Translated from {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "পাওয়া যাচ্ছে না", "status.unmute_conversation": "আলোচনার প্রজ্ঞাপন চালু করতে", "status.unpin": "নিজের পাতা থেকে পিন করে রাখাটির পিন খুলতে", @@ -538,7 +599,6 @@ "tabs_bar.home": "বাড়ি", "tabs_bar.local_timeline": "স্থানীয়", "tabs_bar.notifications": "প্রজ্ঞাপনগুলো", - "tabs_bar.search": "অনুসন্ধান", "time_remaining.days": "{number, plural, one {# day} other {# days}} বাকি আছে", "time_remaining.hours": "{number, plural, one {# hour} other {# hours}} বাকি আছে", "time_remaining.minutes": "{number, plural, one {# মিনিট} other {# মিনিট}} বাকি আছে", diff --git a/app/javascript/mastodon/locales/br.json b/app/javascript/mastodon/locales/br.json index 4d772416c..237f44329 100644 --- a/app/javascript/mastodon/locales/br.json +++ b/app/javascript/mastodon/locales/br.json @@ -1,54 +1,70 @@ { + "about.blocks": "Servijerioù habaskaet", + "about.contact": "Darempred :", + "about.domain_blocks.comment": "Abeg", + "about.domain_blocks.domain": "Domani", + "about.domain_blocks.preamble": "Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.", + "about.domain_blocks.severity": "Strizhder", + "about.domain_blocks.silenced.explanation": "Ne vo ket gwelet profiloù eus ar servijer-mañ ganeoc'h peurliesañ, nemet ma vefec'h o klask war o lec'h pe choazfec'h o heuliañ.", + "about.domain_blocks.silenced.title": "Limited", + "about.domain_blocks.suspended.explanation": "No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.", + "about.domain_blocks.suspended.title": "Suspended", + "about.not_available": "This information has not been made available on this server.", + "about.powered_by": "Decentralized social media powered by {mastodon}", + "about.rules": "Reolennoù ar servijer", "account.account_note_header": "Notenn", "account.add_or_remove_from_list": "Ouzhpenn pe dilemel eus al listennadoù", "account.badges.bot": "Robot", "account.badges.group": "Strollad", - "account.block": "Berzañ @{name}", - "account.block_domain": "Berzañ pep tra eus {domain}", + "account.block": "Stankañ @{name}", + "account.block_domain": "Stankañ an domani {domain}", "account.blocked": "Stanket", - "account.browse_more_on_origin_server": "Furchal muioc'h war ar profil kentañ", - "account.cancel_follow_request": "Nullañ ar bedadenn heuliañ", - "account.direct": "Kas ur gemennadenn prevez da @{name}", - "account.disable_notifications": "Paouez d'am c'hemenn pa vez toudet gant @{name}", - "account.domain_blocked": "Domani berzet", - "account.edit_profile": "Aozañ ar profil", - "account.enable_notifications": "Ma c'hemenn pa vez toudet gant @{name}", + "account.browse_more_on_origin_server": "Furchal pelloc'h war ar profil orin", + "account.cancel_follow_request": "Withdraw follow request", + "account.direct": "Kas ur c'hemennad eeun da @{name}", + "account.disable_notifications": "Paouez d'am c'hemenn pa vez embannet traoù gant @{name}", + "account.domain_blocked": "Domani stanket", + "account.edit_profile": "Kemmañ ar profil", + "account.enable_notifications": "Ma c'hemenn pa vez embannet traoù gant @{name}", "account.endorse": "Lakaat war-wel war ar profil", + "account.featured_tags.last_status_at": "Kemennad diwezhañ : {date}", + "account.featured_tags.last_status_never": "Kemennad ebet", + "account.featured_tags.title": "{name}'s featured hashtags", "account.follow": "Heuliañ", "account.followers": "Heulier·ezed·ien", - "account.followers.empty": "Den na heul an implijer-mañ c'hoazh.", - "account.followers_counter": "{count, plural, other{{counter} Heulier}}", - "account.following": "O heuliañ", - "account.following_counter": "{count, plural, other {{counter} Heuliañ}}", + "account.followers.empty": "Den na heul an implijer·ez-mañ c'hoazh.", + "account.followers_counter": "{count, plural, other{{counter} Heulier·ez}}", + "account.following": "Koumanantoù", + "account.following_counter": "{count, plural, one{{counter} C'houmanant} two{{counter} Goumanant} other {{counter} a Goumanant}}", "account.follows.empty": "An implijer·ez-mañ na heul den ebet.", - "account.follows_you": "Ho heul", - "account.hide_reblogs": "Kuzh toudoù rannet gant @{name}", - "account.joined": "Amañ abaoe {date}", + "account.follows_you": "Ho heuilh", + "account.hide_reblogs": "Kuzh skignadennoù gant @{name}", + "account.joined_short": "Joined", "account.languages": "Change subscribed languages", "account.link_verified_on": "Gwiriet eo bet perc'hennidigezh al liamm d'an deiziad-mañ : {date}", - "account.locked_info": "Prennet eo ar gont-mañ. Dibab a ra ar perc'henn ar re a c'hall heuliañ anezhi pe anezhañ.", + "account.locked_info": "Prennet eo ar gont-mañ. Gant ar perc'henn e vez dibabet piv a c'hall heuliañ anezhi pe anezhañ.", "account.media": "Media", "account.mention": "Menegiñ @{name}", "account.moved_to": "Dilojet en·he deus {name} da :", "account.mute": "Kuzhat @{name}", - "account.mute_notifications": "Kuzh kemennoù eus @{name}", + "account.mute_notifications": "Kuzh kemennoù a-berzh @{name}", "account.muted": "Kuzhet", - "account.posts": "a doudoù", - "account.posts_with_replies": "Toudoù ha respontoù", + "account.posts": "Kemennadoù", + "account.posts_with_replies": "Kemennadoù ha respontoù", "account.report": "Disklêriañ @{name}", "account.requested": "O c'hortoz an asant. Klikit evit nullañ ar goulenn heuliañ", "account.share": "Skignañ profil @{name}", "account.show_reblogs": "Diskouez skignadennoù @{name}", - "account.statuses_counter": "{count, plural, one {{counter} Toud} other {{counter} Toud}}", + "account.statuses_counter": "{count, plural, one {{counter} C'hemennad} two {{counter} Gemennad} other {{counter} a Gemennad}}", "account.unblock": "Diverzañ @{name}", "account.unblock_domain": "Diverzañ an domani {domain}", "account.unblock_short": "Distankañ", "account.unendorse": "Paouez da lakaat war-wel war ar profil", "account.unfollow": "Diheuliañ", "account.unmute": "Diguzhat @{name}", - "account.unmute_notifications": "Diguzhat kemennoù a @{name}", - "account.unmute_short": "Unmute", - "account_note.placeholder": "Klikit evit ouzhpenniñ un notenn", + "account.unmute_notifications": "Diguzhat kemennoù a-berzh @{name}", + "account.unmute_short": "Diguzhat", + "account_note.placeholder": "Klikit evit ouzhpennañ un notenn", "admin.dashboard.daily_retention": "User retention rate by day after sign-up", "admin.dashboard.monthly_retention": "User retention rate by month after sign-up", "admin.dashboard.retention.average": "Keidenn", @@ -57,18 +73,30 @@ "alert.rate_limited.message": "Klaskit en-dro a-benn {retry_time, time, medium}.", "alert.rate_limited.title": "Feur bevennet", "alert.unexpected.message": "Ur fazi dic'hortozet zo degouezhet.", - "alert.unexpected.title": "Hopala!", + "alert.unexpected.title": "Hopala !", "announcement.announcement": "Kemenn", "attachments_list.unprocessed": "(ket meret)", "audio.hide": "Hide audio", "autosuggest_hashtag.per_week": "{count} bep sizhun", "boost_modal.combo": "Ar wezh kentañ e c'halliot gwaskañ war {combo} evit tremen hebiou", - "bundle_column_error.body": "Degouezhet ez eus bet ur fazi en ur gargañ an elfenn-mañ.", + "bundle_column_error.copy_stacktrace": "Copy error report", + "bundle_column_error.error.body": "The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.", + "bundle_column_error.error.title": "Oh, no!", + "bundle_column_error.network.body": "There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.", + "bundle_column_error.network.title": "Network error", "bundle_column_error.retry": "Klask en-dro", - "bundle_column_error.title": "Fazi rouedad", + "bundle_column_error.return": "Go back home", + "bundle_column_error.routing.body": "The requested page could not be found. Are you sure the URL in the address bar is correct?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Serriñ", "bundle_modal_error.message": "Degouezhet ez eus bet ur fazi en ur gargañ an elfenn-mañ.", "bundle_modal_error.retry": "Klask en-dro", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "About", "column.blocks": "Implijer·ezed·ien berzet", "column.bookmarks": "Sinedoù", "column.community": "Red-amzer lec'hel", @@ -81,7 +109,7 @@ "column.lists": "Listennoù", "column.mutes": "Implijer·ion·ezed kuzhet", "column.notifications": "Kemennoù", - "column.pins": "Toudoù spilhennet", + "column.pins": "Kemennadoù spilhennet", "column.public": "Red-amzer kevreet", "column_back_button.label": "Distro", "column_header.hide_settings": "Kuzhat an arventennoù", @@ -97,11 +125,11 @@ "compose.language.change": "Cheñch yezh", "compose.language.search": "Search languages...", "compose_form.direct_message_warning_learn_more": "Gouzout hiroc'h", - "compose_form.encryption_warning": "Posts on Mastodon are not end-to-end encrypted. Do not share any dangerous information over Mastodon.", - "compose_form.hashtag_warning": "Ne vo ket lakaet an toud-mañ er rolloù gerioù-klik dre mard eo anlistennet. N'eus nemet an toudoù foran a c'hall bezañ klasket dre c'her-klik.", - "compose_form.lock_disclaimer": "N'eo ket {locked} ho kont. An holl a c'hal heuliañ ac'hanoc'h evit gwelout ho toudoù prevez.", + "compose_form.encryption_warning": "Kemennadoù war Mastodon na vezont ket sifret penn-da-benn. Na rannit ket titouroù kizidik dre Mastodon.", + "compose_form.hashtag_warning": "Ne vo ket listennet ar c'hemennad-mañ dindan gerioù-klik ebet dre m'eo anlistennet. N'eus nemet ar c'hemennadoù foran a c'hall bezañ klasket dre c'her-klik.", + "compose_form.lock_disclaimer": "N'eo ket {locked} ho kont. An holl a c'hal ho heuliañ evit gwelet ho kemennadoù prevez.", "compose_form.lock_disclaimer.lock": "prennet", - "compose_form.placeholder": "Petra eh oc'h é soñjal a-barzh ?", + "compose_form.placeholder": "Petra emaoc'h o soñjal e-barzh ?", "compose_form.poll.add_option": "Ouzhpenniñ un dibab", "compose_form.poll.duration": "Pad ar sontadeg", "compose_form.poll.option_placeholder": "Dibab {number}", @@ -121,8 +149,10 @@ "confirmations.block.block_and_report": "Berzañ ha Disklêriañ", "confirmations.block.confirm": "Stankañ", "confirmations.block.message": "Ha sur oc'h e fell deoc'h stankañ {name} ?", + "confirmations.cancel_follow_request.confirm": "Withdraw request", + "confirmations.cancel_follow_request.message": "Are you sure you want to withdraw your request to follow {name}?", "confirmations.delete.confirm": "Dilemel", - "confirmations.delete.message": "Ha sur oc'h e fell deoc'h dilemel an toud-mañ ?", + "confirmations.delete.message": "Ha sur oc'h e fell deoc'h dilemel ar c'hemennad-mañ ?", "confirmations.delete_list.confirm": "Dilemel", "confirmations.delete_list.message": "Ha sur eo hoc'h eus c'hoant da zilemel ar roll-mañ da vat ?", "confirmations.discard_edit_media.confirm": "Nac'hañ", @@ -132,10 +162,10 @@ "confirmations.logout.confirm": "Digevreañ", "confirmations.logout.message": "Ha sur oc'h e fell deoc'h digevreañ ?", "confirmations.mute.confirm": "Kuzhat", - "confirmations.mute.explanation": "Kuzhat a raio an toudoù skrivet gantañ·i hag ar re a veneg anezhañ·i, met aotren a raio anezhañ·i da welet ho todoù ha a heuliañ ac'hanoc'h.", + "confirmations.mute.explanation": "Kement-se a guzho ar c'hemennadoù skrivet gantañ·i hag ar re a veneg anezhañ·i, met ne viro ket outañ·i a welet ho kemennadoù nag a heuliañ ac'hanoc'h.", "confirmations.mute.message": "Ha sur oc'h e fell deoc'h kuzhaat {name} ?", "confirmations.redraft.confirm": "Diverkañ ha skrivañ en-dro", - "confirmations.redraft.message": "Ha sur oc'h e fell deoc'h dilemel ar statud-mañ hag adlakaat anezhañ er bouilhoñs? Kollet e vo ar merkoù muiañ-karet hag ar skignadennoù hag emzivat e vo ar respontoù d'an toud orin.", + "confirmations.redraft.message": "Ha sur oc'h e fell deoc'h dilemel ar c'hemennad-mañ hag e adskrivañ ? Kollet e vo ar merkoù « muiañ-karet » hag ar skignadennoù, hag emzivat e vo ar respontoù d'ar c'hemennad orin.", "confirmations.reply.confirm": "Respont", "confirmations.reply.message": "Respont bremañ a zilamo ar gemennadenn emaoc'h o skrivañ. Sur e oc'h e fell deoc'h kenderc'hel ganti?", "confirmations.unfollow.confirm": "Diheuliañ", @@ -144,12 +174,20 @@ "conversation.mark_as_read": "Merkañ evel lennet", "conversation.open": "Gwelout ar gaozeadenn", "conversation.with": "Gant {names}", - "directory.federated": "Eus ar c'hevrebed anavezet", + "copypaste.copied": "Copied", + "copypaste.copy": "Copy", + "directory.federated": "Eus ar fedibed anavezet", "directory.local": "Eus {domain} hepken", "directory.new_arrivals": "Degouezhet a-nevez", "directory.recently_active": "Oberiant nevez zo", - "embed.instructions": "Enkorfit ar statud war ho lec'hienn en ur eilañ ar c'hod dindan.", - "embed.preview": "Setu penaos e vo diskouezet:", + "dismissable_banner.community_timeline": "Setu kemennadoù foran nevesañ an dud a zo herberc’hiet o c'hontoù gant {domain}.", + "dismissable_banner.dismiss": "Dismiss", + "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", + "dismissable_banner.explore_statuses": "These posts from this and other servers in the decentralized network are gaining traction on this server right now.", + "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", + "dismissable_banner.public_timeline": "These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.", + "embed.instructions": "Enframmit ar c'hemennad-mañ en ho lec'hienn en ur eilañ ar c'hod amañ-dindan.", + "embed.preview": "Setu penaos e teuio war wel :", "emoji_button.activity": "Obererezh", "emoji_button.clear": "Diverkañ", "emoji_button.custom": "Kempennet", @@ -166,22 +204,22 @@ "emoji_button.symbols": "Arouezioù", "emoji_button.travel": "Lec'hioù ha Beajoù", "empty_column.account_suspended": "Kont ehanet", - "empty_column.account_timeline": "Toud ebet amañ!", + "empty_column.account_timeline": "Kemennad ebet amañ !", "empty_column.account_unavailable": "Profil dihegerz", "empty_column.blocks": "N'eus ket bet berzet implijer·ez ganeoc'h c'hoazh.", - "empty_column.bookmarked_statuses": "N'ho peus toud ebet enrollet en ho sinedoù c'hoazh. Pa vo ouzhpennet unan ganeoc'h e teuio war wel amañ.", + "empty_column.bookmarked_statuses": "N'ho peus kemennad ebet enrollet en ho sinedoù c'hoazh. Pa vo ouzhpennet unan e teuio war wel amañ.", "empty_column.community": "Goulo eo ar red-amzer lec'hel. Skrivit'ta un dra evit lakaat tan dezhi !", "empty_column.direct": "N'ho peus kemennad prevez ebet c'hoazh. Pa vo resevet pe kaset unan ganeoc'h e teuio war wel amañ.", "empty_column.domain_blocks": "N'eus domani kuzh ebet c'hoazh.", "empty_column.explore_statuses": "Nothing is trending right now. Check back later!", - "empty_column.favourited_statuses": "N'ho peus toud muiañ-karet ebet c'hoazh. Pa vo lakaet unan ganeoc'h e vo diskouezet amañ.", - "empty_column.favourites": "Den ebet n'eus lakaet an toud-mañ en e reoù muiañ-karet. Pa vo graet gant unan bennak e vo diskouezet amañ.", + "empty_column.favourited_statuses": "N'ho peus kemennad muiañ-karet ebet c'hoazh. Pa vo ouzhpennet unan e teuio war wel amañ.", + "empty_column.favourites": "Den ebet n'eus lakaet ar c'hemennad-mañ en e reoù muiañ-karet c'hoazh. Pa vo graet gant unan bennak e teuio war wel amañ.", "empty_column.follow_recommendations": "Seblant a ra ne vez ket genelet damvenegoù evidoc'h. Gallout a rit implijout un enklask evit klask tud hag a vefe anavezet ganeoc'h pe ergerzhout gerioù-klik diouzh ar c'hiz.", "empty_column.follow_requests": "N'ho peus goulenn heuliañ ebet c'hoazh. Pa resevot reoù e vo diskouezet amañ.", "empty_column.hashtag": "N'eus netra er ger-klik-mañ c'hoazh.", "empty_column.home": "Goullo eo ho red-amzer degemer! Kit da weladenniñ {public} pe implijit ar c'hlask evit kregiñ ganti ha kejañ gant implijer·ien·ezed all.", "empty_column.home.suggestions": "Gwellout damvenegoù", - "empty_column.list": "Goullo eo ar roll-mañ evit ar poent. Pa vo toudet gant e izili e vo diskouezet amañ.", + "empty_column.list": "Goullo eo ar roll-mañ evit c'hoazh. Pa vo embannet kemennadoù nevez gant e izili e teuint war wel amañ.", "empty_column.lists": "N'ho peus roll ebet c'hoazh. Pa vo krouet unan ganeoc'h e vo diskouezet amañ.", "empty_column.mutes": "N'ho peus kuzhet implijer ebet c'hoazh.", "empty_column.notifications": "N'ho peus kemenn ebet c'hoazh. Grit gant implijer·ezed·ien all evit loc'hañ ar gomz.", @@ -196,7 +234,7 @@ "explore.suggested_follows": "Evidoc'h", "explore.title": "Ergerzhit", "explore.trending_links": "Keleier", - "explore.trending_statuses": "Posts", + "explore.trending_statuses": "Kemennadoù", "explore.trending_tags": "Gerioù-klik", "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.", "filter_modal.added.context_mismatch_title": "Context mismatch!", @@ -205,30 +243,30 @@ "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.", "filter_modal.added.review_and_configure_title": "Filter settings", "filter_modal.added.settings_link": "settings page", - "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.", + "filter_modal.added.short_explanation": "Ar c'hemennad-mañ zo bet ouzhpennet d'ar rummad sil-mañ : {title}.", "filter_modal.added.title": "Filter added!", "filter_modal.select_filter.context_mismatch": "does not apply to this context", "filter_modal.select_filter.expired": "expired", "filter_modal.select_filter.prompt_new": "New category: {name}", "filter_modal.select_filter.search": "Search or create", "filter_modal.select_filter.subtitle": "Use an existing category or create a new one", - "filter_modal.select_filter.title": "Filter this post", - "filter_modal.title.status": "Filter a post", + "filter_modal.select_filter.title": "Silañ ar c'hemennad-mañ", + "filter_modal.title.status": "Silañ ur c'hemennad", "follow_recommendations.done": "Graet", - "follow_recommendations.heading": "Heuliit tud e plijfe deoc'h lenn toudoù! Setu un tamm alioù.", - "follow_recommendations.lead": "Toudoù eus tud heuliet ganeoc'h a zeuio war wel en un urzh amzeroniezhel war ho red degemer. N'ho peus ket aon ober fazioù, gallout a rit paouez heuliañ tud ken aes n'eus forzh pegoulz!", + "follow_recommendations.heading": "Heuilhit tud a blijfe deoc'h lenn o c'hemennadoù ! Setu un nebeud erbedadennoù.", + "follow_recommendations.lead": "Kemennadoù gant tud a vez heuliet ganeoc'h a zeuio war wel en urzh kronologel war ho red degemer. Arabat kaout aon ober fazioù, diheuliañ tud a c'hellit ober aes ha forzh pegoulz !", "follow_request.authorize": "Aotren", "follow_request.reject": "Nac'hañ", "follow_requests.unlocked_explanation": "Daoust ma n'eo ket ho kont prennet, skipailh {domain} a soñj e fellfe deoc'h gwiriekaat pedadennoù heuliañ deus ar c'hontoù-se diwar-zorn.", "generic.saved": "Enrollet", - "getting_started.developers": "Diorroerien", - "getting_started.directory": "Roll ar profiloù", + "getting_started.directory": "Directory", "getting_started.documentation": "Teuliadur", + "getting_started.free_software_notice": "Mastodon is free, open source software. You can view the source code, contribute or report issues at {repository}.", "getting_started.heading": "Loc'hañ", "getting_started.invite": "Pediñ tud", - "getting_started.open_source_notice": "Mastodoñ zo ur meziant digor e darzh. Gallout a rit kenoberzhiañ dezhañ pe danevellañ kudennoù war GitHub e {github}.", "getting_started.privacy_policy": "Privacy Policy", "getting_started.security": "Arventennoù ar gont", + "getting_started.what_is_mastodon": "About Mastodon", "hashtag.column_header.tag_mode.all": "ha {additional}", "hashtag.column_header.tag_mode.any": "pe {additional}", "hashtag.column_header.tag_mode.none": "hep {additional}", @@ -245,19 +283,31 @@ "home.column_settings.show_replies": "Diskouez ar respontoù", "home.hide_announcements": "Kuzhat ar c'hemennoù", "home.show_announcements": "Diskouez ar c'hemennoù", + "interaction_modal.description.favourite": "Gant ur gont Mastodon e c'hellit ouzhpennañ ar c'hemennad-mañ d'ho re vuiañ-karet evit lakaat an den en deus eñ skrivet da c'houzout e plij deoc'h hag e enrollañ evit diwezhatoc'h.", + "interaction_modal.description.follow": "Gant ur gont Mastodon e c'hellit heuliañ {name} evit resev h·e gemennadoù war ho red degemer.", + "interaction_modal.description.reblog": "Gant ur gont Mastodon e c'hellit skignañ ar c'hemennad-mañ evit rannañ anezhañ gant ho heulierien·ezed.", + "interaction_modal.description.reply": "Gant ur gont Mastodon e c'hellit respont d'ar c'hemennad-mañ.", + "interaction_modal.on_another_server": "On a different server", + "interaction_modal.on_this_server": "On this server", + "interaction_modal.other_server_instructions": "Simply copy and paste this URL into the search bar of your favourite app or the web interface where you are signed in.", + "interaction_modal.preamble": "Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one.", + "interaction_modal.title.favourite": "Ouzhpennañ kemennad {name} d'ar re vuiañ-karet", + "interaction_modal.title.follow": "Follow {name}", + "interaction_modal.title.reblog": "Skignañ kemennad {name}", + "interaction_modal.title.reply": "Respont da gemennad {name}", "intervals.full.days": "{number, plural, one {# devezh} other{# a zevezhioù}}", "intervals.full.hours": "{number, plural, one {# eurvezh} other{# eurvezh}}", "intervals.full.minutes": "{number, plural, one {# munut} other{# a vunutoù}}", "keyboard_shortcuts.back": "Distreiñ", "keyboard_shortcuts.blocked": "Digeriñ roll an implijer.ezed.rien stanket", - "keyboard_shortcuts.boost": "da skignañ", + "keyboard_shortcuts.boost": "Skignañ ar c'hemennad", "keyboard_shortcuts.column": "Fokus ar bann", "keyboard_shortcuts.compose": "Fokus an takad testenn", "keyboard_shortcuts.description": "Deskrivadur", "keyboard_shortcuts.direct": "to open direct messages column", "keyboard_shortcuts.down": "Diskennañ er roll", - "keyboard_shortcuts.enter": "evit digeriñ un toud", - "keyboard_shortcuts.favourite": "Lakaat an toud evel muiañ-karet", + "keyboard_shortcuts.enter": "Digeriñ ar c'hemennad", + "keyboard_shortcuts.favourite": "Ouzhpennañ ar c'hemennad d'ar re vuiañ-karet", "keyboard_shortcuts.favourites": "Digeriñ roll an toudoù muiañ-karet", "keyboard_shortcuts.federated": "Digeriñ ar red-amzer kevreet", "keyboard_shortcuts.heading": "Berradennoù klavier", @@ -270,16 +320,16 @@ "keyboard_shortcuts.my_profile": "Digeriñ ho profil", "keyboard_shortcuts.notifications": "Digeriñ bann kemennoù", "keyboard_shortcuts.open_media": "Digeriñ ar media", - "keyboard_shortcuts.pinned": "Digeriñ roll an toudoù spilhennet", + "keyboard_shortcuts.pinned": "Digeriñ roll ar c'hemennadoù spilhennet", "keyboard_shortcuts.profile": "Digeriñ profil an aozer.ez", - "keyboard_shortcuts.reply": "da respont", + "keyboard_shortcuts.reply": "Respont d'ar c'hemennad", "keyboard_shortcuts.requests": "Digeriñ roll goulennoù heuliañ", "keyboard_shortcuts.search": "Fokus barenn klask", "keyboard_shortcuts.spoilers": "da guzhat/ziguzhat tachenn CW", "keyboard_shortcuts.start": "Digeriñ bann \"Kregiñ\"", "keyboard_shortcuts.toggle_hidden": "da guzhat/ziguzhat an desten a-dreñv CW", "keyboard_shortcuts.toggle_sensitivity": "da guzhat/ziguzhat ur media", - "keyboard_shortcuts.toot": "da gregiñ gant un toud nevez-flamm", + "keyboard_shortcuts.toot": "Kregiñ gant ur c'hemennad nevez", "keyboard_shortcuts.unfocus": "Difokus an dachenn testenn/klask", "keyboard_shortcuts.up": "Pignat er roll", "lightbox.close": "Serriñ", @@ -310,11 +360,12 @@ "mute_modal.duration": "Padelezh", "mute_modal.hide_notifications": "Kuzhat kemenadennoù eus an implijer-se ?", "mute_modal.indefinite": "Amstrizh", - "navigation_bar.apps": "Arloadoù pellgomz", + "navigation_bar.about": "About", + "navigation_bar.apps": "Get the app", "navigation_bar.blocks": "Implijer·ezed·ien berzet", "navigation_bar.bookmarks": "Sinedoù", "navigation_bar.community_timeline": "Red-amzer lec'hel", - "navigation_bar.compose": "Skrivañ un toud nevez", + "navigation_bar.compose": "Skrivañ ur c'hemennad nevez", "navigation_bar.direct": "Kemennadoù prevez", "navigation_bar.discover": "Dizoleiñ", "navigation_bar.domain_blocks": "Domanioù kuzhet", @@ -324,27 +375,29 @@ "navigation_bar.filters": "Gerioù kuzhet", "navigation_bar.follow_requests": "Pedadoù heuliañ", "navigation_bar.follows_and_followers": "Heuliadennoù ha heulier·ezed·ien", - "navigation_bar.info": "Diwar-benn an dafariad-mañ", + "navigation_bar.info": "About", "navigation_bar.keyboard_shortcuts": "Berradurioù", "navigation_bar.lists": "Listennoù", "navigation_bar.logout": "Digennaskañ", "navigation_bar.mutes": "Implijer·ion·ezed kuzhet", "navigation_bar.personal": "Personel", - "navigation_bar.pins": "Toudoù spilhennet", + "navigation_bar.pins": "Kemennadoù spilhennet", "navigation_bar.preferences": "Gwellvezioù", "navigation_bar.public_timeline": "Red-amzer kevreet", + "navigation_bar.search": "Search", "navigation_bar.security": "Diogelroez", + "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", "notification.admin.report": "Disklêriet eo bet {target} gant {name}", "notification.admin.sign_up": "{name} en·he deus lakaet e·hec'h anv", - "notification.favourite": "{name} en/he deus lakaet ho toud en e/he muiañ-karet", + "notification.favourite": "{name} en·he deus ouzhpennet ho kemennad d'h·e re vuiañ-karet", "notification.follow": "heuliañ a ra {name} ac'hanoc'h", "notification.follow_request": "{name} en/he deus goulennet da heuliañ ac'hanoc'h", "notification.mention": "{name} en/he deus meneget ac'hanoc'h", "notification.own_poll": "Echu eo ho sontadeg", "notification.poll": "Ur sontadeg ho deus mouezhet warnañ a zo echuet", - "notification.reblog": "{name} skignet ho toud", - "notification.status": "{name} en/he deus toudet", - "notification.update": "{name} edited a post", + "notification.reblog": "{name} en·he deus skignet ho kemennad", + "notification.status": "{name} en·he deus embannet", + "notification.update": "{name} en·he deus kemmet ur c'hemennad", "notifications.clear": "Skarzhañ ar c'hemennoù", "notifications.clear_confirmation": "Ha sur oc'h e fell deoc'h skarzhañ ho kemennoù penn-da-benn?", "notifications.column_settings.admin.report": "New reports:", @@ -362,7 +415,7 @@ "notifications.column_settings.reblog": "Skignadennoù:", "notifications.column_settings.show": "Diskouez er bann", "notifications.column_settings.sound": "Seniñ", - "notifications.column_settings.status": "Toudoù nevez:", + "notifications.column_settings.status": "Kemennadoù nevez :", "notifications.column_settings.unread_notifications.category": "Kemennoù n'int ket lennet", "notifications.column_settings.unread_notifications.highlight": "Usskediñ kemennoù nevez", "notifications.column_settings.update": "Edits:", @@ -392,7 +445,7 @@ "poll.votes": "{votes, plural,one {#votadenn} other {# votadenn}}", "poll_button.add_poll": "Ouzhpennañ ur sontadeg", "poll_button.remove_poll": "Dilemel ar sontadeg", - "privacy.change": "Kemmañ gwelidigezh ar statud", + "privacy.change": "Cheñch prevezded ar c'hemennad", "privacy.direct.long": "Embann evit an implijer·ezed·ien meneget hepken", "privacy.direct.short": "Direct", "privacy.private.long": "Embann evit ar re a heuilh ac'hanon hepken", @@ -401,6 +454,8 @@ "privacy.public.short": "Publik", "privacy.unlisted.long": "Visible for all, but opted-out of discovery features", "privacy.unlisted.short": "Anlistennet", + "privacy_policy.last_updated": "Last updated {date}", + "privacy_policy.title": "Privacy Policy", "refresh": "Freskaat", "regeneration_indicator.label": "O kargañ…", "regeneration_indicator.sublabel": "War brientiñ emañ ho red degemer!", @@ -417,20 +472,20 @@ "relative_time.today": "hiziv", "reply_indicator.cancel": "Nullañ", "report.block": "Stankañ", - "report.block_explanation": "You will not see their posts. They will not be able to see your posts or follow you. They will be able to tell that they are blocked.", + "report.block_explanation": "Ne vo ket gwelet h·e gemennadoù ken. Ne welo ket ho kemennadoù ha ne c'hello ket ho heuliañ ken. Gouzout a raio eo bet stanket ganeoc'h.", "report.categories.other": "Other", "report.categories.spam": "Spam", "report.categories.violation": "Content violates one or more server rules", "report.category.subtitle": "Choose the best match", - "report.category.title": "Tell us what's going on with this {type}", + "report.category.title": "Lârit deomp petra c'hoarvez gant {type}", "report.category.title_account": "profil", - "report.category.title_status": "post", + "report.category.title_status": "ar c'hemennad-mañ", "report.close": "Graet", "report.comment.title": "Is there anything else you think we should know?", "report.forward": "Treuzkas da: {target}", "report.forward_hint": "War ur servijer all emañ ar c'hont-se. Kas dezhañ un adskrid disanv eus an danevell ivez?", "report.mute": "Mute", - "report.mute_explanation": "You will not see their posts. They can still follow you and see your posts and will not know that they are muted.", + "report.mute_explanation": "Ne vo ket gwelet h·e gemennadoù ken. Gwelet ho kemennadoù ha ho heuliañ a c'hello ha ne ouezo ket eo bet kuzhet ganeoc'h.", "report.next": "Next", "report.placeholder": "Askelennoù ouzhpenn", "report.reasons.dislike": "I don't like it", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "Klask toudoù dre oc'h endalc'h n'eo ket aotreet war ar servijer-mañ.", "search_results.title": "Search for {q}", "search_results.total": "{count, number} {count, plural, one {disoc'h} other {a zisoc'h}}", + "server_banner.about_active_users": "People using this server during the last 30 days (Monthly Active Users)", + "server_banner.active_users": "active users", + "server_banner.administered_by": "Administered by:", + "server_banner.introduction": "{domain} is part of the decentralized social network powered by {mastodon}.", + "server_banner.learn_more": "Learn more", + "server_banner.server_stats": "Server stats:", "sign_in_banner.create_account": "Create account", "sign_in_banner.sign_in": "Sign in", "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "Den ebet n'eus skignet an toud-mañ c'hoazh. Pa vo graet gant unan bennak e vo diskouezet amañ.", "status.redraft": "Diverkañ ha skrivañ en-dro", "status.remove_bookmark": "Dilemel ar sined", + "status.replied_to": "Replied to {name}", "status.reply": "Respont", "status.replyAll": "Respont d'ar gaozeadenn", "status.report": "Disklêriañ @{name}", @@ -523,9 +585,8 @@ "status.show_more": "Diskouez muioc'h", "status.show_more_all": "Diskouez miuoc'h evit an holl", "status.show_original": "Show original", - "status.show_thread": "Diskouez ar gaozeadenn", "status.translate": "Translate", - "status.translated_from": "Translated from {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Dihegerz", "status.unmute_conversation": "Diguzhat ar gaozeadenn", "status.unpin": "Dispilhennañ eus ar profil", @@ -538,7 +599,6 @@ "tabs_bar.home": "Degemer", "tabs_bar.local_timeline": "Lec'hel", "tabs_bar.notifications": "Kemennoù", - "tabs_bar.search": "Klask", "time_remaining.days": "{number, plural,one {# devezh} other {# a zevezh}} a chom", "time_remaining.hours": "{number, plural, one {# eurvezh} other{# eurvezh}} a chom", "time_remaining.minutes": "{number, plural, one {# munut} other{# a vunut}} a chom", diff --git a/app/javascript/mastodon/locales/ca.json b/app/javascript/mastodon/locales/ca.json index f2d9b9822..c21e2c84d 100644 --- a/app/javascript/mastodon/locales/ca.json +++ b/app/javascript/mastodon/locales/ca.json @@ -1,4 +1,17 @@ { + "about.blocks": "Servidors moderats", + "about.contact": "Contacte:", + "about.domain_blocks.comment": "Motiu", + "about.domain_blocks.domain": "Domini", + "about.domain_blocks.preamble": "En general, Mastodon et permet veure el contingut i interaccionar amb els usuaris de qualsevol altre servidor del fedivers. Aquestes són les excepcions que s'han fet en aquest servidor particular.", + "about.domain_blocks.severity": "Severitat", + "about.domain_blocks.silenced.explanation": "Generalment no veuràs perfils ni contingut d'aquest servidor, a menys que el cerquis explícitament o optis per ell seguint-lo.", + "about.domain_blocks.silenced.title": "Limitat", + "about.domain_blocks.suspended.explanation": "No es processaran, emmagatzemaran ni s'intercanviaran dades d'aquest servidor, fent impossible qualsevol interacció o comunicació amb els usuaris d'aquest servidor.", + "about.domain_blocks.suspended.title": "Suspès", + "about.not_available": "Aquesta informació no s'ha fet disponible en aquest servidor.", + "about.powered_by": "Xarxa social descentralitzada impulsada per {mastodon}", + "about.rules": "Normes del servidor", "account.account_note_header": "Nota", "account.add_or_remove_from_list": "Afegeix o elimina de les llistes", "account.badges.bot": "Bot", @@ -7,13 +20,16 @@ "account.block_domain": "Bloqueja el domini {domain}", "account.blocked": "Bloquejat", "account.browse_more_on_origin_server": "Navega més en el perfil original", - "account.cancel_follow_request": "Anul·la la sol·licitud de seguiment", + "account.cancel_follow_request": "Retirar la sol·licitud de seguiment", "account.direct": "Envia missatge directe a @{name}", "account.disable_notifications": "No em notifiquis les publicacions de @{name}", "account.domain_blocked": "Domini bloquejat", "account.edit_profile": "Edita el perfil", "account.enable_notifications": "Notifica’m les publicacions de @{name}", "account.endorse": "Recomana en el teu perfil", + "account.featured_tags.last_status_at": "Darrer apunt el {date}", + "account.featured_tags.last_status_never": "Sense apunts", + "account.featured_tags.title": "etiquetes destacades de {name}", "account.follow": "Segueix", "account.followers": "Seguidors", "account.followers.empty": "Ningú segueix aquest usuari encara.", @@ -23,7 +39,7 @@ "account.follows.empty": "Aquest usuari encara no segueix ningú.", "account.follows_you": "Et segueix", "account.hide_reblogs": "Amaga els impulsos de @{name}", - "account.joined": "Membre des de {date}", + "account.joined_short": "Joined", "account.languages": "Canviar les llengües subscrits", "account.link_verified_on": "La propietat d'aquest enllaç es va verificar el dia {date}", "account.locked_info": "Aquest estat de privadesa del compte està definit com a bloquejat. El propietari revisa manualment qui pot seguir-lo.", @@ -48,7 +64,7 @@ "account.unmute": "Deixar de silenciar @{name}", "account.unmute_notifications": "Activar notificacions de @{name}", "account.unmute_short": "Deixa de silenciar", - "account_note.placeholder": "Fes clic per afegir una nota", + "account_note.placeholder": "Clica per afegir-hi una nota", "admin.dashboard.daily_retention": "Ràtio de retenció d'usuaris nous, per dia, després del registre", "admin.dashboard.monthly_retention": "Ràtio de retenció d'usuaris nous, per mes, després del registre", "admin.dashboard.retention.average": "Mitjana", @@ -63,12 +79,24 @@ "audio.hide": "Amaga l'àudio", "autosuggest_hashtag.per_week": "{count} per setmana", "boost_modal.combo": "Pots prémer {combo} per evitar-ho el pròxim cop", - "bundle_column_error.body": "S'ha produït un error en carregar aquest component.", + "bundle_column_error.copy_stacktrace": "Copiar l'informe d'error", + "bundle_column_error.error.body": "No s'ha pogut renderitzar la pàgina sol·licitada. Podría ser degut a un error en el nostre codi o un problema de compatibilitat del navegador.", + "bundle_column_error.error.title": "Oh, no!", + "bundle_column_error.network.body": "Hi ha hagut un error al intentar carregar aquesta pàgina. Això podria ser degut a un problem temporal amb la teva connexió a internet o amb aquest servidor.", + "bundle_column_error.network.title": "Error de xarxa", "bundle_column_error.retry": "Tornar-ho a provar", - "bundle_column_error.title": "Error de connexió", + "bundle_column_error.return": "Torna a Inici", + "bundle_column_error.routing.body": "No es pot trobar la pàgina sol·licitada. Estàs segur que la URL de la barra d'adreces és correcte?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Tanca", "bundle_modal_error.message": "S'ha produït un error en carregar aquest component.", "bundle_modal_error.retry": "Tornar-ho a provar", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "Quant a", "column.blocks": "Usuaris bloquejats", "column.bookmarks": "Marcadors", "column.community": "Línia de temps local", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "Bloqueja i informa", "confirmations.block.confirm": "Bloqueja", "confirmations.block.message": "Segur que vols bloquejar a {name}?", + "confirmations.cancel_follow_request.confirm": "Retirar sol·licitud", + "confirmations.cancel_follow_request.message": "Estàs segur que vols retirar la teva sol·licitud de seguiment de {name}?", "confirmations.delete.confirm": "Suprimeix", "confirmations.delete.message": "Segur que vols eliminar la publicació?", "confirmations.delete_list.confirm": "Suprimeix", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Marca com a llegida", "conversation.open": "Mostra la conversa", "conversation.with": "Amb {names}", + "copypaste.copied": "Copiat", + "copypaste.copy": "Copia", "directory.federated": "Del fedivers conegut", "directory.local": "Només de {domain}", "directory.new_arrivals": "Arribades noves", "directory.recently_active": "Recentment actius", + "dismissable_banner.community_timeline": "Aquests son els apunts més recents d'usuaris amb els seus comptes a {domain}.", + "dismissable_banner.dismiss": "Ometre", + "dismissable_banner.explore_links": "Aquests son els enllaços que els usuaris estan comentant ara mateix en aquest i altres servidors de la xarxa descentralitzada.", + "dismissable_banner.explore_statuses": "Aquests apunts d'aquest i altres servidors de la xarxa descentralitzada estan guanyant l'atenció ara mateix en aquest servidor.", + "dismissable_banner.explore_tags": "Aquestes etiquetes estan guanyant l'atenció ara mateix dels usuaris d'aquest i altres servidors de la xarxa descentralitzada.", + "dismissable_banner.public_timeline": "Aquests son els apunts més recents dels usuaris d'aquest i d'altres servidors de la xarxa descentralitzada que aquest servidor en té coneixement.", "embed.instructions": "Incrusta aquesta publicació a la teva pàgina web copiant el codi següent.", "embed.preview": "Aquí està quin aspecte tindrà:", "emoji_button.activity": "Activitat", @@ -221,14 +259,14 @@ "follow_request.reject": "Rebutja", "follow_requests.unlocked_explanation": "Tot i que el teu compte no està bloquejat, el personal de {domain} ha pensat que és possible que vulguis revisar les sol·licituds de seguiment d’aquests comptes manualment.", "generic.saved": "Desat", - "getting_started.developers": "Desenvolupadors", - "getting_started.directory": "Directori de perfils", + "getting_started.directory": "Directori", "getting_started.documentation": "Documentació", + "getting_started.free_software_notice": "Mastodon és lliure, programari de codi obert. Pots veure el codi font, contribuir-hi o reportar-hi incidències a {repository}.", "getting_started.heading": "Primers passos", "getting_started.invite": "Convidar gent", - "getting_started.open_source_notice": "Mastodon és un programari de codi obert. Pots contribuir-hi o informar de problemes a GitHub a {github}.", "getting_started.privacy_policy": "Política de Privacitat", "getting_started.security": "Configuració del compte", + "getting_started.what_is_mastodon": "Quant a Mastodon", "hashtag.column_header.tag_mode.all": "i {additional}", "hashtag.column_header.tag_mode.any": "o {additional}", "hashtag.column_header.tag_mode.none": "sense {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Mostra les respostes", "home.hide_announcements": "Amaga els anuncis", "home.show_announcements": "Mostra els anuncis", + "interaction_modal.description.favourite": "Amb un compte a Mastodon, pots afavorir aquest apunt per a deixar que l'autor sàpiga que t'ha agradat i desar-lo per més tard.", + "interaction_modal.description.follow": "Amb un compte a Mastodon, pots seguir a {name} per a rebre els seus apunts en la teva línia de temps Inici.", + "interaction_modal.description.reblog": "Amb un compte a Mastodon, pots impulsar aquest apunt per a compartir-lo amb els teus seguidors.", + "interaction_modal.description.reply": "Amb un compte a Mastodon, pots respondre aquest apunt.", + "interaction_modal.on_another_server": "En un servidor diferent", + "interaction_modal.on_this_server": "En aquest servidor", + "interaction_modal.other_server_instructions": "Simplement còpia i enganxa aquesta URL en la barra de cerca de la teva aplicació preferida o en l'interfície web on tens sessió iniciada.", + "interaction_modal.preamble": "Donat que Mastodon és descentralitzat, pots fer servir el teu compte existent a un altre servidor Mastodon o plataforma compatible si és que no tens compte en aquest.", + "interaction_modal.title.favourite": "Afavoreix l'apunt de {name}", + "interaction_modal.title.follow": "Segueix {name}", + "interaction_modal.title.reblog": "Impulsa l'apunt de {name}", + "interaction_modal.title.reply": "Respon l'apunt de {name}", "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}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Durada", "mute_modal.hide_notifications": "Amagar les notificacions d'aquest usuari?", "mute_modal.indefinite": "Indefinit", - "navigation_bar.apps": "Aplicacions mòbils", + "navigation_bar.about": "Quant a", + "navigation_bar.apps": "Aconsegueix l'app", "navigation_bar.blocks": "Usuaris bloquejats", "navigation_bar.bookmarks": "Marcadors", "navigation_bar.community_timeline": "Línia de temps local", @@ -324,7 +375,7 @@ "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.info": "Quant a", "navigation_bar.keyboard_shortcuts": "Dreceres de teclat", "navigation_bar.lists": "Llistes", "navigation_bar.logout": "Tancar sessió", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Publicacions fixades", "navigation_bar.preferences": "Preferències", "navigation_bar.public_timeline": "Línia de temps federada", + "navigation_bar.search": "Search", "navigation_bar.security": "Seguretat", + "not_signed_in_indicator.not_signed_in": "Necessites registrar-te per a accedir aquest recurs.", "notification.admin.report": "{name} ha reportat {target}", "notification.admin.sign_up": "{name} s'ha registrat", "notification.favourite": "{name} ha afavorit la teva publicació", @@ -401,6 +454,8 @@ "privacy.public.short": "Públic", "privacy.unlisted.long": "Visible per tothom però exclosa de les funcions de descobriment", "privacy.unlisted.short": "No llistat", + "privacy_policy.last_updated": "Darrera actualització {date}", + "privacy_policy.title": "Política de Privacitat", "refresh": "Actualitza", "regeneration_indicator.label": "Carregant…", "regeneration_indicator.sublabel": "S'està preparant la teva línia de temps d'Inici!", @@ -473,7 +528,13 @@ "search_results.statuses_fts_disabled": "La cerca de publicacions pel seu contingut no està habilitada en aquest servidor Mastodon.", "search_results.title": "Cerca de {q}", "search_results.total": "{count, number} {count, plural, one {resultat} other {resultats}}", - "sign_in_banner.create_account": "Crear compte", + "server_banner.about_active_users": "Gent fem servir aquest servidor en els darrers 30 dies (Usuaris Actius Mensuals)", + "server_banner.active_users": "usuaris actius", + "server_banner.administered_by": "Administrat per:", + "server_banner.introduction": "{domain} és part de la xarxa social descentralitzada, potenciat per {mastodon}.", + "server_banner.learn_more": "Aprèn més", + "server_banner.server_stats": "Estadístiques del servidor:", + "sign_in_banner.create_account": "Crea un compte", "sign_in_banner.sign_in": "Inicia sessió", "sign_in_banner.text": "Inicia sessió per a seguir perfils o etiquetes, afavorir, compartir o respondre apunts, o interactuar des d'el teu compte amb un servidor diferent.", "status.admin_account": "Obre l'interfície de moderació per a @{name}", @@ -512,6 +573,7 @@ "status.reblogs.empty": "Encara ningú no ha impulsat aquesta publicació. Quan algú ho faci, apareixeran aquí.", "status.redraft": "Esborra-la i reescriure-la", "status.remove_bookmark": "Suprimeix el marcador", + "status.replied_to": "Replied to {name}", "status.reply": "Respon", "status.replyAll": "Respon al fil", "status.report": "Denuncia @{name}", @@ -523,9 +585,8 @@ "status.show_more": "Mostrar-ne més", "status.show_more_all": "Mostrar-ne més per a tot", "status.show_original": "Mostra l'original", - "status.show_thread": "Mostra el fil", "status.translate": "Tradueix", - "status.translated_from": "Traduït del: {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "No està disponible", "status.unmute_conversation": "No silenciïs la conversa", "status.unpin": "No fixis al perfil", @@ -538,7 +599,6 @@ "tabs_bar.home": "Inici", "tabs_bar.local_timeline": "Local", "tabs_bar.notifications": "Notificacions", - "tabs_bar.search": "Cerca", "time_remaining.days": "{number, plural, one {# dia} other {# dies}} restants", "time_remaining.hours": "{number, plural, one {# hora} other {# hores}} restants", "time_remaining.minutes": "{number, plural, one {# minut} other {# minuts}} restants", diff --git a/app/javascript/mastodon/locales/ckb.json b/app/javascript/mastodon/locales/ckb.json index 0e2991541..06664597e 100644 --- a/app/javascript/mastodon/locales/ckb.json +++ b/app/javascript/mastodon/locales/ckb.json @@ -1,4 +1,17 @@ { + "about.blocks": "Moderated servers", + "about.contact": "Contact:", + "about.domain_blocks.comment": "Reason", + "about.domain_blocks.domain": "Domain", + "about.domain_blocks.preamble": "Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.", + "about.domain_blocks.severity": "Severity", + "about.domain_blocks.silenced.explanation": "You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.", + "about.domain_blocks.silenced.title": "Limited", + "about.domain_blocks.suspended.explanation": "No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.", + "about.domain_blocks.suspended.title": "Suspended", + "about.not_available": "This information has not been made available on this server.", + "about.powered_by": "Decentralized social media powered by {mastodon}", + "about.rules": "Server rules", "account.account_note_header": "تێبینی ", "account.add_or_remove_from_list": "زیادکردن یان سڕینەوە لە پێرستەکان", "account.badges.bot": "بوت", @@ -7,13 +20,16 @@ "account.block_domain": "بلۆکی هەموو شتێک لە {domain}", "account.blocked": "بلۆککرا", "account.browse_more_on_origin_server": "گەڕانی فرەتر لە سەر پرۆفایلی سەرەکی", - "account.cancel_follow_request": "بەتاڵکردنی داوای شوێنکەوتن", + "account.cancel_follow_request": "Withdraw follow request", "account.direct": "پەیامی تایبەت بە @{name}", "account.disable_notifications": "ئاگانامە مەنێرە بۆم کاتێک @{name} پۆست دەکرێت", "account.domain_blocked": "دۆمەین قەپاتکرا", "account.edit_profile": "دەستکاری پرۆفایل", "account.enable_notifications": "ئاگادارم بکەوە کاتێک @{name} بابەتەکان", "account.endorse": "ناساندن لە پرۆفایل", + "account.featured_tags.last_status_at": "Last post on {date}", + "account.featured_tags.last_status_never": "No posts", + "account.featured_tags.title": "{name}'s featured hashtags", "account.follow": "شوێنکەوتن", "account.followers": "شوێنکەوتووان", "account.followers.empty": "کەسێک شوێن ئەم بەکارهێنەرە نەکەوتووە", @@ -23,7 +39,7 @@ "account.follows.empty": "ئەم بەکارهێنەرە تا ئێستا شوێن کەس نەکەوتووە.", "account.follows_you": "شوێنکەوتووەکانت", "account.hide_reblogs": "داشاردنی بووستەکان لە @{name}", - "account.joined": "بەشداری {date}", + "account.joined_short": "Joined", "account.languages": "Change subscribed languages", "account.link_verified_on": "خاوەنداریەتی ئەم لینکە لە {date} چێک کراوە", "account.locked_info": "تایبەتمەندی ئەم هەژمارەیە ڕیکخراوە بۆ قوفڵدراوە. خاوەنەکە بە دەستی پێداچوونەوە دەکات کە کێ دەتوانێت شوێنیان بکەوێت.", @@ -63,12 +79,24 @@ "audio.hide": "Hide audio", "autosuggest_hashtag.per_week": "{count} هەرهەفتە", "boost_modal.combo": "دەتوانیت دەست بنێی بە سەر {combo} بۆ بازدان لە جاری داهاتوو", - "bundle_column_error.body": "هەڵەیەک ڕوویدا لەکاتی بارکردنی ئەم پێکهاتەیە.", + "bundle_column_error.copy_stacktrace": "Copy error report", + "bundle_column_error.error.body": "The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.", + "bundle_column_error.error.title": "Oh, no!", + "bundle_column_error.network.body": "There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.", + "bundle_column_error.network.title": "Network error", "bundle_column_error.retry": "دووبارە هەوڵبدە", - "bundle_column_error.title": "هەڵيی تۆڕ", + "bundle_column_error.return": "Go back home", + "bundle_column_error.routing.body": "The requested page could not be found. Are you sure the URL in the address bar is correct?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "داخستن", "bundle_modal_error.message": "هەڵەیەک ڕوویدا لەکاتی بارکردنی ئەم پێکهاتەیە.", "bundle_modal_error.retry": "دووبارە تاقی بکەوە", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "About", "column.blocks": "بەکارهێنەرە بلۆککراوەکان", "column.bookmarks": "نیشانەکان", "column.community": "هێڵی کاتی ناوخۆیی", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "بلۆک & گوزارشت", "confirmations.block.confirm": "بلۆک", "confirmations.block.message": "ئایا دڵنیایت لەوەی دەتەوێت {name} بلۆک بکەیت?", + "confirmations.cancel_follow_request.confirm": "Withdraw request", + "confirmations.cancel_follow_request.message": "Are you sure you want to withdraw your request to follow {name}?", "confirmations.delete.confirm": "سڕینەوە", "confirmations.delete.message": "ئایا دڵنیایت لەوەی دەتەوێت ئەم توتە بسڕیتەوە?", "confirmations.delete_list.confirm": "سڕینەوە", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "نیشانەکردن وەک خوێندراوە", "conversation.open": "نیشاندان گفتوگۆ", "conversation.with": "لەگەڵ{names}", + "copypaste.copied": "Copied", + "copypaste.copy": "Copy", "directory.federated": "لە ڕاژەکانی ناسراو", "directory.local": "تەنها لە {domain}", "directory.new_arrivals": "تازە گەیشتنەکان", "directory.recently_active": "بەم دواییانە چالاکە", + "dismissable_banner.community_timeline": "These are the most recent public posts from people whose accounts are hosted by {domain}.", + "dismissable_banner.dismiss": "Dismiss", + "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", + "dismissable_banner.explore_statuses": "These posts from this and other servers in the decentralized network are gaining traction on this server right now.", + "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", + "dismissable_banner.public_timeline": "These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.", "embed.instructions": "ئەم توتە بنچین بکە لەسەر وێب سایتەکەت بە کۆپیکردنی کۆدەکەی خوارەوە.", "embed.preview": "ئەمە ئەو شتەیە کە لە شێوەی خۆی دەچێت:", "emoji_button.activity": "چالاکی", @@ -221,14 +259,14 @@ "follow_request.reject": "ڕەتکردنەوە", "follow_requests.unlocked_explanation": "هەرچەندە هەژمارەکەت داخراو نییە، ستافی {domain} وا بیریان کردەوە کە لەوانەیە بتانەوێت پێداچوونەوە بە داواکاریەکانی ئەم هەژمارەدا بکەن بە دەستی.", "generic.saved": "پاشکەوتکرا", - "getting_started.developers": "پەرەپێدەران", - "getting_started.directory": "پەڕەی پرۆفایل", + "getting_started.directory": "Directory", "getting_started.documentation": "بەڵگەنامە", + "getting_started.free_software_notice": "Mastodon is free, open source software. You can view the source code, contribute or report issues at {repository}.", "getting_started.heading": "دەست پێکردن", "getting_started.invite": "بانگهێشتکردنی خەڵک", - "getting_started.open_source_notice": "ماستۆدۆن نەرمەکالایەکی سەرچاوەی کراوەیە. دەتوانیت بەشداری بکەیت یان گوزارشت بکەیت لەسەر کێشەکانی لە پەڕەی گیتهاب {github}.", "getting_started.privacy_policy": "Privacy Policy", "getting_started.security": "ڕێکخستنەکانی هەژمارە", + "getting_started.what_is_mastodon": "About Mastodon", "hashtag.column_header.tag_mode.all": "و {additional}", "hashtag.column_header.tag_mode.any": "یا {additional}", "hashtag.column_header.tag_mode.none": "بەبێ {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "وەڵامدانەوەکان پیشان بدە", "home.hide_announcements": "شاردنەوەی راگەیەنراوەکان", "home.show_announcements": "پیشاندانی راگەیەنراوەکان", + "interaction_modal.description.favourite": "With an account on Mastodon, you can favourite this post to let the author know you appreciate it and save it for later.", + "interaction_modal.description.follow": "With an account on Mastodon, you can follow {name} to receive their posts in your home feed.", + "interaction_modal.description.reblog": "With an account on Mastodon, you can boost this post to share it with your own followers.", + "interaction_modal.description.reply": "With an account on Mastodon, you can respond to this post.", + "interaction_modal.on_another_server": "On a different server", + "interaction_modal.on_this_server": "On this server", + "interaction_modal.other_server_instructions": "Simply copy and paste this URL into the search bar of your favourite app or the web interface where you are signed in.", + "interaction_modal.preamble": "Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one.", + "interaction_modal.title.favourite": "Favourite {name}'s post", + "interaction_modal.title.follow": "Follow {name}", + "interaction_modal.title.reblog": "Boost {name}'s post", + "interaction_modal.title.reply": "Reply to {name}'s post", "intervals.full.days": "{number, plural, one {# ڕۆژ} other {# ڕۆژەک}}", "intervals.full.hours": "{number, plural, one {# کات} other {# کات}}", "intervals.full.minutes": "{number, plural, one {# خولەک} other {# خولەک}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "ماوە", "mute_modal.hide_notifications": "شاردنەوەی ئاگانامەکان لەم بەکارهێنەرە؟ ", "mute_modal.indefinite": "نادیار", - "navigation_bar.apps": "بەرنامەی مۆبایل", + "navigation_bar.about": "About", + "navigation_bar.apps": "Get the app", "navigation_bar.blocks": "بەکارهێنەرە بلۆککراوەکان", "navigation_bar.bookmarks": "نیشانکراوەکان", "navigation_bar.community_timeline": "دەمنامەی ناوخۆیی", @@ -324,7 +375,7 @@ "navigation_bar.filters": "وشە کپەکان", "navigation_bar.follow_requests": "بەدواداچوی داواکاریەکان بکە", "navigation_bar.follows_and_followers": "شوێنکەوتوو و شوێنکەوتوان", - "navigation_bar.info": "دەربارەی ئەم ڕاژە", + "navigation_bar.info": "About", "navigation_bar.keyboard_shortcuts": "هۆتکەی", "navigation_bar.lists": "لیستەکان", "navigation_bar.logout": "دەرچوون", @@ -333,7 +384,9 @@ "navigation_bar.pins": "توتی چەسپاو", "navigation_bar.preferences": "پەسەندەکان", "navigation_bar.public_timeline": "نووسراوەکانی هەمووشوێنێک", + "navigation_bar.search": "Search", "navigation_bar.security": "ئاسایش", + "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", "notification.admin.report": "{name} reported {target}", "notification.admin.sign_up": "{name} تۆمارکرا", "notification.favourite": "{name} نووسراوەکەتی پەسەند کرد", @@ -401,6 +454,8 @@ "privacy.public.short": "گشتی", "privacy.unlisted.long": "بۆ هەمووان دیارە، بەڵام لە تایبەتمەندییەکانی دۆزینەوە دەرچووە", "privacy.unlisted.short": "لە لیست نەکراو", + "privacy_policy.last_updated": "Last updated {date}", + "privacy_policy.title": "Privacy Policy", "refresh": "نوێکردنەوە", "regeneration_indicator.label": "بارکردن…", "regeneration_indicator.sublabel": "ڕاگەیەنەری ماڵەوەت ئامادە دەکرێت!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "گەڕانی توتەکان بە ناوەڕۆکیان لەسەر ئەم ڕاژەی ماستۆدۆن چالاک نەکراوە.", "search_results.title": "Search for {q}", "search_results.total": "{count, number} {count, plural, one {دەرئەنجام} other {دەرئەنجام}}", + "server_banner.about_active_users": "People using this server during the last 30 days (Monthly Active Users)", + "server_banner.active_users": "active users", + "server_banner.administered_by": "Administered by:", + "server_banner.introduction": "{domain} is part of the decentralized social network powered by {mastodon}.", + "server_banner.learn_more": "Learn more", + "server_banner.server_stats": "Server stats:", "sign_in_banner.create_account": "Create account", "sign_in_banner.sign_in": "Sign in", "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "کەس ئەم توتەی دووبارە نەتوتاندوە ،کاتێک کەسێک وا بکات، لێرە دەرئەکەون.", "status.redraft": "سڕینەوەی و دووبارە ڕەشنووس", "status.remove_bookmark": "لابردنی نیشانه", + "status.replied_to": "Replied to {name}", "status.reply": "وەڵام", "status.replyAll": "بە نووسراوە وەڵام بدەوە", "status.report": "گوزارشت @{name}", @@ -523,9 +585,8 @@ "status.show_more": "زیاتر نیشان بدە", "status.show_more_all": "زیاتر نیشان بدە بۆ هەمووی", "status.show_original": "Show original", - "status.show_thread": "نیشاندانی گفتوگۆ", "status.translate": "Translate", - "status.translated_from": "Translated from {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "بەردەست نیە", "status.unmute_conversation": "گفتوگۆی بێدەنگ", "status.unpin": "لە سەرەوە لایبە", @@ -538,7 +599,6 @@ "tabs_bar.home": "سەرەتا", "tabs_bar.local_timeline": "ناوخۆیی", "tabs_bar.notifications": "ئاگادارییەکان", - "tabs_bar.search": "بگەڕێ", "time_remaining.days": "{number, plural, one {# ڕۆژ} other {# ڕۆژ}} ماوە", "time_remaining.hours": "{number, plural, one {# کاتژمێر} other {# کاتژمێر}} ماوە", "time_remaining.minutes": "{number, plural, one {# خولەک} other {# خولەک}} ماوە", diff --git a/app/javascript/mastodon/locales/co.json b/app/javascript/mastodon/locales/co.json index 58e3772e5..4be800665 100644 --- a/app/javascript/mastodon/locales/co.json +++ b/app/javascript/mastodon/locales/co.json @@ -1,4 +1,17 @@ { + "about.blocks": "Moderated servers", + "about.contact": "Contact:", + "about.domain_blocks.comment": "Reason", + "about.domain_blocks.domain": "Domain", + "about.domain_blocks.preamble": "Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.", + "about.domain_blocks.severity": "Severity", + "about.domain_blocks.silenced.explanation": "You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.", + "about.domain_blocks.silenced.title": "Limited", + "about.domain_blocks.suspended.explanation": "No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.", + "about.domain_blocks.suspended.title": "Suspended", + "about.not_available": "This information has not been made available on this server.", + "about.powered_by": "Decentralized social media powered by {mastodon}", + "about.rules": "Server rules", "account.account_note_header": "Nota", "account.add_or_remove_from_list": "Aghjunghje o toglie da e liste", "account.badges.bot": "Bot", @@ -7,13 +20,16 @@ "account.block_domain": "Piattà u duminiu {domain}", "account.blocked": "Bluccatu", "account.browse_more_on_origin_server": "Vede di più nant'à u prufile uriginale", - "account.cancel_follow_request": "Annullà a dumanda d'abbunamentu", + "account.cancel_follow_request": "Withdraw follow request", "account.direct": "Missaghju direttu @{name}", "account.disable_notifications": "Ùn mi nutificate più quandu @{name} pubblica qualcosa", "account.domain_blocked": "Duminiu piattatu", "account.edit_profile": "Mudificà u prufile", "account.enable_notifications": "Nutificate mi quandu @{name} pubblica qualcosa", "account.endorse": "Fà figurà nant'à u prufilu", + "account.featured_tags.last_status_at": "Last post on {date}", + "account.featured_tags.last_status_never": "No posts", + "account.featured_tags.title": "{name}'s featured hashtags", "account.follow": "Siguità", "account.followers": "Abbunati", "account.followers.empty": "Nisunu hè abbunatu à st'utilizatore.", @@ -23,7 +39,7 @@ "account.follows.empty": "St'utilizatore ùn seguita nisunu.", "account.follows_you": "Vi seguita", "account.hide_reblogs": "Piattà spartere da @{name}", - "account.joined": "Quì dapoi {date}", + "account.joined_short": "Joined", "account.languages": "Change subscribed languages", "account.link_verified_on": "A prupietà di stu ligame hè stata verificata u {date}", "account.locked_info": "U statutu di vita privata di u contu hè chjosu. U pruprietariu esamina manualmente e dumande d'abbunamentu.", @@ -63,12 +79,24 @@ "audio.hide": "Hide audio", "autosuggest_hashtag.per_week": "{count} per settimana", "boost_modal.combo": "Pudete appughjà nant'à {combo} per saltà quessa a prussima volta", - "bundle_column_error.body": "C'hè statu un prublemu caricandu st'elementu.", + "bundle_column_error.copy_stacktrace": "Copy error report", + "bundle_column_error.error.body": "The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.", + "bundle_column_error.error.title": "Oh, no!", + "bundle_column_error.network.body": "There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.", + "bundle_column_error.network.title": "Network error", "bundle_column_error.retry": "Pruvà torna", - "bundle_column_error.title": "Errore di cunnessione", + "bundle_column_error.return": "Go back home", + "bundle_column_error.routing.body": "The requested page could not be found. Are you sure the URL in the address bar is correct?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Chjudà", "bundle_modal_error.message": "C'hè statu un prublemu caricandu st'elementu.", "bundle_modal_error.retry": "Pruvà torna", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "About", "column.blocks": "Utilizatori bluccati", "column.bookmarks": "Segnalibri", "column.community": "Linea pubblica lucale", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "Bluccà è signalà", "confirmations.block.confirm": "Bluccà", "confirmations.block.message": "Site sicuru·a che vulete bluccà @{name}?", + "confirmations.cancel_follow_request.confirm": "Withdraw request", + "confirmations.cancel_follow_request.message": "Are you sure you want to withdraw your request to follow {name}?", "confirmations.delete.confirm": "Toglie", "confirmations.delete.message": "Site sicuru·a che vulete sguassà stu statutu?", "confirmations.delete_list.confirm": "Toglie", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Marcà cum'è lettu", "conversation.open": "Vede a cunversazione", "conversation.with": "Cù {names}", + "copypaste.copied": "Copied", + "copypaste.copy": "Copy", "directory.federated": "Da u fediversu cunisciutu", "directory.local": "Solu da {domain}", "directory.new_arrivals": "Ultimi arrivi", "directory.recently_active": "Attività ricente", + "dismissable_banner.community_timeline": "These are the most recent public posts from people whose accounts are hosted by {domain}.", + "dismissable_banner.dismiss": "Dismiss", + "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", + "dismissable_banner.explore_statuses": "These posts from this and other servers in the decentralized network are gaining traction on this server right now.", + "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", + "dismissable_banner.public_timeline": "These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.", "embed.instructions": "Integrà stu statutu à u vostru situ cù u codice quì sottu.", "embed.preview": "Hà da parè à quessa:", "emoji_button.activity": "Attività", @@ -221,14 +259,14 @@ "follow_request.reject": "Righjittà", "follow_requests.unlocked_explanation": "U vostru contu ùn hè micca privatu, ma a squadra d'amministrazione di {domain} pensa chì e dumande d'abbunamentu di questi conti anu bisognu d'esse verificate manualmente.", "generic.saved": "Salvatu", - "getting_started.developers": "Sviluppatori", - "getting_started.directory": "Annuariu di i prufili", + "getting_started.directory": "Directory", "getting_started.documentation": "Ducumentazione", + "getting_started.free_software_notice": "Mastodon is free, open source software. You can view the source code, contribute or report issues at {repository}.", "getting_started.heading": "Per principià", "getting_started.invite": "Invità ghjente", - "getting_started.open_source_notice": "Mastodon ghjè un lugiziale liberu. Pudete cuntribuisce à u codice o a traduzione, o palisà un bug, nant'à GitHub: {github}.", "getting_started.privacy_policy": "Privacy Policy", "getting_started.security": "Sicurità", + "getting_started.what_is_mastodon": "About Mastodon", "hashtag.column_header.tag_mode.all": "è {additional}", "hashtag.column_header.tag_mode.any": "o {additional}", "hashtag.column_header.tag_mode.none": "senza {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Vede e risposte", "home.hide_announcements": "Piattà annunzii", "home.show_announcements": "Vede annunzii", + "interaction_modal.description.favourite": "With an account on Mastodon, you can favourite this post to let the author know you appreciate it and save it for later.", + "interaction_modal.description.follow": "With an account on Mastodon, you can follow {name} to receive their posts in your home feed.", + "interaction_modal.description.reblog": "With an account on Mastodon, you can boost this post to share it with your own followers.", + "interaction_modal.description.reply": "With an account on Mastodon, you can respond to this post.", + "interaction_modal.on_another_server": "On a different server", + "interaction_modal.on_this_server": "On this server", + "interaction_modal.other_server_instructions": "Simply copy and paste this URL into the search bar of your favourite app or the web interface where you are signed in.", + "interaction_modal.preamble": "Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one.", + "interaction_modal.title.favourite": "Favourite {name}'s post", + "interaction_modal.title.follow": "Follow {name}", + "interaction_modal.title.reblog": "Boost {name}'s post", + "interaction_modal.title.reply": "Reply to {name}'s post", "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}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Durata", "mute_modal.hide_notifications": "Piattà nutificazione da st'utilizatore?", "mute_modal.indefinite": "Indifinita", - "navigation_bar.apps": "Applicazione per u telefuninu", + "navigation_bar.about": "About", + "navigation_bar.apps": "Get the app", "navigation_bar.blocks": "Utilizatori bluccati", "navigation_bar.bookmarks": "Segnalibri", "navigation_bar.community_timeline": "Linea pubblica lucale", @@ -324,7 +375,7 @@ "navigation_bar.filters": "Parolle silenzate", "navigation_bar.follow_requests": "Dumande d'abbunamentu", "navigation_bar.follows_and_followers": "Abbunati è abbunamenti", - "navigation_bar.info": "À prupositu di u servore", + "navigation_bar.info": "About", "navigation_bar.keyboard_shortcuts": "Accorte cù a tastera", "navigation_bar.lists": "Liste", "navigation_bar.logout": "Scunnettassi", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Statuti puntarulati", "navigation_bar.preferences": "Preferenze", "navigation_bar.public_timeline": "Linea pubblica glubale", + "navigation_bar.search": "Search", "navigation_bar.security": "Sicurità", + "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", "notification.admin.report": "{name} reported {target}", "notification.admin.sign_up": "{name} signed up", "notification.favourite": "{name} hà aghjuntu u vostru statutu à i so favuriti", @@ -401,6 +454,8 @@ "privacy.public.short": "Pubblicu", "privacy.unlisted.long": "Visible for all, but opted-out of discovery features", "privacy.unlisted.short": "Micca listatu", + "privacy_policy.last_updated": "Last updated {date}", + "privacy_policy.title": "Privacy Policy", "refresh": "Attualizà", "regeneration_indicator.label": "Caricamentu…", "regeneration_indicator.sublabel": "Priparazione di a vostra pagina d'accolta!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "A ricerca di i cuntinuti di i statuti ùn hè micca attivata nant'à stu servore Mastodon.", "search_results.title": "Search for {q}", "search_results.total": "{count, number} {count, plural, one {risultatu} other {risultati}}", + "server_banner.about_active_users": "People using this server during the last 30 days (Monthly Active Users)", + "server_banner.active_users": "active users", + "server_banner.administered_by": "Administered by:", + "server_banner.introduction": "{domain} is part of the decentralized social network powered by {mastodon}.", + "server_banner.learn_more": "Learn more", + "server_banner.server_stats": "Server stats:", "sign_in_banner.create_account": "Create account", "sign_in_banner.sign_in": "Sign in", "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "Per avà nisunu hà spartutu u statutu. Quandu qualch'unu u sparterà, u so contu sarà mustratu quì.", "status.redraft": "Sguassà è riscrive", "status.remove_bookmark": "Toglie segnalibru", + "status.replied_to": "Replied to {name}", "status.reply": "Risponde", "status.replyAll": "Risponde à tutti", "status.report": "Palisà @{name}", @@ -523,9 +585,8 @@ "status.show_more": "Slibrà", "status.show_more_all": "Slibrà tuttu", "status.show_original": "Show original", - "status.show_thread": "Vede u filu", "status.translate": "Translate", - "status.translated_from": "Translated from {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Micca dispunibule", "status.unmute_conversation": "Ùn piattà più a cunversazione", "status.unpin": "Spuntarulà da u prufile", @@ -538,7 +599,6 @@ "tabs_bar.home": "Accolta", "tabs_bar.local_timeline": "Lucale", "tabs_bar.notifications": "Nutificazione", - "tabs_bar.search": "Cercà", "time_remaining.days": "{number, plural, one {# ghjornu ferma} other {# ghjorni fermanu}}", "time_remaining.hours": "{number, plural, one {# ora ferma} other {# ore fermanu}}", "time_remaining.minutes": "{number, plural, one {# minuta ferma} other {# minute fermanu}} left", diff --git a/app/javascript/mastodon/locales/cs.json b/app/javascript/mastodon/locales/cs.json index 43b494af9..5ccbf73dc 100644 --- a/app/javascript/mastodon/locales/cs.json +++ b/app/javascript/mastodon/locales/cs.json @@ -1,4 +1,17 @@ { + "about.blocks": "Moderované servery", + "about.contact": "Kontakt:", + "about.domain_blocks.comment": "Důvod", + "about.domain_blocks.domain": "Doména", + "about.domain_blocks.preamble": "Mastodon vám obecně umožňuje prohlížet obsah a komunikovat s uživateli z jakéhokoliv jiného serveru ve fediveru. Toto jsou výjimky, které byly uděleny na tomto konkrétním serveru.", + "about.domain_blocks.severity": "Závažnost", + "about.domain_blocks.silenced.explanation": "Z tohoto serveru obecně neuvidíte profily a obsah, pokud se na něj výslovně nepodíváte, nebo se k němu připojíte sledováním.", + "about.domain_blocks.silenced.title": "Omezeno", + "about.domain_blocks.suspended.explanation": "Žádná data z tohoto serveru nebudou zpracovávána, uložena ani vyměňována, což znemožňuje jakoukoli interakci nebo komunikaci s uživateli z tohoto serveru.", + "about.domain_blocks.suspended.title": "Pozastaveno", + "about.not_available": "Tato informace nebyla zpřístupněna na tomto serveru.", + "about.powered_by": "Decentralizovaná sociální média poháněná {mastodon}", + "about.rules": "Pravidla serveru", "account.account_note_header": "Poznámka", "account.add_or_remove_from_list": "Přidat nebo odstranit ze seznamů", "account.badges.bot": "Robot", @@ -7,13 +20,16 @@ "account.block_domain": "Blokovat doménu {domain}", "account.blocked": "Blokován", "account.browse_more_on_origin_server": "Více na původním profilu", - "account.cancel_follow_request": "Zrušit žádost o sledování", + "account.cancel_follow_request": "Vybrat žádost o následování", "account.direct": "Poslat @{name} přímou zprávu", "account.disable_notifications": "Zrušit upozorňování na příspěvky @{name}", "account.domain_blocked": "Doména blokována", "account.edit_profile": "Upravit profil", "account.enable_notifications": "Oznamovat mi příspěvky @{name}", "account.endorse": "Zvýraznit na profilu", + "account.featured_tags.last_status_at": "Poslední příspěvek na {date}", + "account.featured_tags.last_status_never": "Žádné příspěvky", + "account.featured_tags.title": "Hlavní hashtagy {name}", "account.follow": "Sledovat", "account.followers": "Sledující", "account.followers.empty": "Tohoto uživatele ještě nikdo nesleduje.", @@ -23,7 +39,7 @@ "account.follows.empty": "Tento uživatel ještě nikoho nesleduje.", "account.follows_you": "Sleduje vás", "account.hide_reblogs": "Skrýt boosty od @{name}", - "account.joined": "Založen {date}", + "account.joined_short": "Joined", "account.languages": "Změnit odebírané jazyky", "account.link_verified_on": "Vlastnictví tohoto odkazu bylo zkontrolováno {date}", "account.locked_info": "Stav soukromí tohoto účtu je nastaven na zamčeno. Jeho vlastník ručně posuzuje, kdo ho může sledovat.", @@ -63,12 +79,24 @@ "audio.hide": "Skrýt zvuk", "autosuggest_hashtag.per_week": "{count} za týden", "boost_modal.combo": "Příště můžete pro přeskočení stisknout {combo}", - "bundle_column_error.body": "Při načítání této komponenty se něco pokazilo.", + "bundle_column_error.copy_stacktrace": "Kopírovat zprávu o chybě", + "bundle_column_error.error.body": "Požadovanou stránku nelze vykreslit. Může to být způsobeno chybou v našem kódu nebo problémem s kompatibilitou prohlížeče.", + "bundle_column_error.error.title": "Ale ne!", + "bundle_column_error.network.body": "Při pokusu o načtení této stránky došlo k chybě. To může být způsobeno dočasným problémem s připojením k Internetu nebo k tomuto serveru.", + "bundle_column_error.network.title": "Chyba sítě", "bundle_column_error.retry": "Zkuste to znovu", - "bundle_column_error.title": "Chyba sítě", + "bundle_column_error.return": "Zpět na domovskou stránku", + "bundle_column_error.routing.body": "Požadovaná stránka nebyla nalezena. Opravdu je adresa správná?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Zavřít", "bundle_modal_error.message": "Při načítání této komponenty se něco pokazilo.", "bundle_modal_error.retry": "Zkusit znovu", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "O aplikaci", "column.blocks": "Blokovaní uživatelé", "column.bookmarks": "Záložky", "column.community": "Místní časová osa", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "Blokovat a nahlásit", "confirmations.block.confirm": "Blokovat", "confirmations.block.message": "Opravdu chcete zablokovat {name}?", + "confirmations.cancel_follow_request.confirm": "Withdraw request", + "confirmations.cancel_follow_request.message": "Are you sure you want to withdraw your request to follow {name}?", "confirmations.delete.confirm": "Smazat", "confirmations.delete.message": "Opravdu chcete smazat tento příspěvek?", "confirmations.delete_list.confirm": "Smazat", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Označit jako přečtenou", "conversation.open": "Zobrazit konverzaci", "conversation.with": "S {names}", + "copypaste.copied": "Zkopírováno", + "copypaste.copy": "Kopírovat", "directory.federated": "Ze známého fedivesmíru", "directory.local": "Pouze z domény {domain}", "directory.new_arrivals": "Nově příchozí", "directory.recently_active": "Nedávno aktivní", + "dismissable_banner.community_timeline": "Toto jsou nejnovější veřejné příspěvky od lidí, jejichž účty hostuje {domain}.", + "dismissable_banner.dismiss": "Odmítnout", + "dismissable_banner.explore_links": "O těchto novinkách hovoří lidé na tomto a dalších serverech decentralizované sítě.", + "dismissable_banner.explore_statuses": "Tyto příspěvky z této a dalších serverů v decentralizované síti nyní získávají trakci na tomto serveru.", + "dismissable_banner.explore_tags": "Tyto hashtagy právě teď získávají na popularitě mezi lidmi na tomto a dalších serverech decentralizované sítě.", + "dismissable_banner.public_timeline": "Toto jsou nejnovější veřejné příspěvky od lidí na tomto a jiných serverech decentralizované sítě, o které tento server ví.", "embed.instructions": "Pro přidání příspěvku na vaši webovou stránku zkopírujte níže uvedený kód.", "embed.preview": "Takhle to bude vypadat:", "emoji_button.activity": "Aktivita", @@ -221,14 +259,14 @@ "follow_request.reject": "Odmítnout", "follow_requests.unlocked_explanation": "Přestože váš účet není uzamčen, personál {domain} usoudil, že byste mohli chtít tyto požadavky na sledování zkontrolovat ručně.", "generic.saved": "Uloženo", - "getting_started.developers": "Vývojáři", - "getting_started.directory": "Adresář profilů", + "getting_started.directory": "Adresář", "getting_started.documentation": "Dokumentace", + "getting_started.free_software_notice": "Mastodon je svobodný software s otevřeným zdrojovým kódem. Zdrojový kód si můžete prohlédnout, přispět do něj nebo nahlásit problémy na {repository}.", "getting_started.heading": "Začínáme", "getting_started.invite": "Pozvat lidi", - "getting_started.open_source_notice": "Mastodon je otevřený software. Přispět do jeho vývoje nebo hlásit chyby můžete na GitHubu {github}.", "getting_started.privacy_policy": "Zásady ochrany osobních údajů", "getting_started.security": "Nastavení účtu", + "getting_started.what_is_mastodon": "O Mastodon", "hashtag.column_header.tag_mode.all": "a {additional}", "hashtag.column_header.tag_mode.any": "nebo {additional}", "hashtag.column_header.tag_mode.none": "bez {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Zobrazit odpovědi", "home.hide_announcements": "Skrýt oznámení", "home.show_announcements": "Zobrazit oznámení", + "interaction_modal.description.favourite": "Pokud máte účet na Mastodonu, můžete tento příspěvek označit jako oblíbený a dát tak autorovi najevo, že si ho vážíte, a uložit si ho na později.", + "interaction_modal.description.follow": "S účtem na Mastodonu můžete sledovat {name} a přijímat příspěvky ve vašem domovském kanálu.", + "interaction_modal.description.reblog": "S účtem na Mastodonu můžete podpořit tento příspěvek a sdílet jej s vlastními sledujícími.", + "interaction_modal.description.reply": "S účtem na Mastodonu můžete reagovat na tento příspěvek.", + "interaction_modal.on_another_server": "Na jiném serveru", + "interaction_modal.on_this_server": "Na tomto serveru", + "interaction_modal.other_server_instructions": "Jednoduše zkopírujte a vložte tuto adresu do vyhledávacího panelu vaší oblíbené aplikace nebo webového rozhraní, kde jste přihlášeni.", + "interaction_modal.preamble": "Protože je Mastodon decentralizovaný, pokud nemáte účet na tomto serveru, můžete použít svůj existující účet hostovaný jiným Mastodon serverem nebo kompatibilní platformou.", + "interaction_modal.title.favourite": "Oblíbený příspěvek {name}", + "interaction_modal.title.follow": "Sledovat {name}", + "interaction_modal.title.reblog": "Zvýšit příspěvek uživatele {name}", + "interaction_modal.title.reply": "Odpovědět na příspěvek uživatele {name}", "intervals.full.days": "{number, plural, one {# den} few {# dny} many {# dní} other {# dní}}", "intervals.full.hours": "{number, plural, one {# hodina} few {# hodiny} many {# hodin} other {# hodin}}", "intervals.full.minutes": "{number, plural, one {# minuta} few {# minuty} many {# minut} other {# minut}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Trvání", "mute_modal.hide_notifications": "Skrýt oznámení od tohoto uživatele?", "mute_modal.indefinite": "Neomezeně", - "navigation_bar.apps": "Mobilní aplikace", + "navigation_bar.about": "O aplikaci", + "navigation_bar.apps": "Stáhnout aplikaci", "navigation_bar.blocks": "Blokovaní uživatelé", "navigation_bar.bookmarks": "Záložky", "navigation_bar.community_timeline": "Místní časová osa", @@ -324,7 +375,7 @@ "navigation_bar.filters": "Skrytá slova", "navigation_bar.follow_requests": "Žádosti o sledování", "navigation_bar.follows_and_followers": "Sledovaní a sledující", - "navigation_bar.info": "O tomto serveru", + "navigation_bar.info": "O aplikaci", "navigation_bar.keyboard_shortcuts": "Klávesové zkratky", "navigation_bar.lists": "Seznamy", "navigation_bar.logout": "Odhlásit", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Připnuté příspěvky", "navigation_bar.preferences": "Předvolby", "navigation_bar.public_timeline": "Federovaná časová osa", + "navigation_bar.search": "Search", "navigation_bar.security": "Zabezpečení", + "not_signed_in_indicator.not_signed_in": "Pro přístup k tomuto zdroji se musíte přihlásit.", "notification.admin.report": "Uživatel {name} nahlásil {target}", "notification.admin.sign_up": "Uživatel {name} se zaregistroval", "notification.favourite": "Uživatel {name} si oblíbil váš příspěvek", @@ -401,6 +454,8 @@ "privacy.public.short": "Veřejný", "privacy.unlisted.long": "Viditelný pro všechny, ale vyňat z funkcí objevování", "privacy.unlisted.short": "Neuvedený", + "privacy_policy.last_updated": "Naposledy aktualizováno {date}", + "privacy_policy.title": "Zásady ochrany osobních údajů", "refresh": "Obnovit", "regeneration_indicator.label": "Načítání…", "regeneration_indicator.sublabel": "Váš domovský kanál se připravuje!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "Vyhledávání příspěvků podle jejich obsahu není na tomto Mastodon serveru povoleno.", "search_results.title": "Hledat {q}", "search_results.total": "{count, number} {count, plural, one {výsledek} few {výsledky} many {výsledků} other {výsledků}}", + "server_banner.about_active_users": "Lidé používající tento server během posledních 30 dní (měsíční aktivní uživatelé)", + "server_banner.active_users": "aktivní uživatelé", + "server_banner.administered_by": "Spravováno:", + "server_banner.introduction": "{domain} je součástí decentralizované sociální sítě běžící na {mastodon}.", + "server_banner.learn_more": "Zjistit více", + "server_banner.server_stats": "Statistiky serveru:", "sign_in_banner.create_account": "Vytvořit účet", "sign_in_banner.sign_in": "Přihlásit se", "sign_in_banner.text": "Přihlaste se pro sledování profilů nebo hashtagů, oblíbených, sdílení a odpovědi na příspěvky nebo interakci z vašeho účtu na jiném serveru.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "Tento příspěvek ještě nikdo neboostnul. Pokud to někdo udělá, zobrazí se zde.", "status.redraft": "Smazat a přepsat", "status.remove_bookmark": "Odstranit ze záložek", + "status.replied_to": "Replied to {name}", "status.reply": "Odpovědět", "status.replyAll": "Odpovědět na vlákno", "status.report": "Nahlásit @{name}", @@ -523,9 +585,8 @@ "status.show_more": "Zobrazit více", "status.show_more_all": "Zobrazit více pro všechny", "status.show_original": "Zobrazit původní", - "status.show_thread": "Zobrazit vlákno", "status.translate": "Přeložit", - "status.translated_from": "Přeloženo z {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Nedostupné", "status.unmute_conversation": "Odkrýt konverzaci", "status.unpin": "Odepnout z profilu", @@ -538,7 +599,6 @@ "tabs_bar.home": "Domovská", "tabs_bar.local_timeline": "Místní", "tabs_bar.notifications": "Oznámení", - "tabs_bar.search": "Hledat", "time_remaining.days": "{number, plural, one {Zbývá # den} few {Zbývají # dny} many {Zbývá # dní} other {Zbývá # dní}}", "time_remaining.hours": "{number, plural, one {Zbývá # hodina} few {Zbývají # hodiny} many {Zbývá # hodin} other {Zbývá # hodin}}", "time_remaining.minutes": "{number, plural, one {Zbývá # minuta} few {Zbývají # minuty} many {Zbývá # minut} other {Zbývá # minut}}", diff --git a/app/javascript/mastodon/locales/cy.json b/app/javascript/mastodon/locales/cy.json index 70418a609..7b5387fa1 100644 --- a/app/javascript/mastodon/locales/cy.json +++ b/app/javascript/mastodon/locales/cy.json @@ -1,4 +1,17 @@ { + "about.blocks": "Moderated servers", + "about.contact": "Contact:", + "about.domain_blocks.comment": "Reason", + "about.domain_blocks.domain": "Domain", + "about.domain_blocks.preamble": "Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.", + "about.domain_blocks.severity": "Severity", + "about.domain_blocks.silenced.explanation": "You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.", + "about.domain_blocks.silenced.title": "Limited", + "about.domain_blocks.suspended.explanation": "No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.", + "about.domain_blocks.suspended.title": "Suspended", + "about.not_available": "This information has not been made available on this server.", + "about.powered_by": "Decentralized social media powered by {mastodon}", + "about.rules": "Server rules", "account.account_note_header": "Nodyn", "account.add_or_remove_from_list": "Ychwanegu neu Dileu o'r rhestrau", "account.badges.bot": "Bot", @@ -7,13 +20,16 @@ "account.block_domain": "Blocio parth {domain}", "account.blocked": "Blociwyd", "account.browse_more_on_origin_server": "Pori mwy ar y proffil gwreiddiol", - "account.cancel_follow_request": "Canslo cais dilyn", + "account.cancel_follow_request": "Withdraw follow request", "account.direct": "Neges breifat @{name}", "account.disable_notifications": "Stopiwch fy hysbysu pan fydd @{name} yn postio", "account.domain_blocked": "Parth wedi ei flocio", "account.edit_profile": "Golygu proffil", "account.enable_notifications": "Rhowch wybod i fi pan fydd @{name} yn postio", "account.endorse": "Arddangos ar fy mhroffil", + "account.featured_tags.last_status_at": "Last post on {date}", + "account.featured_tags.last_status_never": "No posts", + "account.featured_tags.title": "{name}'s featured hashtags", "account.follow": "Dilyn", "account.followers": "Dilynwyr", "account.followers.empty": "Does neb yn dilyn y defnyddiwr hwn eto.", @@ -23,7 +39,7 @@ "account.follows.empty": "Nid yw'r defnyddiwr hwn yn dilyn unrhyw un eto.", "account.follows_you": "Yn eich dilyn chi", "account.hide_reblogs": "Cuddio bwstiau o @{name}", - "account.joined": "Ymunodd {date}", + "account.joined_short": "Joined", "account.languages": "Change subscribed languages", "account.link_verified_on": "Gwiriwyd perchnogaeth y ddolen yma ar {date}", "account.locked_info": "Mae'r statws preifatrwydd cyfrif hwn wedi'i osod i gloi. Mae'r perchennog yn adolygu'r sawl sy'n gallu eu dilyn.", @@ -63,12 +79,24 @@ "audio.hide": "Hide audio", "autosuggest_hashtag.per_week": "{count} yr wythnos", "boost_modal.combo": "Mae modd gwasgu {combo} er mwyn sgipio hyn tro nesa", - "bundle_column_error.body": "Aeth rhywbeth o'i le tra'n llwytho'r elfen hon.", + "bundle_column_error.copy_stacktrace": "Copy error report", + "bundle_column_error.error.body": "The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.", + "bundle_column_error.error.title": "Oh, no!", + "bundle_column_error.network.body": "There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.", + "bundle_column_error.network.title": "Network error", "bundle_column_error.retry": "Ceisiwch eto", - "bundle_column_error.title": "Gwall rhwydwaith", + "bundle_column_error.return": "Go back home", + "bundle_column_error.routing.body": "The requested page could not be found. Are you sure the URL in the address bar is correct?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Cau", "bundle_modal_error.message": "Aeth rhywbeth o'i le tra'n llwytho'r elfen hon.", "bundle_modal_error.retry": "Ceiswich eto", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "About", "column.blocks": "Defnyddwyr a flociwyd", "column.bookmarks": "Tudalnodau", "column.community": "Ffrwd lleol", @@ -121,6 +149,8 @@ "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.cancel_follow_request.confirm": "Withdraw request", + "confirmations.cancel_follow_request.message": "Are you sure you want to withdraw your request to follow {name}?", "confirmations.delete.confirm": "Dileu", "confirmations.delete.message": "Ydych chi'n sicr eich bod eisiau dileu y post hwn?", "confirmations.delete_list.confirm": "Dileu", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Nodi fel wedi'i ddarllen", "conversation.open": "Gweld sgwrs", "conversation.with": "Gyda {names}", + "copypaste.copied": "Copied", + "copypaste.copy": "Copy", "directory.federated": "O'r ffedysawd cyfan", "directory.local": "O {domain} yn unig", "directory.new_arrivals": "Newydd-ddyfodiaid", "directory.recently_active": "Yn weithredol yn ddiweddar", + "dismissable_banner.community_timeline": "These are the most recent public posts from people whose accounts are hosted by {domain}.", + "dismissable_banner.dismiss": "Dismiss", + "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", + "dismissable_banner.explore_statuses": "These posts from this and other servers in the decentralized network are gaining traction on this server right now.", + "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", + "dismissable_banner.public_timeline": "These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.", "embed.instructions": "Gosodwch y post hwn ar eich gwefan drwy gopïo'r côd isod.", "embed.preview": "Dyma sut olwg fydd arno:", "emoji_button.activity": "Gweithgarwch", @@ -221,14 +259,14 @@ "follow_request.reject": "Gwrthod", "follow_requests.unlocked_explanation": "Er nid yw eich cyfrif wedi'i gloi, oedd y staff {domain} yn meddwl efallai hoffech adolygu ceisiadau dilyn o'r cyfrifau rhain wrth law.", "generic.saved": "Wedi'i Gadw", - "getting_started.developers": "Datblygwyr", - "getting_started.directory": "Cyfeiriadur proffil", + "getting_started.directory": "Directory", "getting_started.documentation": "Dogfennaeth", + "getting_started.free_software_notice": "Mastodon is free, open source software. You can view the source code, contribute or report issues at {repository}.", "getting_started.heading": "Dechrau", "getting_started.invite": "Gwahodd pobl", - "getting_started.open_source_notice": "Mae Mastodon yn feddalwedd côd agored. Mae modd cyfrannu neu adrodd materion ar GitHUb ar {github}.", "getting_started.privacy_policy": "Privacy Policy", "getting_started.security": "Diogelwch", + "getting_started.what_is_mastodon": "About Mastodon", "hashtag.column_header.tag_mode.all": "a {additional}", "hashtag.column_header.tag_mode.any": "neu {additional}", "hashtag.column_header.tag_mode.none": "heb {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Dangos ymatebion", "home.hide_announcements": "Cuddio cyhoeddiadau", "home.show_announcements": "Dangos cyhoeddiadau", + "interaction_modal.description.favourite": "With an account on Mastodon, you can favourite this post to let the author know you appreciate it and save it for later.", + "interaction_modal.description.follow": "With an account on Mastodon, you can follow {name} to receive their posts in your home feed.", + "interaction_modal.description.reblog": "With an account on Mastodon, you can boost this post to share it with your own followers.", + "interaction_modal.description.reply": "With an account on Mastodon, you can respond to this post.", + "interaction_modal.on_another_server": "On a different server", + "interaction_modal.on_this_server": "On this server", + "interaction_modal.other_server_instructions": "Simply copy and paste this URL into the search bar of your favourite app or the web interface where you are signed in.", + "interaction_modal.preamble": "Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one.", + "interaction_modal.title.favourite": "Favourite {name}'s post", + "interaction_modal.title.follow": "Follow {name}", + "interaction_modal.title.reblog": "Boost {name}'s post", + "interaction_modal.title.reply": "Reply to {name}'s post", "intervals.full.days": "{number, plural, one {# dydd} two {# ddydd} other {# o ddyddiau}}", "intervals.full.hours": "{number, plural, one {# awr} other {# o oriau}}", "intervals.full.minutes": "{number, plural, one {# funud} other {# o funudau}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Hyd", "mute_modal.hide_notifications": "Cuddio hysbysiadau rhag y defnyddiwr hwn?", "mute_modal.indefinite": "Amhenodol", - "navigation_bar.apps": "Apiau symudol", + "navigation_bar.about": "About", + "navigation_bar.apps": "Get the app", "navigation_bar.blocks": "Defnyddwyr wedi eu blocio", "navigation_bar.bookmarks": "Tudalnodau", "navigation_bar.community_timeline": "Ffrwd leol", @@ -324,7 +375,7 @@ "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.info": "About", "navigation_bar.keyboard_shortcuts": "Bysellau brys", "navigation_bar.lists": "Rhestrau", "navigation_bar.logout": "Allgofnodi", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Postiadau wedi eu pinio", "navigation_bar.preferences": "Dewisiadau", "navigation_bar.public_timeline": "Ffrwd y ffederasiwn", + "navigation_bar.search": "Search", "navigation_bar.security": "Diogelwch", + "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", "notification.admin.report": "{name} reported {target}", "notification.admin.sign_up": "Cofrestrodd {name}", "notification.favourite": "Hoffodd {name} eich post", @@ -401,6 +454,8 @@ "privacy.public.short": "Cyhoeddus", "privacy.unlisted.long": "Gweladwy i bawb, ond wedi optio allan o nodweddion darganfod", "privacy.unlisted.short": "Heb ei restru", + "privacy_policy.last_updated": "Last updated {date}", + "privacy_policy.title": "Privacy Policy", "refresh": "Adnewyddu", "regeneration_indicator.label": "Llwytho…", "regeneration_indicator.sublabel": "Mae eich ffrwd cartref yn cael ei baratoi!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "Nid yw chwilio postiadau yn ôl eu cynnwys wedi'i alluogi ar y gweinydd Mastodon hwn.", "search_results.title": "Search for {q}", "search_results.total": "{count, number} {count, plural, zero {canlyniad} one {canlyniad} two {ganlyniad} other {o ganlyniadau}}", + "server_banner.about_active_users": "People using this server during the last 30 days (Monthly Active Users)", + "server_banner.active_users": "active users", + "server_banner.administered_by": "Administered by:", + "server_banner.introduction": "{domain} is part of the decentralized social network powered by {mastodon}.", + "server_banner.learn_more": "Learn more", + "server_banner.server_stats": "Server stats:", "sign_in_banner.create_account": "Create account", "sign_in_banner.sign_in": "Sign in", "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "Does neb wedi hybio'r post yma eto. Pan y bydd rhywun yn gwneud, byddent yn ymddangos yma.", "status.redraft": "Dileu & ailddrafftio", "status.remove_bookmark": "Tynnu'r tudalnod", + "status.replied_to": "Replied to {name}", "status.reply": "Ateb", "status.replyAll": "Ateb i edefyn", "status.report": "Adrodd @{name}", @@ -523,9 +585,8 @@ "status.show_more": "Dangos mwy", "status.show_more_all": "Dangos mwy i bawb", "status.show_original": "Show original", - "status.show_thread": "Dangos edefyn", "status.translate": "Translate", - "status.translated_from": "Translated from {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Dim ar gael", "status.unmute_conversation": "Dad-dawelu sgwrs", "status.unpin": "Dadbinio o'r proffil", @@ -538,7 +599,6 @@ "tabs_bar.home": "Hafan", "tabs_bar.local_timeline": "Lleol", "tabs_bar.notifications": "Hysbysiadau", - "tabs_bar.search": "Chwilio", "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", diff --git a/app/javascript/mastodon/locales/da.json b/app/javascript/mastodon/locales/da.json index 2cdc99073..b62d99297 100644 --- a/app/javascript/mastodon/locales/da.json +++ b/app/javascript/mastodon/locales/da.json @@ -1,4 +1,17 @@ { + "about.blocks": "Modererede servere", + "about.contact": "Kontakt:", + "about.domain_blocks.comment": "Årsag", + "about.domain_blocks.domain": "Domæne", + "about.domain_blocks.preamble": "Mastodon tillader generelt, at man ser indhold og interagere med brugere fra enhver anden server i fediverset. Disse er undtagelserne, som er implementeret på netop denne server.", + "about.domain_blocks.severity": "Alvorlighed", + "about.domain_blocks.silenced.explanation": "Man vil generelt ikke se profiler og indhold fra denne server, medmindre man udtrykkeligt slå den op eller vælger den ved at følge.", + "about.domain_blocks.silenced.title": "Begrænset", + "about.domain_blocks.suspended.explanation": "Data fra denne server hverken behandles, gemmes eller udveksles, hvilket umuliggør interaktion eller kommunikation med brugere fra denne server.", + "about.domain_blocks.suspended.title": "Udelukket", + "about.not_available": "Denne information er ikke blevet gjort tilgængelig på denne server.", + "about.powered_by": "Decentraliserede sociale medier drevet af {mastodon}", + "about.rules": "Serverregler", "account.account_note_header": "Notat", "account.add_or_remove_from_list": "Tilføj eller fjern fra lister", "account.badges.bot": "Bot", @@ -7,13 +20,16 @@ "account.block_domain": "Blokér domænet {domain}", "account.blocked": "Blokeret", "account.browse_more_on_origin_server": "Tjek mere ud på den oprindelige profil", - "account.cancel_follow_request": "Annullér følgeanmodning", + "account.cancel_follow_request": "Annullér følg-anmodning", "account.direct": "Direkte besked til @{name}", "account.disable_notifications": "Advisér mig ikke længere, når @{name} poster", "account.domain_blocked": "Domæne blokeret", "account.edit_profile": "Redigér profil", "account.enable_notifications": "Advisér mig, når @{name} poster", "account.endorse": "Fremhæv på profil", + "account.featured_tags.last_status_at": "Seneste indlæg {date}", + "account.featured_tags.last_status_never": "Ingen indlæg", + "account.featured_tags.title": "{name}s fremhævede hashtags", "account.follow": "Følg", "account.followers": "Følgere", "account.followers.empty": "Ingen følger denne bruger endnu.", @@ -23,8 +39,8 @@ "account.follows.empty": "Denne bruger følger ikke nogen endnu.", "account.follows_you": "Følger dig", "account.hide_reblogs": "Skjul boosts fra @{name}", - "account.joined": "Tilmeldt {date}", - "account.languages": "Change subscribed languages", + "account.joined_short": "Joined", + "account.languages": "Skift abonnementssprog", "account.link_verified_on": "Ejerskab af dette link blev tjekket {date}", "account.locked_info": "Denne kontos fortrolighedsstatus er sat til låst. Ejeren bedømmer manuelt, hvem der kan følge vedkommende.", "account.media": "Medier", @@ -63,12 +79,24 @@ "audio.hide": "Skjul lyd", "autosuggest_hashtag.per_week": "{count} pr. uge", "boost_modal.combo": "Du kan trykke på {combo} for at overspringe dette næste gang", - "bundle_column_error.body": "Noget gik galt under indlæsningen af denne komponent.", + "bundle_column_error.copy_stacktrace": "Kopiér fejlrapport", + "bundle_column_error.error.body": "Den anmodede side kunne ikke gengives. Dette kan skyldes flere typer fejl.", + "bundle_column_error.error.title": "Åh nej!", + "bundle_column_error.network.body": "En fejl opstod under forsøget på at indlæse denne side. Dette kan skyldes flere typer af fejl.", + "bundle_column_error.network.title": "Netværksfejl", "bundle_column_error.retry": "Forsøg igen", - "bundle_column_error.title": "Netværksfejl", + "bundle_column_error.return": "Retur til hjem", + "bundle_column_error.routing.body": "Den anmodede side kunne ikke findes. Sikker på, at URL'en er korrekt?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Luk", "bundle_modal_error.message": "Noget gik galt under indlæsningen af denne komponent.", "bundle_modal_error.retry": "Forsøg igen", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "Om", "column.blocks": "Blokerede brugere", "column.bookmarks": "Bogmærker", "column.community": "Lokal tidslinje", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "Blokér og Anmeld", "confirmations.block.confirm": "Blokér", "confirmations.block.message": "Sikker på, at du vil blokere {name}?", + "confirmations.cancel_follow_request.confirm": "Annullér anmodning", + "confirmations.cancel_follow_request.message": "Sikker på, at anmodningen om at følge {name} skal annulleres?", "confirmations.delete.confirm": "Slet", "confirmations.delete.message": "Sikker på, at du vil slette dette indlæg?", "confirmations.delete_list.confirm": "Slet", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Markér som læst", "conversation.open": "Vis konversation", "conversation.with": "Med {names}", + "copypaste.copied": "Kopieret", + "copypaste.copy": "Kopiér", "directory.federated": "Fra kendt fedivers", "directory.local": "Kun fra {domain}", "directory.new_arrivals": "Nye ankomster", "directory.recently_active": "Nyligt aktive", + "dismissable_banner.community_timeline": "Disse er de seneste offentlige indlæg fra personer med konti hostes af {domain}.", + "dismissable_banner.dismiss": "Afvis", + "dismissable_banner.explore_links": "Der tales lige nu om disse nyhedshistorier af folk på denne og andre servere i det decentraliserede netværk.", + "dismissable_banner.explore_statuses": "Disse indlæg vinder lige nu fodfæste på denne og andre servere i det decentraliserede netværk.", + "dismissable_banner.explore_tags": "Disse hashtages vinder lige nu fodfæste blandt folk på denne og andre servere i det decentraliserede netværk.", + "dismissable_banner.public_timeline": "Disse er de seneste offentlige indlæg fra folk på denne og andre servere i det decentraliserede netværk, som denne server kender.", "embed.instructions": "Indlejr dette indlæg på dit websted ved at kopiere nedenstående kode.", "embed.preview": "Sådan kommer det til at se ud:", "emoji_button.activity": "Aktivitet", @@ -221,14 +259,14 @@ "follow_request.reject": "Afvis", "follow_requests.unlocked_explanation": "Selvom din konto ikke er låst, antog {domain}-personalet, at du måske vil gennemgå dine anmodninger manuelt.", "generic.saved": "Gemt", - "getting_started.developers": "Udviklere", - "getting_started.directory": "Profilmappe", + "getting_started.directory": "Mappe", "getting_started.documentation": "Dokumentation", + "getting_started.free_software_notice": "Mastodon er gratis, open-source software. Kildekoden kan ses, bidrages til eller problemer kan indrapporteres på {repository}.", "getting_started.heading": "Startmenu", "getting_started.invite": "Invitér folk", - "getting_started.open_source_notice": "Mastodon er open-source software. Du kan bidrage eller anmelde fejl via GitHub {github}.", "getting_started.privacy_policy": "Fortrolighedspolitik", "getting_started.security": "Kontoindstillinger", + "getting_started.what_is_mastodon": "Om Mastodon", "hashtag.column_header.tag_mode.all": "og {additional}", "hashtag.column_header.tag_mode.any": "eller {additional}", "hashtag.column_header.tag_mode.none": "uden {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Vis svar", "home.hide_announcements": "Skjul bekendtgørelser", "home.show_announcements": "Vis bekendtgørelser", + "interaction_modal.description.favourite": "Med en konto på Mastodon kan dette indlæg gøres til favorit for at lade forfatteren vide, at det værdsættes, samt gemme det til senere.", + "interaction_modal.description.follow": "Med en konto på Mastodon kan du {name} følges for at modtage vedkommendes indlæg i hjemmefeed'et.", + "interaction_modal.description.reblog": "Med en konto på Mastodon kan dette indlæg boostes for at dele det med egne følgere.", + "interaction_modal.description.reply": "Med en konto på Mastodon kan dette indlæg besvares.", + "interaction_modal.on_another_server": "På en anden server", + "interaction_modal.on_this_server": "På denne server", + "interaction_modal.other_server_instructions": "Kopiér og indsæt blot denne URL i søgefeltet i den foretrukne app eller webgrænsefladen, hvor man er logget ind.", + "interaction_modal.preamble": "Da Mastodon er decentraliseret, kan man bruge sin eksisterende konto hostet af en anden Mastodon-server eller kompatibel platform, såfremt man ikke har en konto på denne.", + "interaction_modal.title.favourite": "Gør {name}s indlæg til favorit", + "interaction_modal.title.follow": "Følg {name}", + "interaction_modal.title.reblog": "Boost {name}s indlæg", + "interaction_modal.title.reply": "Besvar {name}s indlæg", "intervals.full.days": "{number, plural, one {# dag} other {# dage}}", "intervals.full.hours": "{number, plural, one {# time} other {# timer}}", "intervals.full.minutes": "{number, plural, one {# minut} other {# minutter}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Varighed", "mute_modal.hide_notifications": "Skjul notifikationer fra denne bruger?", "mute_modal.indefinite": "Tidsubegrænset", - "navigation_bar.apps": "Mobil-apps", + "navigation_bar.about": "Om", + "navigation_bar.apps": "Hent appen", "navigation_bar.blocks": "Blokerede brugere", "navigation_bar.bookmarks": "Bogmærker", "navigation_bar.community_timeline": "Lokal tidslinje", @@ -324,7 +375,7 @@ "navigation_bar.filters": "Tavsgjorte ord", "navigation_bar.follow_requests": "Følgeanmodninger", "navigation_bar.follows_and_followers": "Følges og følgere", - "navigation_bar.info": "Om denne server", + "navigation_bar.info": "Om", "navigation_bar.keyboard_shortcuts": "Genvejstaster", "navigation_bar.lists": "Lister", "navigation_bar.logout": "Log af", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Fastgjorte indlæg", "navigation_bar.preferences": "Præferencer", "navigation_bar.public_timeline": "Fælles tidslinje", + "navigation_bar.search": "Search", "navigation_bar.security": "Sikkerhed", + "not_signed_in_indicator.not_signed_in": "Man skal logge ind for at tilgå denne ressource.", "notification.admin.report": "{name} anmeldte {target}", "notification.admin.sign_up": "{name} tilmeldte sig", "notification.favourite": "{name} favoritmarkerede dit indlæg", @@ -401,6 +454,8 @@ "privacy.public.short": "Offentlig", "privacy.unlisted.long": "Synlig for alle, men med fravalgt visning i opdagelsesfunktioner", "privacy.unlisted.short": "Diskret", + "privacy_policy.last_updated": "Senest opdateret {date}", + "privacy_policy.title": "Fortrolighedspolitik", "refresh": "Genindlæs", "regeneration_indicator.label": "Indlæser…", "regeneration_indicator.sublabel": "Din hjemmetidslinje klargøres!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "Søgning på indlæg efter deres indhold ikke aktiveret på denne Mastodon-server.", "search_results.title": "Søg efter {q}", "search_results.total": "{count, number} {count, plural, one {resultat} other {resultater}}", + "server_banner.about_active_users": "Folk, som brugte denne server de seneste 30 dage (månedlige aktive brugere)", + "server_banner.active_users": "aktive brugere", + "server_banner.administered_by": "Håndteres af:", + "server_banner.introduction": "{domain} er en del af det decentraliserede, sociale netværk drevet af {mastodon}.", + "server_banner.learn_more": "Læs mere", + "server_banner.server_stats": "Serverstatstik:", "sign_in_banner.create_account": "Opret konto", "sign_in_banner.sign_in": "Log ind", "sign_in_banner.text": "Log ind for at følge profiler eller hashtags, dele og svar på indlæg eller interagere fra kontoen på en anden server.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "Ingen har endnu boostet dette indlæg. Når nogen gør, vil det fremgå hér.", "status.redraft": "Slet og omformulér", "status.remove_bookmark": "Fjern bogmærke", + "status.replied_to": "Replied to {name}", "status.reply": "Besvar", "status.replyAll": "Besvar alle", "status.report": "Anmeld @{name}", @@ -523,22 +585,20 @@ "status.show_more": "Vis mere", "status.show_more_all": "Vis mere for alle", "status.show_original": "Vis original", - "status.show_thread": "Vis tråd", "status.translate": "Oversæt", - "status.translated_from": "Oversat fra {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Utilgængelig", "status.unmute_conversation": "Genaktivér samtale", "status.unpin": "Frigør fra profil", "subscribed_languages.lead": "Kun indlæg på udvalgte sprog vil fremgå på Hjem og listetidslinjer efter ændringen. Vælg ingen for at modtage indlæg på alle sprog.", "subscribed_languages.save": "Gem ændringer", - "subscribed_languages.target": "Change subscribed languages for {target}", + "subscribed_languages.target": "Skift abonnementssprog for {target}", "suggestions.dismiss": "Afvis foreslag", "suggestions.header": "Du er måske interesseret i…", "tabs_bar.federated_timeline": "Fælles", "tabs_bar.home": "Hjem", "tabs_bar.local_timeline": "Lokal", "tabs_bar.notifications": "Notifikationer", - "tabs_bar.search": "Søg", "time_remaining.days": "{number, plural, one {# dag} other {# dage}} tilbage", "time_remaining.hours": "{number, plural, one {# time} other {# timer}} tilbage", "time_remaining.minutes": "{number, plural, one {# minut} other {# minutter}} tilbage", diff --git a/app/javascript/mastodon/locales/de.json b/app/javascript/mastodon/locales/de.json index 007c38fc3..c0f385b66 100644 --- a/app/javascript/mastodon/locales/de.json +++ b/app/javascript/mastodon/locales/de.json @@ -1,4 +1,17 @@ { + "about.blocks": "Moderierte Server", + "about.contact": "Kontakt:", + "about.domain_blocks.comment": "Begründung", + "about.domain_blocks.domain": "Domain", + "about.domain_blocks.preamble": "Mastodon erlaubt es dir generell, mit Inhalten zu interagieren, diese anzuzeigen und mit anderen Nutzern im Fediversum über Server hinweg zu interagieren. Dies sind die Ausnahmen, die auf diesem bestimmten Server gemacht wurden.", + "about.domain_blocks.severity": "Schweregrad", + "about.domain_blocks.silenced.explanation": "In der Regel werden Sie keine Profile und Inhalte von diesem Server sehen, es sei denn, Sie suchen explizit danach oder entscheiden sich für diesen Server, indem Sie ihm folgen.", + "about.domain_blocks.silenced.title": "Limitiert", + "about.domain_blocks.suspended.explanation": "Es werden keine Daten von diesem Server verarbeitet, gespeichert oder ausgetauscht, so dass eine Interaktion oder Kommunikation mit Nutzern dieses Servers nicht möglich ist.", + "about.domain_blocks.suspended.title": "Gesperrt", + "about.not_available": "Diese Informationen sind auf diesem Server nicht verfügbar.", + "about.powered_by": "Dezentrale soziale Medien betrieben von {mastodon}", + "about.rules": "Serverregeln", "account.account_note_header": "Notiz", "account.add_or_remove_from_list": "Hinzufügen oder Entfernen von Listen", "account.badges.bot": "Bot", @@ -7,13 +20,16 @@ "account.block_domain": "Alles von {domain} verstecken", "account.blocked": "Blockiert", "account.browse_more_on_origin_server": "Mehr auf dem Originalprofil durchsuchen", - "account.cancel_follow_request": "Folgeanfrage abbrechen", + "account.cancel_follow_request": "Withdraw follow request", "account.direct": "Direktnachricht an @{name}", "account.disable_notifications": "Höre auf mich zu benachrichtigen wenn @{name} etwas postet", "account.domain_blocked": "Domain versteckt", "account.edit_profile": "Profil bearbeiten", "account.enable_notifications": "Benachrichtige mich wenn @{name} etwas postet", "account.endorse": "Auf Profil hervorheben", + "account.featured_tags.last_status_at": "Letzter Beitrag am {date}", + "account.featured_tags.last_status_never": "Keine Beiträge", + "account.featured_tags.title": "{name}'s vorgestellte Hashtags", "account.follow": "Folgen", "account.followers": "Follower", "account.followers.empty": "Diesem Profil folgt noch niemand.", @@ -23,7 +39,7 @@ "account.follows.empty": "Diesem Profil folgt niemand", "account.follows_you": "Folgt dir", "account.hide_reblogs": "Geteilte Beiträge von @{name} verbergen", - "account.joined": "Beigetreten am {date}", + "account.joined_short": "Joined", "account.languages": "Abonnierte Sprachen ändern", "account.link_verified_on": "Diesem Profil folgt niemand", "account.locked_info": "Der Privatsphärenstatus dieses Accounts wurde auf „gesperrt“ gesetzt. Die Person bestimmt manuell, wer ihm/ihr folgen darf.", @@ -63,12 +79,24 @@ "audio.hide": "Audio stummschalten", "autosuggest_hashtag.per_week": "{count} pro Woche", "boost_modal.combo": "Drücke {combo}, um dieses Fenster zu überspringen", - "bundle_column_error.body": "Etwas ist beim Laden schiefgelaufen.", + "bundle_column_error.copy_stacktrace": "Fehlerbericht kopieren", + "bundle_column_error.error.body": "The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.", + "bundle_column_error.error.title": "Oh nein!", + "bundle_column_error.network.body": "There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.", + "bundle_column_error.network.title": "Netzwerkfehler", "bundle_column_error.retry": "Erneut versuchen", - "bundle_column_error.title": "Netzwerkfehler", + "bundle_column_error.return": "Zurück zur Startseite", + "bundle_column_error.routing.body": "The requested page could not be found. Are you sure the URL in the address bar is correct?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Schließen", "bundle_modal_error.message": "Etwas ist beim Laden schiefgelaufen.", "bundle_modal_error.retry": "Erneut versuchen", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "Über", "column.blocks": "Blockierte Profile", "column.bookmarks": "Lesezeichen", "column.community": "Lokale Zeitleiste", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "Blockieren und melden", "confirmations.block.confirm": "Blockieren", "confirmations.block.message": "Bist du dir sicher, dass du {name} blockieren möchtest?", + "confirmations.cancel_follow_request.confirm": "Anfrage zurückziehen", + "confirmations.cancel_follow_request.message": "Are you sure you want to withdraw your request to follow {name}?", "confirmations.delete.confirm": "Löschen", "confirmations.delete.message": "Bist du dir sicher, dass du diesen Beitrag löschen möchtest?", "confirmations.delete_list.confirm": "Löschen", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Als gelesen markieren", "conversation.open": "Unterhaltung anzeigen", "conversation.with": "Mit {names}", + "copypaste.copied": "Kopiert", + "copypaste.copy": "Kopieren", "directory.federated": "Aus dem Fediverse", "directory.local": "Nur von {domain}", "directory.new_arrivals": "Neue Benutzer", "directory.recently_active": "Kürzlich aktiv", + "dismissable_banner.community_timeline": "Dies sind die neuesten öffentlichen Beiträge von Personen, deren Konten von {domain} gehostet werden.", + "dismissable_banner.dismiss": "Ablehnen", + "dismissable_banner.explore_links": "Diese Nachrichten werden gerade von Leuten auf diesem und anderen Servern des dezentralen Netzwerks besprochen.", + "dismissable_banner.explore_statuses": "Diese Beiträge von diesem und anderen Servern im dezentralen Netzwerk gewinnen gerade an Reichweite auf diesem Server.", + "dismissable_banner.explore_tags": "Diese Hashtags gewinnen gerade unter den Leuten auf diesem und anderen Servern des dezentralen Netzwerkes an Reichweite.", + "dismissable_banner.public_timeline": "Dies sind die neuesten öffentlichen Beiträge von Personen auf diesem und anderen Servern des dezentralen Netzwerks, die dieser Server kennt.", "embed.instructions": "Du kannst diesen Beitrag auf deiner Webseite einbetten, indem du den folgenden Code einfügst.", "embed.preview": "So wird es aussehen:", "emoji_button.activity": "Aktivitäten", @@ -221,14 +259,14 @@ "follow_request.reject": "Ablehnen", "follow_requests.unlocked_explanation": "Auch wenn dein Konto nicht gesperrt ist, haben die Moderator_innen von {domain} gedacht, dass du diesen Follower lieber manuell bestätigen solltest.", "generic.saved": "Gespeichert", - "getting_started.developers": "Entwickler", - "getting_started.directory": "Profilverzeichnis", + "getting_started.directory": "Verzeichnis", "getting_started.documentation": "Dokumentation", + "getting_started.free_software_notice": "Mastodon ist kostenlos, Open-Source-Software. Sie können den Quellcode einsehen, beisteuern oder Fehler melden unter {repository}.", "getting_started.heading": "Erste Schritte", "getting_started.invite": "Leute einladen", - "getting_started.open_source_notice": "Mastodon ist quelloffene Software. Du kannst auf GitHub unter {github} dazu beitragen oder Probleme melden.", "getting_started.privacy_policy": "Datenschutzerklärung", "getting_started.security": "Konto & Sicherheit", + "getting_started.what_is_mastodon": "Über Mastodon", "hashtag.column_header.tag_mode.all": "und {additional}", "hashtag.column_header.tag_mode.any": "oder {additional}", "hashtag.column_header.tag_mode.none": "ohne {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Antworten anzeigen", "home.hide_announcements": "Verstecke Ankündigungen", "home.show_announcements": "Zeige Ankündigungen", + "interaction_modal.description.favourite": "Mit einem Account auf Mastodon können Sie diesen Beitrag favorisieren, um dem Autor mitzuteilen, dass Sie den Beitrag schätzen und ihn für einen späteren Zeitpunkt speichern.", + "interaction_modal.description.follow": "Mit einem Konto auf Mastodon kannst du {name} folgen, um seine Beiträge in deinem Home Feed zu erhalten.", + "interaction_modal.description.reblog": "Mit einem Account auf Mastodon, kannst du diesen Beitrag boosten um ihn mit deinen eigenen Followern teilen.", + "interaction_modal.description.reply": "Mit einem Account auf Mastodon können Sie auf diesen Beitrag antworten.", + "interaction_modal.on_another_server": "Auf einem anderen Server", + "interaction_modal.on_this_server": "Auf diesem Server", + "interaction_modal.other_server_instructions": "Kopiere einfach diese URL und füge sie in die Suchleiste deiner Lieblings-App oder in die Weboberfläche, in der du angemeldet bist, ein.", + "interaction_modal.preamble": "Da Mastodon dezentralisiert ist, kannst du dein bestehendes Konto auf einem anderen Mastodon-Server oder einer kompatiblen Plattform nutzen, wenn du kein Konto auf dieser Plattform hast.", + "interaction_modal.title.favourite": "Lieblingsbeitrag von {name}", + "interaction_modal.title.follow": "Folge {name}", + "interaction_modal.title.reblog": "Erhöhe {name}'s Beitrag", + "interaction_modal.title.reply": "Antworte auf den Post von {name}", "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}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Dauer", "mute_modal.hide_notifications": "Benachrichtigungen von diesem Account verbergen?", "mute_modal.indefinite": "Unbestimmt", - "navigation_bar.apps": "Mobile Apps", + "navigation_bar.about": "Über", + "navigation_bar.apps": "App downloaden", "navigation_bar.blocks": "Blockierte Profile", "navigation_bar.bookmarks": "Lesezeichen", "navigation_bar.community_timeline": "Lokale Zeitleiste", @@ -324,7 +375,7 @@ "navigation_bar.filters": "Stummgeschaltene Wörter", "navigation_bar.follow_requests": "Folgeanfragen", "navigation_bar.follows_and_followers": "Folgende und Gefolgte", - "navigation_bar.info": "Über diesen Server", + "navigation_bar.info": "Über", "navigation_bar.keyboard_shortcuts": "Tastenkombinationen", "navigation_bar.lists": "Listen", "navigation_bar.logout": "Abmelden", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Angeheftete Beiträge", "navigation_bar.preferences": "Einstellungen", "navigation_bar.public_timeline": "Föderierte Zeitleiste", + "navigation_bar.search": "Search", "navigation_bar.security": "Sicherheit", + "not_signed_in_indicator.not_signed_in": "Sie müssen sich anmelden, um diese Funktion zu nutzen.", "notification.admin.report": "{target} wurde von {name} gemeldet", "notification.admin.sign_up": "{name} hat sich registriert", "notification.favourite": "{name} hat deinen Beitrag favorisiert", @@ -401,6 +454,8 @@ "privacy.public.short": "Öffentlich", "privacy.unlisted.long": "Sichtbar für alle, aber nicht über Entdeckungsfunktionen", "privacy.unlisted.short": "Nicht gelistet", + "privacy_policy.last_updated": "Letztes Update am {date}", + "privacy_policy.title": "Datenschutzbestimmungen", "refresh": "Aktualisieren", "regeneration_indicator.label": "Laden…", "regeneration_indicator.sublabel": "Deine Startseite wird gerade vorbereitet!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "Die Suche für Beiträge nach ihrem Inhalt ist auf diesem Mastodon-Server deaktiviert.", "search_results.title": "Suchen nach {q}", "search_results.total": "{count, number} {count, plural, one {Ergebnis} other {Ergebnisse}}", + "server_banner.about_active_users": "Personen, die diesen Server in den letzten 30 Tagen genutzt haben (monatlich aktive Benutzer)", + "server_banner.active_users": "aktive Benutzer", + "server_banner.administered_by": "Verwaltet von:", + "server_banner.introduction": "{domain} ist Teil des dezentralen sozialen Netzwerks, das von {mastodon} betrieben wird.", + "server_banner.learn_more": "Mehr erfahren", + "server_banner.server_stats": "Serverstatistiken:", "sign_in_banner.create_account": "Account erstellen", "sign_in_banner.sign_in": "Einloggen", "sign_in_banner.text": "Melden Sie sich an, um Profilen oder Hashtags zu folgen, Favoriten, Teilen und Antworten auf Beiträge oder interagieren Sie von Ihrem Konto auf einem anderen Server.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "Diesen Beitrag hat noch niemand geteilt. Sobald es jemand tut, wird diese Person hier angezeigt.", "status.redraft": "Löschen und neu erstellen", "status.remove_bookmark": "Lesezeichen entfernen", + "status.replied_to": "Replied to {name}", "status.reply": "Antworten", "status.replyAll": "Allen antworten", "status.report": "@{name} melden", @@ -523,9 +585,8 @@ "status.show_more": "Mehr anzeigen", "status.show_more_all": "Alle Inhaltswarnungen aufklappen", "status.show_original": "Original anzeigen", - "status.show_thread": "Zeige Konversation", "status.translate": "Übersetzen", - "status.translated_from": "Aus {lang} übersetzt", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Nicht verfügbar", "status.unmute_conversation": "Stummschaltung von Konversation aufheben", "status.unpin": "Vom Profil lösen", @@ -538,7 +599,6 @@ "tabs_bar.home": "Startseite", "tabs_bar.local_timeline": "Lokal", "tabs_bar.notifications": "Mitteilungen", - "tabs_bar.search": "Suche", "time_remaining.days": "{number, plural, one {# Tag} other {# Tage}} verbleibend", "time_remaining.hours": "{number, plural, one {# Stunde} other {# Stunden}} verbleibend", "time_remaining.minutes": "{number, plural, one {# Minute} other {# Minuten}} verbleibend", diff --git a/app/javascript/mastodon/locales/defaultMessages.json b/app/javascript/mastodon/locales/defaultMessages.json index 6f0f309d8..9cca24d19 100644 --- a/app/javascript/mastodon/locales/defaultMessages.json +++ b/app/javascript/mastodon/locales/defaultMessages.json @@ -231,6 +231,15 @@ { "descriptors": [ { + "defaultMessage": "Dismiss", + "id": "dismissable_banner.dismiss" + } + ], + "path": "app/javascript/mastodon/components/dismissable_banner.json" + }, + { + "descriptors": [ + { "defaultMessage": "Unblock domain {domain}", "id": "account.unblock_domain" } @@ -360,6 +369,15 @@ { "descriptors": [ { + "defaultMessage": "You need to sign in to access this resource.", + "id": "not_signed_in_indicator.not_signed_in" + } + ], + "path": "app/javascript/mastodon/components/not_signed_in_indicator.json" + }, + { + "descriptors": [ + { "defaultMessage": "Put it back", "id": "picture_in_picture.restore" } @@ -484,6 +502,35 @@ { "descriptors": [ { + "defaultMessage": "People using this server during the last 30 days (Monthly Active Users)", + "id": "server_banner.about_active_users" + }, + { + "defaultMessage": "{domain} is part of the decentralized social network powered by {mastodon}.", + "id": "server_banner.introduction" + }, + { + "defaultMessage": "Administered by:", + "id": "server_banner.administered_by" + }, + { + "defaultMessage": "Server stats:", + "id": "server_banner.server_stats" + }, + { + "defaultMessage": "active users", + "id": "server_banner.active_users" + }, + { + "defaultMessage": "Learn more", + "id": "server_banner.learn_more" + } + ], + "path": "app/javascript/mastodon/components/server_banner.json" + }, + { + "descriptors": [ + { "defaultMessage": "{count}K", "id": "units.short.thousand" }, @@ -642,16 +689,8 @@ { "descriptors": [ { - "defaultMessage": "Show thread", - "id": "status.show_thread" - }, - { - "defaultMessage": "Read more", - "id": "status.read_more" - }, - { - "defaultMessage": "Translated from {lang}", - "id": "status.translated_from" + "defaultMessage": "Translated from {lang} using {provider}", + "id": "status.translated_from_with" }, { "defaultMessage": "Show original", @@ -662,6 +701,10 @@ "id": "status.translate" }, { + "defaultMessage": "Read more", + "id": "status.read_more" + }, + { "defaultMessage": "Show more", "id": "status.show_more" }, @@ -709,6 +752,10 @@ { "defaultMessage": "{name} boosted", "id": "status.reblogged_by" + }, + { + "defaultMessage": "Replied to {name}", + "id": "status.replied_to" } ], "path": "app/javascript/mastodon/components/status.json" @@ -792,6 +839,71 @@ { "descriptors": [ { + "defaultMessage": "About", + "id": "column.about" + }, + { + "defaultMessage": "Server rules", + "id": "about.rules" + }, + { + "defaultMessage": "Moderated servers", + "id": "about.blocks" + }, + { + "defaultMessage": "Limited", + "id": "about.domain_blocks.silenced.title" + }, + { + "defaultMessage": "You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.", + "id": "about.domain_blocks.silenced.explanation" + }, + { + "defaultMessage": "Suspended", + "id": "about.domain_blocks.suspended.title" + }, + { + "defaultMessage": "No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.", + "id": "about.domain_blocks.suspended.explanation" + }, + { + "defaultMessage": "Decentralized social media powered by {mastodon}", + "id": "about.powered_by" + }, + { + "defaultMessage": "Administered by:", + "id": "server_banner.administered_by" + }, + { + "defaultMessage": "Contact:", + "id": "about.contact" + }, + { + "defaultMessage": "This information has not been made available on this server.", + "id": "about.not_available" + }, + { + "defaultMessage": "Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.", + "id": "about.domain_blocks.preamble" + }, + { + "defaultMessage": "Domain", + "id": "about.domain_blocks.domain" + }, + { + "defaultMessage": "Severity", + "id": "about.domain_blocks.severity" + }, + { + "defaultMessage": "Reason", + "id": "about.domain_blocks.comment" + } + ], + "path": "app/javascript/mastodon/features/about/index.json" + }, + { + "descriptors": [ + { "defaultMessage": "Account suspended", "id": "empty_column.account_suspended" }, @@ -844,6 +956,10 @@ { "descriptors": [ { + "defaultMessage": "Withdraw request", + "id": "confirmations.cancel_follow_request.confirm" + }, + { "defaultMessage": "Unfollow", "id": "confirmations.unfollow.confirm" }, @@ -856,6 +972,10 @@ "id": "confirmations.unfollow.message" }, { + "defaultMessage": "Are you sure you want to withdraw your request to follow {name}?", + "id": "confirmations.cancel_follow_request.message" + }, + { "defaultMessage": "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.", "id": "confirmations.domain_block.message" } @@ -903,6 +1023,23 @@ { "descriptors": [ { + "defaultMessage": "Last post on {date}", + "id": "account.featured_tags.last_status_at" + }, + { + "defaultMessage": "No posts", + "id": "account.featured_tags.last_status_never" + }, + { + "defaultMessage": "{name}'s featured hashtags", + "id": "account.featured_tags.title" + } + ], + "path": "app/javascript/mastodon/features/account/components/featured_tags.json" + }, + { + "descriptors": [ + { "defaultMessage": "Unfollow", "id": "account.unfollow" }, @@ -911,7 +1048,7 @@ "id": "account.follow" }, { - "defaultMessage": "Cancel follow request", + "defaultMessage": "Withdraw follow request", "id": "account.cancel_follow_request" }, { @@ -1067,8 +1204,8 @@ "id": "account.badges.group" }, { - "defaultMessage": "Joined {date}", - "id": "account.joined" + "defaultMessage": "Joined", + "id": "account.joined_short" } ], "path": "app/javascript/mastodon/features/account/components/header.json" @@ -1139,6 +1276,39 @@ { "descriptors": [ { + "defaultMessage": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "id": "closed_registrations_modal.description" + }, + { + "defaultMessage": "Signing up on Mastodon", + "id": "closed_registrations_modal.title" + }, + { + "defaultMessage": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "id": "closed_registrations_modal.preamble" + }, + { + "defaultMessage": "On this server", + "id": "interaction_modal.on_this_server" + }, + { + "defaultMessage": "On a different server", + "id": "interaction_modal.on_another_server" + }, + { + "defaultMessage": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "id": "closed_registrations.other_server_instructions" + }, + { + "defaultMessage": "Find another server", + "id": "closed_registrations_modal.find_another_server" + } + ], + "path": "app/javascript/mastodon/features/closed_registrations_modal/index.json" + }, + { + "descriptors": [ + { "defaultMessage": "Media only", "id": "community.column_settings.media_only" } @@ -1152,6 +1322,10 @@ "id": "column.community" }, { + "defaultMessage": "These are the most recent public posts from people whose accounts are hosted by {domain}.", + "id": "dismissable_banner.community_timeline" + }, + { "defaultMessage": "The local timeline is empty. Write something publicly to get the ball rolling!", "id": "empty_column.community" } @@ -1723,7 +1897,7 @@ "id": "account.follow" }, { - "defaultMessage": "Cancel follow request", + "defaultMessage": "Withdraw follow request", "id": "account.cancel_follow_request" }, { @@ -1839,6 +2013,10 @@ { "descriptors": [ { + "defaultMessage": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", + "id": "dismissable_banner.explore_links" + }, + { "defaultMessage": "Nothing is trending right now. Check back later!", "id": "empty_column.explore_statuses" } @@ -1879,6 +2057,10 @@ { "defaultMessage": "Nothing is trending right now. Check back later!", "id": "empty_column.explore_statuses" + }, + { + "defaultMessage": "These posts from this and other servers in the decentralized network are gaining traction on this server right now.", + "id": "dismissable_banner.explore_statuses" } ], "path": "app/javascript/mastodon/features/explore/statuses.json" @@ -1895,6 +2077,10 @@ { "descriptors": [ { + "defaultMessage": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", + "id": "dismissable_banner.explore_tags" + }, + { "defaultMessage": "Nothing is trending right now. Check back later!", "id": "empty_column.explore_statuses" } @@ -2333,6 +2519,75 @@ { "descriptors": [ { + "defaultMessage": "Copied", + "id": "copypaste.copied" + }, + { + "defaultMessage": "Copy", + "id": "copypaste.copy" + }, + { + "defaultMessage": "Reply to {name}'s post", + "id": "interaction_modal.title.reply" + }, + { + "defaultMessage": "With an account on Mastodon, you can respond to this post.", + "id": "interaction_modal.description.reply" + }, + { + "defaultMessage": "Boost {name}'s post", + "id": "interaction_modal.title.reblog" + }, + { + "defaultMessage": "With an account on Mastodon, you can boost this post to share it with your own followers.", + "id": "interaction_modal.description.reblog" + }, + { + "defaultMessage": "Favourite {name}'s post", + "id": "interaction_modal.title.favourite" + }, + { + "defaultMessage": "With an account on Mastodon, you can favourite this post to let the author know you appreciate it and save it for later.", + "id": "interaction_modal.description.favourite" + }, + { + "defaultMessage": "Follow {name}", + "id": "interaction_modal.title.follow" + }, + { + "defaultMessage": "With an account on Mastodon, you can follow {name} to receive their posts in your home feed.", + "id": "interaction_modal.description.follow" + }, + { + "defaultMessage": "Create account", + "id": "sign_in_banner.create_account" + }, + { + "defaultMessage": "Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one.", + "id": "interaction_modal.preamble" + }, + { + "defaultMessage": "On this server", + "id": "interaction_modal.on_this_server" + }, + { + "defaultMessage": "Sign in", + "id": "sign_in_banner.sign_in" + }, + { + "defaultMessage": "On a different server", + "id": "interaction_modal.on_another_server" + }, + { + "defaultMessage": "Simply copy and paste this URL into the search bar of your favourite app or the web interface where you are signed in.", + "id": "interaction_modal.other_server_instructions" + } + ], + "path": "app/javascript/mastodon/features/interaction_modal/index.json" + }, + { + "descriptors": [ + { "defaultMessage": "Keyboard Shortcuts", "id": "keyboard_shortcuts.heading" }, @@ -2943,6 +3198,19 @@ { "descriptors": [ { + "defaultMessage": "Privacy Policy", + "id": "privacy_policy.title" + }, + { + "defaultMessage": "Last updated {date}", + "id": "privacy_policy.last_updated" + } + ], + "path": "app/javascript/mastodon/features/privacy_policy/index.json" + }, + { + "descriptors": [ + { "defaultMessage": "Media only", "id": "community.column_settings.media_only" }, @@ -2960,6 +3228,10 @@ "id": "column.public" }, { + "defaultMessage": "These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.", + "id": "dismissable_banner.public_timeline" + }, + { "defaultMessage": "There is nothing here! Write something publicly, or manually follow users from other servers to fill it up", "id": "empty_column.public" } @@ -3355,35 +3627,6 @@ "id": "confirmations.redraft.message" }, { - "defaultMessage": "Reply", - "id": "confirmations.reply.confirm" - }, - { - "defaultMessage": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?", - "id": "confirmations.reply.message" - } - ], - "path": "app/javascript/mastodon/features/status/containers/detailed_status_container.json" - }, - { - "descriptors": [ - { - "defaultMessage": "Delete", - "id": "confirmations.delete.confirm" - }, - { - "defaultMessage": "Are you sure you want to delete this status?", - "id": "confirmations.delete.message" - }, - { - "defaultMessage": "Delete & redraft", - "id": "confirmations.redraft.confirm" - }, - { - "defaultMessage": "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.", - "id": "confirmations.redraft.message" - }, - { "defaultMessage": "Show more for all", "id": "status.show_more_all" }, @@ -3492,29 +3735,44 @@ { "descriptors": [ { - "defaultMessage": "Favourite", - "id": "status.favourite" + "defaultMessage": "Copied", + "id": "copypaste.copied" }, { - "defaultMessage": "You can press {combo} to skip this next time", - "id": "favourite_modal.combo" - } - ], - "path": "app/javascript/mastodon/features/ui/components/favourite_modal.json" - }, - { - "descriptors": [ + "defaultMessage": "404", + "id": "bundle_column_error.routing.title" + }, + { + "defaultMessage": "The requested page could not be found. Are you sure the URL in the address bar is correct?", + "id": "bundle_column_error.routing.body" + }, { "defaultMessage": "Network error", - "id": "bundle_column_error.title" + "id": "bundle_column_error.network.title" }, { - "defaultMessage": "Something went wrong while loading this component.", - "id": "bundle_column_error.body" + "defaultMessage": "There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.", + "id": "bundle_column_error.network.body" + }, + { + "defaultMessage": "Oh, no!", + "id": "bundle_column_error.error.title" + }, + { + "defaultMessage": "The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.", + "id": "bundle_column_error.error.body" }, { "defaultMessage": "Try again", "id": "bundle_column_error.retry" + }, + { + "defaultMessage": "Copy error report", + "id": "bundle_column_error.copy_stacktrace" + }, + { + "defaultMessage": "Go back home", + "id": "bundle_column_error.return" } ], "path": "app/javascript/mastodon/features/ui/components/bundle_column_error.json" @@ -3539,15 +3797,6 @@ { "descriptors": [ { - "defaultMessage": "Publish", - "id": "compose_form.publish" - } - ], - "path": "app/javascript/mastodon/features/ui/components/columns_area.json" - }, - { - "descriptors": [ - { "defaultMessage": "{name} created {date}", "id": "status.history.created" }, @@ -3681,7 +3930,24 @@ "id": "navigation_bar.follow_requests" } ], - "path": "app/javascript/mastodon/features/ui/components/follow_requests_nav_link.json" + "path": "app/javascript/mastodon/features/ui/components/follow_requests_column_link.json" + }, + { + "descriptors": [ + { + "defaultMessage": "Publish", + "id": "compose_form.publish" + }, + { + "defaultMessage": "Sign in", + "id": "sign_in_banner.sign_in" + }, + { + "defaultMessage": "Create account", + "id": "sign_in_banner.create_account" + } + ], + "path": "app/javascript/mastodon/features/ui/components/header.json" }, { "descriptors": [ @@ -3694,48 +3960,48 @@ "id": "confirmations.logout.confirm" }, { - "defaultMessage": "Invite people", - "id": "getting_started.invite" + "defaultMessage": "Get the app", + "id": "navigation_bar.apps" }, { - "defaultMessage": "Hotkeys", - "id": "navigation_bar.keyboard_shortcuts" + "defaultMessage": "About", + "id": "navigation_bar.info" }, { - "defaultMessage": "Security", - "id": "getting_started.security" + "defaultMessage": "About Mastodon", + "id": "getting_started.what_is_mastodon" }, { - "defaultMessage": "About this server", - "id": "navigation_bar.info" + "defaultMessage": "Documentation", + "id": "getting_started.documentation" }, { - "defaultMessage": "Profile directory", - "id": "getting_started.directory" + "defaultMessage": "Privacy Policy", + "id": "getting_started.privacy_policy" }, { - "defaultMessage": "Mobile apps", - "id": "navigation_bar.apps" + "defaultMessage": "Hotkeys", + "id": "navigation_bar.keyboard_shortcuts" }, { - "defaultMessage": "Privacy Policy", - "id": "getting_started.privacy_policy" + "defaultMessage": "Directory", + "id": "getting_started.directory" }, { - "defaultMessage": "Developers", - "id": "getting_started.developers" + "defaultMessage": "Invite people", + "id": "getting_started.invite" }, { - "defaultMessage": "Documentation", - "id": "getting_started.documentation" + "defaultMessage": "Security", + "id": "getting_started.security" }, { "defaultMessage": "Logout", "id": "navigation_bar.logout" }, { - "defaultMessage": "Mastodon is open source software. You can contribute or report issues on GitHub at {github}.", - "id": "getting_started.open_source_notice" + "defaultMessage": "Mastodon is free, open source software. You can view the source code, contribute or report issues at {repository}.", + "id": "getting_started.free_software_notice" } ], "path": "app/javascript/mastodon/features/ui/components/link_footer.json" @@ -3847,6 +4113,14 @@ { "defaultMessage": "Follows and followers", "id": "navigation_bar.follows_and_followers" + }, + { + "defaultMessage": "About", + "id": "navigation_bar.about" + }, + { + "defaultMessage": "Search", + "id": "navigation_bar.search" } ], "path": "app/javascript/mastodon/features/ui/components/navigation_panel.json" @@ -3867,16 +4141,16 @@ { "descriptors": [ { + "defaultMessage": "Create account", + "id": "sign_in_banner.create_account" + }, + { "defaultMessage": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", "id": "sign_in_banner.text" }, { "defaultMessage": "Sign in", "id": "sign_in_banner.sign_in" - }, - { - "defaultMessage": "Create account", - "id": "sign_in_banner.create_account" } ], "path": "app/javascript/mastodon/features/ui/components/sign_in_banner.json" @@ -3884,31 +4158,6 @@ { "descriptors": [ { - "defaultMessage": "Home", - "id": "tabs_bar.home" - }, - { - "defaultMessage": "Notifications", - "id": "tabs_bar.notifications" - }, - { - "defaultMessage": "Local", - "id": "tabs_bar.local_timeline" - }, - { - "defaultMessage": "Federated", - "id": "tabs_bar.federated_timeline" - }, - { - "defaultMessage": "Search", - "id": "tabs_bar.search" - } - ], - "path": "app/javascript/mastodon/features/ui/components/tabs_bar.json" - }, - { - "descriptors": [ - { "defaultMessage": "Drag & drop to upload", "id": "upload_area.title" } diff --git a/app/javascript/mastodon/locales/el.json b/app/javascript/mastodon/locales/el.json index 125517d3f..6bf6cabaa 100644 --- a/app/javascript/mastodon/locales/el.json +++ b/app/javascript/mastodon/locales/el.json @@ -1,4 +1,17 @@ { + "about.blocks": "Moderated servers", + "about.contact": "Επικοινωνία:", + "about.domain_blocks.comment": "Reason", + "about.domain_blocks.domain": "Τομέας (Domain)", + "about.domain_blocks.preamble": "Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.", + "about.domain_blocks.severity": "Σοβαρότητα", + "about.domain_blocks.silenced.explanation": "You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.", + "about.domain_blocks.silenced.title": "Limited", + "about.domain_blocks.suspended.explanation": "No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.", + "about.domain_blocks.suspended.title": "Suspended", + "about.not_available": "This information has not been made available on this server.", + "about.powered_by": "Decentralized social media powered by {mastodon}", + "about.rules": "Server rules", "account.account_note_header": "Σημείωση", "account.add_or_remove_from_list": "Προσθήκη ή Αφαίρεση από λίστες", "account.badges.bot": "Μποτ", @@ -7,13 +20,16 @@ "account.block_domain": "Αποκλεισμός {domain}", "account.blocked": "Αποκλεισμένος/η", "account.browse_more_on_origin_server": "Δες περισσότερα στο αρχικό προφίλ", - "account.cancel_follow_request": "Ακύρωση αιτήματος ακολούθησης", + "account.cancel_follow_request": "Απόσυρση αιτήματος παρακολούθησης", "account.direct": "Άμεσο μήνυμα προς @{name}", "account.disable_notifications": "Διακοπή ειδοποιήσεων για τις δημοσιεύσεις του/της @{name}", "account.domain_blocked": "Ο τομέας αποκλείστηκε", "account.edit_profile": "Επεξεργασία προφίλ", "account.enable_notifications": "Έναρξη ειδοποιήσεων για τις δημοσιεύσεις του/της @{name}", "account.endorse": "Προβολή στο προφίλ", + "account.featured_tags.last_status_at": "Τελευταία δημοσίευση στις {date}", + "account.featured_tags.last_status_never": "Καμία Ανάρτηση", + "account.featured_tags.title": "προβεβλημένα hashtags του/της {name}", "account.follow": "Ακολούθησε", "account.followers": "Ακόλουθοι", "account.followers.empty": "Κανείς δεν ακολουθεί αυτό τον χρήστη ακόμα.", @@ -23,7 +39,7 @@ "account.follows.empty": "Αυτός ο χρήστης δεν ακολουθεί κανέναν ακόμα.", "account.follows_you": "Σε ακολουθεί", "account.hide_reblogs": "Απόκρυψη προωθήσεων από @{name}", - "account.joined": "Μέλος από τις {date}", + "account.joined_short": "Joined", "account.languages": "Change subscribed languages", "account.link_verified_on": "Η ιδιοκτησία αυτού του συνδέσμου ελέχθηκε την {date}", "account.locked_info": "Η κατάσταση απορρήτου αυτού του λογαριασμού είναι κλειδωμένη. Ο ιδιοκτήτης επιβεβαιώνει χειροκίνητα ποιος μπορεί να τον ακολουθήσει.", @@ -63,12 +79,24 @@ "audio.hide": "Απόκρυψη αρχείου ήχου", "autosuggest_hashtag.per_week": "{count} ανα εβδομάδα", "boost_modal.combo": "Μπορείς να πατήσεις {combo} για να το προσπεράσεις αυτό την επόμενη φορά", - "bundle_column_error.body": "Κάτι πήγε στραβά ενώ φορτωνόταν αυτό το στοιχείο.", + "bundle_column_error.copy_stacktrace": "Αντιγραφή αναφοράς σφάλματος", + "bundle_column_error.error.body": "Δεν ήταν δυνατή η απόδοση της σελίδας που ζητήσατε. Μπορεί να οφείλεται σε σφάλμα στον κώδικά μας ή σε πρόβλημα συμβατότητας του προγράμματος περιήγησης.", + "bundle_column_error.error.title": "Ωχ όχι!", + "bundle_column_error.network.body": "Παρουσιάστηκε σφάλμα κατά την προσπάθεια φόρτωσης αυτής της σελίδας. Αυτό θα μπορούσε να οφείλεται σε ένα προσωρινό πρόβλημα με τη σύνδεσή σας στο διαδίκτυο ή σε αυτόν τον διακομιστή.", + "bundle_column_error.network.title": "Σφάλμα δικτύου", "bundle_column_error.retry": "Δοκίμασε ξανά", - "bundle_column_error.title": "Σφάλμα δικτύου", + "bundle_column_error.return": "Μετάβαση πίσω στην αρχική σελίδα", + "bundle_column_error.routing.body": "The requested page could not be found. Are you sure the URL in the address bar is correct?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Κλείσιμο", "bundle_modal_error.message": "Κάτι πήγε στραβά κατά τη φόρτωση του στοιχείου.", "bundle_modal_error.retry": "Δοκίμασε ξανά", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "Σχετικά με", "column.blocks": "Αποκλεισμένοι χρήστες", "column.bookmarks": "Σελιδοδείκτες", "column.community": "Τοπική ροή", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "Αποκλεισμός & Καταγγελία", "confirmations.block.confirm": "Απόκλεισε", "confirmations.block.message": "Σίγουρα θες να αποκλείσεις {name};", + "confirmations.cancel_follow_request.confirm": "Απόσυρση αιτήματος", + "confirmations.cancel_follow_request.message": "Are you sure you want to withdraw your request to follow {name}?", "confirmations.delete.confirm": "Διέγραψε", "confirmations.delete.message": "Σίγουρα θες να διαγράψεις αυτή τη δημοσίευση;", "confirmations.delete_list.confirm": "Διέγραψε", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Σήμανση ως αναγνωσμένο", "conversation.open": "Προβολή συνομιλίας", "conversation.with": "Με {names}", + "copypaste.copied": "Αντιγράφηκε", + "copypaste.copy": "Αντιγραφή", "directory.federated": "Από το γνωστό fediverse", "directory.local": "Μόνο από {domain}", "directory.new_arrivals": "Νέες αφίξεις", "directory.recently_active": "Πρόσφατα ενεργοί", + "dismissable_banner.community_timeline": "These are the most recent public posts from people whose accounts are hosted by {domain}.", + "dismissable_banner.dismiss": "Παράβλεψη", + "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", + "dismissable_banner.explore_statuses": "These posts from this and other servers in the decentralized network are gaining traction on this server right now.", + "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", + "dismissable_banner.public_timeline": "These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.", "embed.instructions": "Ενσωματώστε αυτή την κατάσταση στην ιστοσελίδα σας αντιγράφοντας τον παρακάτω κώδικα.", "embed.preview": "Ορίστε πως θα φαίνεται:", "emoji_button.activity": "Δραστηριότητα", @@ -221,14 +259,14 @@ "follow_request.reject": "Απέρριψε", "follow_requests.unlocked_explanation": "Παρόλο που ο λογαριασμός σου δεν είναι κλειδωμένος, οι διαχειριστές του {domain} θεώρησαν πως ίσως να θέλεις να ελέγξεις χειροκίνητα αυτά τα αιτήματα ακολούθησης.", "generic.saved": "Αποθηκεύτηκε", - "getting_started.developers": "Ανάπτυξη", - "getting_started.directory": "Κατάλογος λογαριασμών", + "getting_started.directory": "Κατάλογος", "getting_started.documentation": "Τεκμηρίωση", + "getting_started.free_software_notice": "Mastodon is free, open source software. You can view the source code, contribute or report issues at {repository}.", "getting_started.heading": "Αφετηρία", "getting_started.invite": "Προσκάλεσε κόσμο", - "getting_started.open_source_notice": "Το Mastodon είναι ελεύθερο λογισμικό. Μπορείς να συνεισφέρεις ή να αναφέρεις ζητήματα στο GitHub στο {github}.", "getting_started.privacy_policy": "Privacy Policy", "getting_started.security": "Ασφάλεια", + "getting_started.what_is_mastodon": "Σχετικά με το Mastodon", "hashtag.column_header.tag_mode.all": "και {additional}", "hashtag.column_header.tag_mode.any": "ή {additional}", "hashtag.column_header.tag_mode.none": "χωρίς {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Εμφάνιση απαντήσεων", "home.hide_announcements": "Απόκρυψη ανακοινώσεων", "home.show_announcements": "Εμφάνιση ανακοινώσεων", + "interaction_modal.description.favourite": "With an account on Mastodon, you can favourite this post to let the author know you appreciate it and save it for later.", + "interaction_modal.description.follow": "With an account on Mastodon, you can follow {name} to receive their posts in your home feed.", + "interaction_modal.description.reblog": "With an account on Mastodon, you can boost this post to share it with your own followers.", + "interaction_modal.description.reply": "With an account on Mastodon, you can respond to this post.", + "interaction_modal.on_another_server": "Σε διαφορετικό διακομιστή", + "interaction_modal.on_this_server": "Σε αυτόν τον διακομιστή", + "interaction_modal.other_server_instructions": "Simply copy and paste this URL into the search bar of your favourite app or the web interface where you are signed in.", + "interaction_modal.preamble": "Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one.", + "interaction_modal.title.favourite": "Favourite {name}'s post", + "interaction_modal.title.follow": "Follow {name}", + "interaction_modal.title.reblog": "Boost {name}'s post", + "interaction_modal.title.reply": "Απάντηση στην ανάρτηση του {name}", "intervals.full.days": "{number, plural, one {# μέρα} other {# μέρες}}", "intervals.full.hours": "{number, plural, one {# ώρα} other {# ώρες}}", "intervals.full.minutes": "{number, plural, one {# λεπτό} other {# λεπτά}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Διάρκεια", "mute_modal.hide_notifications": "Απόκρυψη ειδοποιήσεων αυτού του χρήστη;", "mute_modal.indefinite": "Αόριστη", - "navigation_bar.apps": "Εφαρμογές φορητών συσκευών", + "navigation_bar.about": "Σχετικά με", + "navigation_bar.apps": "Αποκτήστε την Εφαρμογή", "navigation_bar.blocks": "Αποκλεισμένοι χρήστες", "navigation_bar.bookmarks": "Σελιδοδείκτες", "navigation_bar.community_timeline": "Τοπική ροή", @@ -324,7 +375,7 @@ "navigation_bar.filters": "Αποσιωπημένες λέξεις", "navigation_bar.follow_requests": "Αιτήματα ακολούθησης", "navigation_bar.follows_and_followers": "Ακολουθείς και σε ακολουθούν", - "navigation_bar.info": "Πληροφορίες κόμβου", + "navigation_bar.info": "Σχετικά με", "navigation_bar.keyboard_shortcuts": "Συντομεύσεις", "navigation_bar.lists": "Λίστες", "navigation_bar.logout": "Αποσύνδεση", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Καρφιτσωμένα τουτ", "navigation_bar.preferences": "Προτιμήσεις", "navigation_bar.public_timeline": "Ομοσπονδιακή ροή", + "navigation_bar.search": "Search", "navigation_bar.security": "Ασφάλεια", + "not_signed_in_indicator.not_signed_in": "Πρέπει να συνδεθείτε για να αποκτήσετε πρόσβαση σε αυτόν τον πόρο.", "notification.admin.report": "{name} ανέφερε {target}", "notification.admin.sign_up": "{name} έχει εγγραφεί", "notification.favourite": "Ο/Η {name} σημείωσε ως αγαπημένη την κατάστασή σου", @@ -401,6 +454,8 @@ "privacy.public.short": "Δημόσιο", "privacy.unlisted.long": "Ορατό για όλους, αλλά opted-out των χαρακτηριστικών της ανακάλυψης", "privacy.unlisted.short": "Μη καταχωρημένα", + "privacy_policy.last_updated": "Τελευταία ενημέρωση {date}", + "privacy_policy.title": "Πολιτική Απορρήτου", "refresh": "Ανανέωση", "regeneration_indicator.label": "Φορτώνει…", "regeneration_indicator.sublabel": "Η αρχική σου ροή ετοιμάζεται!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "Η αναζήτηση τουτ βάσει του περιεχόμενού τους δεν είναι ενεργοποιημένη σε αυτό τον κόμβο.", "search_results.title": "Search for {q}", "search_results.total": "{count, number} {count, plural, zero {αποτελέσματα} one {αποτέλεσμα} other {αποτελέσματα}}", + "server_banner.about_active_users": "Άτομα που χρησιμοποιούν αυτόν τον διακομιστή κατά τις τελευταίες 30 ημέρες (Μηνιαία Ενεργοί Χρήστες)", + "server_banner.active_users": "ενεργοί χρήστες", + "server_banner.administered_by": "Διαχειριστής:", + "server_banner.introduction": "{domain} is part of the decentralized social network powered by {mastodon}.", + "server_banner.learn_more": "Μάθετε περισσότερα", + "server_banner.server_stats": "Στατιστικά διακομιστή:", "sign_in_banner.create_account": "Create account", "sign_in_banner.sign_in": "Sign in", "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "Κανείς δεν προώθησε αυτό το τουτ ακόμα. Μόλις το κάνει κάποια, θα εμφανιστούν εδώ.", "status.redraft": "Σβήσε & ξαναγράψε", "status.remove_bookmark": "Αφαίρεση σελιδοδείκτη", + "status.replied_to": "Replied to {name}", "status.reply": "Απάντησε", "status.replyAll": "Απάντησε στην συζήτηση", "status.report": "Κατάγγειλε @{name}", @@ -523,9 +585,8 @@ "status.show_more": "Δείξε περισσότερα", "status.show_more_all": "Δείξε περισσότερα για όλα", "status.show_original": "Εμφάνιση αρχικού", - "status.show_thread": "Εμφάνιση νήματος", "status.translate": "Μετάφραση", - "status.translated_from": "Μεταφράστηκε από {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Μη διαθέσιμα", "status.unmute_conversation": "Διέκοψε την αποσιώπηση της συζήτησης", "status.unpin": "Ξεκαρφίτσωσε από το προφίλ", @@ -538,7 +599,6 @@ "tabs_bar.home": "Αρχική", "tabs_bar.local_timeline": "Τοπική", "tabs_bar.notifications": "Ειδοποιήσεις", - "tabs_bar.search": "Αναζήτηση", "time_remaining.days": "απομένουν {number, plural, one {# ημέρα} other {# ημέρες}}", "time_remaining.hours": "απομένουν {number, plural, one {# ώρα} other {# ώρες}}", "time_remaining.minutes": "απομένουν {number, plural, one {# λεπτό} other {# λεπτά}}", diff --git a/app/javascript/mastodon/locales/en-GB.json b/app/javascript/mastodon/locales/en-GB.json index 9a533693d..c4bfc40b1 100644 --- a/app/javascript/mastodon/locales/en-GB.json +++ b/app/javascript/mastodon/locales/en-GB.json @@ -1,4 +1,17 @@ { + "about.blocks": "Moderated servers", + "about.contact": "Contact:", + "about.domain_blocks.comment": "Reason", + "about.domain_blocks.domain": "Domain", + "about.domain_blocks.preamble": "Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.", + "about.domain_blocks.severity": "Severity", + "about.domain_blocks.silenced.explanation": "You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.", + "about.domain_blocks.silenced.title": "Limited", + "about.domain_blocks.suspended.explanation": "No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.", + "about.domain_blocks.suspended.title": "Suspended", + "about.not_available": "This information has not been made available on this server.", + "about.powered_by": "Decentralized social media powered by {mastodon}", + "about.rules": "Server rules", "account.account_note_header": "Note", "account.add_or_remove_from_list": "Add or Remove from lists", "account.badges.bot": "Bot", @@ -7,13 +20,16 @@ "account.block_domain": "Block domain {domain}", "account.blocked": "Blocked", "account.browse_more_on_origin_server": "Browse more on the original profile", - "account.cancel_follow_request": "Cancel follow request", + "account.cancel_follow_request": "Withdraw follow request", "account.direct": "Direct message @{name}", "account.disable_notifications": "Stop notifying me when @{name} posts", "account.domain_blocked": "Domain blocked", "account.edit_profile": "Edit profile", "account.enable_notifications": "Notify me when @{name} posts", "account.endorse": "Feature on profile", + "account.featured_tags.last_status_at": "Last post on {date}", + "account.featured_tags.last_status_never": "No posts", + "account.featured_tags.title": "{name}'s featured hashtags", "account.follow": "Follow", "account.followers": "Followers", "account.followers.empty": "No one follows this user yet.", @@ -23,7 +39,7 @@ "account.follows.empty": "This user doesn't follow anyone yet.", "account.follows_you": "Follows you", "account.hide_reblogs": "Hide boosts from @{name}", - "account.joined": "Joined {date}", + "account.joined_short": "Joined", "account.languages": "Change subscribed languages", "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.", @@ -63,12 +79,24 @@ "audio.hide": "Hide audio", "autosuggest_hashtag.per_week": "{count} per week", "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.copy_stacktrace": "Copy error report", + "bundle_column_error.error.body": "The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.", + "bundle_column_error.error.title": "Oh, no!", + "bundle_column_error.network.body": "There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.", + "bundle_column_error.network.title": "Network error", "bundle_column_error.retry": "Try again", - "bundle_column_error.title": "Network error", + "bundle_column_error.return": "Go back home", + "bundle_column_error.routing.body": "The requested page could not be found. Are you sure the URL in the address bar is correct?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Close", "bundle_modal_error.message": "Something went wrong while loading this component.", "bundle_modal_error.retry": "Try again", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "About", "column.blocks": "Blocked users", "column.bookmarks": "Bookmarks", "column.community": "Local timeline", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "Block & Report", "confirmations.block.confirm": "Block", "confirmations.block.message": "Are you sure you want to block {name}?", + "confirmations.cancel_follow_request.confirm": "Withdraw request", + "confirmations.cancel_follow_request.message": "Are you sure you want to withdraw your request to follow {name}?", "confirmations.delete.confirm": "Delete", "confirmations.delete.message": "Are you sure you want to delete this status?", "confirmations.delete_list.confirm": "Delete", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Mark as read", "conversation.open": "View conversation", "conversation.with": "With {names}", + "copypaste.copied": "Copied", + "copypaste.copy": "Copy", "directory.federated": "From known fediverse", "directory.local": "From {domain} only", "directory.new_arrivals": "New arrivals", "directory.recently_active": "Recently active", + "dismissable_banner.community_timeline": "These are the most recent public posts from people whose accounts are hosted by {domain}.", + "dismissable_banner.dismiss": "Dismiss", + "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", + "dismissable_banner.explore_statuses": "These posts from this and other servers in the decentralized network are gaining traction on this server right now.", + "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", + "dismissable_banner.public_timeline": "These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.", "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", @@ -221,14 +259,14 @@ "follow_request.reject": "Reject", "follow_requests.unlocked_explanation": "Even though your account is not locked, the {domain} staff thought you might want to review follow requests from these accounts manually.", "generic.saved": "Saved", - "getting_started.developers": "Developers", - "getting_started.directory": "Profile directory", + "getting_started.directory": "Directory", "getting_started.documentation": "Documentation", + "getting_started.free_software_notice": "Mastodon is free, open source software. You can view the source code, contribute or report issues at {repository}.", "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.privacy_policy": "Privacy Policy", "getting_started.security": "Security", + "getting_started.what_is_mastodon": "About Mastodon", "hashtag.column_header.tag_mode.all": "and {additional}", "hashtag.column_header.tag_mode.any": "or {additional}", "hashtag.column_header.tag_mode.none": "without {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Show replies", "home.hide_announcements": "Hide announcements", "home.show_announcements": "Show announcements", + "interaction_modal.description.favourite": "With an account on Mastodon, you can favourite this post to let the author know you appreciate it and save it for later.", + "interaction_modal.description.follow": "With an account on Mastodon, you can follow {name} to receive their posts in your home feed.", + "interaction_modal.description.reblog": "With an account on Mastodon, you can boost this post to share it with your own followers.", + "interaction_modal.description.reply": "With an account on Mastodon, you can respond to this post.", + "interaction_modal.on_another_server": "On a different server", + "interaction_modal.on_this_server": "On this server", + "interaction_modal.other_server_instructions": "Simply copy and paste this URL into the search bar of your favourite app or the web interface where you are signed in.", + "interaction_modal.preamble": "Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one.", + "interaction_modal.title.favourite": "Favourite {name}'s post", + "interaction_modal.title.follow": "Follow {name}", + "interaction_modal.title.reblog": "Boost {name}'s post", + "interaction_modal.title.reply": "Reply to {name}'s post", "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}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Duration", "mute_modal.hide_notifications": "Hide notifications from this user?", "mute_modal.indefinite": "Indefinite", - "navigation_bar.apps": "Mobile apps", + "navigation_bar.about": "About", + "navigation_bar.apps": "Get the app", "navigation_bar.blocks": "Blocked users", "navigation_bar.bookmarks": "Bookmarks", "navigation_bar.community_timeline": "Local timeline", @@ -324,7 +375,7 @@ "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.info": "About", "navigation_bar.keyboard_shortcuts": "Hotkeys", "navigation_bar.lists": "Lists", "navigation_bar.logout": "Logout", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Pinned posts", "navigation_bar.preferences": "Preferences", "navigation_bar.public_timeline": "Federated timeline", + "navigation_bar.search": "Search", "navigation_bar.security": "Security", + "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", "notification.admin.report": "{name} reported {target}", "notification.admin.sign_up": "{name} signed up", "notification.favourite": "{name} favourited your status", @@ -401,6 +454,8 @@ "privacy.public.short": "Public", "privacy.unlisted.long": "Visible for all, but opted-out of discovery features", "privacy.unlisted.short": "Unlisted", + "privacy_policy.last_updated": "Last updated {date}", + "privacy_policy.title": "Privacy Policy", "refresh": "Refresh", "regeneration_indicator.label": "Loading…", "regeneration_indicator.sublabel": "Your home feed is being prepared!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "Searching posts by their content is not enabled on this Mastodon server.", "search_results.title": "Search for {q}", "search_results.total": "{count, number} {count, plural, one {result} other {results}}", + "server_banner.about_active_users": "People using this server during the last 30 days (Monthly Active Users)", + "server_banner.active_users": "active users", + "server_banner.administered_by": "Administered by:", + "server_banner.introduction": "{domain} is part of the decentralized social network powered by {mastodon}.", + "server_banner.learn_more": "Learn more", + "server_banner.server_stats": "Server stats:", "sign_in_banner.create_account": "Create account", "sign_in_banner.sign_in": "Sign in", "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "No one has boosted this post yet. When someone does, they will show up here.", "status.redraft": "Delete & re-draft", "status.remove_bookmark": "Remove bookmark", + "status.replied_to": "Replied to {name}", "status.reply": "Reply", "status.replyAll": "Reply to thread", "status.report": "Report @{name}", @@ -523,9 +585,8 @@ "status.show_more": "Show more", "status.show_more_all": "Show more for all", "status.show_original": "Show original", - "status.show_thread": "Show thread", "status.translate": "Translate", - "status.translated_from": "Translated from {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Not available", "status.unmute_conversation": "Unmute conversation", "status.unpin": "Unpin from profile", @@ -538,7 +599,6 @@ "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", diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json index e2cb2e5f6..2d687ab50 100644 --- a/app/javascript/mastodon/locales/en.json +++ b/app/javascript/mastodon/locales/en.json @@ -1,4 +1,17 @@ { + "about.blocks": "Moderated servers", + "about.contact": "Contact:", + "about.domain_blocks.comment": "Reason", + "about.domain_blocks.domain": "Domain", + "about.domain_blocks.preamble": "Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.", + "about.domain_blocks.severity": "Severity", + "about.domain_blocks.silenced.explanation": "You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.", + "about.domain_blocks.silenced.title": "Limited", + "about.domain_blocks.suspended.explanation": "No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.", + "about.domain_blocks.suspended.title": "Suspended", + "about.not_available": "This information has not been made available on this server.", + "about.powered_by": "Decentralized social media powered by {mastodon}", + "about.rules": "Server rules", "account.account_note_header": "Note", "account.add_or_remove_from_list": "Add or Remove from lists", "account.badges.bot": "Bot", @@ -7,13 +20,16 @@ "account.block_domain": "Block domain {domain}", "account.blocked": "Blocked", "account.browse_more_on_origin_server": "Browse more on the original profile", - "account.cancel_follow_request": "Cancel follow request", + "account.cancel_follow_request": "Withdraw follow request", "account.direct": "Direct message @{name}", "account.disable_notifications": "Stop notifying me when @{name} posts", "account.domain_blocked": "Domain blocked", "account.edit_profile": "Edit profile", "account.enable_notifications": "Notify me when @{name} posts", "account.endorse": "Feature on profile", + "account.featured_tags.last_status_at": "Last post on {date}", + "account.featured_tags.last_status_never": "No posts", + "account.featured_tags.title": "{name}'s featured hashtags", "account.follow": "Follow", "account.followers": "Followers", "account.followers.empty": "No one follows this user yet.", @@ -23,7 +39,7 @@ "account.follows.empty": "This user doesn't follow anyone yet.", "account.follows_you": "Follows you", "account.hide_reblogs": "Hide boosts from @{name}", - "account.joined": "Joined {date}", + "account.joined_short": "Joined", "account.languages": "Change subscribed languages", "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.", @@ -63,12 +79,24 @@ "audio.hide": "Hide audio", "autosuggest_hashtag.per_week": "{count} per week", "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.copy_stacktrace": "Copy error report", + "bundle_column_error.error.body": "The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.", + "bundle_column_error.error.title": "Oh, no!", + "bundle_column_error.network.body": "There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.", + "bundle_column_error.network.title": "Network error", "bundle_column_error.retry": "Try again", - "bundle_column_error.title": "Network error", + "bundle_column_error.return": "Go back home", + "bundle_column_error.routing.body": "The requested page could not be found. Are you sure the URL in the address bar is correct?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Close", "bundle_modal_error.message": "Something went wrong while loading this component.", "bundle_modal_error.retry": "Try again", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "About", "column.blocks": "Blocked users", "column.bookmarks": "Bookmarks", "column.community": "Local timeline", @@ -125,6 +153,8 @@ "confirmations.block.block_and_report": "Block & Report", "confirmations.block.confirm": "Block", "confirmations.block.message": "Are you sure you want to block {name}?", + "confirmations.cancel_follow_request.confirm": "Withdraw request", + "confirmations.cancel_follow_request.message": "Are you sure you want to withdraw your request to follow {name}?", "confirmations.delete.confirm": "Delete", "confirmations.delete.message": "Are you sure you want to delete this post?", "confirmations.delete_list.confirm": "Delete", @@ -148,10 +178,18 @@ "conversation.mark_as_read": "Mark as read", "conversation.open": "View conversation", "conversation.with": "With {names}", + "copypaste.copied": "Copied", + "copypaste.copy": "Copy", "directory.federated": "From known fediverse", "directory.local": "From {domain} only", "directory.new_arrivals": "New arrivals", "directory.recently_active": "Recently active", + "dismissable_banner.community_timeline": "These are the most recent public posts from people whose accounts are hosted by {domain}.", + "dismissable_banner.dismiss": "Dismiss", + "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", + "dismissable_banner.explore_statuses": "These posts from this and other servers in the decentralized network are gaining traction on this server right now.", + "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", + "dismissable_banner.public_timeline": "These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.", "embed.instructions": "Embed this post on your website by copying the code below.", "embed.preview": "Here is what it will look like:", "emoji_button.activity": "Activity", @@ -225,14 +263,14 @@ "follow_request.reject": "Reject", "follow_requests.unlocked_explanation": "Even though your account is not locked, the {domain} staff thought you might want to review follow requests from these accounts manually.", "generic.saved": "Saved", - "getting_started.developers": "Developers", - "getting_started.directory": "Profile directory", + "getting_started.directory": "Directory", "getting_started.documentation": "Documentation", + "getting_started.free_software_notice": "Mastodon is free, open source software. You can view the source code, contribute or report issues at {repository}.", "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.privacy_policy": "Privacy Policy", "getting_started.security": "Account settings", + "getting_started.what_is_mastodon": "About Mastodon", "hashtag.column_header.tag_mode.all": "and {additional}", "hashtag.column_header.tag_mode.any": "or {additional}", "hashtag.column_header.tag_mode.none": "without {additional}", @@ -249,6 +287,18 @@ "home.column_settings.show_replies": "Show replies", "home.hide_announcements": "Hide announcements", "home.show_announcements": "Show announcements", + "interaction_modal.description.favourite": "With an account on Mastodon, you can favourite this post to let the author know you appreciate it and save it for later.", + "interaction_modal.description.follow": "With an account on Mastodon, you can follow {name} to receive their posts in your home feed.", + "interaction_modal.description.reblog": "With an account on Mastodon, you can boost this post to share it with your own followers.", + "interaction_modal.description.reply": "With an account on Mastodon, you can respond to this post.", + "interaction_modal.on_another_server": "On a different server", + "interaction_modal.on_this_server": "On this server", + "interaction_modal.other_server_instructions": "Simply copy and paste this URL into the search bar of your favourite app or the web interface where you are signed in.", + "interaction_modal.preamble": "Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one.", + "interaction_modal.title.favourite": "Favourite {name}'s post", + "interaction_modal.title.follow": "Follow {name}", + "interaction_modal.title.reblog": "Boost {name}'s post", + "interaction_modal.title.reply": "Reply to {name}'s post", "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}}", @@ -314,7 +364,8 @@ "mute_modal.duration": "Duration", "mute_modal.hide_notifications": "Hide notifications from this user?", "mute_modal.indefinite": "Indefinite", - "navigation_bar.apps": "Mobile apps", + "navigation_bar.about": "About", + "navigation_bar.apps": "Get the app", "navigation_bar.blocks": "Blocked users", "navigation_bar.bookmarks": "Bookmarks", "navigation_bar.community_timeline": "Local timeline", @@ -328,7 +379,7 @@ "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.info": "About", "navigation_bar.keyboard_shortcuts": "Hotkeys", "navigation_bar.lists": "Lists", "navigation_bar.misc": "Misc", @@ -338,7 +389,9 @@ "navigation_bar.pins": "Pinned posts", "navigation_bar.preferences": "Preferences", "navigation_bar.public_timeline": "Federated timeline", + "navigation_bar.search": "Search", "navigation_bar.security": "Security", + "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", "notification.admin.report": "{name} reported {target}", "notification.admin.sign_up": "{name} signed up", "notification.favourite": "{name} favourited your post", @@ -406,6 +459,8 @@ "privacy.public.short": "Public", "privacy.unlisted.long": "Visible for all, but opted-out of discovery features", "privacy.unlisted.short": "Unlisted", + "privacy_policy.last_updated": "Last updated {date}", + "privacy_policy.title": "Privacy Policy", "refresh": "Refresh", "regeneration_indicator.label": "Loading…", "regeneration_indicator.sublabel": "Your home feed is being prepared!", @@ -478,6 +533,12 @@ "search_results.statuses_fts_disabled": "Searching posts by their content is not enabled on this Mastodon server.", "search_results.title": "Search for {q}", "search_results.total": "{count, number} {count, plural, one {result} other {results}}", + "server_banner.about_active_users": "People using this server during the last 30 days (Monthly Active Users)", + "server_banner.active_users": "active users", + "server_banner.administered_by": "Administered by:", + "server_banner.introduction": "{domain} is part of the decentralized social network powered by {mastodon}.", + "server_banner.learn_more": "Learn more", + "server_banner.server_stats": "Server stats:", "sign_in_banner.create_account": "Create account", "sign_in_banner.sign_in": "Sign in", "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", @@ -517,6 +578,7 @@ "status.reblogs.empty": "No one has boosted this post yet. When someone does, they will show up here.", "status.redraft": "Delete & re-draft", "status.remove_bookmark": "Remove bookmark", + "status.replied_to": "Replied to {name}", "status.reply": "Reply", "status.replyAll": "Reply to thread", "status.report": "Report @{name}", @@ -528,9 +590,8 @@ "status.show_more": "Show more", "status.show_more_all": "Show more for all", "status.show_original": "Show original", - "status.show_thread": "Show thread", "status.translate": "Translate", - "status.translated_from": "Translated from {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Not available", "status.unmute_conversation": "Unmute conversation", "status.unpin": "Unpin from profile", @@ -543,7 +604,6 @@ "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", diff --git a/app/javascript/mastodon/locales/eo.json b/app/javascript/mastodon/locales/eo.json index 0fa681483..cf66a5af3 100644 --- a/app/javascript/mastodon/locales/eo.json +++ b/app/javascript/mastodon/locales/eo.json @@ -1,4 +1,17 @@ { + "about.blocks": "Moderated servers", + "about.contact": "Contact:", + "about.domain_blocks.comment": "Reason", + "about.domain_blocks.domain": "Domain", + "about.domain_blocks.preamble": "Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.", + "about.domain_blocks.severity": "Severity", + "about.domain_blocks.silenced.explanation": "You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.", + "about.domain_blocks.silenced.title": "Limited", + "about.domain_blocks.suspended.explanation": "No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.", + "about.domain_blocks.suspended.title": "Suspended", + "about.not_available": "This information has not been made available on this server.", + "about.powered_by": "Decentralized social media powered by {mastodon}", + "about.rules": "Server rules", "account.account_note_header": "Noto", "account.add_or_remove_from_list": "Aldoni al aŭ forigi el listoj", "account.badges.bot": "Roboto", @@ -7,13 +20,16 @@ "account.block_domain": "Bloki la domajnon {domain}", "account.blocked": "Blokita", "account.browse_more_on_origin_server": "Foliumi pli ĉe la originala profilo", - "account.cancel_follow_request": "Nuligi la demandon de sekvado", + "account.cancel_follow_request": "Withdraw follow request", "account.direct": "Rekte mesaĝi @{name}", "account.disable_notifications": "Ne plu sciigi min kiam @{name} mesaĝas", "account.domain_blocked": "Domajno blokita", "account.edit_profile": "Redakti la profilon", "account.enable_notifications": "Sciigi min kiam @{name} mesaĝas", "account.endorse": "Rekomendi ĉe via profilo", + "account.featured_tags.last_status_at": "Last post on {date}", + "account.featured_tags.last_status_never": "No posts", + "account.featured_tags.title": "{name}'s featured hashtags", "account.follow": "Sekvi", "account.followers": "Sekvantoj", "account.followers.empty": "Ankoraŭ neniu sekvas tiun uzanton.", @@ -23,7 +39,7 @@ "account.follows.empty": "La uzanto ankoraŭ ne sekvas iun ajn.", "account.follows_you": "Sekvas vin", "account.hide_reblogs": "Kaŝi la plusendojn de @{name}", - "account.joined": "Kuniĝis {date}", + "account.joined_short": "Joined", "account.languages": "Change subscribed languages", "account.link_verified_on": "La posedanto de tiu ligilo estis kontrolita je {date}", "account.locked_info": "La privateco de tiu konto estas elektita kiel fermita. La posedanto povas mane akcepti tiun, kiu povas sekvi rin.", @@ -63,12 +79,24 @@ "audio.hide": "Kaŝi aŭdion", "autosuggest_hashtag.per_week": "{count} semajne", "boost_modal.combo": "Vi povas premi {combo} por preterpasi sekvafoje", - "bundle_column_error.body": "Io misfunkciis en la ŝargado de ĉi tiu elemento.", + "bundle_column_error.copy_stacktrace": "Copy error report", + "bundle_column_error.error.body": "The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.", + "bundle_column_error.error.title": "Oh, no!", + "bundle_column_error.network.body": "There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.", + "bundle_column_error.network.title": "Network error", "bundle_column_error.retry": "Provu refoje", - "bundle_column_error.title": "Eraro de reto", + "bundle_column_error.return": "Go back home", + "bundle_column_error.routing.body": "The requested page could not be found. Are you sure the URL in the address bar is correct?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Fermi", "bundle_modal_error.message": "Io misfunkciis en la ŝargado de ĉi tiu elemento.", "bundle_modal_error.retry": "Provu refoje", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "About", "column.blocks": "Blokitaj uzantoj", "column.bookmarks": "Legosignoj", "column.community": "Loka templinio", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "Bloki kaj raporti", "confirmations.block.confirm": "Bloki", "confirmations.block.message": "Ĉu vi certas, ke vi volas bloki {name}?", + "confirmations.cancel_follow_request.confirm": "Withdraw request", + "confirmations.cancel_follow_request.message": "Are you sure you want to withdraw your request to follow {name}?", "confirmations.delete.confirm": "Forigi", "confirmations.delete.message": "Ĉu vi certas, ke vi volas forigi ĉi tiun mesaĝon?", "confirmations.delete_list.confirm": "Forigi", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Marki legita", "conversation.open": "Vidi konversacion", "conversation.with": "Kun {names}", + "copypaste.copied": "Copied", + "copypaste.copy": "Copy", "directory.federated": "El konata fediverso", "directory.local": "Nur de {domain}", "directory.new_arrivals": "Novaj alvenoj", "directory.recently_active": "Lastatempe aktiva", + "dismissable_banner.community_timeline": "These are the most recent public posts from people whose accounts are hosted by {domain}.", + "dismissable_banner.dismiss": "Dismiss", + "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", + "dismissable_banner.explore_statuses": "These posts from this and other servers in the decentralized network are gaining traction on this server right now.", + "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", + "dismissable_banner.public_timeline": "These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.", "embed.instructions": "Enkorpigu ĉi tiun mesaĝon en vian retejon per kopio de la suba kodo.", "embed.preview": "Ĝi aperos tiel:", "emoji_button.activity": "Agadoj", @@ -221,14 +259,14 @@ "follow_request.reject": "Rifuzi", "follow_requests.unlocked_explanation": "Kvankam via konto ne estas ŝlosita, la teamo de {domain} pensas, ke vi eble volas permane kontroli la demandojn de sekvado de ĉi tiuj kontoj.", "generic.saved": "Konservita", - "getting_started.developers": "Programistoj", - "getting_started.directory": "Profilujo", + "getting_started.directory": "Directory", "getting_started.documentation": "Dokumentado", + "getting_started.free_software_notice": "Mastodon is free, open source software. You can view the source code, contribute or report issues at {repository}.", "getting_started.heading": "Por komenci", "getting_started.invite": "Inviti homojn", - "getting_started.open_source_notice": "Mastodon estas malfermitkoda programo. Vi povas kontribui aŭ raporti problemojn en GitHub je {github}.", "getting_started.privacy_policy": "Privacy Policy", "getting_started.security": "Sekureco", + "getting_started.what_is_mastodon": "About Mastodon", "hashtag.column_header.tag_mode.all": "kaj {additional}", "hashtag.column_header.tag_mode.any": "aŭ {additional}", "hashtag.column_header.tag_mode.none": "sen {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Montri respondojn", "home.hide_announcements": "Kaŝi la anoncojn", "home.show_announcements": "Montri anoncojn", + "interaction_modal.description.favourite": "With an account on Mastodon, you can favourite this post to let the author know you appreciate it and save it for later.", + "interaction_modal.description.follow": "With an account on Mastodon, you can follow {name} to receive their posts in your home feed.", + "interaction_modal.description.reblog": "With an account on Mastodon, you can boost this post to share it with your own followers.", + "interaction_modal.description.reply": "With an account on Mastodon, you can respond to this post.", + "interaction_modal.on_another_server": "On a different server", + "interaction_modal.on_this_server": "On this server", + "interaction_modal.other_server_instructions": "Simply copy and paste this URL into the search bar of your favourite app or the web interface where you are signed in.", + "interaction_modal.preamble": "Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one.", + "interaction_modal.title.favourite": "Favourite {name}'s post", + "interaction_modal.title.follow": "Follow {name}", + "interaction_modal.title.reblog": "Boost {name}'s post", + "interaction_modal.title.reply": "Reply to {name}'s post", "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}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Daŭro", "mute_modal.hide_notifications": "Ĉu vi volas kaŝi la sciigojn de ĉi tiu uzanto?", "mute_modal.indefinite": "Nedifinita", - "navigation_bar.apps": "Telefonaj aplikaĵoj", + "navigation_bar.about": "About", + "navigation_bar.apps": "Get the app", "navigation_bar.blocks": "Blokitaj uzantoj", "navigation_bar.bookmarks": "Legosignoj", "navigation_bar.community_timeline": "Loka templinio", @@ -324,7 +375,7 @@ "navigation_bar.filters": "Silentigitaj vortoj", "navigation_bar.follow_requests": "Demandoj de sekvado", "navigation_bar.follows_and_followers": "Sekvatoj kaj sekvantoj", - "navigation_bar.info": "Pri ĉi tiu servilo", + "navigation_bar.info": "About", "navigation_bar.keyboard_shortcuts": "Rapidklavoj", "navigation_bar.lists": "Listoj", "navigation_bar.logout": "Adiaŭi", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Alpinglitaj mesaĝoj", "navigation_bar.preferences": "Preferoj", "navigation_bar.public_timeline": "Fratara templinio", + "navigation_bar.search": "Search", "navigation_bar.security": "Sekureco", + "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", "notification.admin.report": "{name} raportis {target}", "notification.admin.sign_up": "{name} registris", "notification.favourite": "{name} aldonis vian mesaĝon al siaj preferaĵoj", @@ -401,6 +454,8 @@ "privacy.public.short": "Publika", "privacy.unlisted.long": "Videbla por ĉiuj, sed ekskluzive de la funkcio de esploro", "privacy.unlisted.short": "Nelistigita", + "privacy_policy.last_updated": "Last updated {date}", + "privacy_policy.title": "Privacy Policy", "refresh": "Refreŝigu", "regeneration_indicator.label": "Ŝargado…", "regeneration_indicator.sublabel": "Via abonfluo estas preparata!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "Serĉi mesaĝojn laŭ enhavo ne estas ebligita en ĉi tiu Mastodon-servilo.", "search_results.title": "Search for {q}", "search_results.total": "{count, number} {count, plural, one {rezulto} other {rezultoj}}", + "server_banner.about_active_users": "People using this server during the last 30 days (Monthly Active Users)", + "server_banner.active_users": "active users", + "server_banner.administered_by": "Administered by:", + "server_banner.introduction": "{domain} is part of the decentralized social network powered by {mastodon}.", + "server_banner.learn_more": "Learn more", + "server_banner.server_stats": "Server stats:", "sign_in_banner.create_account": "Create account", "sign_in_banner.sign_in": "Sign in", "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "Ankoraŭ neniu plusendis la mesaĝon. Kiam iu faras tion, ili aperos ĉi tie.", "status.redraft": "Forigi kaj reskribi", "status.remove_bookmark": "Forigi legosignon", + "status.replied_to": "Replied to {name}", "status.reply": "Respondi", "status.replyAll": "Respondi al la fadeno", "status.report": "Raporti @{name}", @@ -523,9 +585,8 @@ "status.show_more": "Montri pli", "status.show_more_all": "Montri pli ĉiun", "status.show_original": "Show original", - "status.show_thread": "Montri la mesaĝaron", "status.translate": "Translate", - "status.translated_from": "Translated from {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Nedisponebla", "status.unmute_conversation": "Malsilentigi la konversacion", "status.unpin": "Depingli de profilo", @@ -538,7 +599,6 @@ "tabs_bar.home": "Hejmo", "tabs_bar.local_timeline": "Loka templinio", "tabs_bar.notifications": "Sciigoj", - "tabs_bar.search": "Serĉi", "time_remaining.days": "{number, plural, one {# tago} other {# tagoj}} restas", "time_remaining.hours": "{number, plural, one {# horo} other {# horoj}} restas", "time_remaining.minutes": "{number, plural, one {# minuto} other {# minutoj}} restas", diff --git a/app/javascript/mastodon/locales/es-AR.json b/app/javascript/mastodon/locales/es-AR.json index 84a24aa04..f157022b8 100644 --- a/app/javascript/mastodon/locales/es-AR.json +++ b/app/javascript/mastodon/locales/es-AR.json @@ -1,4 +1,17 @@ { + "about.blocks": "Servidores moderados", + "about.contact": "Contacto:", + "about.domain_blocks.comment": "Motivo", + "about.domain_blocks.domain": "Dominio", + "about.domain_blocks.preamble": "Mastodon normalmente te permite ver el contenido e interactuar con los usuarios de cualquier otro servidor en el fediverso. Estas son las excepciones que se han hecho en este servidor en particular.", + "about.domain_blocks.severity": "Gravedad", + "about.domain_blocks.silenced.explanation": "Normalmente no verás perfiles y contenido de este servidor, a menos que lo busqués explícitamente o sigás alguna cuenta.", + "about.domain_blocks.silenced.title": "Limitados", + "about.domain_blocks.suspended.explanation": "Ningún dato de este servidor será procesado, almacenado o intercambiado, haciendo imposible cualquier interacción o comunicación con los usuarios de este servidor.", + "about.domain_blocks.suspended.title": "Suspendidos", + "about.not_available": "Esta información no está disponible en este servidor.", + "about.powered_by": "Redes sociales descentralizadas con tecnología de {mastodon}", + "about.rules": "Reglas del servidor", "account.account_note_header": "Nota", "account.add_or_remove_from_list": "Agregar o quitar de las listas", "account.badges.bot": "Bot", @@ -7,13 +20,16 @@ "account.block_domain": "Bloquear dominio {domain}", "account.blocked": "Bloqueado", "account.browse_more_on_origin_server": "Explorar más en el perfil original", - "account.cancel_follow_request": "Cancelar la solicitud de seguimiento", + "account.cancel_follow_request": "Retirar la solicitud de seguimiento", "account.direct": "Mensaje directo a @{name}", "account.disable_notifications": "Dejar de notificarme cuando @{name} envíe mensajes", "account.domain_blocked": "Dominio bloqueado", "account.edit_profile": "Editar perfil", "account.enable_notifications": "Notificarme cuando @{name} envíe mensajes", "account.endorse": "Destacar en el perfil", + "account.featured_tags.last_status_at": "Último mensaje: {date}", + "account.featured_tags.last_status_never": "Sin mensajes", + "account.featured_tags.title": "Etiquetas destacadas de {name}", "account.follow": "Seguir", "account.followers": "Seguidores", "account.followers.empty": "Todavía nadie sigue a este usuario.", @@ -23,7 +39,7 @@ "account.follows.empty": "Todavía este usuario no sigue a nadie.", "account.follows_you": "Te sigue", "account.hide_reblogs": "Ocultar adhesiones de @{name}", - "account.joined": "En este servidor desde {date}", + "account.joined_short": "Joined", "account.languages": "Cambiar idiomas suscritos", "account.link_verified_on": "La propiedad de este enlace fue verificada el {date}", "account.locked_info": "Esta cuenta es privada. El propietario manualmente revisa quién puede seguirle.", @@ -63,12 +79,24 @@ "audio.hide": "Ocultar audio", "autosuggest_hashtag.per_week": "{count} por semana", "boost_modal.combo": "Podés hacer clic en {combo} para saltar esto la próxima vez", - "bundle_column_error.body": "Algo salió mal al cargar este componente.", + "bundle_column_error.copy_stacktrace": "Copiar informe de error", + "bundle_column_error.error.body": "La página solicitada no pudo ser cargada. Podría deberse a un error de programación en nuestro código o a un problema de compatibilidad con el navegador web.", + "bundle_column_error.error.title": "¡Epa!", + "bundle_column_error.network.body": "Se produjo un error al intentar cargar esta página. Esto puede deberse a un problema temporal con tu conexión a internet o a este servidor.", + "bundle_column_error.network.title": "Error de red", "bundle_column_error.retry": "Intentá de nuevo", - "bundle_column_error.title": "Error de red", + "bundle_column_error.return": "Volver al inicio", + "bundle_column_error.routing.body": "No se pudo encontrar la página solicitada. ¿Estás seguro que la dirección web es correcta?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Cerrar", "bundle_modal_error.message": "Algo salió mal al cargar este componente.", "bundle_modal_error.retry": "Intentá de nuevo", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "Información", "column.blocks": "Usuarios bloqueados", "column.bookmarks": "Marcadores", "column.community": "Línea temporal local", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "Bloquear y denunciar", "confirmations.block.confirm": "Bloquear", "confirmations.block.message": "¿Estás seguro que querés bloquear a {name}?", + "confirmations.cancel_follow_request.confirm": "Retirar solicitud", + "confirmations.cancel_follow_request.message": "¿Estás seguro que querés retirar tu solicitud para seguir a {name}?", "confirmations.delete.confirm": "Eliminar", "confirmations.delete.message": "¿Estás seguro que querés eliminar este mensaje?", "confirmations.delete_list.confirm": "Eliminar", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Marcar como leída", "conversation.open": "Ver conversación", "conversation.with": "Con {names}", + "copypaste.copied": "Copiado", + "copypaste.copy": "Copiar", "directory.federated": "Desde fediverso conocido", "directory.local": "Sólo de {domain}", "directory.new_arrivals": "Recién llegados", "directory.recently_active": "Recientemente activos", + "dismissable_banner.community_timeline": "Estos son los mensajes públicos más recientes de cuentas alojadas en {domain}.", + "dismissable_banner.dismiss": "Descartar", + "dismissable_banner.explore_links": "Estas noticias están siendo discutidas por personas en este y otros servidores de la red descentralizada ahora mismo.", + "dismissable_banner.explore_statuses": "Estos mensajes de este y otros servidores en la red descentralizada están ganando tracción en este servidor ahora mismo.", + "dismissable_banner.explore_tags": "Estas etiquetas están ganando tracción entre la gente en este y otros servidores de la red descentralizada ahora mismo.", + "dismissable_banner.public_timeline": "Estos son los mensajes públicos más recientes de personas en este y otros servidores de la red descentralizada que este servidor conoce.", "embed.instructions": "Insertá este mensaje a tu sitio web copiando el código de abajo.", "embed.preview": "Así es cómo se verá:", "emoji_button.activity": "Actividad", @@ -221,14 +259,14 @@ "follow_request.reject": "Rechazar", "follow_requests.unlocked_explanation": "A pesar de que tu cuenta no es privada, el equipo de {domain} pensó que podrías querer revisar manualmente las solicitudes de seguimiento de estas cuentas.", "generic.saved": "Guardado", - "getting_started.developers": "Desarrolladores", - "getting_started.directory": "Directorio de perfiles", + "getting_started.directory": "Directorio", "getting_started.documentation": "Documentación", + "getting_started.free_software_notice": "Mastodon es software libre y de código abierto. Podés ver el código fuente, contribuir o informar sobre problemas en {repository}.", "getting_started.heading": "Introducción", "getting_started.invite": "Invitar gente", - "getting_started.open_source_notice": "Mastodon es software libre. Podés contribuir o informar errores en {github}.", "getting_started.privacy_policy": "Política de privacidad", "getting_started.security": "Configuración de la cuenta", + "getting_started.what_is_mastodon": "Acerca de Mastodon", "hashtag.column_header.tag_mode.all": "y {additional}", "hashtag.column_header.tag_mode.any": "o {additional}", "hashtag.column_header.tag_mode.none": "sin {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Mostrar respuestas", "home.hide_announcements": "Ocultar anuncios", "home.show_announcements": "Mostrar anuncios", + "interaction_modal.description.favourite": "Con una cuenta en Mastodon, podés marcar este mensaje como favorito para que el autor sepa que lo apreciás y lo guardás para más adelante.", + "interaction_modal.description.follow": "Con una cuenta en Mastodon, podés seguir a {name} para recibir sus mensajes en tu línea temporal principal.", + "interaction_modal.description.reblog": "Con una cuenta en Mastodon, podés adherir a este mensaje para compartirlo con tus propios seguidores.", + "interaction_modal.description.reply": "Con una cuenta en Mastodon, podés responder a este mensaje.", + "interaction_modal.on_another_server": "En un servidor diferente", + "interaction_modal.on_this_server": "En este servidor", + "interaction_modal.other_server_instructions": "Simplemente copiá y pegá esta dirección web en la barra de búsqueda de tu aplicación favorita o en la interface web en donde hayás iniciado sesión.", + "interaction_modal.preamble": "Ya que Mastodon es descentralizado, podés usar tu cuenta existente alojada por otro servidor Mastodon (u otra plataforma compatible, si no tenés una cuenta en ésta).", + "interaction_modal.title.favourite": "Marcar como favorito el mensaje de {name}", + "interaction_modal.title.follow": "Seguir a {name}", + "interaction_modal.title.reblog": "Adherir al mensaje de {name}", + "interaction_modal.title.reply": "Responder al mensaje de {name}", "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}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Duración", "mute_modal.hide_notifications": "¿Querés ocultar las notificaciones de este usuario?", "mute_modal.indefinite": "Indefinida", - "navigation_bar.apps": "Aplicaciones móviles", + "navigation_bar.about": "Información", + "navigation_bar.apps": "Obtené la aplicación", "navigation_bar.blocks": "Usuarios bloqueados", "navigation_bar.bookmarks": "Marcadores", "navigation_bar.community_timeline": "Línea temporal local", @@ -324,7 +375,7 @@ "navigation_bar.filters": "Palabras silenciadas", "navigation_bar.follow_requests": "Solicitudes de seguimiento", "navigation_bar.follows_and_followers": "Cuentas seguidas y seguidores", - "navigation_bar.info": "Este servidor", + "navigation_bar.info": "Información", "navigation_bar.keyboard_shortcuts": "Atajos", "navigation_bar.lists": "Listas", "navigation_bar.logout": "Cerrar sesión", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Mensajes fijados", "navigation_bar.preferences": "Configuración", "navigation_bar.public_timeline": "Línea temporal federada", + "navigation_bar.search": "Search", "navigation_bar.security": "Seguridad", + "not_signed_in_indicator.not_signed_in": "Necesitas iniciar sesión para acceder a este recurso.", "notification.admin.report": "{name} denunció a {target}", "notification.admin.sign_up": "Se registró {name}", "notification.favourite": "{name} marcó tu mensaje como favorito", @@ -401,6 +454,8 @@ "privacy.public.short": "Público", "privacy.unlisted.long": "Visible para todos, pero excluido de las características de descubrimiento", "privacy.unlisted.short": "No listado", + "privacy_policy.last_updated": "Última actualización: {date}", + "privacy_policy.title": "Política de privacidad", "refresh": "Refrescar", "regeneration_indicator.label": "Cargando…", "regeneration_indicator.sublabel": "¡Se está preparando tu línea temporal principal!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "No se pueden buscar mensajes por contenido en este servidor de Mastodon.", "search_results.title": "Buscar {q}", "search_results.total": "{count, number} {count, plural, one {resultado} other {resultados}}", + "server_banner.about_active_users": "Personas usando este servidor durante los últimos 30 días (Usuarios Activos Mensuales)", + "server_banner.active_users": "usuarios activos", + "server_banner.administered_by": "Administrado por:", + "server_banner.introduction": "{domain} es parte de la red social descentralizada con la tecnología de {mastodon}.", + "server_banner.learn_more": "Aprendé más", + "server_banner.server_stats": "Estadísticas del servidor:", "sign_in_banner.create_account": "Crear cuenta", "sign_in_banner.sign_in": "Iniciar sesión", "sign_in_banner.text": "Iniciá sesión para seguir cuentas o etiquetas, marcar mensajes como favoritos, compartirlos y responderlos o interactuar desde tu cuenta en un servidor diferente.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "Todavía nadie adhirió a este mensaje. Cuando alguien lo haga, se mostrará acá.", "status.redraft": "Eliminar mensaje original y editarlo", "status.remove_bookmark": "Quitar marcador", + "status.replied_to": "Replied to {name}", "status.reply": "Responder", "status.replyAll": "Responder al hilo", "status.report": "Denunciar a @{name}", @@ -523,9 +585,8 @@ "status.show_more": "Mostrar más", "status.show_more_all": "Mostrar más para todo", "status.show_original": "Mostrar original", - "status.show_thread": "Mostrar hilo", "status.translate": "Traducir", - "status.translated_from": "Traducido desde el {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "No disponible", "status.unmute_conversation": "Dejar de silenciar conversación", "status.unpin": "Dejar de fijar", @@ -538,7 +599,6 @@ "tabs_bar.home": "Principal", "tabs_bar.local_timeline": "Local", "tabs_bar.notifications": "Notificaciones", - "tabs_bar.search": "Buscar", "time_remaining.days": "{number, plural,one {queda # día} other {quedan # días}}", "time_remaining.hours": "{number, plural,one {queda # hora} other {quedan # horas}}", "time_remaining.minutes": "{number, plural,one {queda # minuto} other {quedan # minutos}}", diff --git a/app/javascript/mastodon/locales/es-MX.json b/app/javascript/mastodon/locales/es-MX.json index 59c1c50e7..6f69cbabc 100644 --- a/app/javascript/mastodon/locales/es-MX.json +++ b/app/javascript/mastodon/locales/es-MX.json @@ -1,4 +1,17 @@ { + "about.blocks": "Servidores moderados", + "about.contact": "Contacto:", + "about.domain_blocks.comment": "Razón", + "about.domain_blocks.domain": "Dominio", + "about.domain_blocks.preamble": "Mastodon normalmente te permite ver el contenido e interactuar con los usuarios de cualquier otro servidor en el fediverso. Estas son las excepciones que se han hecho en este servidor en particular.", + "about.domain_blocks.severity": "Gravedad", + "about.domain_blocks.silenced.explanation": "Normalmente no verás perfiles y contenido de este servidor, a menos que lo busques explícitamente o sigas alguna cuenta.", + "about.domain_blocks.silenced.title": "Limitado", + "about.domain_blocks.suspended.explanation": "Ningún dato de este servidor será procesado, almacenado o intercambiado, haciendo imposible cualquier interacción o comunicación con los usuarios de este servidor.", + "about.domain_blocks.suspended.title": "Suspendido", + "about.not_available": "Esta información no está disponible en este servidor.", + "about.powered_by": "Redes sociales descentralizadas con tecnología de {mastodon}", + "about.rules": "Reglas del servidor", "account.account_note_header": "Nota", "account.add_or_remove_from_list": "Agregar o eliminar de las listas", "account.badges.bot": "Bot", @@ -7,13 +20,16 @@ "account.block_domain": "Bloquear dominio {domain}", "account.blocked": "Bloqueado", "account.browse_more_on_origin_server": "Ver más en el perfil original", - "account.cancel_follow_request": "Cancelar la solicitud de seguimiento", + "account.cancel_follow_request": "Retirar solicitud de seguimiento", "account.direct": "Mensaje directo a @{name}", "account.disable_notifications": "Dejar de notificarme cuando @{name} publique algo", "account.domain_blocked": "Dominio oculto", "account.edit_profile": "Editar perfil", "account.enable_notifications": "Notificarme cuando @{name} publique algo", "account.endorse": "Destacar en mi perfil", + "account.featured_tags.last_status_at": "Última publicación el {date}", + "account.featured_tags.last_status_never": "Sin publicaciones", + "account.featured_tags.title": "Etiquetas destacadas de {name}", "account.follow": "Seguir", "account.followers": "Seguidores", "account.followers.empty": "Todavía nadie sigue a este usuario.", @@ -23,7 +39,7 @@ "account.follows.empty": "Este usuario todavía no sigue a nadie.", "account.follows_you": "Te sigue", "account.hide_reblogs": "Ocultar retoots de @{name}", - "account.joined": "Se unió el {date}", + "account.joined_short": "Joined", "account.languages": "Cambiar idiomas suscritos", "account.link_verified_on": "El proprietario de este link fue comprobado el {date}", "account.locked_info": "El estado de privacidad de esta cuenta està configurado como bloqueado. El proprietario debe revisar manualmente quien puede seguirle.", @@ -63,12 +79,24 @@ "audio.hide": "Ocultar audio", "autosuggest_hashtag.per_week": "{count} por semana", "boost_modal.combo": "Puedes hacer clic en {combo} para saltar este aviso la próxima vez", - "bundle_column_error.body": "Algo salió mal al cargar este componente.", + "bundle_column_error.copy_stacktrace": "Copy error report", + "bundle_column_error.error.body": "The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.", + "bundle_column_error.error.title": "Oh, no!", + "bundle_column_error.network.body": "There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.", + "bundle_column_error.network.title": "Network error", "bundle_column_error.retry": "Inténtalo de nuevo", - "bundle_column_error.title": "Error de red", + "bundle_column_error.return": "Go back home", + "bundle_column_error.routing.body": "The requested page could not be found. Are you sure the URL in the address bar is correct?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Cerrar", "bundle_modal_error.message": "Algo salió mal al cargar este componente.", "bundle_modal_error.retry": "Inténtalo de nuevo", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "Acerca de", "column.blocks": "Usuarios bloqueados", "column.bookmarks": "Marcadores", "column.community": "Línea de tiempo local", @@ -121,6 +149,8 @@ "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.cancel_follow_request.confirm": "Retirar solicitud", + "confirmations.cancel_follow_request.message": "¿Estás seguro de que deseas retirar tu solicitud para seguir a {name}?", "confirmations.delete.confirm": "Eliminar", "confirmations.delete.message": "¿Estás seguro de que quieres borrar este toot?", "confirmations.delete_list.confirm": "Eliminar", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Marcar como leído", "conversation.open": "Ver conversación", "conversation.with": "Con {names}", + "copypaste.copied": "Copiado", + "copypaste.copy": "Copiar", "directory.federated": "Desde el fediverso conocido", "directory.local": "Sólo de {domain}", "directory.new_arrivals": "Recién llegados", "directory.recently_active": "Recientemente activo", + "dismissable_banner.community_timeline": "Estas son las publicaciones públicas más recientes de personas cuyas cuentas están alojadas en {domain}.", + "dismissable_banner.dismiss": "Descartar", + "dismissable_banner.explore_links": "Estas noticias están siendo discutidas por personas en este y otros servidores de la red descentralizada en este momento.", + "dismissable_banner.explore_statuses": "Estas publicaciones de este y otros servidores en la red descentralizada están ganando popularidad en este servidor en este momento.", + "dismissable_banner.explore_tags": "Estas tendencias están ganando popularidad entre la gente en este y otros servidores de la red descentralizada en este momento.", + "dismissable_banner.public_timeline": "Estas son las publicaciones públicas más recientes de personas en este y otros servidores de la red descentralizada que este servidor conoce.", "embed.instructions": "Añade este toot a tu sitio web con el siguiente código.", "embed.preview": "Así es como se verá:", "emoji_button.activity": "Actividad", @@ -221,14 +259,14 @@ "follow_request.reject": "Rechazar", "follow_requests.unlocked_explanation": "A pesar de que tu cuenta no es privada, el personal de {domain} ha pensado que quizás deberías revisar manualmente las solicitudes de seguimiento de estas cuentas.", "generic.saved": "Guardado", - "getting_started.developers": "Desarrolladores", - "getting_started.directory": "Directorio de perfil", + "getting_started.directory": "Directorio", "getting_started.documentation": "Documentación", + "getting_started.free_software_notice": "Mastodon es un software libre y de código abierto. Puedes ver el código fuente, contribuir o reportar problemas en {repository}.", "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.privacy_policy": "Privacy Policy", + "getting_started.privacy_policy": "Política de Privacidad", "getting_started.security": "Seguridad", + "getting_started.what_is_mastodon": "Acerca de Mastodon", "hashtag.column_header.tag_mode.all": "y {additional}", "hashtag.column_header.tag_mode.any": "o {additional}", "hashtag.column_header.tag_mode.none": "sin {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Mostrar respuestas", "home.hide_announcements": "Ocultar anuncios", "home.show_announcements": "Mostrar anuncios", + "interaction_modal.description.favourite": "Con una cuenta en Mastodon, puedes marcar como favorita esta publicación para que el autor sepa que te gusta y guardarla así para más adelante.", + "interaction_modal.description.follow": "Con una cuenta en Mastodon, puedes seguir {name} para recibir sus publicaciones en tu línea temporal de inicio.", + "interaction_modal.description.reblog": "Con una cuenta en Mastodon, puedes impulsar esta publicación para compartirla con tus propios seguidores.", + "interaction_modal.description.reply": "Con una cuenta en Mastodon, puedes responder a esta publicación.", + "interaction_modal.on_another_server": "En un servidor diferente", + "interaction_modal.on_this_server": "En este servidor", + "interaction_modal.other_server_instructions": "Simplemente copia y pega esta URL en la barra de búsqueda de tu aplicación favorita o en la interfaz web donde hayas iniciado sesión.", + "interaction_modal.preamble": "Ya que Mastodon es descentralizado, puedes usar tu cuenta existente alojada en otro servidor Mastodon o plataforma compatible si no tienes una cuenta en este servidor.", + "interaction_modal.title.favourite": "Marcar como favorita la publicación de {name}", + "interaction_modal.title.follow": "Seguir a {name}", + "interaction_modal.title.reblog": "Impulsar la publicación de {name}", + "interaction_modal.title.reply": "Responder a la publicación de {name}", "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}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Duración", "mute_modal.hide_notifications": "Ocultar notificaciones de este usuario?", "mute_modal.indefinite": "Indefinida", - "navigation_bar.apps": "Aplicaciones móviles", + "navigation_bar.about": "Acerca de", + "navigation_bar.apps": "Obtener la aplicación", "navigation_bar.blocks": "Usuarios bloqueados", "navigation_bar.bookmarks": "Marcadores", "navigation_bar.community_timeline": "Historia local", @@ -324,7 +375,7 @@ "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.info": "Acerca de", "navigation_bar.keyboard_shortcuts": "Atajos", "navigation_bar.lists": "Listas", "navigation_bar.logout": "Cerrar sesión", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Toots fijados", "navigation_bar.preferences": "Preferencias", "navigation_bar.public_timeline": "Historia federada", + "navigation_bar.search": "Search", "navigation_bar.security": "Seguridad", + "not_signed_in_indicator.not_signed_in": "Necesitas iniciar sesión para acceder a este recurso.", "notification.admin.report": "{name} informó {target}", "notification.admin.sign_up": "{name} se unio", "notification.favourite": "{name} marcó tu estado como favorito", @@ -401,6 +454,8 @@ "privacy.public.short": "Público", "privacy.unlisted.long": "Visible para todos, pero excluido de las funciones de descubrimiento", "privacy.unlisted.short": "No listado", + "privacy_policy.last_updated": "Ultima vez actualizado {date}", + "privacy_policy.title": "Política de Privacidad", "refresh": "Actualizar", "regeneration_indicator.label": "Cargando…", "regeneration_indicator.sublabel": "¡Tu historia de inicio se está preparando!", @@ -471,11 +526,17 @@ "search_results.nothing_found": "No se pudo encontrar nada para estos términos de busqueda", "search_results.statuses": "Toots", "search_results.statuses_fts_disabled": "Buscar toots por su contenido no está disponible en este servidor de Mastodon.", - "search_results.title": "Search for {q}", + "search_results.title": "Buscar {q}", "search_results.total": "{count, number} {count, plural, one {resultado} other {resultados}}", - "sign_in_banner.create_account": "Create account", - "sign_in_banner.sign_in": "Sign in", - "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", + "server_banner.about_active_users": "Usuarios activos en el servidor durante los últimos 30 días (Usuarios Activos Mensuales)", + "server_banner.active_users": "usuarios activos", + "server_banner.administered_by": "Administrado por:", + "server_banner.introduction": "{domain} es parte de la red social descentralizada liderada por {mastodon}.", + "server_banner.learn_more": "Saber más", + "server_banner.server_stats": "Estadísticas del servidor:", + "sign_in_banner.create_account": "Crear cuenta", + "sign_in_banner.sign_in": "Iniciar sesión", + "sign_in_banner.text": "Inicia sesión en este servidor para seguir perfiles o etiquetas, guardar, compartir y responder a mensajes. También puedes interactuar desde otra cuenta en un servidor diferente.", "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}", @@ -512,6 +573,7 @@ "status.reblogs.empty": "Nadie retooteó este toot todavía. Cuando alguien lo haga, aparecerá aquí.", "status.redraft": "Borrar y volver a borrador", "status.remove_bookmark": "Eliminar marcador", + "status.replied_to": "Replied to {name}", "status.reply": "Responder", "status.replyAll": "Responder al hilo", "status.report": "Reportar", @@ -523,9 +585,8 @@ "status.show_more": "Mostrar más", "status.show_more_all": "Mostrar más para todo", "status.show_original": "Mostrar original", - "status.show_thread": "Mostrar hilo", "status.translate": "Traducir", - "status.translated_from": "Traducido del {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "No disponible", "status.unmute_conversation": "Dejar de silenciar conversación", "status.unpin": "Dejar de fijar", @@ -538,7 +599,6 @@ "tabs_bar.home": "Inicio", "tabs_bar.local_timeline": "Reciente", "tabs_bar.notifications": "Notificaciones", - "tabs_bar.search": "Buscar", "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}}", diff --git a/app/javascript/mastodon/locales/es.json b/app/javascript/mastodon/locales/es.json index e8c39655f..ec299cf1e 100644 --- a/app/javascript/mastodon/locales/es.json +++ b/app/javascript/mastodon/locales/es.json @@ -1,4 +1,17 @@ { + "about.blocks": "Servidores moderados", + "about.contact": "Contacto:", + "about.domain_blocks.comment": "Razón", + "about.domain_blocks.domain": "Dominio", + "about.domain_blocks.preamble": "Mastodon normalmente te permite ver el contenido e interactuar con los usuarios de cualquier otro servidor en el fediverso. Estas son las excepciones que se han hecho en este servidor en particular.", + "about.domain_blocks.severity": "Gravedad", + "about.domain_blocks.silenced.explanation": "Normalmente no verás perfiles y contenido de este servidor, a menos que lo busques explícitamente o sigas alguna cuenta.", + "about.domain_blocks.silenced.title": "Limitado", + "about.domain_blocks.suspended.explanation": "Ningún dato de este servidor será procesado, almacenado o intercambiado, haciendo imposible cualquier interacción o comunicación con los usuarios de este servidor.", + "about.domain_blocks.suspended.title": "Suspendido", + "about.not_available": "Esta información no está disponible en este servidor.", + "about.powered_by": "Redes sociales descentralizadas con tecnología de {mastodon}", + "about.rules": "Reglas del servidor", "account.account_note_header": "Nota", "account.add_or_remove_from_list": "Agregar o eliminar de listas", "account.badges.bot": "Bot", @@ -7,13 +20,16 @@ "account.block_domain": "Bloquear dominio {domain}", "account.blocked": "Bloqueado", "account.browse_more_on_origin_server": "Ver más en el perfil original", - "account.cancel_follow_request": "Cancelar la solicitud de seguimiento", + "account.cancel_follow_request": "Retirar solicitud de seguimiento", "account.direct": "Mensaje directo a @{name}", "account.disable_notifications": "Dejar de notificarme cuando @{name} publique algo", "account.domain_blocked": "Dominio oculto", "account.edit_profile": "Editar perfil", "account.enable_notifications": "Notificarme cuando @{name} publique algo", "account.endorse": "Mostrar en perfil", + "account.featured_tags.last_status_at": "Última publicación el {date}", + "account.featured_tags.last_status_never": "Sin publicaciones", + "account.featured_tags.title": "Etiquetas destacadas de {name}", "account.follow": "Seguir", "account.followers": "Seguidores", "account.followers.empty": "Todavía nadie sigue a este usuario.", @@ -23,7 +39,7 @@ "account.follows.empty": "Este usuario todavía no sigue a nadie.", "account.follows_you": "Te sigue", "account.hide_reblogs": "Ocultar retoots de @{name}", - "account.joined": "Se unió el {date}", + "account.joined_short": "Joined", "account.languages": "Cambiar idiomas suscritos", "account.link_verified_on": "El proprietario de este link fue comprobado el {date}", "account.locked_info": "El estado de privacidad de esta cuenta està configurado como bloqueado. El proprietario debe revisar manualmente quien puede seguirle.", @@ -63,12 +79,24 @@ "audio.hide": "Ocultar audio", "autosuggest_hashtag.per_week": "{count} por semana", "boost_modal.combo": "Puedes hacer clic en {combo} para saltar este aviso la próxima vez", - "bundle_column_error.body": "Algo salió mal al cargar este componente.", + "bundle_column_error.copy_stacktrace": "Copy error report", + "bundle_column_error.error.body": "The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.", + "bundle_column_error.error.title": "Oh, no!", + "bundle_column_error.network.body": "There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.", + "bundle_column_error.network.title": "Network error", "bundle_column_error.retry": "Inténtalo de nuevo", - "bundle_column_error.title": "Error de red", + "bundle_column_error.return": "Go back home", + "bundle_column_error.routing.body": "The requested page could not be found. Are you sure the URL in the address bar is correct?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Cerrar", "bundle_modal_error.message": "Algo salió mal al cargar este componente.", "bundle_modal_error.retry": "Inténtalo de nuevo", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "Acerca de", "column.blocks": "Usuarios bloqueados", "column.bookmarks": "Marcadores", "column.community": "Línea de tiempo local", @@ -121,6 +149,8 @@ "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.cancel_follow_request.confirm": "Retirar solicitud", + "confirmations.cancel_follow_request.message": "¿Estás seguro de que deseas retirar tu solicitud para seguir a {name}?", "confirmations.delete.confirm": "Eliminar", "confirmations.delete.message": "¿Estás seguro de que quieres borrar esta publicación?", "confirmations.delete_list.confirm": "Eliminar", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Marcar como leído", "conversation.open": "Ver conversación", "conversation.with": "Con {names}", + "copypaste.copied": "Copiado", + "copypaste.copy": "Copiar", "directory.federated": "Desde el fediverso conocido", "directory.local": "Sólo de {domain}", "directory.new_arrivals": "Recién llegados", "directory.recently_active": "Recientemente activo", + "dismissable_banner.community_timeline": "Estas son las publicaciones públicas más recientes de personas cuyas cuentas están alojadas en {domain}.", + "dismissable_banner.dismiss": "Descartar", + "dismissable_banner.explore_links": "Estas noticias están siendo discutidas por personas en este y otros servidores de la red descentralizada en este momento.", + "dismissable_banner.explore_statuses": "Estas publicaciones de este y otros servidores en la red descentralizada están ganando popularidad en este servidor en este momento.", + "dismissable_banner.explore_tags": "Estas tendencias están ganando popularidad entre la gente en este y otros servidores de la red descentralizada en este momento.", + "dismissable_banner.public_timeline": "Estas son las publicaciones públicas más recientes de personas en este y otros servidores de la red descentralizada que este servidor conoce.", "embed.instructions": "Añade esta publicación a tu sitio web con el siguiente código.", "embed.preview": "Así es como se verá:", "emoji_button.activity": "Actividad", @@ -221,14 +259,14 @@ "follow_request.reject": "Rechazar", "follow_requests.unlocked_explanation": "A pesar de que tu cuenta no es privada, el personal de {domain} ha pensado que quizás deberías revisar manualmente las solicitudes de seguimiento de estas cuentas.", "generic.saved": "Guardado", - "getting_started.developers": "Desarrolladores", - "getting_started.directory": "Directorio de perfil", + "getting_started.directory": "Directorio", "getting_started.documentation": "Documentación", + "getting_started.free_software_notice": "Mastodon es un software libre y de código abierto. Puedes ver el código fuente, contribuir o reportar problemas en {repository}.", "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.privacy_policy": "Política de Privacidad", "getting_started.security": "Seguridad", + "getting_started.what_is_mastodon": "Acerca de Mastodon", "hashtag.column_header.tag_mode.all": "y {additional}", "hashtag.column_header.tag_mode.any": "o {additional}", "hashtag.column_header.tag_mode.none": "sin {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Mostrar respuestas", "home.hide_announcements": "Ocultar anuncios", "home.show_announcements": "Mostrar anuncios", + "interaction_modal.description.favourite": "Con una cuenta en Mastodon, puedes marcar como favorita esta publicación para que el autor sepa que te gusta y guardarla así para más adelante.", + "interaction_modal.description.follow": "Con una cuenta en Mastodon, puedes seguir {name} para recibir sus publicaciones en tu línea temporal de inicio.", + "interaction_modal.description.reblog": "Con una cuenta en Mastodon, puedes impulsar esta publicación para compartirla con tus propios seguidores.", + "interaction_modal.description.reply": "Con una cuenta en Mastodon, puedes responder a esta publicación.", + "interaction_modal.on_another_server": "En un servidor diferente", + "interaction_modal.on_this_server": "En este servidor", + "interaction_modal.other_server_instructions": "Simplemente copia y pega esta URL en la barra de búsqueda de tu aplicación favorita o en la interfaz web donde hayas iniciado sesión.", + "interaction_modal.preamble": "Ya que Mastodon es descentralizado, puedes usar tu cuenta existente alojada en otro servidor Mastodon o plataforma compatible si no tienes una cuenta en este servidor.", + "interaction_modal.title.favourite": "Marcar como favorita la publicación de {name}", + "interaction_modal.title.follow": "Seguir a {name}", + "interaction_modal.title.reblog": "Impulsar la publicación de {name}", + "interaction_modal.title.reply": "Responder a la publicación de {name}", "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}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Duración", "mute_modal.hide_notifications": "Ocultar notificaciones de este usuario?", "mute_modal.indefinite": "Indefinida", - "navigation_bar.apps": "Aplicaciones móviles", + "navigation_bar.about": "Acerca de", + "navigation_bar.apps": "Obtener la aplicación", "navigation_bar.blocks": "Usuarios bloqueados", "navigation_bar.bookmarks": "Marcadores", "navigation_bar.community_timeline": "Línea de tiempo local", @@ -324,7 +375,7 @@ "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.info": "Acerca de", "navigation_bar.keyboard_shortcuts": "Atajos", "navigation_bar.lists": "Listas", "navigation_bar.logout": "Cerrar sesión", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Publicaciones fijadas", "navigation_bar.preferences": "Preferencias", "navigation_bar.public_timeline": "Línea de tiempo federada", + "navigation_bar.search": "Search", "navigation_bar.security": "Seguridad", + "not_signed_in_indicator.not_signed_in": "Necesitas iniciar sesión para acceder a este recurso.", "notification.admin.report": "{name} informó {target}", "notification.admin.sign_up": "{name} se registró", "notification.favourite": "{name} marcó tu estado como favorito", @@ -401,6 +454,8 @@ "privacy.public.short": "Público", "privacy.unlisted.long": "Visible para todos, pero excluido de las funciones de descubrimiento", "privacy.unlisted.short": "No listado", + "privacy_policy.last_updated": "Ultima vez actualizado {date}", + "privacy_policy.title": "Política de Privacidad", "refresh": "Actualizar", "regeneration_indicator.label": "Cargando…", "regeneration_indicator.sublabel": "¡Tu historia de inicio se está preparando!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "Buscar publicaciones por su contenido no está disponible en este servidor de Mastodon.", "search_results.title": "Buscar {q}", "search_results.total": "{count, number} {count, plural, one {resultado} other {resultados}}", + "server_banner.about_active_users": "Usuarios activos en el servidor durante los últimos 30 días (Usuarios Activos Mensuales)", + "server_banner.active_users": "usuarios activos", + "server_banner.administered_by": "Administrado por:", + "server_banner.introduction": "{domain} es parte de la red social descentralizada liderada por {mastodon}.", + "server_banner.learn_more": "Saber más", + "server_banner.server_stats": "Estadísticas del servidor:", "sign_in_banner.create_account": "Crear cuenta", "sign_in_banner.sign_in": "Iniciar sesión", "sign_in_banner.text": "Inicia sesión en este servidor para seguir perfiles o etiquetas, guardar, compartir y responder a mensajes. También puedes interactuar desde otra cuenta en un servidor diferente.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "Nadie retooteó este toot todavía. Cuando alguien lo haga, aparecerá aquí.", "status.redraft": "Borrar y volver a borrador", "status.remove_bookmark": "Eliminar marcador", + "status.replied_to": "Replied to {name}", "status.reply": "Responder", "status.replyAll": "Responder al hilo", "status.report": "Reportar", @@ -523,9 +585,8 @@ "status.show_more": "Mostrar más", "status.show_more_all": "Mostrar más para todo", "status.show_original": "Mostrar original", - "status.show_thread": "Mostrar hilo", "status.translate": "Traducir", - "status.translated_from": "Traducido del {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "No disponible", "status.unmute_conversation": "Dejar de silenciar conversación", "status.unpin": "Dejar de fijar", @@ -538,7 +599,6 @@ "tabs_bar.home": "Inicio", "tabs_bar.local_timeline": "Local", "tabs_bar.notifications": "Notificaciones", - "tabs_bar.search": "Buscar", "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}}", diff --git a/app/javascript/mastodon/locales/et.json b/app/javascript/mastodon/locales/et.json index 096367eb4..b483b61a8 100644 --- a/app/javascript/mastodon/locales/et.json +++ b/app/javascript/mastodon/locales/et.json @@ -1,4 +1,17 @@ { + "about.blocks": "Moderated servers", + "about.contact": "Contact:", + "about.domain_blocks.comment": "Reason", + "about.domain_blocks.domain": "Domain", + "about.domain_blocks.preamble": "Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.", + "about.domain_blocks.severity": "Severity", + "about.domain_blocks.silenced.explanation": "You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.", + "about.domain_blocks.silenced.title": "Limited", + "about.domain_blocks.suspended.explanation": "No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.", + "about.domain_blocks.suspended.title": "Suspended", + "about.not_available": "This information has not been made available on this server.", + "about.powered_by": "Decentralized social media powered by {mastodon}", + "about.rules": "Server rules", "account.account_note_header": "Märge", "account.add_or_remove_from_list": "Lisa või Eemalda nimekirjadest", "account.badges.bot": "Robot", @@ -7,13 +20,16 @@ "account.block_domain": "Peida kõik domeenist {domain}", "account.blocked": "Blokeeritud", "account.browse_more_on_origin_server": "Browse more on the original profile", - "account.cancel_follow_request": "Tühista jälgimistaotlus", + "account.cancel_follow_request": "Withdraw follow request", "account.direct": "Saada otsesõnum @{name}'ile", "account.disable_notifications": "Stop notifying me when @{name} posts", "account.domain_blocked": "Domeen peidetud", "account.edit_profile": "Muuda profiili", "account.enable_notifications": "Notify me when @{name} posts", "account.endorse": "Too profiilil esile", + "account.featured_tags.last_status_at": "Last post on {date}", + "account.featured_tags.last_status_never": "No posts", + "account.featured_tags.title": "{name}'s featured hashtags", "account.follow": "Jälgi", "account.followers": "Jälgijad", "account.followers.empty": "Keegi ei jälgi seda kasutajat veel.", @@ -23,7 +39,7 @@ "account.follows.empty": "See kasutaja ei jälgi veel kedagi.", "account.follows_you": "Jälgib Teid", "account.hide_reblogs": "Peida upitused kasutajalt @{name}", - "account.joined": "Liitus {date}", + "account.joined_short": "Joined", "account.languages": "Change subscribed languages", "account.link_verified_on": "Selle lingi autorsust kontrolliti {date}", "account.locked_info": "Selle konto privaatsussätteks on lukustatud. Omanik vaatab manuaalselt üle, kes teda jägida saab.", @@ -63,12 +79,24 @@ "audio.hide": "Hide audio", "autosuggest_hashtag.per_week": "{count} nädalas", "boost_modal.combo": "Võite vajutada {combo}, et see järgmine kord vahele jätta", - "bundle_column_error.body": "Midagi läks valesti selle komponendi laadimisel.", + "bundle_column_error.copy_stacktrace": "Copy error report", + "bundle_column_error.error.body": "The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.", + "bundle_column_error.error.title": "Oh, no!", + "bundle_column_error.network.body": "There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.", + "bundle_column_error.network.title": "Network error", "bundle_column_error.retry": "Proovi uuesti", - "bundle_column_error.title": "Võrgu viga", + "bundle_column_error.return": "Go back home", + "bundle_column_error.routing.body": "The requested page could not be found. Are you sure the URL in the address bar is correct?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Sulge", "bundle_modal_error.message": "Selle komponendi laadimisel läks midagi viltu.", "bundle_modal_error.retry": "Proovi uuesti", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "About", "column.blocks": "Blokeeritud kasutajad", "column.bookmarks": "Järjehoidjad", "column.community": "Kohalik ajajoon", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "Blokeeri & Teata", "confirmations.block.confirm": "Blokeeri", "confirmations.block.message": "Olete kindel, et soovite blokeerida {name}?", + "confirmations.cancel_follow_request.confirm": "Withdraw request", + "confirmations.cancel_follow_request.message": "Are you sure you want to withdraw your request to follow {name}?", "confirmations.delete.confirm": "Kustuta", "confirmations.delete.message": "Olete kindel, et soovite selle staatuse kustutada?", "confirmations.delete_list.confirm": "Kustuta", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Märgi loetuks", "conversation.open": "Vaata vestlust", "conversation.with": "Koos {names}", + "copypaste.copied": "Copied", + "copypaste.copy": "Copy", "directory.federated": "Teatud fediversumist", "directory.local": "Ainult domeenilt {domain}", "directory.new_arrivals": "Uustulijad", "directory.recently_active": "Hiljuti aktiivne", + "dismissable_banner.community_timeline": "These are the most recent public posts from people whose accounts are hosted by {domain}.", + "dismissable_banner.dismiss": "Dismiss", + "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", + "dismissable_banner.explore_statuses": "These posts from this and other servers in the decentralized network are gaining traction on this server right now.", + "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", + "dismissable_banner.public_timeline": "These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.", "embed.instructions": "Manusta see staatus oma veebilehele, kopeerides alloleva koodi.", "embed.preview": "Nii näeb see välja:", "emoji_button.activity": "Tegevus", @@ -221,14 +259,14 @@ "follow_request.reject": "Hülga", "follow_requests.unlocked_explanation": "Kuigi Teie konto pole lukustatud, soovitab {domain} personal siiski manuaalselt üle vaadata jälgimistaotlused nendelt kontodelt.", "generic.saved": "Saved", - "getting_started.developers": "Arendajad", - "getting_started.directory": "Profiili kataloog", + "getting_started.directory": "Directory", "getting_started.documentation": "Dokumentatsioon", + "getting_started.free_software_notice": "Mastodon is free, open source software. You can view the source code, contribute or report issues at {repository}.", "getting_started.heading": "Alustamine", "getting_started.invite": "Kutsu inimesi", - "getting_started.open_source_notice": "Mastodon on avatud lähtekoodiga tarkvara. Saate panustada või teatada probleemidest GitHubis {github}.", "getting_started.privacy_policy": "Privacy Policy", "getting_started.security": "Turvalisus", + "getting_started.what_is_mastodon": "About Mastodon", "hashtag.column_header.tag_mode.all": "ja {additional}", "hashtag.column_header.tag_mode.any": "või {additional}", "hashtag.column_header.tag_mode.none": "ilma {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Näita vastuseid", "home.hide_announcements": "Peida teadaanded", "home.show_announcements": "Kuva teadaandeid", + "interaction_modal.description.favourite": "With an account on Mastodon, you can favourite this post to let the author know you appreciate it and save it for later.", + "interaction_modal.description.follow": "With an account on Mastodon, you can follow {name} to receive their posts in your home feed.", + "interaction_modal.description.reblog": "With an account on Mastodon, you can boost this post to share it with your own followers.", + "interaction_modal.description.reply": "With an account on Mastodon, you can respond to this post.", + "interaction_modal.on_another_server": "On a different server", + "interaction_modal.on_this_server": "On this server", + "interaction_modal.other_server_instructions": "Simply copy and paste this URL into the search bar of your favourite app or the web interface where you are signed in.", + "interaction_modal.preamble": "Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one.", + "interaction_modal.title.favourite": "Favourite {name}'s post", + "interaction_modal.title.follow": "Follow {name}", + "interaction_modal.title.reblog": "Boost {name}'s post", + "interaction_modal.title.reply": "Reply to {name}'s post", "intervals.full.days": "{number, plural, one {# päev} other {# päevad}}", "intervals.full.hours": "{number, plural, one {# tund} other {# tundi}}", "intervals.full.minutes": "{number, plural, one {# minut} other {# minutit}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Duration", "mute_modal.hide_notifications": "Kas peita teated sellelt kasutajalt?", "mute_modal.indefinite": "Indefinite", - "navigation_bar.apps": "Mobiilirakendused", + "navigation_bar.about": "About", + "navigation_bar.apps": "Get the app", "navigation_bar.blocks": "Blokeeritud kasutajad", "navigation_bar.bookmarks": "Järjehoidjad", "navigation_bar.community_timeline": "Kohalik ajajoon", @@ -324,7 +375,7 @@ "navigation_bar.filters": "Vaigistatud sõnad", "navigation_bar.follow_requests": "Jälgimistaotlused", "navigation_bar.follows_and_followers": "Jälgitud ja jälgijad", - "navigation_bar.info": "Selle serveri kohta", + "navigation_bar.info": "About", "navigation_bar.keyboard_shortcuts": "Kiirklahvid", "navigation_bar.lists": "Nimistud", "navigation_bar.logout": "Logi välja", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Kinnitatud tuutid", "navigation_bar.preferences": "Eelistused", "navigation_bar.public_timeline": "Föderatiivne ajajoon", + "navigation_bar.search": "Search", "navigation_bar.security": "Turvalisus", + "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", "notification.admin.report": "{name} reported {target}", "notification.admin.sign_up": "{name} signed up", "notification.favourite": "{name} märkis Teie staatuse lemmikuks", @@ -401,6 +454,8 @@ "privacy.public.short": "Avalik", "privacy.unlisted.long": "Visible for all, but opted-out of discovery features", "privacy.unlisted.short": "Määramata", + "privacy_policy.last_updated": "Last updated {date}", + "privacy_policy.title": "Privacy Policy", "refresh": "Värskenda", "regeneration_indicator.label": "Laeb…", "regeneration_indicator.sublabel": "Teie kodu voog on ettevalmistamisel!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "Tuutsude otsimine nende sisu järgi ei ole sellel Mastodoni serveril sisse lülitatud.", "search_results.title": "Search for {q}", "search_results.total": "{count, number} {count, plural, one {tulemus} other {tulemust}}", + "server_banner.about_active_users": "People using this server during the last 30 days (Monthly Active Users)", + "server_banner.active_users": "active users", + "server_banner.administered_by": "Administered by:", + "server_banner.introduction": "{domain} is part of the decentralized social network powered by {mastodon}.", + "server_banner.learn_more": "Learn more", + "server_banner.server_stats": "Server stats:", "sign_in_banner.create_account": "Create account", "sign_in_banner.sign_in": "Sign in", "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "Keegi pole seda tuuti veel upitanud. Kui keegi upitab, näed seda siin.", "status.redraft": "Kustuta & alga uuesti", "status.remove_bookmark": "Eemalda järjehoidja", + "status.replied_to": "Replied to {name}", "status.reply": "Vasta", "status.replyAll": "Vasta lõimele", "status.report": "Raporteeri @{name}", @@ -523,9 +585,8 @@ "status.show_more": "Näita veel", "status.show_more_all": "Näita enam kõigile", "status.show_original": "Show original", - "status.show_thread": "Kuva lõim", "status.translate": "Translate", - "status.translated_from": "Translated from {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Pole saadaval", "status.unmute_conversation": "Ära vaigista vestlust", "status.unpin": "Kinnita profiililt lahti", @@ -538,7 +599,6 @@ "tabs_bar.home": "Kodu", "tabs_bar.local_timeline": "Kohalik", "tabs_bar.notifications": "Teated", - "tabs_bar.search": "Otsi", "time_remaining.days": "{number, plural, one {# päev} other {# päeva}} jäänud", "time_remaining.hours": "{number, plural, one {# tund} other {# tundi}} jäänud", "time_remaining.minutes": "{number, plural, one {# minut} other {# minutit}} jäänud", diff --git a/app/javascript/mastodon/locales/eu.json b/app/javascript/mastodon/locales/eu.json index 29365199b..08263367c 100644 --- a/app/javascript/mastodon/locales/eu.json +++ b/app/javascript/mastodon/locales/eu.json @@ -1,4 +1,17 @@ { + "about.blocks": "Moderated servers", + "about.contact": "Contact:", + "about.domain_blocks.comment": "Reason", + "about.domain_blocks.domain": "Domain", + "about.domain_blocks.preamble": "Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.", + "about.domain_blocks.severity": "Severity", + "about.domain_blocks.silenced.explanation": "You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.", + "about.domain_blocks.silenced.title": "Limited", + "about.domain_blocks.suspended.explanation": "No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.", + "about.domain_blocks.suspended.title": "Suspended", + "about.not_available": "This information has not been made available on this server.", + "about.powered_by": "Decentralized social media powered by {mastodon}", + "about.rules": "Server rules", "account.account_note_header": "Oharra", "account.add_or_remove_from_list": "Gehitu edo kendu zerrendetatik", "account.badges.bot": "Bot-a", @@ -7,13 +20,16 @@ "account.block_domain": "Ezkutatu {domain} domeinuko guztia", "account.blocked": "Blokeatuta", "account.browse_more_on_origin_server": "Arakatu gehiago jatorrizko profilean", - "account.cancel_follow_request": "Ezeztatu jarraitzeko eskaria", + "account.cancel_follow_request": "Withdraw follow request", "account.direct": "Mezu zuzena @{name}(r)i", "account.disable_notifications": "Utzi jakinarazteari @{name} erabiltzailearen bidalketetan", "account.domain_blocked": "Ezkutatutako domeinua", "account.edit_profile": "Aldatu profila", "account.enable_notifications": "Jakinarazi @{name} erabiltzaileak bidalketak egitean", "account.endorse": "Nabarmendu profilean", + "account.featured_tags.last_status_at": "Last post on {date}", + "account.featured_tags.last_status_never": "No posts", + "account.featured_tags.title": "{name}'s featured hashtags", "account.follow": "Jarraitu", "account.followers": "Jarraitzaileak", "account.followers.empty": "Ez du inork erabiltzaile hau jarraitzen oraindik.", @@ -23,7 +39,7 @@ "account.follows.empty": "Erabiltzaile honek ez du inor jarraitzen oraindik.", "account.follows_you": "Jarraitzen dizu", "account.hide_reblogs": "Ezkutatu @{name}(r)en bultzadak", - "account.joined": "{date}(e)an elkartua", + "account.joined_short": "Joined", "account.languages": "Change subscribed languages", "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.", @@ -63,12 +79,24 @@ "audio.hide": "Hide audio", "autosuggest_hashtag.per_week": "{count} asteko", "boost_modal.combo": "{combo} sakatu dezakezu hurrengoan hau saltatzeko", - "bundle_column_error.body": "Zerbait okerra gertatu da osagai hau kargatzean.", + "bundle_column_error.copy_stacktrace": "Copy error report", + "bundle_column_error.error.body": "The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.", + "bundle_column_error.error.title": "Oh, no!", + "bundle_column_error.network.body": "There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.", + "bundle_column_error.network.title": "Network error", "bundle_column_error.retry": "Saiatu berriro", - "bundle_column_error.title": "Sareko errorea", + "bundle_column_error.return": "Go back home", + "bundle_column_error.routing.body": "The requested page could not be found. Are you sure the URL in the address bar is correct?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Itxi", "bundle_modal_error.message": "Zerbait okerra gertatu da osagai hau kargatzean.", "bundle_modal_error.retry": "Saiatu berriro", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "About", "column.blocks": "Blokeatutako erabiltzaileak", "column.bookmarks": "Laster-markak", "column.community": "Denbora-lerro lokala", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "Blokeatu eta salatu", "confirmations.block.confirm": "Blokeatu", "confirmations.block.message": "Ziur {name} blokeatu nahi duzula?", + "confirmations.cancel_follow_request.confirm": "Withdraw request", + "confirmations.cancel_follow_request.message": "Are you sure you want to withdraw your request to follow {name}?", "confirmations.delete.confirm": "Ezabatu", "confirmations.delete.message": "Ziur bidalketa hau ezabatu nahi duzula?", "confirmations.delete_list.confirm": "Ezabatu", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Markatu irakurrita bezala", "conversation.open": "Ikusi elkarrizketa", "conversation.with": "Hauekin: {names}", + "copypaste.copied": "Copied", + "copypaste.copy": "Copy", "directory.federated": "Fedibertso ezagunekoak", "directory.local": "{domain} domeinukoak soilik", "directory.new_arrivals": "Iritsi berriak", "directory.recently_active": "Duela gutxi aktibo", + "dismissable_banner.community_timeline": "These are the most recent public posts from people whose accounts are hosted by {domain}.", + "dismissable_banner.dismiss": "Dismiss", + "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", + "dismissable_banner.explore_statuses": "These posts from this and other servers in the decentralized network are gaining traction on this server right now.", + "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", + "dismissable_banner.public_timeline": "These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.", "embed.instructions": "Txertatu bidalketa hau zure webgunean beheko kodea kopiatuz.", "embed.preview": "Hau da izango duen itxura:", "emoji_button.activity": "Jarduera", @@ -221,14 +259,14 @@ "follow_request.reject": "Ukatu", "follow_requests.unlocked_explanation": "Zure kontua blokeatuta ez badago ere, {domain} domeinuko arduradunek uste dute kontu hauetako jarraipen eskariak agian eskuz begiratu nahiko dituzula.", "generic.saved": "Gordea", - "getting_started.developers": "Garatzaileak", - "getting_started.directory": "Profil-direktorioa", + "getting_started.directory": "Directory", "getting_started.documentation": "Dokumentazioa", + "getting_started.free_software_notice": "Mastodon is free, open source software. You can view the source code, contribute or report issues at {repository}.", "getting_started.heading": "Menua", "getting_started.invite": "Gonbidatu jendea", - "getting_started.open_source_notice": "Mastodon software librea da. Ekarpenak egin ditzakezu edo akatsen berri eman GitHub bidez: {github}.", "getting_started.privacy_policy": "Privacy Policy", "getting_started.security": "Segurtasuna", + "getting_started.what_is_mastodon": "About Mastodon", "hashtag.column_header.tag_mode.all": "eta {osagarria}", "hashtag.column_header.tag_mode.any": "edo {osagarria}", "hashtag.column_header.tag_mode.none": "gabe {osagarria}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Erakutsi erantzunak", "home.hide_announcements": "Ezkutatu iragarpenak", "home.show_announcements": "Erakutsi iragarpenak", + "interaction_modal.description.favourite": "With an account on Mastodon, you can favourite this post to let the author know you appreciate it and save it for later.", + "interaction_modal.description.follow": "With an account on Mastodon, you can follow {name} to receive their posts in your home feed.", + "interaction_modal.description.reblog": "With an account on Mastodon, you can boost this post to share it with your own followers.", + "interaction_modal.description.reply": "With an account on Mastodon, you can respond to this post.", + "interaction_modal.on_another_server": "On a different server", + "interaction_modal.on_this_server": "On this server", + "interaction_modal.other_server_instructions": "Simply copy and paste this URL into the search bar of your favourite app or the web interface where you are signed in.", + "interaction_modal.preamble": "Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one.", + "interaction_modal.title.favourite": "Favourite {name}'s post", + "interaction_modal.title.follow": "Follow {name}", + "interaction_modal.title.reblog": "Boost {name}'s post", + "interaction_modal.title.reply": "Reply to {name}'s post", "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}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Iraupena", "mute_modal.hide_notifications": "Ezkutatu erabiltzaile honen jakinarazpenak?", "mute_modal.indefinite": "Zehaztu gabe", - "navigation_bar.apps": "Mugikorrerako aplikazioak", + "navigation_bar.about": "About", + "navigation_bar.apps": "Get the app", "navigation_bar.blocks": "Blokeatutako erabiltzaileak", "navigation_bar.bookmarks": "Laster-markak", "navigation_bar.community_timeline": "Denbora-lerro lokala", @@ -324,7 +375,7 @@ "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.info": "About", "navigation_bar.keyboard_shortcuts": "Laster-teklak", "navigation_bar.lists": "Zerrendak", "navigation_bar.logout": "Amaitu saioa", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Finkatutako bidalketak", "navigation_bar.preferences": "Hobespenak", "navigation_bar.public_timeline": "Federatutako denbora-lerroa", + "navigation_bar.search": "Search", "navigation_bar.security": "Segurtasuna", + "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", "notification.admin.report": "{name} reported {target}", "notification.admin.sign_up": "{name} erabiltzailea erregistratu da", "notification.favourite": "{name}(e)k zure bidalketa gogoko du", @@ -401,6 +454,8 @@ "privacy.public.short": "Publikoa", "privacy.unlisted.long": "Visible for all, but opted-out of discovery features", "privacy.unlisted.short": "Zerrendatu gabea", + "privacy_policy.last_updated": "Last updated {date}", + "privacy_policy.title": "Privacy Policy", "refresh": "Berritu", "regeneration_indicator.label": "Kargatzen…", "regeneration_indicator.sublabel": "Zure hasiera-jarioa prestatzen ari da!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "Mastodon zerbitzari honek ez du bidalketen edukiaren bilaketa gaitu.", "search_results.title": "Search for {q}", "search_results.total": "{count, number} {count, plural, one {emaitza} other {emaitza}}", + "server_banner.about_active_users": "People using this server during the last 30 days (Monthly Active Users)", + "server_banner.active_users": "active users", + "server_banner.administered_by": "Administered by:", + "server_banner.introduction": "{domain} is part of the decentralized social network powered by {mastodon}.", + "server_banner.learn_more": "Learn more", + "server_banner.server_stats": "Server stats:", "sign_in_banner.create_account": "Create account", "sign_in_banner.sign_in": "Sign in", "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "Inork ez dio bultzada eman bidalketa honi oraindik. Inork egiten badu, hemen agertuko da.", "status.redraft": "Ezabatu eta berridatzi", "status.remove_bookmark": "Kendu laster-marka", + "status.replied_to": "Replied to {name}", "status.reply": "Erantzun", "status.replyAll": "Erantzun harian", "status.report": "Salatu @{name}", @@ -523,9 +585,8 @@ "status.show_more": "Erakutsi gehiago", "status.show_more_all": "Erakutsi denetarik gehiago", "status.show_original": "Show original", - "status.show_thread": "Erakutsi haria", "status.translate": "Translate", - "status.translated_from": "Translated from {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Ez eskuragarri", "status.unmute_conversation": "Desmututu elkarrizketa", "status.unpin": "Desfinkatu profiletik", @@ -538,7 +599,6 @@ "tabs_bar.home": "Hasiera", "tabs_bar.local_timeline": "Lokala", "tabs_bar.notifications": "Jakinarazpenak", - "tabs_bar.search": "Bilatu", "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", diff --git a/app/javascript/mastodon/locales/fa.json b/app/javascript/mastodon/locales/fa.json index fe6b6a780..9788de690 100644 --- a/app/javascript/mastodon/locales/fa.json +++ b/app/javascript/mastodon/locales/fa.json @@ -1,4 +1,17 @@ { + "about.blocks": "Moderated servers", + "about.contact": "Contact:", + "about.domain_blocks.comment": "Reason", + "about.domain_blocks.domain": "Domain", + "about.domain_blocks.preamble": "Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.", + "about.domain_blocks.severity": "Severity", + "about.domain_blocks.silenced.explanation": "You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.", + "about.domain_blocks.silenced.title": "Limited", + "about.domain_blocks.suspended.explanation": "No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.", + "about.domain_blocks.suspended.title": "Suspended", + "about.not_available": "This information has not been made available on this server.", + "about.powered_by": "Decentralized social media powered by {mastodon}", + "about.rules": "Server rules", "account.account_note_header": "یادداشت", "account.add_or_remove_from_list": "افزودن یا برداشتن از سیاههها", "account.badges.bot": "روبات", @@ -7,13 +20,16 @@ "account.block_domain": "مسدود کردن دامنهٔ {domain}", "account.blocked": "مسدود", "account.browse_more_on_origin_server": "مرور بیشتر روی نمایهٔ اصلی", - "account.cancel_follow_request": "لغو درخواست پیگیری", + "account.cancel_follow_request": "Withdraw follow request", "account.direct": "پیام مستقیم به @{name}", "account.disable_notifications": "آگاه کردن من هنگام فرستههای @{name} را متوقّف کن", "account.domain_blocked": "دامنه مسدود شد", "account.edit_profile": "ویرایش نمایه", "account.enable_notifications": "هنگام فرستههای @{name} مرا آگاه کن", "account.endorse": "معرّفی در نمایه", + "account.featured_tags.last_status_at": "Last post on {date}", + "account.featured_tags.last_status_never": "No posts", + "account.featured_tags.title": "{name}'s featured hashtags", "account.follow": "پیگیری", "account.followers": "پیگیرندگان", "account.followers.empty": "هنوز کسی این کاربر را پیگیری نمیکند.", @@ -23,7 +39,7 @@ "account.follows.empty": "این کاربر هنوز پیگیر کسی نیست.", "account.follows_you": "پی میگیردتان", "account.hide_reblogs": "نهفتن تقویتهای @{name}", - "account.joined": "پیوسته از {date}", + "account.joined_short": "Joined", "account.languages": "Change subscribed languages", "account.link_verified_on": "مالکیت این پیوند در {date} بررسی شد", "account.locked_info": "این حساب خصوصی است. صاحبش تصمیم میگیرد که چه کسی پیگیرش باشد.", @@ -63,12 +79,24 @@ "audio.hide": "Hide audio", "autosuggest_hashtag.per_week": "{count} در هفته", "boost_modal.combo": "دکمهٔ {combo} را بزنید تا دیگر این را نبینید", - "bundle_column_error.body": "هنگام بار کردن این مولفه، اشتباهی رخ داد.", + "bundle_column_error.copy_stacktrace": "Copy error report", + "bundle_column_error.error.body": "The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.", + "bundle_column_error.error.title": "Oh, no!", + "bundle_column_error.network.body": "There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.", + "bundle_column_error.network.title": "Network error", "bundle_column_error.retry": "تلاش دوباره", - "bundle_column_error.title": "خطای شبکه", + "bundle_column_error.return": "Go back home", + "bundle_column_error.routing.body": "The requested page could not be found. Are you sure the URL in the address bar is correct?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "بستن", "bundle_modal_error.message": "هنگام بار کردن این مولفه، اشتباهی رخ داد.", "bundle_modal_error.retry": "تلاش دوباره", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "About", "column.blocks": "کاربران مسدود شده", "column.bookmarks": "نشانکها", "column.community": "خط زمانی محلّی", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "مسدود کردن و گزارش", "confirmations.block.confirm": "مسدود کردن", "confirmations.block.message": "مطمئنید که میخواهید {name} را مسدود کنید؟", + "confirmations.cancel_follow_request.confirm": "Withdraw request", + "confirmations.cancel_follow_request.message": "Are you sure you want to withdraw your request to follow {name}?", "confirmations.delete.confirm": "حذف", "confirmations.delete.message": "آیا مطمئنید که میخواهید این فرسته را حذف کنید؟", "confirmations.delete_list.confirm": "حذف", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "علامتگذاری به عنوان خوانده شده", "conversation.open": "دیدن گفتگو", "conversation.with": "با {names}", + "copypaste.copied": "Copied", + "copypaste.copy": "Copy", "directory.federated": "از کارسازهای شناختهشده", "directory.local": "تنها از {domain}", "directory.new_arrivals": "تازهواردان", "directory.recently_active": "کاربران فعال اخیر", + "dismissable_banner.community_timeline": "These are the most recent public posts from people whose accounts are hosted by {domain}.", + "dismissable_banner.dismiss": "Dismiss", + "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", + "dismissable_banner.explore_statuses": "These posts from this and other servers in the decentralized network are gaining traction on this server right now.", + "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", + "dismissable_banner.public_timeline": "These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.", "embed.instructions": "برای جاسازی این فرسته در سایت خودتان، کد زیر را رونوشت کنید.", "embed.preview": "این گونه دیده خواهد شد:", "emoji_button.activity": "فعالیت", @@ -221,14 +259,14 @@ "follow_request.reject": "رد کنید", "follow_requests.unlocked_explanation": "با این که حسابتان قفل نیست، کارکنان {domain} فکر کردند که ممکن است بخواهید درخواستها از این حسابها را به صورت دستی بازبینی کنید.", "generic.saved": "ذخیره شده", - "getting_started.developers": "توسعهدهندگان", - "getting_started.directory": "شاخهٔ نمایه", + "getting_started.directory": "Directory", "getting_started.documentation": "مستندات", + "getting_started.free_software_notice": "Mastodon is free, open source software. You can view the source code, contribute or report issues at {repository}.", "getting_started.heading": "آغاز کنید", "getting_started.invite": "دعوت از دیگران", - "getting_started.open_source_notice": "ماستودون نرمافزاری آزاد است. میتوانید روی {github} در آن مشارکت کرده یا مشکلاتش را گزارش دهید.", "getting_started.privacy_policy": "Privacy Policy", "getting_started.security": "تنظیمات حساب", + "getting_started.what_is_mastodon": "About Mastodon", "hashtag.column_header.tag_mode.all": "و {additional}", "hashtag.column_header.tag_mode.any": "یا {additional}", "hashtag.column_header.tag_mode.none": "بدون {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "نمایش پاسخها", "home.hide_announcements": "نهفتن اعلامیهها", "home.show_announcements": "نمایش اعلامیهها", + "interaction_modal.description.favourite": "With an account on Mastodon, you can favourite this post to let the author know you appreciate it and save it for later.", + "interaction_modal.description.follow": "With an account on Mastodon, you can follow {name} to receive their posts in your home feed.", + "interaction_modal.description.reblog": "With an account on Mastodon, you can boost this post to share it with your own followers.", + "interaction_modal.description.reply": "With an account on Mastodon, you can respond to this post.", + "interaction_modal.on_another_server": "On a different server", + "interaction_modal.on_this_server": "On this server", + "interaction_modal.other_server_instructions": "Simply copy and paste this URL into the search bar of your favourite app or the web interface where you are signed in.", + "interaction_modal.preamble": "Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one.", + "interaction_modal.title.favourite": "Favourite {name}'s post", + "interaction_modal.title.follow": "Follow {name}", + "interaction_modal.title.reblog": "Boost {name}'s post", + "interaction_modal.title.reply": "Reply to {name}'s post", "intervals.full.days": "{number, plural, one {# روز} other {# روز}}", "intervals.full.hours": "{number, plural, one {# ساعت} other {# ساعت}}", "intervals.full.minutes": "{number, plural, one {# دقیقه} other {# دقیقه}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "مدت زمان", "mute_modal.hide_notifications": "نهفتن آگاهیها از این کاربر؟", "mute_modal.indefinite": "نامعلوم", - "navigation_bar.apps": "برنامههای تلفن همراه", + "navigation_bar.about": "About", + "navigation_bar.apps": "Get the app", "navigation_bar.blocks": "کاربران مسدود شده", "navigation_bar.bookmarks": "نشانکها", "navigation_bar.community_timeline": "خط زمانی محلّی", @@ -324,7 +375,7 @@ "navigation_bar.filters": "واژههای خموش", "navigation_bar.follow_requests": "درخواستهای پیگیری", "navigation_bar.follows_and_followers": "پیگرفتگان و پیگیرندگان", - "navigation_bar.info": "دربارهٔ این کارساز", + "navigation_bar.info": "About", "navigation_bar.keyboard_shortcuts": "میانبرها", "navigation_bar.lists": "سیاههها", "navigation_bar.logout": "خروج", @@ -333,7 +384,9 @@ "navigation_bar.pins": "فرستههای سنجاق شده", "navigation_bar.preferences": "ترجیحات", "navigation_bar.public_timeline": "خط زمانی همگانی", + "navigation_bar.search": "Search", "navigation_bar.security": "امنیت", + "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", "notification.admin.report": "{name} reported {target}", "notification.admin.sign_up": "{name} ثبت نام کرد", "notification.favourite": "{name} فرستهتان را پسندید", @@ -401,6 +454,8 @@ "privacy.public.short": "عمومی", "privacy.unlisted.long": "نمایان برای همه، ولی خارج از قابلیتهای کشف", "privacy.unlisted.short": "فهرست نشده", + "privacy_policy.last_updated": "Last updated {date}", + "privacy_policy.title": "Privacy Policy", "refresh": "نوسازی", "regeneration_indicator.label": "در حال بار شدن…", "regeneration_indicator.sublabel": "خوراک خانگیان دارد آماده میشود!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "جستوجوی محتوای فرستهها در این کارساز ماستودون به کار انداخته نشده است.", "search_results.title": "Search for {q}", "search_results.total": "{count, number} {count, plural, one {نتیجه} other {نتیجه}}", + "server_banner.about_active_users": "People using this server during the last 30 days (Monthly Active Users)", + "server_banner.active_users": "active users", + "server_banner.administered_by": "Administered by:", + "server_banner.introduction": "{domain} is part of the decentralized social network powered by {mastodon}.", + "server_banner.learn_more": "Learn more", + "server_banner.server_stats": "Server stats:", "sign_in_banner.create_account": "Create account", "sign_in_banner.sign_in": "Sign in", "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "هنوز هیچ کسی این فرسته را تقویت نکرده است. وقتی کسی چنین کاری کند، اینجا نمایش داده خواهد شد.", "status.redraft": "حذف و بازنویسی", "status.remove_bookmark": "برداشتن نشانک", + "status.replied_to": "Replied to {name}", "status.reply": "پاسخ", "status.replyAll": "پاسخ به رشته", "status.report": "گزارش @{name}", @@ -523,9 +585,8 @@ "status.show_more": "نمایش بیشتر", "status.show_more_all": "نمایش بیشتر همه", "status.show_original": "Show original", - "status.show_thread": "نمایش رشته", "status.translate": "Translate", - "status.translated_from": "Translated from {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "ناموجود", "status.unmute_conversation": "رفع خموشی گفتوگو", "status.unpin": "برداشتن سنجاق از نمایه", @@ -538,7 +599,6 @@ "tabs_bar.home": "خانه", "tabs_bar.local_timeline": "محلّی", "tabs_bar.notifications": "آگاهیها", - "tabs_bar.search": "جستوجو", "time_remaining.days": "{number, plural, one {# روز} other {# روز}} باقی مانده", "time_remaining.hours": "{number, plural, one {# ساعت} other {# ساعت}} باقی مانده", "time_remaining.minutes": "{number, plural, one {# دقیقه} other {# دقیقه}} باقی مانده", diff --git a/app/javascript/mastodon/locales/fi.json b/app/javascript/mastodon/locales/fi.json index 0e04c7cd6..bd7b7f8ac 100644 --- a/app/javascript/mastodon/locales/fi.json +++ b/app/javascript/mastodon/locales/fi.json @@ -1,4 +1,17 @@ { + "about.blocks": "Moderoidut palvelimet", + "about.contact": "Yhteystiedot:", + "about.domain_blocks.comment": "Syy", + "about.domain_blocks.domain": "Verkkotunnus", + "about.domain_blocks.preamble": "Mastodonin avulla voit yleensä tarkastella sisältöä ja olla vuorovaikutuksessa käyttäjien kanssa millä tahansa muulla palvelimella fediversessä. Nämä ovat poikkeuksia, jotka on tehty tälle palvelimelle.", + "about.domain_blocks.severity": "Vakavuus", + "about.domain_blocks.silenced.explanation": "Et yleensä näe profiileja ja sisältöä tältä palvelimelta, ellet nimenomaisesti etsi tai valitse sitä seuraamalla.", + "about.domain_blocks.silenced.title": "Rajoitettu", + "about.domain_blocks.suspended.explanation": "Tämän palvelimen tietoja ei käsitellä, tallenneta tai vaihdeta, mikä tekee käyttäjän kanssa vuorovaikutuksen tai yhteydenpidon mahdottomaksi tällä palvelimella.", + "about.domain_blocks.suspended.title": "Keskeytetty", + "about.not_available": "Näitä tietoja ei ole julkaistu tällä palvelimella.", + "about.powered_by": "Hajautettu sosiaalinen media, tarjoaa {mastodon}", + "about.rules": "Palvelimen säännöt", "account.account_note_header": "Muistiinpano", "account.add_or_remove_from_list": "Lisää tai poista listoilta", "account.badges.bot": "Botti", @@ -7,13 +20,16 @@ "account.block_domain": "Piilota kaikki sisältö verkkotunnuksesta {domain}", "account.blocked": "Estetty", "account.browse_more_on_origin_server": "Selaile lisää alkuperäisellä palvelimella", - "account.cancel_follow_request": "Peruuta seurauspyyntö", + "account.cancel_follow_request": "Peruuta seurantapyyntö", "account.direct": "Pikaviesti käyttäjälle @{name}", "account.disable_notifications": "Lopeta @{name}:n julkaisuista ilmoittaminen", "account.domain_blocked": "Verkko-osoite piilotettu", "account.edit_profile": "Muokkaa profiilia", "account.enable_notifications": "Ilmoita @{name}:n julkaisuista", "account.endorse": "Suosittele profiilissasi", + "account.featured_tags.last_status_at": "Viimeisin viesti {date}", + "account.featured_tags.last_status_never": "Ei viestejä", + "account.featured_tags.title": "{name} esillä olevat hashtagit", "account.follow": "Seuraa", "account.followers": "Seuraajat", "account.followers.empty": "Kukaan ei seuraa tätä käyttäjää vielä.", @@ -23,8 +39,8 @@ "account.follows.empty": "Tämä käyttäjä ei vielä seuraa ketään.", "account.follows_you": "Seuraa sinua", "account.hide_reblogs": "Piilota buustaukset käyttäjältä @{name}", - "account.joined": "Liittynyt {date}", - "account.languages": "Change subscribed languages", + "account.joined_short": "Joined", + "account.languages": "Vaihda tilattuja kieliä", "account.link_verified_on": "Tämän linkin omistaja tarkistettiin {date}", "account.locked_info": "Tämän tilin yksityisyyden tila on asetettu lukituksi. Omistaja arvioi manuaalisesti, kuka voi seurata niitä.", "account.media": "Media", @@ -63,12 +79,24 @@ "audio.hide": "Piilota ääni", "autosuggest_hashtag.per_week": "{count} viikossa", "boost_modal.combo": "Ensi kerralla voit ohittaa tämän painamalla {combo}", - "bundle_column_error.body": "Jokin meni vikaan komponenttia ladattaessa.", + "bundle_column_error.copy_stacktrace": "Kopioi virheraportti", + "bundle_column_error.error.body": "Pyydettyä sivua ei voitu hahmontaa. Se voi johtua virheestä koodissamme tai selaimen yhteensopivuudessa.", + "bundle_column_error.error.title": "Voi ei!", + "bundle_column_error.network.body": "Sivun lataamisessa tapahtui virhe. Tämä voi johtua tilapäisestä Internet-yhteyden tai tämän palvelimen ongelmasta.", + "bundle_column_error.network.title": "Verkkovirhe", "bundle_column_error.retry": "Yritä uudestaan", - "bundle_column_error.title": "Verkkovirhe", + "bundle_column_error.return": "Palaa takaisin kotiin", + "bundle_column_error.routing.body": "Pyydettyä sivua ei löytynyt. Oletko varma, että osoitepalkin URL-osoite on oikein?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Sulje", "bundle_modal_error.message": "Jokin meni vikaan komponenttia ladattaessa.", "bundle_modal_error.retry": "Yritä uudelleen", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "Tietoja", "column.blocks": "Estetyt käyttäjät", "column.bookmarks": "Kirjanmerkit", "column.community": "Paikallinen aikajana", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "Estä ja raportoi", "confirmations.block.confirm": "Estä", "confirmations.block.message": "Haluatko varmasti estää käyttäjän {name}?", + "confirmations.cancel_follow_request.confirm": "Peruuta pyyntö", + "confirmations.cancel_follow_request.message": "Haluatko varmasti peruuttaa pyyntösi seurata käyttäjää {name}?", "confirmations.delete.confirm": "Poista", "confirmations.delete.message": "Haluatko varmasti poistaa tämän julkaisun?", "confirmations.delete_list.confirm": "Poista", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Merkitse luetuksi", "conversation.open": "Näytä keskustelu", "conversation.with": "{names} kanssa", + "copypaste.copied": "Kopioitu", + "copypaste.copy": "Kopioi", "directory.federated": "Koko tunnettu fediverse", "directory.local": "Vain palvelimelta {domain}", "directory.new_arrivals": "Äskettäin saapuneet", "directory.recently_active": "Hiljattain aktiiviset", + "dismissable_banner.community_timeline": "Nämä ovat uusimmat julkiset viestit ihmisiltä, joiden tilejä isännöi {domain}.", + "dismissable_banner.dismiss": "Hylkää", + "dismissable_banner.explore_links": "Näistä uutisista puhuvat ihmiset juuri nyt tällä ja muilla hajautetun verkon palvelimilla.", + "dismissable_banner.explore_statuses": "Nämä viestit juuri nyt tältä ja muilta hajautetun verkon palvelimilta ovat saamassa vetoa tältä palvelimelta.", + "dismissable_banner.explore_tags": "Nämä hashtagit juuri nyt ovat saamassa vetovoimaa tällä ja muilla hajautetun verkon palvelimilla olevien ihmisten keskuudessa.", + "dismissable_banner.public_timeline": "Nämä ovat viimeisimpiä julkisia viestejä ihmisiltä, jotka ovat tällä ja muilla hajautetun verkon palvelimilla, joista tämä palvelin tietää.", "embed.instructions": "Upota julkaisu verkkosivullesi kopioimalla alla oleva koodi.", "embed.preview": "Se tulee näyttämään tältä:", "emoji_button.activity": "Aktiviteetit", @@ -221,14 +259,14 @@ "follow_request.reject": "Hylkää", "follow_requests.unlocked_explanation": "Vaikka tiliäsi ei ole lukittu, {domain}:n ylläpitäjien mielestä saatat haluta tarkistaa nämä seurauspyynnöt manuaalisesti.", "generic.saved": "Tallennettu", - "getting_started.developers": "Kehittäjät", - "getting_started.directory": "Profiilihakemisto", + "getting_started.directory": "Hakemisto", "getting_started.documentation": "Käyttöohjeet", + "getting_started.free_software_notice": "Mastodon on ilmainen, avoimen lähdekoodin ohjelmisto. Voit tarkastella lähdekoodia, osallistua tai raportoida ongelmista osoitteessa {repository}.", "getting_started.heading": "Näin pääset alkuun", "getting_started.invite": "Kutsu ihmisiä", - "getting_started.open_source_notice": "Mastodon on avoimen lähdekoodin ohjelma. Voit avustaa tai raportoida ongelmia GitHubissa: {github}.", - "getting_started.privacy_policy": "Privacy Policy", + "getting_started.privacy_policy": "Tietosuojakäytäntö", "getting_started.security": "Tiliasetukset", + "getting_started.what_is_mastodon": "Tietoja Mastodonista", "hashtag.column_header.tag_mode.all": "ja {additional}", "hashtag.column_header.tag_mode.any": "tai {additional}", "hashtag.column_header.tag_mode.none": "ilman {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Näytä vastaukset", "home.hide_announcements": "Piilota ilmoitukset", "home.show_announcements": "Näytä ilmoitukset", + "interaction_modal.description.favourite": "Kun sinulla on tili Mastodonissa, voit lisätä tämän viestin suosikkeihin ja tallentaa sen myöhempää käyttöä varten.", + "interaction_modal.description.follow": "Kun sinulla on tili Mastodonissa, voit seurata {name} saadaksesi hänen viestejä sinun kotisyötteeseen.", + "interaction_modal.description.reblog": "Kun sinulla on tili Mastodonissa, voit tehostaa viestiä ja jakaa sen omien seuraajiesi kanssa.", + "interaction_modal.description.reply": "Kun sinulla on tili Mastodonissa, voit vastata tähän viestiin.", + "interaction_modal.on_another_server": "Toisella palvelimella", + "interaction_modal.on_this_server": "Tällä palvelimella", + "interaction_modal.other_server_instructions": "Yksinkertaisesti kopioi ja liitä tämä URL-osoite suosikki sovelluksen tai web-käyttöliittymän hakupalkkiin, jossa olet kirjautunut sisään.", + "interaction_modal.preamble": "Koska Mastodon on hajautettu, voit käyttää toisen Mastodon-palvelimen tai yhteensopivan alustan ylläpitämää tiliäsi, jos sinulla ei ole tiliä tällä palvelimella.", + "interaction_modal.title.favourite": "Suosikin {name} viesti", + "interaction_modal.title.follow": "Seuraa {name}", + "interaction_modal.title.reblog": "Tehosta {name} viestiä", + "interaction_modal.title.reply": "Vastaa {name} viestiin", "intervals.full.days": "{number, plural, one {# päivä} other {# päivää}}", "intervals.full.hours": "{number, plural, one {# tunti} other {# tuntia}}", "intervals.full.minutes": "{number, plural, one {# minuutti} other {# minuuttia}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Kesto", "mute_modal.hide_notifications": "Piilota tältä käyttäjältä tulevat ilmoitukset?", "mute_modal.indefinite": "Ikuisesti", - "navigation_bar.apps": "Mobiilisovellukset", + "navigation_bar.about": "Tietoja", + "navigation_bar.apps": "Hanki sovellus", "navigation_bar.blocks": "Estetyt käyttäjät", "navigation_bar.bookmarks": "Kirjanmerkit", "navigation_bar.community_timeline": "Paikallinen aikajana", @@ -324,7 +375,7 @@ "navigation_bar.filters": "Mykistetyt sanat", "navigation_bar.follow_requests": "Seuraamispyynnöt", "navigation_bar.follows_and_followers": "Seurattavat ja seuraajat", - "navigation_bar.info": "Tietoa tästä palvelimesta", + "navigation_bar.info": "Tietoja", "navigation_bar.keyboard_shortcuts": "Pikanäppäimet", "navigation_bar.lists": "Listat", "navigation_bar.logout": "Kirjaudu ulos", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Kiinnitetyt viestit", "navigation_bar.preferences": "Asetukset", "navigation_bar.public_timeline": "Yleinen aikajana", + "navigation_bar.search": "Search", "navigation_bar.security": "Turvallisuus", + "not_signed_in_indicator.not_signed_in": "Sinun täytyy kirjautua sisään päästäksesi käsiksi tähän resurssiin.", "notification.admin.report": "{name} ilmoitti {target}", "notification.admin.sign_up": "{name} rekisteröitynyt", "notification.favourite": "{name} tykkäsi viestistäsi", @@ -401,6 +454,8 @@ "privacy.public.short": "Julkinen", "privacy.unlisted.long": "Näkyvissä kaikille, mutta jättäen pois hakemisen mahdollisuus", "privacy.unlisted.short": "Listaamaton julkinen", + "privacy_policy.last_updated": "Viimeksi päivitetty {date}", + "privacy_policy.title": "Tietosuojakäytäntö", "refresh": "Päivitä", "regeneration_indicator.label": "Ladataan…", "regeneration_indicator.sublabel": "Kotinäkymääsi valmistellaan!", @@ -471,11 +526,17 @@ "search_results.nothing_found": "Näille hakusanoille ei löytynyt mitään", "search_results.statuses": "Viestit", "search_results.statuses_fts_disabled": "Viestien haku sisällön perusteella ei ole käytössä tällä Mastodon-palvelimella.", - "search_results.title": "Search for {q}", + "search_results.title": "Etsi {q}", "search_results.total": "{count, number} {count, plural, one {tulos} other {tulokset}}", - "sign_in_banner.create_account": "Create account", - "sign_in_banner.sign_in": "Sign in", - "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", + "server_banner.about_active_users": "Palvelinta käyttäneet ihmiset viimeisen 30 päivän aikana (kuukauden aktiiviset käyttäjät)", + "server_banner.active_users": "aktiiviset käyttäjät", + "server_banner.administered_by": "Ylläpitäjä:", + "server_banner.introduction": "{domain} on osa hajautettua sosiaalista verkostoa, jonka tarjoaa {mastodon}.", + "server_banner.learn_more": "Lue lisää", + "server_banner.server_stats": "Palvelimen tilastot:", + "sign_in_banner.create_account": "Luo tili", + "sign_in_banner.sign_in": "Kirjaudu sisään", + "sign_in_banner.text": "Kirjaudu sisään seurataksesi profiileja tai hashtageja, lisätäksesi suosikkeihin, jakaaksesi viestejä ja vastataksesi niihin tai ollaksesi vuorovaikutuksessa tililläsi toisella palvelimella.", "status.admin_account": "Avaa moderaattorinäkymä tilistä @{name}", "status.admin_status": "Avaa julkaisu moderointinäkymässä", "status.block": "Estä @{name}", @@ -512,6 +573,7 @@ "status.reblogs.empty": "Kukaan ei ole vielä buustannut tätä viestiä. Kun joku tekee niin, näkyy kyseinen henkilö tässä.", "status.redraft": "Poista ja palauta muokattavaksi", "status.remove_bookmark": "Poista kirjanmerkki", + "status.replied_to": "Replied to {name}", "status.reply": "Vastaa", "status.replyAll": "Vastaa ketjuun", "status.report": "Raportoi @{name}", @@ -522,23 +584,21 @@ "status.show_less_all": "Näytä vähemmän kaikista", "status.show_more": "Näytä lisää", "status.show_more_all": "Näytä lisää kaikista", - "status.show_original": "Show original", - "status.show_thread": "Näytä ketju", - "status.translate": "Translate", - "status.translated_from": "Translated from {lang}", + "status.show_original": "Näytä alkuperäinen", + "status.translate": "Käännä", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Ei saatavilla", "status.unmute_conversation": "Poista keskustelun mykistys", "status.unpin": "Irrota profiilista", - "subscribed_languages.lead": "Only posts in selected languages will appear on your home and list timelines after the change. Select none to receive posts in all languages.", - "subscribed_languages.save": "Save changes", - "subscribed_languages.target": "Change subscribed languages for {target}", + "subscribed_languages.lead": "Vain valituilla kielillä julkaistut viestit näkyvät etusivullasi ja aikajanalla muutoksen jälkeen. Valitse ei mitään, jos haluat vastaanottaa viestejä kaikilla kielillä.", + "subscribed_languages.save": "Tallenna muutokset", + "subscribed_languages.target": "Vaihda tilatut kielet {target}", "suggestions.dismiss": "Hylkää ehdotus", "suggestions.header": "Saatat olla kiinnostunut myös…", "tabs_bar.federated_timeline": "Yleinen", "tabs_bar.home": "Koti", "tabs_bar.local_timeline": "Paikallinen", "tabs_bar.notifications": "Ilmoitukset", - "tabs_bar.search": "Hae", "time_remaining.days": "{number, plural, one {# päivä} other {# päivää}} jäljellä", "time_remaining.hours": "{number, plural, one {# tunti} other {# tuntia}} jäljellä", "time_remaining.minutes": "{number, plural, one {# minuutti} other {# minuuttia}} jäljellä", diff --git a/app/javascript/mastodon/locales/fr.json b/app/javascript/mastodon/locales/fr.json index d8886d138..d6de0df73 100644 --- a/app/javascript/mastodon/locales/fr.json +++ b/app/javascript/mastodon/locales/fr.json @@ -1,4 +1,17 @@ { + "about.blocks": "Serveurs modérés", + "about.contact": "Contact :", + "about.domain_blocks.comment": "Motif :", + "about.domain_blocks.domain": "Domaine", + "about.domain_blocks.preamble": "Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.", + "about.domain_blocks.severity": "Severity", + "about.domain_blocks.silenced.explanation": "You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.", + "about.domain_blocks.silenced.title": "Limited", + "about.domain_blocks.suspended.explanation": "No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.", + "about.domain_blocks.suspended.title": "Suspendu", + "about.not_available": "This information has not been made available on this server.", + "about.powered_by": "Réseau social décentralisé propulsé par {mastodon}", + "about.rules": "Règles du serveur", "account.account_note_header": "Note", "account.add_or_remove_from_list": "Ajouter ou retirer des listes", "account.badges.bot": "Bot", @@ -7,13 +20,16 @@ "account.block_domain": "Bloquer le domaine {domain}", "account.blocked": "Bloqué·e", "account.browse_more_on_origin_server": "Parcourir davantage sur le profil original", - "account.cancel_follow_request": "Annuler la demande de suivi", + "account.cancel_follow_request": "Retirer la demande d’abonnement", "account.direct": "Envoyer un message direct à @{name}", "account.disable_notifications": "Ne plus me notifier quand @{name} publie quelque chose", "account.domain_blocked": "Domaine bloqué", "account.edit_profile": "Modifier le profil", "account.enable_notifications": "Me notifier quand @{name} publie quelque chose", "account.endorse": "Recommander sur votre profil", + "account.featured_tags.last_status_at": "Dernier message le {date}", + "account.featured_tags.last_status_never": "Aucun message", + "account.featured_tags.title": "Les hashtags en vedette de {name}", "account.follow": "Suivre", "account.followers": "Abonné·e·s", "account.followers.empty": "Personne ne suit cet·te utilisateur·rice pour l’instant.", @@ -23,7 +39,7 @@ "account.follows.empty": "Cet·te utilisateur·rice ne suit personne pour l’instant.", "account.follows_you": "Vous suit", "account.hide_reblogs": "Masquer les partages de @{name}", - "account.joined": "Ici depuis {date}", + "account.joined_short": "Joined", "account.languages": "Changer les langues abonnées", "account.link_verified_on": "La propriété de ce lien a été vérifiée le {date}", "account.locked_info": "Ce compte est privé. Son ou sa propriétaire approuve manuellement qui peut le suivre.", @@ -63,12 +79,24 @@ "audio.hide": "Masquer l'audio", "autosuggest_hashtag.per_week": "{count} par semaine", "boost_modal.combo": "Vous pouvez appuyer sur {combo} pour passer ceci la prochaine fois", - "bundle_column_error.body": "Une erreur s’est produite lors du chargement de ce composant.", + "bundle_column_error.copy_stacktrace": "Copy error report", + "bundle_column_error.error.body": "The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.", + "bundle_column_error.error.title": "Oh non !", + "bundle_column_error.network.body": "There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.", + "bundle_column_error.network.title": "Erreur réseau", "bundle_column_error.retry": "Réessayer", - "bundle_column_error.title": "Erreur réseau", + "bundle_column_error.return": "Go back home", + "bundle_column_error.routing.body": "La page demandée est introuvable. Êtes-vous sûr que l’URL dans la barre d’adresse est correcte ?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Fermer", "bundle_modal_error.message": "Une erreur s’est produite lors du chargement de ce composant.", "bundle_modal_error.retry": "Réessayer", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "À propos", "column.blocks": "Comptes bloqués", "column.bookmarks": "Marque-pages", "column.community": "Fil public local", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "Bloquer et signaler", "confirmations.block.confirm": "Bloquer", "confirmations.block.message": "Voulez-vous vraiment bloquer {name} ?", + "confirmations.cancel_follow_request.confirm": "Withdraw request", + "confirmations.cancel_follow_request.message": "Are you sure you want to withdraw your request to follow {name}?", "confirmations.delete.confirm": "Supprimer", "confirmations.delete.message": "Voulez-vous vraiment supprimer ce message ?", "confirmations.delete_list.confirm": "Supprimer", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Marquer comme lu", "conversation.open": "Afficher la conversation", "conversation.with": "Avec {names}", + "copypaste.copied": "Copié", + "copypaste.copy": "Copier", "directory.federated": "Du fédiverse connu", "directory.local": "De {domain} seulement", "directory.new_arrivals": "Inscrit·e·s récemment", "directory.recently_active": "Actif·ve·s récemment", + "dismissable_banner.community_timeline": "Voici les messages publics les plus récents des personnes dont les comptes sont hébergés par {domain}.", + "dismissable_banner.dismiss": "Dismiss", + "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", + "dismissable_banner.explore_statuses": "These posts from this and other servers in the decentralized network are gaining traction on this server right now.", + "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", + "dismissable_banner.public_timeline": "These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.", "embed.instructions": "Intégrez ce message à votre site en copiant le code ci-dessous.", "embed.preview": "Il apparaîtra comme cela :", "emoji_button.activity": "Activités", @@ -203,17 +241,17 @@ "filter_modal.added.expired_explanation": "Cette catégorie de filtre a expiré, vous devrez modifier la date d'expiration pour qu'elle soit appliquée.", "filter_modal.added.expired_title": "Filtre expiré !", "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.", - "filter_modal.added.review_and_configure_title": "Filter settings", - "filter_modal.added.settings_link": "settings page", - "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.", - "filter_modal.added.title": "Filter added!", - "filter_modal.select_filter.context_mismatch": "does not apply to this context", - "filter_modal.select_filter.expired": "expired", - "filter_modal.select_filter.prompt_new": "New category: {name}", - "filter_modal.select_filter.search": "Search or create", - "filter_modal.select_filter.subtitle": "Use an existing category or create a new one", - "filter_modal.select_filter.title": "Filter this post", - "filter_modal.title.status": "Filter a post", + "filter_modal.added.review_and_configure_title": "Paramètres du filtre", + "filter_modal.added.settings_link": "page des paramètres", + "filter_modal.added.short_explanation": "Ce message a été ajouté à la catégorie de filtre suivante : {title}.", + "filter_modal.added.title": "Filtre ajouté !", + "filter_modal.select_filter.context_mismatch": "ne s’applique pas à ce contexte", + "filter_modal.select_filter.expired": "a expiré", + "filter_modal.select_filter.prompt_new": "Nouvelle catégorie : {name}", + "filter_modal.select_filter.search": "Rechercher ou créer", + "filter_modal.select_filter.subtitle": "Utilisez une catégorie existante ou en créer une nouvelle", + "filter_modal.select_filter.title": "Filtrer ce message", + "filter_modal.title.status": "Filtrer un message", "follow_recommendations.done": "Terminé", "follow_recommendations.heading": "Suivez les personnes dont vous aimeriez voir les messages ! Voici quelques suggestions.", "follow_recommendations.lead": "Les messages des personnes que vous suivez apparaîtront par ordre chronologique sur votre fil d'accueil. Ne craignez pas de faire des erreurs, vous pouvez arrêter de suivre les gens aussi facilement à tout moment !", @@ -221,14 +259,14 @@ "follow_request.reject": "Rejeter", "follow_requests.unlocked_explanation": "Même si votre compte n’est pas privé, l’équipe de {domain} a pensé que vous pourriez vouloir consulter manuellement les demandes de suivi de ces comptes.", "generic.saved": "Sauvegardé", - "getting_started.developers": "Développeur·euse·s", - "getting_started.directory": "Annuaire des profils", + "getting_started.directory": "Annuaire", "getting_started.documentation": "Documentation", + "getting_started.free_software_notice": "Mastodon est un logiciel libre et ouvert. Vous pouvez consulter le code source, contribuer ou soumettre des rapports de bogues sur {repository}.", "getting_started.heading": "Pour commencer", "getting_started.invite": "Inviter des gens", - "getting_started.open_source_notice": "Mastodon est un logiciel libre. Vous pouvez contribuer ou faire des rapports de bogues via {github} sur GitHub.", - "getting_started.privacy_policy": "Privacy Policy", + "getting_started.privacy_policy": "Politique de confidentialité", "getting_started.security": "Sécurité", + "getting_started.what_is_mastodon": "À propos de Mastodon", "hashtag.column_header.tag_mode.all": "et {additional}", "hashtag.column_header.tag_mode.any": "ou {additional}", "hashtag.column_header.tag_mode.none": "sans {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Afficher les réponses", "home.hide_announcements": "Masquer les annonces", "home.show_announcements": "Afficher les annonces", + "interaction_modal.description.favourite": "With an account on Mastodon, you can favourite this post to let the author know you appreciate it and save it for later.", + "interaction_modal.description.follow": "With an account on Mastodon, you can follow {name} to receive their posts in your home feed.", + "interaction_modal.description.reblog": "Avec un compte sur Mastodon, vous pouvez booster ce message pour le partager avec vos propres abonné·e·s.", + "interaction_modal.description.reply": "Avec un compte sur Mastodon, vous pouvez répondre à ce message.", + "interaction_modal.on_another_server": "Sur un autre serveur", + "interaction_modal.on_this_server": "Sur ce serveur", + "interaction_modal.other_server_instructions": "Copiez et collez simplement cette URL dans la barre de recherche de votre application préférée ou dans l’interface web où vous êtes connecté.", + "interaction_modal.preamble": "Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one.", + "interaction_modal.title.favourite": "Favourite {name}'s post", + "interaction_modal.title.follow": "Suivre {name}", + "interaction_modal.title.reblog": "Partager la publication de {name}", + "interaction_modal.title.reply": "Répondre au message de {name}", "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}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Durée", "mute_modal.hide_notifications": "Masquer les notifications de cette personne ?", "mute_modal.indefinite": "Indéfinie", - "navigation_bar.apps": "Applications mobiles", + "navigation_bar.about": "À propos", + "navigation_bar.apps": "Télécharger l’application", "navigation_bar.blocks": "Comptes bloqués", "navigation_bar.bookmarks": "Marque-pages", "navigation_bar.community_timeline": "Fil public local", @@ -324,7 +375,7 @@ "navigation_bar.filters": "Mots masqués", "navigation_bar.follow_requests": "Demandes d’abonnement", "navigation_bar.follows_and_followers": "Abonnements et abonné⋅e·s", - "navigation_bar.info": "À propos de ce serveur", + "navigation_bar.info": "À propos", "navigation_bar.keyboard_shortcuts": "Raccourcis clavier", "navigation_bar.lists": "Listes", "navigation_bar.logout": "Déconnexion", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Messages épinglés", "navigation_bar.preferences": "Préférences", "navigation_bar.public_timeline": "Fil public global", + "navigation_bar.search": "Search", "navigation_bar.security": "Sécurité", + "not_signed_in_indicator.not_signed_in": "Vous devez vous connecter pour accéder à cette ressource.", "notification.admin.report": "{name} a signalé {target}", "notification.admin.sign_up": "{name} s'est inscrit·e", "notification.favourite": "{name} a ajouté le message à ses favoris", @@ -401,6 +454,8 @@ "privacy.public.short": "Public", "privacy.unlisted.long": "Visible pour tous, mais sans fonctionnalités de découverte", "privacy.unlisted.short": "Non listé", + "privacy_policy.last_updated": "Dernière mise à jour {date}", + "privacy_policy.title": "Politique de confidentialité", "refresh": "Actualiser", "regeneration_indicator.label": "Chargement…", "regeneration_indicator.sublabel": "Votre fil principal est en cours de préparation !", @@ -471,10 +526,16 @@ "search_results.nothing_found": "Aucun résultat avec ces mots-clefs", "search_results.statuses": "Messages", "search_results.statuses_fts_disabled": "La recherche de messages par leur contenu n'est pas activée sur ce serveur Mastodon.", - "search_results.title": "Search for {q}", + "search_results.title": "Rechercher {q}", "search_results.total": "{count, number} {count, plural, one {résultat} other {résultats}}", - "sign_in_banner.create_account": "Create account", - "sign_in_banner.sign_in": "Sign in", + "server_banner.about_active_users": "Personnes utilisant ce serveur au cours des 30 derniers jours (Utilisateur·rice·s Actifs·ives Mensuellement)", + "server_banner.active_users": "Utilisateur·rice·s actif·ve·s", + "server_banner.administered_by": "Administré par :", + "server_banner.introduction": "{domain} fait partie du réseau social décentralisé propulsé par {mastodon}.", + "server_banner.learn_more": "En savoir plus", + "server_banner.server_stats": "Statistiques du serveur :", + "sign_in_banner.create_account": "Créer un compte", + "sign_in_banner.sign_in": "Se connecter", "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", "status.admin_account": "Ouvrir l’interface de modération pour @{name}", "status.admin_status": "Ouvrir ce message dans l’interface de modération", @@ -491,7 +552,7 @@ "status.edited_x_times": "Edité {count, plural, one {{count} fois} other {{count} fois}}", "status.embed": "Intégrer", "status.favourite": "Ajouter aux favoris", - "status.filter": "Filter this post", + "status.filter": "Filtrer ce message", "status.filtered": "Filtré", "status.hide": "Cacher le pouet", "status.history.created": "créé par {name} {date}", @@ -512,6 +573,7 @@ "status.reblogs.empty": "Personne n’a encore partagé ce message. Lorsque quelqu’un le fera, il apparaîtra ici.", "status.redraft": "Supprimer et réécrire", "status.remove_bookmark": "Retirer des marque-pages", + "status.replied_to": "Replied to {name}", "status.reply": "Répondre", "status.replyAll": "Répondre au fil", "status.report": "Signaler @{name}", @@ -522,23 +584,21 @@ "status.show_less_all": "Tout replier", "status.show_more": "Déplier", "status.show_more_all": "Tout déplier", - "status.show_original": "Show original", - "status.show_thread": "Montrer le fil", - "status.translate": "Translate", - "status.translated_from": "Translated from {lang}", + "status.show_original": "Afficher l’original", + "status.translate": "Traduire", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Indisponible", "status.unmute_conversation": "Ne plus masquer la conversation", "status.unpin": "Retirer du profil", - "subscribed_languages.lead": "Only posts in selected languages will appear on your home and list timelines after the change. Select none to receive posts in all languages.", - "subscribed_languages.save": "Save changes", - "subscribed_languages.target": "Change subscribed languages for {target}", + "subscribed_languages.lead": "Seuls les messages dans les langues sélectionnées apparaîtront sur votre fil principal et vos listes de fils après le changement. Sélectionnez aucune pour recevoir les messages dans toutes les langues.", + "subscribed_languages.save": "Enregistrer les modifications", + "subscribed_languages.target": "Changer les langues abonnées pour {target}", "suggestions.dismiss": "Rejeter la suggestion", "suggestions.header": "Vous pourriez être intéressé·e par…", "tabs_bar.federated_timeline": "Fil public global", "tabs_bar.home": "Accueil", "tabs_bar.local_timeline": "Fil public local", "tabs_bar.notifications": "Notifications", - "tabs_bar.search": "Chercher", "time_remaining.days": "{number, plural, one {# jour restant} other {# jours restants}}", "time_remaining.hours": "{number, plural, one {# heure restante} other {# heures restantes}}", "time_remaining.minutes": "{number, plural, one {# minute restante} other {# minutes restantes}}", diff --git a/app/javascript/mastodon/locales/fy.json b/app/javascript/mastodon/locales/fy.json index 2973419a9..84fe8f1c9 100644 --- a/app/javascript/mastodon/locales/fy.json +++ b/app/javascript/mastodon/locales/fy.json @@ -1,4 +1,17 @@ { + "about.blocks": "Moderated servers", + "about.contact": "Contact:", + "about.domain_blocks.comment": "Reason", + "about.domain_blocks.domain": "Domain", + "about.domain_blocks.preamble": "Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.", + "about.domain_blocks.severity": "Severity", + "about.domain_blocks.silenced.explanation": "You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.", + "about.domain_blocks.silenced.title": "Limited", + "about.domain_blocks.suspended.explanation": "No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.", + "about.domain_blocks.suspended.title": "Suspended", + "about.not_available": "This information has not been made available on this server.", + "about.powered_by": "Decentralized social media powered by {mastodon}", + "about.rules": "Server rules", "account.account_note_header": "Note", "account.add_or_remove_from_list": "Add or Remove from lists", "account.badges.bot": "Bot", @@ -7,13 +20,16 @@ "account.block_domain": "Block domain {domain}", "account.blocked": "Blocked", "account.browse_more_on_origin_server": "Browse more on the original profile", - "account.cancel_follow_request": "Cancel follow request", + "account.cancel_follow_request": "Withdraw follow request", "account.direct": "Direct message @{name}", "account.disable_notifications": "Stop notifying me when @{name} posts", "account.domain_blocked": "Domein blokkearre", "account.edit_profile": "Profyl oanpasse", "account.enable_notifications": "Notify me when @{name} posts", "account.endorse": "Feature on profile", + "account.featured_tags.last_status_at": "Last post on {date}", + "account.featured_tags.last_status_never": "No posts", + "account.featured_tags.title": "{name}'s featured hashtags", "account.follow": "Folgje", "account.followers": "Folgers", "account.followers.empty": "No one follows this user yet.", @@ -23,7 +39,7 @@ "account.follows.empty": "This user doesn't follow anyone yet.", "account.follows_you": "Folget dy", "account.hide_reblogs": "Hide boosts from @{name}", - "account.joined": "Registrearre op {date}", + "account.joined_short": "Joined", "account.languages": "Change subscribed languages", "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.", @@ -63,12 +79,24 @@ "audio.hide": "Hide audio", "autosuggest_hashtag.per_week": "{count} per week", "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.copy_stacktrace": "Copy error report", + "bundle_column_error.error.body": "The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.", + "bundle_column_error.error.title": "Oh, no!", + "bundle_column_error.network.body": "There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.", + "bundle_column_error.network.title": "Network error", "bundle_column_error.retry": "Try again", - "bundle_column_error.title": "Network error", + "bundle_column_error.return": "Go back home", + "bundle_column_error.routing.body": "The requested page could not be found. Are you sure the URL in the address bar is correct?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Slute", "bundle_modal_error.message": "Something went wrong while loading this component.", "bundle_modal_error.retry": "Opnij probearje", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "About", "column.blocks": "Blokkearre brûkers", "column.bookmarks": "Blêdwizers", "column.community": "Local timeline", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "Blokkearre & Oanjaan", "confirmations.block.confirm": "Blokkearre", "confirmations.block.message": "Wolle jo {name} werklik blokkearre?", + "confirmations.cancel_follow_request.confirm": "Withdraw request", + "confirmations.cancel_follow_request.message": "Are you sure you want to withdraw your request to follow {name}?", "confirmations.delete.confirm": "Fuortsmite", "confirmations.delete.message": "Wolle jo dit berjocht werklik fuortsmite?", "confirmations.delete_list.confirm": "Fuortsmite", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "As lêzen oanmurkje", "conversation.open": "Petear besjen", "conversation.with": "Mei {names}", + "copypaste.copied": "Copied", + "copypaste.copy": "Copy", "directory.federated": "From known fediverse", "directory.local": "From {domain} only", "directory.new_arrivals": "New arrivals", "directory.recently_active": "Resintlik warber", + "dismissable_banner.community_timeline": "These are the most recent public posts from people whose accounts are hosted by {domain}.", + "dismissable_banner.dismiss": "Dismiss", + "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", + "dismissable_banner.explore_statuses": "These posts from this and other servers in the decentralized network are gaining traction on this server right now.", + "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", + "dismissable_banner.public_timeline": "These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.", "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", @@ -221,14 +259,14 @@ "follow_request.reject": "Ofkarre", "follow_requests.unlocked_explanation": "Even though your account is not locked, the {domain} staff thought you might want to review follow requests from these accounts manually.", "generic.saved": "Bewarre", - "getting_started.developers": "Untwikkelders", - "getting_started.directory": "Profile directory", + "getting_started.directory": "Directory", "getting_started.documentation": "Dokumintaasje", + "getting_started.free_software_notice": "Mastodon is free, open source software. You can view the source code, contribute or report issues at {repository}.", "getting_started.heading": "Utein sette", "getting_started.invite": "Minsken útnûgje", - "getting_started.open_source_notice": "Mastodon is iepen boarne software. Jo kinne sels bydrage of problemen oanjaan troch GitHub op {github}.", "getting_started.privacy_policy": "Privacy Policy", "getting_started.security": "Account ynstellings", + "getting_started.what_is_mastodon": "About Mastodon", "hashtag.column_header.tag_mode.all": "en {additional}", "hashtag.column_header.tag_mode.any": "of {additional}", "hashtag.column_header.tag_mode.none": "sûnder {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Show replies", "home.hide_announcements": "Hide announcements", "home.show_announcements": "Show announcements", + "interaction_modal.description.favourite": "With an account on Mastodon, you can favourite this post to let the author know you appreciate it and save it for later.", + "interaction_modal.description.follow": "With an account on Mastodon, you can follow {name} to receive their posts in your home feed.", + "interaction_modal.description.reblog": "With an account on Mastodon, you can boost this post to share it with your own followers.", + "interaction_modal.description.reply": "With an account on Mastodon, you can respond to this post.", + "interaction_modal.on_another_server": "On a different server", + "interaction_modal.on_this_server": "On this server", + "interaction_modal.other_server_instructions": "Simply copy and paste this URL into the search bar of your favourite app or the web interface where you are signed in.", + "interaction_modal.preamble": "Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one.", + "interaction_modal.title.favourite": "Favourite {name}'s post", + "interaction_modal.title.follow": "Follow {name}", + "interaction_modal.title.reblog": "Boost {name}'s post", + "interaction_modal.title.reply": "Reply to {name}'s post", "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}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Duration", "mute_modal.hide_notifications": "Notifikaasjes fan dizze brûker ferstopje?", "mute_modal.indefinite": "Indefinite", - "navigation_bar.apps": "Mobile apps", + "navigation_bar.about": "About", + "navigation_bar.apps": "Get the app", "navigation_bar.blocks": "Blokkearre brûkers", "navigation_bar.bookmarks": "Blêdwiizers", "navigation_bar.community_timeline": "Local timeline", @@ -324,7 +375,7 @@ "navigation_bar.filters": "Negearre wurden", "navigation_bar.follow_requests": "Folgfersiken", "navigation_bar.follows_and_followers": "Folgers en folgjenden", - "navigation_bar.info": "Oer dizze tsjinner", + "navigation_bar.info": "About", "navigation_bar.keyboard_shortcuts": "Fluchtoetsen", "navigation_bar.lists": "Listen", "navigation_bar.logout": "Utlogge", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Fêstsette berjochten", "navigation_bar.preferences": "Foarkarren", "navigation_bar.public_timeline": "Federated timeline", + "navigation_bar.search": "Search", "navigation_bar.security": "Security", + "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", "notification.admin.report": "{name} reported {target}", "notification.admin.sign_up": "{name} hat harren ynskreaun", "notification.favourite": "{name} hat jo berjocht as favoryt markearre", @@ -401,6 +454,8 @@ "privacy.public.short": "Iepenbier", "privacy.unlisted.long": "Visible for all, but opted-out of discovery features", "privacy.unlisted.short": "Unlisted", + "privacy_policy.last_updated": "Last updated {date}", + "privacy_policy.title": "Privacy Policy", "refresh": "Fernije", "regeneration_indicator.label": "Loading…", "regeneration_indicator.sublabel": "Your home feed is being prepared!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "Searching posts by their content is not enabled on this Mastodon server.", "search_results.title": "Search for {q}", "search_results.total": "{count, number} {count, plural, one {result} other {results}}", + "server_banner.about_active_users": "People using this server during the last 30 days (Monthly Active Users)", + "server_banner.active_users": "active users", + "server_banner.administered_by": "Administered by:", + "server_banner.introduction": "{domain} is part of the decentralized social network powered by {mastodon}.", + "server_banner.learn_more": "Learn more", + "server_banner.server_stats": "Server stats:", "sign_in_banner.create_account": "Create account", "sign_in_banner.sign_in": "Sign in", "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "No one has boosted this post yet. When someone does, they will show up here.", "status.redraft": "Fuortsmite en opnij opstelle", "status.remove_bookmark": "Remove bookmark", + "status.replied_to": "Replied to {name}", "status.reply": "Reagearre", "status.replyAll": "Op elkenien reagearre", "status.report": "Jou @{name} oan", @@ -523,9 +585,8 @@ "status.show_more": "Mear sjen litte", "status.show_more_all": "Foar alles mear sjen litte", "status.show_original": "Show original", - "status.show_thread": "Petear sjen litte", "status.translate": "Translate", - "status.translated_from": "Translated from {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Net beskikber", "status.unmute_conversation": "Petear net mear negearre", "status.unpin": "Unpin from profile", @@ -538,7 +599,6 @@ "tabs_bar.home": "Home", "tabs_bar.local_timeline": "Local", "tabs_bar.notifications": "Notifikaasjes", - "tabs_bar.search": "Sykje", "time_remaining.days": "{number, plural, one {# dei} other {# dagen}} te gean", "time_remaining.hours": "{number, plural, one {# oere} other {# oeren}} te gean", "time_remaining.minutes": "{number, plural, one {# minút} other {# minuten}} te gean", diff --git a/app/javascript/mastodon/locales/ga.json b/app/javascript/mastodon/locales/ga.json index bb6c72868..9cc62ddd0 100644 --- a/app/javascript/mastodon/locales/ga.json +++ b/app/javascript/mastodon/locales/ga.json @@ -1,4 +1,17 @@ { + "about.blocks": "Freastalaithe faoi stiúir", + "about.contact": "Teagmháil:", + "about.domain_blocks.comment": "Fáth", + "about.domain_blocks.domain": "Fearann", + "about.domain_blocks.preamble": "Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.", + "about.domain_blocks.severity": "Severity", + "about.domain_blocks.silenced.explanation": "You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.", + "about.domain_blocks.silenced.title": "Limited", + "about.domain_blocks.suspended.explanation": "No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.", + "about.domain_blocks.suspended.title": "Suspended", + "about.not_available": "This information has not been made available on this server.", + "about.powered_by": "Decentralized social media powered by {mastodon}", + "about.rules": "Rialacha an fhreastalaí", "account.account_note_header": "Nóta", "account.add_or_remove_from_list": "Cuir Le nó Bain De na liostaí", "account.badges.bot": "Bota", @@ -7,13 +20,16 @@ "account.block_domain": "Bac ainm fearainn {domain}", "account.blocked": "Bactha", "account.browse_more_on_origin_server": "Brabhsáil níos mó ar an phróifíl bhunaidh", - "account.cancel_follow_request": "Cealaigh iarratas leanúnaí", + "account.cancel_follow_request": "Withdraw follow request", "account.direct": "Seol teachtaireacht dhíreach chuig @{name}", "account.disable_notifications": "Éirigh as ag cuir mé in eol nuair bpostálann @{name}", "account.domain_blocked": "Ainm fearainn bactha", "account.edit_profile": "Cuir an phróifíl in eagar", "account.enable_notifications": "Cuir mé in eol nuair bpostálann @{name}", "account.endorse": "Cuir ar an phróifíl mar ghné", + "account.featured_tags.last_status_at": "Last post on {date}", + "account.featured_tags.last_status_never": "No posts", + "account.featured_tags.title": "{name}'s featured hashtags", "account.follow": "Lean", "account.followers": "Leantóirí", "account.followers.empty": "Ní leanann éinne an t-úsáideoir seo fós.", @@ -23,7 +39,7 @@ "account.follows.empty": "Ní leanann an t-úsáideoir seo duine ar bith fós.", "account.follows_you": "Do do leanúint", "account.hide_reblogs": "Folaigh athphostálacha ó @{name}", - "account.joined": "Ina bhall ó {date}", + "account.joined_short": "Joined", "account.languages": "Change subscribed languages", "account.link_verified_on": "Ownership of this link was checked on {date}", "account.locked_info": "Tá an socrú príobháideachais don cuntas seo curtha go 'faoi ghlas'. Déanann an t-úinéir léirmheas ar cén daoine atá ceadaithe an cuntas leanúint.", @@ -63,15 +79,27 @@ "audio.hide": "Hide audio", "autosuggest_hashtag.per_week": "{count} per week", "boost_modal.combo": "Is féidir leat brúigh {combo} chun é seo a scipeáil an chéad uair eile", - "bundle_column_error.body": "Something went wrong while loading this component.", + "bundle_column_error.copy_stacktrace": "Copy error report", + "bundle_column_error.error.body": "The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.", + "bundle_column_error.error.title": "Oh, no!", + "bundle_column_error.network.body": "There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.", + "bundle_column_error.network.title": "Network error", "bundle_column_error.retry": "Bain triail as arís", - "bundle_column_error.title": "Network error", + "bundle_column_error.return": "Go back home", + "bundle_column_error.routing.body": "The requested page could not be found. Are you sure the URL in the address bar is correct?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Dún", "bundle_modal_error.message": "Something went wrong while loading this component.", "bundle_modal_error.retry": "Bain triail as arís", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "About", "column.blocks": "Cuntais choiscthe", "column.bookmarks": "Leabharmharcanna", - "column.community": "Local timeline", + "column.community": "Amlíne áitiúil", "column.direct": "Direct messages", "column.directory": "Brabhsáil próifílí", "column.domain_blocks": "Blocked domains", @@ -80,7 +108,7 @@ "column.home": "Baile", "column.lists": "Liostaí", "column.mutes": "Úsáideoirí balbhaithe", - "column.notifications": "Notifications", + "column.notifications": "Fógraí", "column.pins": "Pinned post", "column.public": "Federated timeline", "column_back_button.label": "Siar", @@ -91,7 +119,7 @@ "column_header.show_settings": "Show settings", "column_header.unpin": "Díghreamaigh", "column_subheading.settings": "Socruithe", - "community.column_settings.local_only": "Local only", + "community.column_settings.local_only": "Áitiúil amháin", "community.column_settings.media_only": "Media only", "community.column_settings.remote_only": "Remote only", "compose.language.change": "Change language", @@ -117,13 +145,15 @@ "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", + "confirmation_modal.cancel": "Cealaigh", "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.cancel_follow_request.confirm": "Withdraw request", + "confirmations.cancel_follow_request.message": "Are you sure you want to withdraw your request to follow {name}?", + "confirmations.delete.confirm": "Scrios", "confirmations.delete.message": "An bhfuil tú cinnte gur mhaith leat an phostáil seo a scriosadh?", - "confirmations.delete_list.confirm": "Delete", + "confirmations.delete_list.confirm": "Scrios", "confirmations.delete_list.message": "Are you sure you want to permanently delete this list?", "confirmations.discard_edit_media.confirm": "Faigh réidh de", "confirmations.discard_edit_media.message": "Tá athruithe neamhshlánaithe don tuarascáil gné nó réamhamharc agat, faigh réidh dóibh ar aon nós?", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Mark as read", "conversation.open": "View conversation", "conversation.with": "With {names}", + "copypaste.copied": "Copied", + "copypaste.copy": "Copy", "directory.federated": "From known fediverse", - "directory.local": "From {domain} only", + "directory.local": "Ó {domain} amháin", "directory.new_arrivals": "New arrivals", "directory.recently_active": "Recently active", + "dismissable_banner.community_timeline": "These are the most recent public posts from people whose accounts are hosted by {domain}.", + "dismissable_banner.dismiss": "Dismiss", + "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", + "dismissable_banner.explore_statuses": "These posts from this and other servers in the decentralized network are gaining traction on this server right now.", + "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", + "dismissable_banner.public_timeline": "These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.", "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": "Gníomhaíocht", @@ -221,14 +259,14 @@ "follow_request.reject": "Diúltaigh", "follow_requests.unlocked_explanation": "Even though your account is not locked, the {domain} staff thought you might want to review follow requests from these accounts manually.", "generic.saved": "Saved", - "getting_started.developers": "Developers", - "getting_started.directory": "Eolaire na próifíle", + "getting_started.directory": "Directory", "getting_started.documentation": "Documentation", + "getting_started.free_software_notice": "Mastodon is free, open source software. You can view the source code, contribute or report issues at {repository}.", "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.privacy_policy": "Privacy Policy", "getting_started.security": "Security", + "getting_started.what_is_mastodon": "About Mastodon", "hashtag.column_header.tag_mode.all": "and {additional}", "hashtag.column_header.tag_mode.any": "or {additional}", "hashtag.column_header.tag_mode.none": "without {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Show replies", "home.hide_announcements": "Hide announcements", "home.show_announcements": "Show announcements", + "interaction_modal.description.favourite": "With an account on Mastodon, you can favourite this post to let the author know you appreciate it and save it for later.", + "interaction_modal.description.follow": "With an account on Mastodon, you can follow {name} to receive their posts in your home feed.", + "interaction_modal.description.reblog": "With an account on Mastodon, you can boost this post to share it with your own followers.", + "interaction_modal.description.reply": "With an account on Mastodon, you can respond to this post.", + "interaction_modal.on_another_server": "On a different server", + "interaction_modal.on_this_server": "On this server", + "interaction_modal.other_server_instructions": "Simply copy and paste this URL into the search bar of your favourite app or the web interface where you are signed in.", + "interaction_modal.preamble": "Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one.", + "interaction_modal.title.favourite": "Favourite {name}'s post", + "interaction_modal.title.follow": "Follow {name}", + "interaction_modal.title.reblog": "Boost {name}'s post", + "interaction_modal.title.reply": "Reply to {name}'s post", "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}}", @@ -264,7 +314,7 @@ "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.local": "Oscail an amlíne áitiúil", "keyboard_shortcuts.mention": "to mention author", "keyboard_shortcuts.muted": "Oscail liosta na n-úsáideoirí balbhaithe", "keyboard_shortcuts.my_profile": "Oscail do phróifíl", @@ -310,10 +360,11 @@ "mute_modal.duration": "Tréimhse", "mute_modal.hide_notifications": "Cuir póstalacha ón t-úsáideoir seo i bhfolach?", "mute_modal.indefinite": "Gan téarma", - "navigation_bar.apps": "Mobile apps", + "navigation_bar.about": "About", + "navigation_bar.apps": "Get the app", "navigation_bar.blocks": "Blocked users", "navigation_bar.bookmarks": "Bookmarks", - "navigation_bar.community_timeline": "Local timeline", + "navigation_bar.community_timeline": "Amlíne áitiúil", "navigation_bar.compose": "Cum postáil nua", "navigation_bar.direct": "Direct messages", "navigation_bar.discover": "Discover", @@ -324,7 +375,7 @@ "navigation_bar.filters": "Focail bhalbhaithe", "navigation_bar.follow_requests": "Follow requests", "navigation_bar.follows_and_followers": "Ag leanúint agus do do leanúint", - "navigation_bar.info": "About this server", + "navigation_bar.info": "About", "navigation_bar.keyboard_shortcuts": "Eochracha Aicearra", "navigation_bar.lists": "Liostaí", "navigation_bar.logout": "Logáil Amach", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Pinned posts", "navigation_bar.preferences": "Preferences", "navigation_bar.public_timeline": "Federated timeline", + "navigation_bar.search": "Search", "navigation_bar.security": "Security", + "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", "notification.admin.report": "{name} reported {target}", "notification.admin.sign_up": "{name} signed up", "notification.favourite": "Roghnaigh {name} do phostáil", @@ -401,6 +454,8 @@ "privacy.public.short": "Poiblí", "privacy.unlisted.long": "Visible for all, but opted-out of discovery features", "privacy.unlisted.short": "Unlisted", + "privacy_policy.last_updated": "Last updated {date}", + "privacy_policy.title": "Privacy Policy", "refresh": "Refresh", "regeneration_indicator.label": "Ag lódáil…", "regeneration_indicator.sublabel": "Your home feed is being prepared!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "Searching posts by their content is not enabled on this Mastodon server.", "search_results.title": "Search for {q}", "search_results.total": "{count, number} {count, plural, one {result} other {results}}", + "server_banner.about_active_users": "People using this server during the last 30 days (Monthly Active Users)", + "server_banner.active_users": "active users", + "server_banner.administered_by": "Administered by:", + "server_banner.introduction": "{domain} is part of the decentralized social network powered by {mastodon}.", + "server_banner.learn_more": "Learn more", + "server_banner.server_stats": "Server stats:", "sign_in_banner.create_account": "Create account", "sign_in_banner.sign_in": "Sign in", "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "Níor threisigh éinne an phostáil seo fós. Nuair a threisigh duine éigin, beidh siad le feiceáil anseo.", "status.redraft": "Delete & re-draft", "status.remove_bookmark": "Remove bookmark", + "status.replied_to": "Replied to {name}", "status.reply": "Reply", "status.replyAll": "Reply to thread", "status.report": "Report @{name}", @@ -523,9 +585,8 @@ "status.show_more": "Show more", "status.show_more_all": "Show more for all", "status.show_original": "Show original", - "status.show_thread": "Show thread", "status.translate": "Translate", - "status.translated_from": "Translated from {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Not available", "status.unmute_conversation": "Díbhalbhaigh comhrá", "status.unpin": "Díphionnáil de do phróifíl", @@ -536,9 +597,8 @@ "suggestions.header": "You might be interested in…", "tabs_bar.federated_timeline": "Federated", "tabs_bar.home": "Baile", - "tabs_bar.local_timeline": "Local", + "tabs_bar.local_timeline": "Áitiúil", "tabs_bar.notifications": "Notifications", - "tabs_bar.search": "Cuardaigh", "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", diff --git a/app/javascript/mastodon/locales/gd.json b/app/javascript/mastodon/locales/gd.json index df5eb0fed..32030374f 100644 --- a/app/javascript/mastodon/locales/gd.json +++ b/app/javascript/mastodon/locales/gd.json @@ -1,4 +1,17 @@ { + "about.blocks": "Frithealaichean fo mhaorsainneachd", + "about.contact": "Fios thugainn:", + "about.domain_blocks.comment": "Adhbhar", + "about.domain_blocks.domain": "Àrainn", + "about.domain_blocks.preamble": "San fharsaingeachd, leigidh Mastodon leat susbaint o fhrithealaiche sam bith sa cho-shaoghal a shealltainn agus eadar-ghìomh a ghabhail leis na cleachdaichean uapa-san. Seo na h-easgaidhean a tha an sàs air an fhrithealaiche shònraichte seo.", + "about.domain_blocks.severity": "Donad", + "about.domain_blocks.silenced.explanation": "Chan fharsaingeachd, chan fhaic thu pròifilean agus susbaint an fhrithealaiche seo ach ma nì thu lorg no ma leanas tu air.", + "about.domain_blocks.silenced.title": "Cuingichte", + "about.domain_blocks.suspended.explanation": "Cha dèid dàta sam bith on fhrithealaiche seo a phròiseasadh, a stòradh no iomlaid agus chan urrainn do na cleachdaichean on fhrithealaiche sin conaltradh no eadar-ghnìomh a ghabhail an-seo.", + "about.domain_blocks.suspended.title": "’Na dhàil", + "about.not_available": "Cha deach am fiosrachadh seo a sholar air an fhrithealaiche seo.", + "about.powered_by": "Lìonra sòisealta sgaoilte le cumhachd {mastodon}", + "about.rules": "Riaghailtean an fhrithealaiche", "account.account_note_header": "Nòta", "account.add_or_remove_from_list": "Cuir ris no thoir air falbh o na liostaichean", "account.badges.bot": "Bot", @@ -7,13 +20,16 @@ "account.block_domain": "Bac an àrainn {domain}", "account.blocked": "’Ga bhacadh", "account.browse_more_on_origin_server": "Rùraich barrachd dheth air a’ phròifil thùsail", - "account.cancel_follow_request": "Sguir dhen iarrtas leantainn", + "account.cancel_follow_request": "Cuir d’ iarrtas leantainn dhan dàrna taobh", "account.direct": "Cuir teachdaireachd dhìreach gu @{name}", "account.disable_notifications": "Na cuir brath thugam tuilleadh nuair a chuireas @{name} post ris", "account.domain_blocked": "Chaidh an àrainn a bhacadh", "account.edit_profile": "Deasaich a’ phròifil", "account.enable_notifications": "Cuir brath thugam nuair a chuireas @{name} post ris", "account.endorse": "Brosnaich air a’ phròifil", + "account.featured_tags.last_status_at": "Am post mu dheireadh {date}", + "account.featured_tags.last_status_never": "Gun phost", + "account.featured_tags.title": "Na tagaichean hais brosnaichte aig {name}", "account.follow": "Lean air", "account.followers": "Luchd-leantainn", "account.followers.empty": "Chan eil neach sam bith a’ leantainn air a’ chleachdaiche seo fhathast.", @@ -23,8 +39,8 @@ "account.follows.empty": "Chan eil an cleachdaiche seo a’ leantainn air neach sam bith fhathast.", "account.follows_you": "’Gad leantainn", "account.hide_reblogs": "Falaich na brosnachaidhean o @{name}", - "account.joined": "Air ballrachd fhaighinn {date}", - "account.languages": "Change subscribed languages", + "account.joined_short": "Joined", + "account.languages": "Atharraich fo-sgrìobhadh nan cànan", "account.link_verified_on": "Chaidh dearbhadh cò leis a tha an ceangal seo {date}", "account.locked_info": "Tha prìobhaideachd ghlaiste aig a’ chunntais seo. Nì an sealbhadair lèirmheas a làimh air cò dh’fhaodas leantainn orra.", "account.media": "Meadhanan", @@ -51,7 +67,7 @@ "account_note.placeholder": "Briog airson nòta a chur ris", "admin.dashboard.daily_retention": "Reat glèidheadh nan cleachdaichean às dèidh an clàradh a-rèir latha", "admin.dashboard.monthly_retention": "Reat glèidheadh nan cleachdaichean às dèidh an clàradh a-rèir mìos", - "admin.dashboard.retention.average": "Średnia", + "admin.dashboard.retention.average": "Cuibheasach", "admin.dashboard.retention.cohort": "Mìos a’ chlàraidh", "admin.dashboard.retention.cohort_size": "Cleachdaichean ùra", "alert.rate_limited.message": "Feuch ris a-rithist às dèidh {retry_time, time, medium}.", @@ -63,12 +79,24 @@ "audio.hide": "Falaich an fhuaim", "autosuggest_hashtag.per_week": "{count} san t-seachdain", "boost_modal.combo": "Brùth air {combo} nam b’ fheàrr leat leum a ghearradh thar seo an ath-thuras", - "bundle_column_error.body": "Chaidh rudeigin cearr nuair a dh’fheuch sinn ris a’ cho-phàirt seo a luchdadh.", + "bundle_column_error.copy_stacktrace": "Dèan lethbhreac de aithris na mearachd", + "bundle_column_error.error.body": "Cha b’ urrainn dhuinn an duilleag a dh’iarr thu a reandaradh. Dh’fhaoidte gu bheil buga sa chòd againn no duilgheadas co-chòrdalachd leis a’ bhrabhsair.", + "bundle_column_error.error.title": "Ìoc!", + "bundle_column_error.network.body": "Thachair mearachd nuair a dh’fheuch sinn ris an duilleag seo a luchdadh. Dh’fhaoidte gu bheil duilgheadas sealach leis a’ cheangal agad ris an eadar-lìon no leis an fhrithealaiche seo.", + "bundle_column_error.network.title": "Mearachd lìonraidh", "bundle_column_error.retry": "Feuch ris a-rithist", - "bundle_column_error.title": "Mearachd lìonraidh", + "bundle_column_error.return": "Dhachaigh", + "bundle_column_error.routing.body": "Cha do lorg sinn an duilleag a dh’iarr thu. A bheil thu cinnteach gu bheil an t-URL ann am bàr an t-seòlaidh mar bu chòir?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Dùin", "bundle_modal_error.message": "Chaidh rudeigin cearr nuair a dh’fheuch sinn ris a’ cho-phàirt seo a luchdadh.", "bundle_modal_error.retry": "Feuch ris a-rithist", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "Mu dhèidhinn", "column.blocks": "Cleachdaichean bacte", "column.bookmarks": "Comharran-lìn", "column.community": "Loidhne-ama ionadail", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "Bac ⁊ dèan gearan", "confirmations.block.confirm": "Bac", "confirmations.block.message": "A bheil thu cinnteach gu bheil thu airson {name} a bhacadh?", + "confirmations.cancel_follow_request.confirm": "Cuir d’ iarrtas dhan dàrna taobh", + "confirmations.cancel_follow_request.message": "A bheil thu cinnteach gu bheil thu airson d’ iarrtas leantainn air {name} a chur dhan dàrna taobh?", "confirmations.delete.confirm": "Sguab às", "confirmations.delete.message": "A bheil thu cinnteach gu bheil thu airson am post seo a sguabadh às?", "confirmations.delete_list.confirm": "Sguab às", @@ -143,11 +173,19 @@ "conversation.delete": "Sguab às an còmhradh", "conversation.mark_as_read": "Cuir comharra gun deach a leughadh", "conversation.open": "Seall an còmhradh", - "conversation.with": "Le {names}", + "conversation.with": "Còmhla ri {names}", + "copypaste.copied": "Chaidh lethbhreac dheth a dhèanamh", + "copypaste.copy": "Dèan lethbhreac", "directory.federated": "On cho-shaoghal aithnichte", "directory.local": "O {domain} a-mhàin", "directory.new_arrivals": "Feadhainn ùra", "directory.recently_active": "Gnìomhach o chionn goirid", + "dismissable_banner.community_timeline": "Seo na postaichean poblach as ùire o dhaoine aig a bheil cunntas air {domain}.", + "dismissable_banner.dismiss": "Leig seachad", + "dismissable_banner.explore_links": "Seo na naidheachdan air a bhithear a’ bruidhinn an-dràsta fhèin air an fhrithealaiche seo is frithealaichean eile dhen lìonra sgaoilte.", + "dismissable_banner.explore_statuses": "Tha fèill air na postaichean seo on fhrithealaiche seo is frithealaichean eile dhen lìonra sgaoilte a’ fàs air an fhrithealaich seo an-dràsta fhèin.", + "dismissable_banner.explore_tags": "Tha fèill air na tagaichean hais seo a’ fàs an-dràsta fhèin air an fhrithealaich seo is frithealaichean eile dhen lìonra sgaoilte.", + "dismissable_banner.public_timeline": "Seo na postaichean poblach as ùire o dhaoine air an fhrithealaich seo is frithealaichean eile dhen lìonra sgaoilte air a bheil am frithealaiche seo eòlach.", "embed.instructions": "Leabaich am post seo san làrach-lìn agad is tu a’ dèanamh lethbhreac dhen chòd gu h-ìosal.", "embed.preview": "Seo an coltas a bhios air:", "emoji_button.activity": "Gnìomhachd", @@ -198,22 +236,22 @@ "explore.trending_links": "Naidheachdan", "explore.trending_statuses": "Postaichean", "explore.trending_tags": "Tagaichean hais", - "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.", - "filter_modal.added.context_mismatch_title": "Context mismatch!", - "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.", - "filter_modal.added.expired_title": "Expired filter!", - "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.", - "filter_modal.added.review_and_configure_title": "Filter settings", - "filter_modal.added.settings_link": "settings page", - "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.", - "filter_modal.added.title": "Filter added!", - "filter_modal.select_filter.context_mismatch": "does not apply to this context", - "filter_modal.select_filter.expired": "expired", - "filter_modal.select_filter.prompt_new": "New category: {name}", - "filter_modal.select_filter.search": "Search or create", - "filter_modal.select_filter.subtitle": "Use an existing category or create a new one", - "filter_modal.select_filter.title": "Filter this post", - "filter_modal.title.status": "Filter a post", + "filter_modal.added.context_mismatch_explanation": "Chan eil an roinn-seòrsa criathraidh iom seo chaidh dhan cho-theacs san do dh’inntrig thu am post seo. Ma tha thu airson am post a chriathradh sa cho-theacs seo cuideachd, feumaidh tu a’ chriathrag a dheasachadh.", + "filter_modal.added.context_mismatch_title": "Co-theacsa neo-iomchaidh!", + "filter_modal.added.expired_explanation": "Dh’fhalbh an ùine air an roinn-seòrsa criathraidh seo agus feumaidh tu an ceann-là crìochnachaidh atharrachadh mus cuir thu an sàs i.", + "filter_modal.added.expired_title": "Dh’fhalbh an ùine air a’ chriathrag!", + "filter_modal.added.review_and_configure": "Airson an roinn-seòrsa criathraidh seo a sgrùdadh ’s a rèiteachadh, tadhail air {settings_link}.", + "filter_modal.added.review_and_configure_title": "Roghainnean na criathraige", + "filter_modal.added.settings_link": "duilleag nan roghainnean", + "filter_modal.added.short_explanation": "Chaidh am post seo a chur ris an roinn-seòrsa criathraidh seo: {title}.", + "filter_modal.added.title": "Chaidh a’ chriathrag a chur ris!", + "filter_modal.select_filter.context_mismatch": "chan eil e iomchaidh dhan cho-theacs seo", + "filter_modal.select_filter.expired": "dh’fhalbh an ùine air", + "filter_modal.select_filter.prompt_new": "Roinn-seòrsa ùr: {name}", + "filter_modal.select_filter.search": "Lorg no cruthaich", + "filter_modal.select_filter.subtitle": "Cleachd roinn-seòrsa a tha ann no cruthaich tè ùr", + "filter_modal.select_filter.title": "Criathraich am post seo", + "filter_modal.title.status": "Criathraich post", "follow_recommendations.done": "Deiseil", "follow_recommendations.heading": "Lean air daoine ma tha thu airson nam postaichean aca fhaicinn! Seo moladh no dà dhut.", "follow_recommendations.lead": "Nochdaidh na postaichean aig na daoine air a leanas tu a-rèir an ama air inbhir na dachaighe agad. Bi dàna on as urrainn dhut sgur de leantainn air daoine cuideachd uair sam bith!", @@ -221,14 +259,14 @@ "follow_request.reject": "Diùlt", "follow_requests.unlocked_explanation": "Ged nach eil an cunntas agad glaiste, tha sgioba {domain} dhen bheachd gum b’ fheàirrde thu lèirmheas a dhèanamh air na h-iarrtasan leantainn o na cunntasan seo a làimh.", "generic.saved": "Chaidh a shàbhaladh", - "getting_started.developers": "Luchd-leasachaidh", - "getting_started.directory": "Eòlaire nam pròifil", + "getting_started.directory": "Eòlaire", "getting_started.documentation": "Docamaideadh", + "getting_started.free_software_notice": "’S e bathar-bog saor le bun-tùs fosgailte a th’ ann am Mastodon. Chì thu am bun-tùs agus ’s urrainn dhut cuideachadh leis no aithris a dhèanamh air duilgheadasan air {repository}.", "getting_started.heading": "Toiseach", "getting_started.invite": "Thoir cuireadh do dhaoine", - "getting_started.open_source_notice": "’S e bathar-bog le bun-tùs fosgailte a th’ ann am Mastodon. ’S urrainn dhut cuideachadh leis no aithris a dhèanamh air duilgheadasan air GitHub fo {github}.", - "getting_started.privacy_policy": "Privacy Policy", + "getting_started.privacy_policy": "Poileasaidh prìobhaideachd", "getting_started.security": "Roghainnean a’ chunntais", + "getting_started.what_is_mastodon": "Mu Mhastodon", "hashtag.column_header.tag_mode.all": "agus {additional}", "hashtag.column_header.tag_mode.any": "no {additional}", "hashtag.column_header.tag_mode.none": "às aonais {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Seall na freagairtean", "home.hide_announcements": "Falaich na brathan-fios", "home.show_announcements": "Seall na brathan-fios", + "interaction_modal.description.favourite": "Le cunntas air Mastodon, ’s urrainn dhut am post seo a chur ris na h-annsachdan airson innse dhan ùghdar gu bheil e a’ còrdadh dhut ’s a shàbhaladh do uaireigin eile.", + "interaction_modal.description.follow": "Le cunntas air Mastodon, ’s urrainn dhut leantainn air {name} ach am faigh thu na postaichean aca air inbhir na dachaigh agad.", + "interaction_modal.description.reblog": "Le cunntas air Mastodon, ’s urrainn dhut am post seo a bhrosnachadh gus a cho-roinneadh leis an luchd-leantainn agad fhèin.", + "interaction_modal.description.reply": "Le cunntas air Mastodon, ’s urrainn dhut freagairt a chur dhan phost seo.", + "interaction_modal.on_another_server": "Air frithealaiche eile", + "interaction_modal.on_this_server": "Air an frithealaiche seo", + "interaction_modal.other_server_instructions": "Dèan lethbhreac dhen URL seo is cuir ann am bàr nan lorg e san aplacaid as fheàrr leat no san eadar-aghaidh-lìn far a bheil thu air do chlàradh a-steach.", + "interaction_modal.preamble": "Air sgàth ’s gu bheil Mastodon sgaoilte, ’s urrainn dhut cunntas a chleachdadh a tha ’ga òstadh le frithealaiche Mastodon no le ùrlar co-chòrdail eile mur eil cunntas agad air an fhear seo.", + "interaction_modal.title.favourite": "Cuir am post aig {name} ris na h-annsachdan", + "interaction_modal.title.follow": "Lean air {name}", + "interaction_modal.title.reblog": "Brosnaich am post aig {name}", + "interaction_modal.title.reply": "Freagair dhan phost aig {name}", "intervals.full.days": "{number, plural, one {# latha} two {# latha} few {# làithean} other {# latha}}", "intervals.full.hours": "{number, plural, one {# uair a thìde} two {# uair a thìde} few {# uairean a thìde} other {# uair a thìde}}", "intervals.full.minutes": "{number, plural, one {# mhionaid} two {# mhionaid} few {# mionaidean} other {# mionaid}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Faide", "mute_modal.hide_notifications": "A bheil thu airson na brathan fhalach on chleachdaiche seo?", "mute_modal.indefinite": "Gun chrìoch", - "navigation_bar.apps": "Aplacaidean mobile", + "navigation_bar.about": "Mu dhèidhinn", + "navigation_bar.apps": "Faigh an aplacaid", "navigation_bar.blocks": "Cleachdaichean bacte", "navigation_bar.bookmarks": "Comharran-lìn", "navigation_bar.community_timeline": "Loidhne-ama ionadail", @@ -324,7 +375,7 @@ "navigation_bar.filters": "Faclan mùchte", "navigation_bar.follow_requests": "Iarrtasan leantainn", "navigation_bar.follows_and_followers": "Dàimhean leantainn", - "navigation_bar.info": "Mun fhrithealaiche seo", + "navigation_bar.info": "Mu dhèidhinn", "navigation_bar.keyboard_shortcuts": "Grad-iuchraichean", "navigation_bar.lists": "Liostaichean", "navigation_bar.logout": "Clàraich a-mach", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Postaichean prìnichte", "navigation_bar.preferences": "Roghainnean", "navigation_bar.public_timeline": "Loidhne-ama cho-naisgte", + "navigation_bar.search": "Search", "navigation_bar.security": "Tèarainteachd", + "not_signed_in_indicator.not_signed_in": "Feumaidh tu clàradh a-steach mus fhaigh thu cothrom air a’ ghoireas seo.", "notification.admin.report": "Rinn {name} mu {target}", "notification.admin.sign_up": "Chlàraich {name}", "notification.favourite": "Is annsa le {name} am post agad", @@ -401,6 +454,8 @@ "privacy.public.short": "Poblach", "privacy.unlisted.long": "Chì a h-uile duine e ach cha nochd e ann an gleusan rùrachaidh", "privacy.unlisted.short": "Falaichte o liostaichean", + "privacy_policy.last_updated": "An t-ùrachadh mu dheireadh {date}", + "privacy_policy.title": "Poileasaidh prìobhaideachd", "refresh": "Ath-nuadhaich", "regeneration_indicator.label": "’Ga luchdadh…", "regeneration_indicator.sublabel": "Tha inbhir na dachaigh agad ’ga ullachadh!", @@ -471,18 +526,24 @@ "search_results.nothing_found": "Cha do lorg sinn dad dha na h-abairtean-luirg seo", "search_results.statuses": "Postaichean", "search_results.statuses_fts_disabled": "Chan eil lorg phostaichean a-rèir an susbaint an comas air an fhrithealaiche Mastodon seo.", - "search_results.title": "Search for {q}", + "search_results.title": "Lorg {q}", "search_results.total": "{count, number} {count, plural, one {toradh} two {thoradh} few {toraidhean} other {toradh}}", - "sign_in_banner.create_account": "Create account", - "sign_in_banner.sign_in": "Sign in", - "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", + "server_banner.about_active_users": "Daoine a chleachd am frithealaiche seo rè an 30 latha mu dheireadh (Cleachdaichean gnìomhach gach mìos)", + "server_banner.active_users": "cleachdaichean gnìomhach", + "server_banner.administered_by": "Rianachd le:", + "server_banner.introduction": "Tha {domain} am measg an lìonraidh shòisealta sgaoilte le cumhachd {mastodon}.", + "server_banner.learn_more": "Barrachd fiosrachaidh", + "server_banner.server_stats": "Stadastaireachd an fhrithealaiche:", + "sign_in_banner.create_account": "Cruthaich cunntas", + "sign_in_banner.sign_in": "Clàraich a-steach", + "sign_in_banner.text": "Clàraich a-steach a leantainn air pròifilean no tagaichean hais, a’ cur postaichean ris na h-annsachdan ’s ’gan co-roinneadh is freagairt dhaibh no gabh gnìomh le cunntas o fhrithealaiche eile.", "status.admin_account": "Fosgail eadar-aghaidh na maorsainneachd dha @{name}", "status.admin_status": "Fosgail am post seo ann an eadar-aghaidh na maorsainneachd", "status.block": "Bac @{name}", "status.bookmark": "Cuir ris na comharran-lìn", "status.cancel_reblog_private": "Na brosnaich tuilleadh", "status.cannot_reblog": "Cha ghabh am post seo brosnachadh", - "status.copy": "Dèan lethbhreac dhen cheangal air a’ phost", + "status.copy": "Dèan lethbhreac dhen cheangal dhan phost", "status.delete": "Sguab às", "status.detailed_status": "Mion-shealladh a’ chòmhraidh", "status.direct": "Cuir teachdaireachd dhìreach gu @{name}", @@ -491,7 +552,7 @@ "status.edited_x_times": "Chaidh a dheasachadh {count, plural, one {{counter} turas} two {{counter} thuras} few {{counter} tursan} other {{counter} turas}}", "status.embed": "Leabaich", "status.favourite": "Cuir ris na h-annsachdan", - "status.filter": "Filter this post", + "status.filter": "Criathraich am post seo", "status.filtered": "Criathraichte", "status.hide": "Falaich am post", "status.history.created": "Chruthaich {name} {date} e", @@ -512,6 +573,7 @@ "status.reblogs.empty": "Chan deach am post seo a bhrosnachadh le duine sam bith fhathast. Nuair a bhrosnaicheas cuideigin e, nochdaidh iad an-seo.", "status.redraft": "Sguab às ⁊ dèan dreachd ùr", "status.remove_bookmark": "Thoir an comharra-lìn air falbh", + "status.replied_to": "Replied to {name}", "status.reply": "Freagair", "status.replyAll": "Freagair dhan t-snàithlean", "status.report": "Dèan gearan mu @{name}", @@ -522,23 +584,21 @@ "status.show_less_all": "Seall nas lugha dhen a h-uile", "status.show_more": "Seall barrachd dheth", "status.show_more_all": "Seall barrachd dhen a h-uile", - "status.show_original": "Show original", - "status.show_thread": "Seall an snàithlean", - "status.translate": "Translate", - "status.translated_from": "Translated from {lang}", + "status.show_original": "Seall an tionndadh tùsail", + "status.translate": "Eadar-theangaich", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Chan eil seo ri fhaighinn", "status.unmute_conversation": "Dì-mhùch an còmhradh", "status.unpin": "Dì-phrìnich on phròifil", - "subscribed_languages.lead": "Only posts in selected languages will appear on your home and list timelines after the change. Select none to receive posts in all languages.", - "subscribed_languages.save": "Save changes", - "subscribed_languages.target": "Change subscribed languages for {target}", + "subscribed_languages.lead": "Cha nochd ach na postaichean sna cànanan a thagh thu air loidhnichean-ama na dachaigh ’s nan liostaichean às dèidh an atharrachaidh seo. Na tagh gin ma tha thu airson na postaichean uile fhaighinn ge b’ e dè an cànan.", + "subscribed_languages.save": "Sàbhail na h-atharraichean", + "subscribed_languages.target": "Atharraich fo-sgrìobhadh nan cànan airson {target}", "suggestions.dismiss": "Leig seachad am moladh", "suggestions.header": "Dh’fhaoidte gu bheil ùidh agad ann an…", "tabs_bar.federated_timeline": "Co-naisgte", "tabs_bar.home": "Dachaigh", "tabs_bar.local_timeline": "Ionadail", "tabs_bar.notifications": "Brathan", - "tabs_bar.search": "Lorg", "time_remaining.days": "{number, plural, one {# latha} two {# latha} few {# làithean} other {# latha}} air fhàgail", "time_remaining.hours": "{number, plural, one {# uair a thìde} two {# uair a thìde} few {# uairean a thìde} other {# uair a thìde}} air fhàgail", "time_remaining.minutes": "{number, plural, one {# mhionaid} two {# mhionaid} few {# mionaidean} other {# mionaid}} air fhàgail", diff --git a/app/javascript/mastodon/locales/gl.json b/app/javascript/mastodon/locales/gl.json index fef04d1b0..5a97a82d1 100644 --- a/app/javascript/mastodon/locales/gl.json +++ b/app/javascript/mastodon/locales/gl.json @@ -1,4 +1,17 @@ { + "about.blocks": "Servidores moderados", + "about.contact": "Contacto:", + "about.domain_blocks.comment": "Razón", + "about.domain_blocks.domain": "Dominio", + "about.domain_blocks.preamble": "Mastodon de xeito xeral permíteche ver contidos doutros servidores do fediverso e interactuar coas súas usuarias. Estas son as excepcións que se estabeleceron neste servidor en particular.", + "about.domain_blocks.severity": "Rigurosidade", + "about.domain_blocks.silenced.explanation": "Por defecto non verás perfís e contido desde este servidor, a menos que mires de xeito explícito ou optes por seguir ese contido ou usuaria.", + "about.domain_blocks.silenced.title": "Limitada", + "about.domain_blocks.suspended.explanation": "Non se procesarán, almacenarán nin intercambiarán datos con este servidor, o que fai imposible calquera interacción ou comunicación coas usuarias deste servidor.", + "about.domain_blocks.suspended.title": "Suspendida", + "about.not_available": "Esta información non está dispoñible neste servidor.", + "about.powered_by": "Comunicación social descentralizada grazas a {mastodon}", + "about.rules": "Regras do servidor", "account.account_note_header": "Nota", "account.add_or_remove_from_list": "Engadir ou eliminar das listaxes", "account.badges.bot": "Bot", @@ -7,13 +20,16 @@ "account.block_domain": "Agochar todo de {domain}", "account.blocked": "Bloqueada", "account.browse_more_on_origin_server": "Busca máis no perfil orixinal", - "account.cancel_follow_request": "Desbotar solicitude de seguimento", + "account.cancel_follow_request": "Retirar solicitude de seguimento", "account.direct": "Mensaxe directa a @{name}", "account.disable_notifications": "Deixar de notificarme cando @{name} publica", "account.domain_blocked": "Dominio agochado", "account.edit_profile": "Editar perfil", "account.enable_notifications": "Noficarme cando @{name} publique", "account.endorse": "Amosar no perfil", + "account.featured_tags.last_status_at": "Última publicación o {date}", + "account.featured_tags.last_status_never": "Sen publicacións", + "account.featured_tags.title": "Cancelos destacados de {name}", "account.follow": "Seguir", "account.followers": "Seguidoras", "account.followers.empty": "Aínda ninguén segue esta usuaria.", @@ -23,7 +39,7 @@ "account.follows.empty": "Esta usuaria aínda non segue a ninguén.", "account.follows_you": "Séguete", "account.hide_reblogs": "Agochar repeticións de @{name}", - "account.joined": "Uníuse {date}", + "account.joined_short": "Joined", "account.languages": "Modificar os idiomas subscritos", "account.link_verified_on": "A propiedade desta ligazón foi verificada o {date}", "account.locked_info": "Esta é unha conta privada. A propietaria revisa de xeito manual quen pode seguila.", @@ -63,12 +79,24 @@ "audio.hide": "Agochar audio", "autosuggest_hashtag.per_week": "{count} por semana", "boost_modal.combo": "Preme {combo} para ignorar isto na seguinte vez", - "bundle_column_error.body": "Ocorreu un erro ó cargar este compoñente.", + "bundle_column_error.copy_stacktrace": "Copiar informe do erro", + "bundle_column_error.error.body": "Non se puido mostrar a páxina solicitada. Podería deberse a un problema no código, ou incompatiblidade co navegador.", + "bundle_column_error.error.title": "Vaites!", + "bundle_column_error.network.body": "Algo fallou ao intentar cargar esta páxina. Podería ser un problema temporal da conexión a internet ao intentar comunicarte este servidor.", + "bundle_column_error.network.title": "Fallo na rede", "bundle_column_error.retry": "Téntao de novo", - "bundle_column_error.title": "Fallo na rede", + "bundle_column_error.return": "Volver ao Inicio", + "bundle_column_error.routing.body": "Non atopamos a páxina solicitada. Tes a certeza de que o URL na barra de enderezos é correcto?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Pechar", "bundle_modal_error.message": "Ocorreu un erro ó cargar este compoñente.", "bundle_modal_error.retry": "Téntao de novo", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "Acerca de", "column.blocks": "Usuarias bloqueadas", "column.bookmarks": "Marcadores", "column.community": "Cronoloxía local", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "Bloquear e denunciar", "confirmations.block.confirm": "Bloquear", "confirmations.block.message": "Tes a certeza de querer bloquear a {name}?", + "confirmations.cancel_follow_request.confirm": "Retirar solicitude", + "confirmations.cancel_follow_request.message": "Tes a certeza de querer retirar a solicitude para seguir a {name}?", "confirmations.delete.confirm": "Eliminar", "confirmations.delete.message": "Tes a certeza de querer eliminar esta publicación?", "confirmations.delete_list.confirm": "Eliminar", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Marcar como lido", "conversation.open": "Ver conversa", "conversation.with": "Con {names}", + "copypaste.copied": "Copiado", + "copypaste.copy": "Copiar", "directory.federated": "Do fediverso coñecido", "directory.local": "Só de {domain}", "directory.new_arrivals": "Recén chegadas", "directory.recently_active": "Activas recentemente", + "dismissable_banner.community_timeline": "Estas son as publicacións máis recentes das persoas que teñen a súa conta en {domain}.", + "dismissable_banner.dismiss": "Desbotar", + "dismissable_banner.explore_links": "As persoas deste servidor e da rede descentralizada están a falar destas historias agora mesmo.", + "dismissable_banner.explore_statuses": "Está aumentando a popularidade destas publicacións no servidor e a rede descentralizada.", + "dismissable_banner.explore_tags": "Estes cancelos están gañando popularidade entre as persoas deste servidor e outros servidores da rede descentralizada.", + "dismissable_banner.public_timeline": "Estas son as publicacións máis recentes das persoas deste servidor e outros servidores da rede descentralizada cos que está conectado.", "embed.instructions": "Engade esta publicación ó teu sitio web copiando o seguinte código.", "embed.preview": "Así será mostrado:", "emoji_button.activity": "Actividade", @@ -188,7 +226,7 @@ "empty_column.public": "Nada por aquí! Escribe algo de xeito público, ou segue de xeito manual usuarias doutros servidores para ir enchéndoo", "error.unexpected_crash.explanation": "Debido a un erro no noso código ou a unha compatilidade co teu navegador, esta páxina non pode ser amosada correctamente.", "error.unexpected_crash.explanation_addons": "Non se puido mostrar correctamente a páxina. Habitualmente este erro está causado por algún engadido do navegador ou ferramentas de tradución automática.", - "error.unexpected_crash.next_steps": "Tenta actualizar a páxina. Se esto non axuda podes tamén empregar Mastodon noutro navegador ou aplicación nativa.", + "error.unexpected_crash.next_steps": "Tenta actualizar a páxina. Se isto non axuda podes tamén empregar Mastodon noutro navegador ou aplicación nativa.", "error.unexpected_crash.next_steps_addons": "Intenta desactivalas e actualiza a páxina. Se isto non funciona, podes seguir usando Mastodon nun navegador diferente ou aplicación nativa.", "errors.unexpected_crash.copy_stacktrace": "Copiar trazas (stacktrace) ó portapapeis", "errors.unexpected_crash.report_issue": "Informar sobre un problema", @@ -221,14 +259,14 @@ "follow_request.reject": "Rexeitar", "follow_requests.unlocked_explanation": "Malia que a túa conta non é privada, a administración de {domain} pensou que quizabes terías que revisar de xeito manual as solicitudes de seguiminto.", "generic.saved": "Gardado", - "getting_started.developers": "Desenvolvedoras", - "getting_started.directory": "Directorio local", + "getting_started.directory": "Directorio", "getting_started.documentation": "Documentación", + "getting_started.free_software_notice": "Mastodon é código aberto e libre. Podes revisar o código, contribuir ou informar de fallos en {repository}.", "getting_started.heading": "Primeiros pasos", "getting_started.invite": "Convidar persoas", - "getting_started.open_source_notice": "Mastodon é software de código aberto. Podes contribuír ou informar de fallos en GitHub en {github}.", "getting_started.privacy_policy": "Política de Privacidade", "getting_started.security": "Seguranza", + "getting_started.what_is_mastodon": "Acerca de Mastodon", "hashtag.column_header.tag_mode.all": "e {additional}", "hashtag.column_header.tag_mode.any": "ou {additional}", "hashtag.column_header.tag_mode.none": "sen {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Amosar respostas", "home.hide_announcements": "Agochar anuncios", "home.show_announcements": "Amosar anuncios", + "interaction_modal.description.favourite": "Cunha conta en Mastodon, poderá marcar esta publicación como favorita, para gardalo e para que o autor saiba o moito que lle gustou.", + "interaction_modal.description.follow": "Cunha conta en Mastodon, poderá seguir {name} e recibir as súas publicacións na súa cronoloxía de inicio.", + "interaction_modal.description.reblog": "Cunha conta en Mastodon, poderá difundir esta publicación e compartila cos seus seguidores.", + "interaction_modal.description.reply": "Cunha conta en Mastodon, poderá responder a esta publicación.", + "interaction_modal.on_another_server": "Nun servidor diferente", + "interaction_modal.on_this_server": "Neste servidor", + "interaction_modal.other_server_instructions": "Só ten que copiar e pegar este URL na barra de procuras da súa aplicación favorita, ou da interface web na que teña unha sesión iniciada.", + "interaction_modal.preamble": "Como Mastodon é descentralizado, é posible usar unha conta existente noutro servidor Mastodon, ou nunha plataforma compatible, se non dispoñe dunha conta neste servidor.", + "interaction_modal.title.favourite": "Marcar coma favorito a publicación de {name}", + "interaction_modal.title.follow": "Seguir a {name}", + "interaction_modal.title.reblog": "Promover a publicación de {name}", + "interaction_modal.title.reply": "Responder á publicación de {name}", "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}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Duración", "mute_modal.hide_notifications": "Agochar notificacións desta usuaria?", "mute_modal.indefinite": "Indefinida", - "navigation_bar.apps": "Aplicacións móbiles", + "navigation_bar.about": "Acerca de", + "navigation_bar.apps": "Obtén a app", "navigation_bar.blocks": "Usuarias bloqueadas", "navigation_bar.bookmarks": "Marcadores", "navigation_bar.community_timeline": "Cronoloxía local", @@ -324,7 +375,7 @@ "navigation_bar.filters": "Palabras silenciadas", "navigation_bar.follow_requests": "Peticións de seguimento", "navigation_bar.follows_and_followers": "Seguindo e seguidoras", - "navigation_bar.info": "Sobre este servidor", + "navigation_bar.info": "Acerca de", "navigation_bar.keyboard_shortcuts": "Atallos do teclado", "navigation_bar.lists": "Listaxes", "navigation_bar.logout": "Pechar sesión", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Publicacións fixadas", "navigation_bar.preferences": "Preferencias", "navigation_bar.public_timeline": "Cronoloxía federada", + "navigation_bar.search": "Search", "navigation_bar.security": "Seguranza", + "not_signed_in_indicator.not_signed_in": "Debes acceder para ver este recurso.", "notification.admin.report": "{name} denunciou a {target}", "notification.admin.sign_up": "{name} rexistrouse", "notification.favourite": "{name} marcou a túa publicación como favorita", @@ -401,6 +454,8 @@ "privacy.public.short": "Público", "privacy.unlisted.long": "Visible por todas, pero excluída da sección descubrir", "privacy.unlisted.short": "Non listado", + "privacy_policy.last_updated": "Actualizado por última vez no {date}", + "privacy_policy.title": "Política de Privacidade", "refresh": "Actualizar", "regeneration_indicator.label": "Estase a cargar…", "regeneration_indicator.sublabel": "Estase a preparar a túa cronoloxía de inicio!", @@ -448,8 +503,8 @@ "report.submit": "Enviar", "report.target": "Denunciar a {target}", "report.thanks.take_action": "Aquí tes unhas opcións para controlar o que ves en Mastodon:", - "report.thanks.take_action_actionable": "Mentras revisamos esto, podes tomar accións contra @{name}:", - "report.thanks.title": "Non queres ver esto?", + "report.thanks.take_action_actionable": "Mentras revisamos isto, podes tomar accións contra @{name}:", + "report.thanks.title": "Non queres ver isto?", "report.thanks.title_actionable": "Grazas pola denuncia, investigarémola.", "report.unfollow": "Non seguir a @{name}", "report.unfollow_explanation": "Estás a seguir esta conta. Deixar de ver as súas publicacións na túa cronoloxía, non seguila.", @@ -468,11 +523,17 @@ "search_results.accounts": "Persoas", "search_results.all": "Todo", "search_results.hashtags": "Cancelos", - "search_results.nothing_found": "Non atopamos nada con estos termos de busca", + "search_results.nothing_found": "Non atopamos nada con estes termos de busca", "search_results.statuses": "Publicacións", "search_results.statuses_fts_disabled": "Procurar publicacións polo seu contido non está activado neste servidor do Mastodon.", "search_results.title": "Resultados para {q}", "search_results.total": "{count, number} {count, plural, one {resultado} other {resultados}}", + "server_banner.about_active_users": "Persoas que usaron este servidor nos últimos 30 días (Usuarias Activas Mensuais)", + "server_banner.active_users": "usuarias activas", + "server_banner.administered_by": "Administrada por:", + "server_banner.introduction": "{domain} é parte da rede social descentralizada que funciona grazas a {mastodon}.", + "server_banner.learn_more": "Saber máis", + "server_banner.server_stats": "Estatísticas do servidor:", "sign_in_banner.create_account": "Crear conta", "sign_in_banner.sign_in": "Acceder", "sign_in_banner.text": "Inicia sesión para seguir perfís ou etiquetas, marcar como favorito, responder a publicacións ou interactuar con outro servidor desde a túa conta.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "Aínda ninguén promoveu esta publicación. Cando alguén o faga, amosarase aquí.", "status.redraft": "Eliminar e reescribir", "status.remove_bookmark": "Eliminar marcador", + "status.replied_to": "Replied to {name}", "status.reply": "Responder", "status.replyAll": "Responder ao tema", "status.report": "Denunciar @{name}", @@ -523,9 +585,8 @@ "status.show_more": "Amosar máis", "status.show_more_all": "Amosar máis para todos", "status.show_original": "Mostrar o orixinal", - "status.show_thread": "Amosar fío", "status.translate": "Traducir", - "status.translated_from": "Traducido do {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Non dispoñíbel", "status.unmute_conversation": "Deixar de silenciar conversa", "status.unpin": "Desafixar do perfil", @@ -538,7 +599,6 @@ "tabs_bar.home": "Inicio", "tabs_bar.local_timeline": "Local", "tabs_bar.notifications": "Notificacións", - "tabs_bar.search": "Procurar", "time_remaining.days": "Remata en {number, plural, one {# día} other {# días}}", "time_remaining.hours": "Remata en {number, plural, one {# hora} other {# horas}}", "time_remaining.minutes": "Remata en {number, plural, one {# minuto} other {# minutos}}", diff --git a/app/javascript/mastodon/locales/he.json b/app/javascript/mastodon/locales/he.json index 42eacd0a4..59a3462ab 100644 --- a/app/javascript/mastodon/locales/he.json +++ b/app/javascript/mastodon/locales/he.json @@ -1,4 +1,17 @@ { + "about.blocks": "Moderated servers", + "about.contact": "Contact:", + "about.domain_blocks.comment": "Reason", + "about.domain_blocks.domain": "Domain", + "about.domain_blocks.preamble": "Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.", + "about.domain_blocks.severity": "Severity", + "about.domain_blocks.silenced.explanation": "You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.", + "about.domain_blocks.silenced.title": "Limited", + "about.domain_blocks.suspended.explanation": "No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.", + "about.domain_blocks.suspended.title": "Suspended", + "about.not_available": "This information has not been made available on this server.", + "about.powered_by": "Decentralized social media powered by {mastodon}", + "about.rules": "Server rules", "account.account_note_header": "הערה", "account.add_or_remove_from_list": "הוסף או הסר מהרשימות", "account.badges.bot": "בוט", @@ -7,13 +20,16 @@ "account.block_domain": "חסמו את קהילת {domain}", "account.blocked": "לחסום", "account.browse_more_on_origin_server": "ראה יותר בפרופיל המקורי", - "account.cancel_follow_request": "בטל בקשת מעקב", + "account.cancel_follow_request": "Withdraw follow request", "account.direct": "הודעה ישירה ל@{name}", "account.disable_notifications": "הפסק לשלוח לי התראות כש@{name} מפרסמים", "account.domain_blocked": "הדומיין חסום", "account.edit_profile": "עריכת פרופיל", "account.enable_notifications": "שלח לי התראות כש@{name} מפרסם", "account.endorse": "קדם את החשבון בפרופיל", + "account.featured_tags.last_status_at": "Last post on {date}", + "account.featured_tags.last_status_never": "No posts", + "account.featured_tags.title": "{name}'s featured hashtags", "account.follow": "עקוב", "account.followers": "עוקבים", "account.followers.empty": "אף אחד לא עוקב אחר המשתמש הזה עדיין.", @@ -23,7 +39,7 @@ "account.follows.empty": "משתמש זה לא עוקב אחר אף אחד עדיין.", "account.follows_you": "במעקב אחריך", "account.hide_reblogs": "להסתיר הידהודים מאת @{name}", - "account.joined": "הצטרפו ב{date}", + "account.joined_short": "Joined", "account.languages": "Change subscribed languages", "account.link_verified_on": "בעלות על הקישור הזה נבדקה לאחרונה ב{date}", "account.locked_info": "מצב הפרטיות של החשבון הנוכחי הוגדר כנעול. בעל החשבון קובע באופן פרטני מי יכול לעקוב אחריו.", @@ -63,12 +79,24 @@ "audio.hide": "השתק", "autosuggest_hashtag.per_week": "{count} לשבוע", "boost_modal.combo": "ניתן להקיש {combo} כדי לדלג בפעם הבאה", - "bundle_column_error.body": "משהו השתבש בעת טעינת הרכיב הזה.", + "bundle_column_error.copy_stacktrace": "Copy error report", + "bundle_column_error.error.body": "The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.", + "bundle_column_error.error.title": "Oh, no!", + "bundle_column_error.network.body": "There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.", + "bundle_column_error.network.title": "Network error", "bundle_column_error.retry": "לנסות שוב", - "bundle_column_error.title": "שגיאת רשת", + "bundle_column_error.return": "Go back home", + "bundle_column_error.routing.body": "The requested page could not be found. Are you sure the URL in the address bar is correct?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "לסגור", "bundle_modal_error.message": "משהו השתבש בעת טעינת הרכיב הזה.", "bundle_modal_error.retry": "לנסות שוב", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "About", "column.blocks": "משתמשים חסומים", "column.bookmarks": "סימניות", "column.community": "פיד שרת מקומי", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "לחסום ולדווח", "confirmations.block.confirm": "לחסום", "confirmations.block.message": "האם את/ה בטוח/ה שברצונך למחוק את \"{name}\"?", + "confirmations.cancel_follow_request.confirm": "Withdraw request", + "confirmations.cancel_follow_request.message": "Are you sure you want to withdraw your request to follow {name}?", "confirmations.delete.confirm": "למחוק", "confirmations.delete.message": "בטוח/ה שאת/ה רוצה למחוק את ההודעה?", "confirmations.delete_list.confirm": "למחוק", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "סמן כנקרא", "conversation.open": "צפו בשיחה", "conversation.with": "עם {names}", + "copypaste.copied": "Copied", + "copypaste.copy": "Copy", "directory.federated": "מהפדרציה הידועה", "directory.local": "מ- {domain} בלבד", "directory.new_arrivals": "חדשים כאן", "directory.recently_active": "פעילים לאחרונה", + "dismissable_banner.community_timeline": "These are the most recent public posts from people whose accounts are hosted by {domain}.", + "dismissable_banner.dismiss": "Dismiss", + "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", + "dismissable_banner.explore_statuses": "These posts from this and other servers in the decentralized network are gaining traction on this server right now.", + "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", + "dismissable_banner.public_timeline": "These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.", "embed.instructions": "ניתן להטמיע את הפוסט הזה באתרך ע\"י העתקת הקוד שלהלן.", "embed.preview": "דוגמא כיצד זה יראה:", "emoji_button.activity": "פעילות", @@ -221,14 +259,14 @@ "follow_request.reject": "דחיה", "follow_requests.unlocked_explanation": "למרות שחשבונך אינו נעול, צוות {domain} חושב שאולי כדאי לוודא את בקשות המעקב האלה ידנית.", "generic.saved": "נשמר", - "getting_started.developers": "מפתחות", - "getting_started.directory": "מדריך פרופילים", + "getting_started.directory": "Directory", "getting_started.documentation": "תיעוד", + "getting_started.free_software_notice": "Mastodon is free, open source software. You can view the source code, contribute or report issues at {repository}.", "getting_started.heading": "בואו נתחיל", "getting_started.invite": "להזמין אנשים", - "getting_started.open_source_notice": "מסטודון היא תוכנה חופשית (בקוד פתוח). ניתן לתרום או לדווח על בעיות בגיטהאב: {github}.", "getting_started.privacy_policy": "Privacy Policy", "getting_started.security": "הגדרות חשבון", + "getting_started.what_is_mastodon": "About Mastodon", "hashtag.column_header.tag_mode.all": "ו- {additional}", "hashtag.column_header.tag_mode.any": "או {additional}", "hashtag.column_header.tag_mode.none": "ללא {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "הצגת תגובות", "home.hide_announcements": "הסתר הכרזות", "home.show_announcements": "הצג הכרזות", + "interaction_modal.description.favourite": "With an account on Mastodon, you can favourite this post to let the author know you appreciate it and save it for later.", + "interaction_modal.description.follow": "With an account on Mastodon, you can follow {name} to receive their posts in your home feed.", + "interaction_modal.description.reblog": "With an account on Mastodon, you can boost this post to share it with your own followers.", + "interaction_modal.description.reply": "With an account on Mastodon, you can respond to this post.", + "interaction_modal.on_another_server": "On a different server", + "interaction_modal.on_this_server": "On this server", + "interaction_modal.other_server_instructions": "Simply copy and paste this URL into the search bar of your favourite app or the web interface where you are signed in.", + "interaction_modal.preamble": "Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one.", + "interaction_modal.title.favourite": "Favourite {name}'s post", + "interaction_modal.title.follow": "Follow {name}", + "interaction_modal.title.reblog": "Boost {name}'s post", + "interaction_modal.title.reply": "Reply to {name}'s post", "intervals.full.days": "{number, plural, one {# יום} other {# ימים}}", "intervals.full.hours": "{number, plural, one {# שעה} other {# שעות}}", "intervals.full.minutes": "{number, plural, one {# דקה} other {# דקות}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "משך הזמן", "mute_modal.hide_notifications": "להסתיר התראות מחשבון זה?", "mute_modal.indefinite": "ללא תאריך סיום", - "navigation_bar.apps": "יישומונים לנייד", + "navigation_bar.about": "About", + "navigation_bar.apps": "Get the app", "navigation_bar.blocks": "משתמשים חסומים", "navigation_bar.bookmarks": "סימניות", "navigation_bar.community_timeline": "פיד שרת מקומי", @@ -324,7 +375,7 @@ "navigation_bar.filters": "מילים מושתקות", "navigation_bar.follow_requests": "בקשות מעקב", "navigation_bar.follows_and_followers": "נעקבים ועוקבים", - "navigation_bar.info": "אודות שרת זה", + "navigation_bar.info": "About", "navigation_bar.keyboard_shortcuts": "קיצורי מקלדת", "navigation_bar.lists": "רשימות", "navigation_bar.logout": "התנתקות", @@ -333,7 +384,9 @@ "navigation_bar.pins": "פוסטים נעוצים", "navigation_bar.preferences": "העדפות", "navigation_bar.public_timeline": "פיד כללי (כל השרתים)", + "navigation_bar.search": "Search", "navigation_bar.security": "אבטחה", + "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", "notification.admin.report": "{name} דיווח.ה על {target}", "notification.admin.sign_up": "{name} נרשמו", "notification.favourite": "{name} חיבב/ה את הפוסט שלך", @@ -401,6 +454,8 @@ "privacy.public.short": "פומבי", "privacy.unlisted.long": "גלוי לכל, אבל מוסתר מאמצעי גילוי", "privacy.unlisted.short": "לא רשום (לא לפיד הכללי)", + "privacy_policy.last_updated": "Last updated {date}", + "privacy_policy.title": "Privacy Policy", "refresh": "רענון", "regeneration_indicator.label": "טוען…", "regeneration_indicator.sublabel": "פיד הבית שלך בהכנה!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "חיפוש פוסטים לפי תוכן לא מאופשר בשרת מסטודון זה.", "search_results.title": "Search for {q}", "search_results.total": "{count, number} {count, plural, one {תוצאה} other {תוצאות}}", + "server_banner.about_active_users": "People using this server during the last 30 days (Monthly Active Users)", + "server_banner.active_users": "active users", + "server_banner.administered_by": "Administered by:", + "server_banner.introduction": "{domain} is part of the decentralized social network powered by {mastodon}.", + "server_banner.learn_more": "Learn more", + "server_banner.server_stats": "Server stats:", "sign_in_banner.create_account": "Create account", "sign_in_banner.sign_in": "Sign in", "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "עוד לא הידהדו את הפוסט הזה. כאשר זה יקרה, ההדהודים יופיעו כאן.", "status.redraft": "מחיקה ועריכה מחדש", "status.remove_bookmark": "הסרת סימניה", + "status.replied_to": "Replied to {name}", "status.reply": "תגובה", "status.replyAll": "תגובה לפתיל", "status.report": "דיווח על @{name}", @@ -523,9 +585,8 @@ "status.show_more": "הראה יותר", "status.show_more_all": "להציג יותר מהכל", "status.show_original": "Show original", - "status.show_thread": "הצג כחלק מפתיל", "status.translate": "Translate", - "status.translated_from": "Translated from {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "לא זמין", "status.unmute_conversation": "הסרת השתקת שיחה", "status.unpin": "לשחרר מקיבוע באודות", @@ -538,7 +599,6 @@ "tabs_bar.home": "פיד הבית", "tabs_bar.local_timeline": "פיד שרת מקומי", "tabs_bar.notifications": "התראות", - "tabs_bar.search": "חיפוש", "time_remaining.days": "נותרו {number, plural, one {# יום} other {# ימים}}", "time_remaining.hours": "נותרו {number, plural, one {# שעה} other {# שעות}}", "time_remaining.minutes": "נותרו {number, plural, one {# דקה} other {# דקות}}", diff --git a/app/javascript/mastodon/locales/hi.json b/app/javascript/mastodon/locales/hi.json index 31c4b3956..591cff025 100644 --- a/app/javascript/mastodon/locales/hi.json +++ b/app/javascript/mastodon/locales/hi.json @@ -1,4 +1,17 @@ { + "about.blocks": "Moderated servers", + "about.contact": "Contact:", + "about.domain_blocks.comment": "Reason", + "about.domain_blocks.domain": "Domain", + "about.domain_blocks.preamble": "Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.", + "about.domain_blocks.severity": "Severity", + "about.domain_blocks.silenced.explanation": "You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.", + "about.domain_blocks.silenced.title": "Limited", + "about.domain_blocks.suspended.explanation": "No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.", + "about.domain_blocks.suspended.title": "Suspended", + "about.not_available": "This information has not been made available on this server.", + "about.powered_by": "Decentralized social media powered by {mastodon}", + "about.rules": "Server rules", "account.account_note_header": "टिप्पणियाँ", "account.add_or_remove_from_list": "सूची में जोड़ें या हटाए", "account.badges.bot": "बॉट", @@ -7,13 +20,16 @@ "account.block_domain": "{domain} के सारी चीज़े छुपाएं", "account.blocked": "ब्लॉक", "account.browse_more_on_origin_server": "मूल प्रोफ़ाइल पर अधिक ब्राउज़ करें", - "account.cancel_follow_request": "फ़ॉलो रिक्वेस्ट रद्द करें", + "account.cancel_follow_request": "Withdraw follow request", "account.direct": "प्रत्यक्ष संदेश @{name}", "account.disable_notifications": "@{name} पोस्ट के लिए मुझे सूचित मत करो", "account.domain_blocked": "छिपा हुआ डोमेन", "account.edit_profile": "प्रोफ़ाइल संपादित करें", "account.enable_notifications": "जब @{name} पोस्ट मौजूद हो सूचित करें", "account.endorse": "प्रोफ़ाइल पर दिखाए", + "account.featured_tags.last_status_at": "Last post on {date}", + "account.featured_tags.last_status_never": "No posts", + "account.featured_tags.title": "{name}'s featured hashtags", "account.follow": "फॉलो करें", "account.followers": "फॉलोवर", "account.followers.empty": "कोई भी इस यूज़र् को फ़ॉलो नहीं करता है", @@ -23,7 +39,7 @@ "account.follows.empty": "यह यूज़र् अभी तक किसी को फॉलो नहीं करता है।", "account.follows_you": "आपको फॉलो करता है", "account.hide_reblogs": "@{name} के बूस्ट छुपाएं", - "account.joined": "शामिल हुये {date}", + "account.joined_short": "Joined", "account.languages": "Change subscribed languages", "account.link_verified_on": "इस लिंक का स्वामित्व {date} को चेक किया गया था", "account.locked_info": "यह खाता गोपनीयता स्थिति लॉक करने के लिए सेट है। मालिक मैन्युअल रूप से समीक्षा करता है कि कौन उनको फॉलो कर सकता है।", @@ -63,12 +79,24 @@ "audio.hide": "Hide audio", "autosuggest_hashtag.per_week": "{count} हर सप्ताह", "boost_modal.combo": "अगली बार स्किप करने के लिए आप {combo} दबा सकते है", - "bundle_column_error.body": "इस कॉम्पोनेन्ट को लोड करते वक्त कुछ गलत हो गया", + "bundle_column_error.copy_stacktrace": "Copy error report", + "bundle_column_error.error.body": "The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.", + "bundle_column_error.error.title": "Oh, no!", + "bundle_column_error.network.body": "There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.", + "bundle_column_error.network.title": "Network error", "bundle_column_error.retry": "दुबारा कोशिश करें", - "bundle_column_error.title": "नेटवर्क त्रुटि", + "bundle_column_error.return": "Go back home", + "bundle_column_error.routing.body": "The requested page could not be found. Are you sure the URL in the address bar is correct?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "बंद", "bundle_modal_error.message": "इस कॉम्पोनेन्ट को लोड करते वक्त कुछ गलत हो गया", "bundle_modal_error.retry": "दुबारा कोशिश करें", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "About", "column.blocks": "ब्लॉक्ड यूज़र्स", "column.bookmarks": "पुस्तकचिह्न:", "column.community": "लोकल टाइम्लाइन", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "ब्लॉक एवं रिपोर्ट", "confirmations.block.confirm": "ब्लॉक", "confirmations.block.message": "क्या आप वाकई {name} को ब्लॉक करना चाहते हैं?", + "confirmations.cancel_follow_request.confirm": "Withdraw request", + "confirmations.cancel_follow_request.message": "Are you sure you want to withdraw your request to follow {name}?", "confirmations.delete.confirm": "मिटाए", "confirmations.delete.message": "क्या आप वाकई इस स्टेटस को हटाना चाहते हैं?", "confirmations.delete_list.confirm": "मिटाए", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "पढ़ा गया के रूप में चिह्नित करें", "conversation.open": "वार्तालाप देखें", "conversation.with": "{names} के साथ", + "copypaste.copied": "Copied", + "copypaste.copy": "Copy", "directory.federated": "ज्ञात फेडीवर्स से", "directory.local": "केवल {domain} से", "directory.new_arrivals": "नए आगंतुक", "directory.recently_active": "हाल में ही सक्रिय", + "dismissable_banner.community_timeline": "These are the most recent public posts from people whose accounts are hosted by {domain}.", + "dismissable_banner.dismiss": "Dismiss", + "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", + "dismissable_banner.explore_statuses": "These posts from this and other servers in the decentralized network are gaining traction on this server right now.", + "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", + "dismissable_banner.public_timeline": "These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.", "embed.instructions": "अपने वेबसाइट पर, निचे दिए कोड को कॉपी करके, इस स्टेटस को एम्बेड करें", "embed.preview": "यह ऐसा दिखेगा :", "emoji_button.activity": "गतिविधि", @@ -221,14 +259,14 @@ "follow_request.reject": "अस्वीकार करें", "follow_requests.unlocked_explanation": "हालाँकि आपका खाता लॉक नहीं है, फिर भी {domain} डोमेन स्टाफ ने सोचा कि आप इन खातों के मैन्युअल अनुरोधों की समीक्षा करना चाहते हैं।", "generic.saved": "Saved", - "getting_started.developers": "डेवॅलपर्स", - "getting_started.directory": "प्रोफ़ाइल निर्देशिका", + "getting_started.directory": "Directory", "getting_started.documentation": "प्रलेखन", + "getting_started.free_software_notice": "Mastodon is free, open source software. You can view the source code, contribute or report issues at {repository}.", "getting_started.heading": "पहले कदम रखें", "getting_started.invite": "दोस्तों को आमंत्रित करें", - "getting_started.open_source_notice": "मास्टोडॉन एक मुक्त स्रोत सॉफ्टवेयर है. आप गिटहब {github} पर इस सॉफ्टवेयर में योगदान या किसी भी समस्या को सूचित कर सकते है.", "getting_started.privacy_policy": "Privacy Policy", "getting_started.security": "अकाउंट सेटिंग्स", + "getting_started.what_is_mastodon": "About Mastodon", "hashtag.column_header.tag_mode.all": "और {additional}", "hashtag.column_header.tag_mode.any": "या {additional}", "hashtag.column_header.tag_mode.none": "बिना {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "जवाबों को दिखाए", "home.hide_announcements": "घोषणाएँ छिपाएँ", "home.show_announcements": "घोषणाएं दिखाएं", + "interaction_modal.description.favourite": "With an account on Mastodon, you can favourite this post to let the author know you appreciate it and save it for later.", + "interaction_modal.description.follow": "With an account on Mastodon, you can follow {name} to receive their posts in your home feed.", + "interaction_modal.description.reblog": "With an account on Mastodon, you can boost this post to share it with your own followers.", + "interaction_modal.description.reply": "With an account on Mastodon, you can respond to this post.", + "interaction_modal.on_another_server": "On a different server", + "interaction_modal.on_this_server": "On this server", + "interaction_modal.other_server_instructions": "Simply copy and paste this URL into the search bar of your favourite app or the web interface where you are signed in.", + "interaction_modal.preamble": "Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one.", + "interaction_modal.title.favourite": "Favourite {name}'s post", + "interaction_modal.title.follow": "Follow {name}", + "interaction_modal.title.reblog": "Boost {name}'s post", + "interaction_modal.title.reply": "Reply to {name}'s post", "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}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Duration", "mute_modal.hide_notifications": "Hide notifications from this user?", "mute_modal.indefinite": "Indefinite", - "navigation_bar.apps": "मोबाइल एप्लिकेशंस", + "navigation_bar.about": "About", + "navigation_bar.apps": "Get the app", "navigation_bar.blocks": "ब्लॉक्ड यूज़र्स", "navigation_bar.bookmarks": "पुस्तकचिह्न:", "navigation_bar.community_timeline": "लोकल टाइम्लाइन", @@ -324,7 +375,7 @@ "navigation_bar.filters": "Muted words", "navigation_bar.follow_requests": "अनुसरण करने के अनुरोध", "navigation_bar.follows_and_followers": "Follows and followers", - "navigation_bar.info": "इस सर्वर के बारे में", + "navigation_bar.info": "About", "navigation_bar.keyboard_shortcuts": "Hotkeys", "navigation_bar.lists": "सूचियाँ", "navigation_bar.logout": "बाहर जाए", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Pinned toots", "navigation_bar.preferences": "Preferences", "navigation_bar.public_timeline": "Federated timeline", + "navigation_bar.search": "Search", "navigation_bar.security": "Security", + "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", "notification.admin.report": "{name} reported {target}", "notification.admin.sign_up": "{name} signed up", "notification.favourite": "{name} favourited your status", @@ -401,6 +454,8 @@ "privacy.public.short": "सार्वजनिक", "privacy.unlisted.long": "Visible for all, but opted-out of discovery features", "privacy.unlisted.short": "अनलिस्टेड", + "privacy_policy.last_updated": "Last updated {date}", + "privacy_policy.title": "Privacy Policy", "refresh": "रीफ्रेश करें", "regeneration_indicator.label": "लोड हो रहा है...", "regeneration_indicator.sublabel": "Your home feed is being prepared!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.title": "Search for {q}", "search_results.total": "{count, number} {count, plural, one {result} other {results}}", + "server_banner.about_active_users": "People using this server during the last 30 days (Monthly Active Users)", + "server_banner.active_users": "active users", + "server_banner.administered_by": "Administered by:", + "server_banner.introduction": "{domain} is part of the decentralized social network powered by {mastodon}.", + "server_banner.learn_more": "Learn more", + "server_banner.server_stats": "Server stats:", "sign_in_banner.create_account": "Create account", "sign_in_banner.sign_in": "Sign in", "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "No one has boosted this toot yet. When someone does, they will show up here.", "status.redraft": "Delete & re-draft", "status.remove_bookmark": "Remove bookmark", + "status.replied_to": "Replied to {name}", "status.reply": "जवाब", "status.replyAll": "Reply to thread", "status.report": "Report @{name}", @@ -523,9 +585,8 @@ "status.show_more": "और दिखाएँ", "status.show_more_all": "Show more for all", "status.show_original": "Show original", - "status.show_thread": "Show thread", "status.translate": "Translate", - "status.translated_from": "Translated from {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "अनुपलब्ध", "status.unmute_conversation": "Unmute conversation", "status.unpin": "Unpin from profile", @@ -538,7 +599,6 @@ "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", diff --git a/app/javascript/mastodon/locales/hr.json b/app/javascript/mastodon/locales/hr.json index 981f85c79..252d08286 100644 --- a/app/javascript/mastodon/locales/hr.json +++ b/app/javascript/mastodon/locales/hr.json @@ -1,4 +1,17 @@ { + "about.blocks": "Moderated servers", + "about.contact": "Contact:", + "about.domain_blocks.comment": "Reason", + "about.domain_blocks.domain": "Domain", + "about.domain_blocks.preamble": "Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.", + "about.domain_blocks.severity": "Severity", + "about.domain_blocks.silenced.explanation": "You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.", + "about.domain_blocks.silenced.title": "Limited", + "about.domain_blocks.suspended.explanation": "No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.", + "about.domain_blocks.suspended.title": "Suspended", + "about.not_available": "This information has not been made available on this server.", + "about.powered_by": "Decentralized social media powered by {mastodon}", + "about.rules": "Server rules", "account.account_note_header": "Bilješka", "account.add_or_remove_from_list": "Dodaj ili ukloni s liste", "account.badges.bot": "Bot", @@ -7,13 +20,16 @@ "account.block_domain": "Blokiraj domenu {domain}", "account.blocked": "Blokirano", "account.browse_more_on_origin_server": "Pogledajte više na izvornom profilu", - "account.cancel_follow_request": "Otkaži zahtjev za praćenje", + "account.cancel_follow_request": "Withdraw follow request", "account.direct": "Pošalji poruku @{name}", "account.disable_notifications": "Nemoj me obavjestiti kada @{name} napravi objavu", "account.domain_blocked": "Domena je blokirana", "account.edit_profile": "Uredi profil", "account.enable_notifications": "Obavjesti me kada @{name} napravi objavu", "account.endorse": "Istakni na profilu", + "account.featured_tags.last_status_at": "Last post on {date}", + "account.featured_tags.last_status_never": "No posts", + "account.featured_tags.title": "{name}'s featured hashtags", "account.follow": "Prati", "account.followers": "Pratitelji", "account.followers.empty": "Nitko još ne prati korisnika/cu.", @@ -23,7 +39,7 @@ "account.follows.empty": "Korisnik/ca još ne prati nikoga.", "account.follows_you": "Prati te", "account.hide_reblogs": "Sakrij boostove od @{name}", - "account.joined": "Pridružio se {date}", + "account.joined_short": "Joined", "account.languages": "Change subscribed languages", "account.link_verified_on": "Vlasništvo ove poveznice provjereno je {date}", "account.locked_info": "Status privatnosti ovog računa postavljen je na zaključano. Vlasnik ručno pregledava tko ih može pratiti.", @@ -63,12 +79,24 @@ "audio.hide": "Hide audio", "autosuggest_hashtag.per_week": "{count} tjedno", "boost_modal.combo": "Možete pritisnuti {combo} kako biste preskočili ovo sljedeći put", - "bundle_column_error.body": "Nešto je pošlo po zlu tijekom učitavanja ove komponente.", + "bundle_column_error.copy_stacktrace": "Copy error report", + "bundle_column_error.error.body": "The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.", + "bundle_column_error.error.title": "Oh, no!", + "bundle_column_error.network.body": "There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.", + "bundle_column_error.network.title": "Network error", "bundle_column_error.retry": "Pokušajte ponovno", - "bundle_column_error.title": "Greška mreže", + "bundle_column_error.return": "Go back home", + "bundle_column_error.routing.body": "The requested page could not be found. Are you sure the URL in the address bar is correct?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Zatvori", "bundle_modal_error.message": "Nešto je pošlo po zlu tijekom učitavanja ove komponente.", "bundle_modal_error.retry": "Pokušajte ponovno", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "About", "column.blocks": "Blokirani korisnici", "column.bookmarks": "Knjižne oznake", "column.community": "Lokalna vremenska crta", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "Blokiraj i prijavi", "confirmations.block.confirm": "Blokiraj", "confirmations.block.message": "Sigurno želite blokirati {name}?", + "confirmations.cancel_follow_request.confirm": "Withdraw request", + "confirmations.cancel_follow_request.message": "Are you sure you want to withdraw your request to follow {name}?", "confirmations.delete.confirm": "Obriši", "confirmations.delete.message": "Stvarno želite obrisati ovaj toot?", "confirmations.delete_list.confirm": "Obriši", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Označi kao pročitano", "conversation.open": "Prikaži razgovor", "conversation.with": "S {names}", + "copypaste.copied": "Copied", + "copypaste.copy": "Copy", "directory.federated": "Iz znanog fediversa", "directory.local": "Samo iz {domain}", "directory.new_arrivals": "Novi korisnici", "directory.recently_active": "Nedavno aktivni", + "dismissable_banner.community_timeline": "These are the most recent public posts from people whose accounts are hosted by {domain}.", + "dismissable_banner.dismiss": "Dismiss", + "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", + "dismissable_banner.explore_statuses": "These posts from this and other servers in the decentralized network are gaining traction on this server right now.", + "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", + "dismissable_banner.public_timeline": "These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.", "embed.instructions": "Embed this status on your website by copying the code below.", "embed.preview": "Evo kako će izgledati:", "emoji_button.activity": "Aktivnost", @@ -221,14 +259,14 @@ "follow_request.reject": "Odbij", "follow_requests.unlocked_explanation": "Even though your account is not locked, the {domain} staff thought you might want to review follow requests from these accounts manually.", "generic.saved": "Spremljeno", - "getting_started.developers": "Razvijatelji", - "getting_started.directory": "Direktorij profila", + "getting_started.directory": "Directory", "getting_started.documentation": "Dokumentacija", + "getting_started.free_software_notice": "Mastodon is free, open source software. You can view the source code, contribute or report issues at {repository}.", "getting_started.heading": "Počnimo", "getting_started.invite": "Pozovi ljude", - "getting_started.open_source_notice": "Mastodon je softver otvorenog kôda. Možete pridonijeti ili prijaviti probleme na GitHubu na {github}.", "getting_started.privacy_policy": "Privacy Policy", "getting_started.security": "Postavke računa", + "getting_started.what_is_mastodon": "About Mastodon", "hashtag.column_header.tag_mode.all": "i {additional}", "hashtag.column_header.tag_mode.any": "ili {additional}", "hashtag.column_header.tag_mode.none": "bez {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Pokaži odgovore", "home.hide_announcements": "Sakrij najave", "home.show_announcements": "Prikaži najave", + "interaction_modal.description.favourite": "With an account on Mastodon, you can favourite this post to let the author know you appreciate it and save it for later.", + "interaction_modal.description.follow": "With an account on Mastodon, you can follow {name} to receive their posts in your home feed.", + "interaction_modal.description.reblog": "With an account on Mastodon, you can boost this post to share it with your own followers.", + "interaction_modal.description.reply": "With an account on Mastodon, you can respond to this post.", + "interaction_modal.on_another_server": "On a different server", + "interaction_modal.on_this_server": "On this server", + "interaction_modal.other_server_instructions": "Simply copy and paste this URL into the search bar of your favourite app or the web interface where you are signed in.", + "interaction_modal.preamble": "Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one.", + "interaction_modal.title.favourite": "Favourite {name}'s post", + "interaction_modal.title.follow": "Follow {name}", + "interaction_modal.title.reblog": "Boost {name}'s post", + "interaction_modal.title.reply": "Reply to {name}'s post", "intervals.full.days": "{number, plural, one {# dan} other {# dana}}", "intervals.full.hours": "{number, plural, one {# sat} few {# sata} other {# sati}}", "intervals.full.minutes": "{number, plural, one {# minuta} few {# minute} other {# minuta}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Trajanje", "mute_modal.hide_notifications": "Hide notifications from this user?", "mute_modal.indefinite": "Indefinite", - "navigation_bar.apps": "Mobilne aplikacije", + "navigation_bar.about": "About", + "navigation_bar.apps": "Get the app", "navigation_bar.blocks": "Blokirani korisnici", "navigation_bar.bookmarks": "Bookmarks", "navigation_bar.community_timeline": "Lokalna vremenska crta", @@ -324,7 +375,7 @@ "navigation_bar.filters": "Utišane riječi", "navigation_bar.follow_requests": "Zahtjevi za praćenje", "navigation_bar.follows_and_followers": "Praćeni i pratitelji", - "navigation_bar.info": "O ovom poslužitelju", + "navigation_bar.info": "About", "navigation_bar.keyboard_shortcuts": "Tipkovnički prečaci", "navigation_bar.lists": "Liste", "navigation_bar.logout": "Odjavi se", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Prikvačeni tootovi", "navigation_bar.preferences": "Postavke", "navigation_bar.public_timeline": "Federalna vremenska crta", + "navigation_bar.search": "Search", "navigation_bar.security": "Sigurnost", + "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", "notification.admin.report": "{name} reported {target}", "notification.admin.sign_up": "{name} signed up", "notification.favourite": "{name} je favorizirao/la Vaš toot", @@ -401,6 +454,8 @@ "privacy.public.short": "Javno", "privacy.unlisted.long": "Visible for all, but opted-out of discovery features", "privacy.unlisted.short": "Neprikazano", + "privacy_policy.last_updated": "Last updated {date}", + "privacy_policy.title": "Privacy Policy", "refresh": "Osvježi", "regeneration_indicator.label": "Učitavanje…", "regeneration_indicator.sublabel": "Priprema se Vaša početna stranica!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.title": "Search for {q}", "search_results.total": "{count, number} {count, plural, one {result} other {results}}", + "server_banner.about_active_users": "People using this server during the last 30 days (Monthly Active Users)", + "server_banner.active_users": "active users", + "server_banner.administered_by": "Administered by:", + "server_banner.introduction": "{domain} is part of the decentralized social network powered by {mastodon}.", + "server_banner.learn_more": "Learn more", + "server_banner.server_stats": "Server stats:", "sign_in_banner.create_account": "Create account", "sign_in_banner.sign_in": "Sign in", "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "Nitko još nije boostao ovaj toot. Kada netko to učini, ovdje će biti prikazani.", "status.redraft": "Izbriši i ponovno uredi", "status.remove_bookmark": "Ukloni knjižnu oznaku", + "status.replied_to": "Replied to {name}", "status.reply": "Odgovori", "status.replyAll": "Odgovori na niz", "status.report": "Prijavi @{name}", @@ -523,9 +585,8 @@ "status.show_more": "Pokaži više", "status.show_more_all": "Show more for all", "status.show_original": "Show original", - "status.show_thread": "Prikaži nit", "status.translate": "Translate", - "status.translated_from": "Translated from {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Nije dostupno", "status.unmute_conversation": "Poništi utišavanje razgovora", "status.unpin": "Otkvači s profila", @@ -538,7 +599,6 @@ "tabs_bar.home": "Početna", "tabs_bar.local_timeline": "Lokalno", "tabs_bar.notifications": "Obavijesti", - "tabs_bar.search": "Traži", "time_remaining.days": "{number, plural, one {preostao # dan} other {preostalo # dana}}", "time_remaining.hours": "{number, plural, one {preostao # sat} few {preostalo # sata} other {preostalo # sati}}", "time_remaining.minutes": "{number, plural, one {preostala # minuta} few {preostale # minute} other {preostalo # minuta}}", diff --git a/app/javascript/mastodon/locales/hu.json b/app/javascript/mastodon/locales/hu.json index fbd6695d4..a3f391bb6 100644 --- a/app/javascript/mastodon/locales/hu.json +++ b/app/javascript/mastodon/locales/hu.json @@ -1,4 +1,17 @@ { + "about.blocks": "Moderált kiszolgálók", + "about.contact": "Kapcsolat:", + "about.domain_blocks.comment": "Indoklás", + "about.domain_blocks.domain": "Domain", + "about.domain_blocks.preamble": "A Mastodon általában mindenféle tartalomcserét és interakciót lehetővé tesz bármelyik másik kiszolgálóval a födiverzumban. Ezek azok a kivételek, amelyek a mi kiszolgálónkon érvényben vannak.", + "about.domain_blocks.severity": "Súlyosság", + "about.domain_blocks.silenced.explanation": "Általában nem fogsz profilokat és tartalmat látni erről a kiszolgálóról, hacsak közvetlenül fel nem keresed vagy követed.", + "about.domain_blocks.silenced.title": "Korlátozott", + "about.domain_blocks.suspended.explanation": "A kiszolgáló adatai nem lesznek feldolgozva, tárolva vagy megosztva, lehetetlenné téve mindennemű interakciót és kommunikációt a kiszolgáló felhasználóival.", + "about.domain_blocks.suspended.title": "Felfüggesztett", + "about.not_available": "Ez az információ nem lett közzétéve ezen a kiszolgálón.", + "about.powered_by": "Decentralizált közösségi média a {mastodon} segítségével", + "about.rules": "Kiszolgáló szabályai", "account.account_note_header": "Jegyzet", "account.add_or_remove_from_list": "Hozzáadás vagy eltávolítás a listákról", "account.badges.bot": "Bot", @@ -7,13 +20,16 @@ "account.block_domain": "Domain blokkolása: {domain}", "account.blocked": "Letiltva", "account.browse_more_on_origin_server": "Böngéssz tovább az eredeti profilon", - "account.cancel_follow_request": "Követési kérelem visszavonása", + "account.cancel_follow_request": "Követési kérés visszavonása", "account.direct": "Közvetlen üzenet @{name} számára", "account.disable_notifications": "Ne figyelmeztessen, ha @{name} bejegyzést tesz közzé", "account.domain_blocked": "Letiltott domain", "account.edit_profile": "Profil szerkesztése", "account.enable_notifications": "Figyelmeztessen, ha @{name} bejegyzést tesz közzé", "account.endorse": "Kiemelés a profilodon", + "account.featured_tags.last_status_at": "Legutolsó bejegyzés ideje: {date}", + "account.featured_tags.last_status_never": "Nincs bejegyzés", + "account.featured_tags.title": "{name} kiemelt hashtagjei", "account.follow": "Követés", "account.followers": "Követő", "account.followers.empty": "Ezt a felhasználót még senki sem követi.", @@ -23,7 +39,7 @@ "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 elrejtése", - "account.joined": "Csatlakozott {date}", + "account.joined_short": "Joined", "account.languages": "Feliratkozott nyelvek módosítása", "account.link_verified_on": "A linket eredetiségét ebben az időpontban ellenőriztük: {date}", "account.locked_info": "Ennek a fióknak zárolt a láthatósága. A tulajdonos kézzel engedélyezi, hogy ki követheti őt.", @@ -63,12 +79,24 @@ "audio.hide": "Hang elrejtése", "autosuggest_hashtag.per_week": "{count} hetente", "boost_modal.combo": "Hogy átugord ezt következő alkalommal, használd {combo}", - "bundle_column_error.body": "Valami hiba történt a komponens betöltése közben.", + "bundle_column_error.copy_stacktrace": "Hibajelentés másolása", + "bundle_column_error.error.body": "A kért lap nem jeleníthető meg. Ez lehet, hogy kódhiba, vagy böngészőkompatibitási hiba.", + "bundle_column_error.error.title": "Jaj ne!", + "bundle_column_error.network.body": "Hiba történt az oldal betöltése során. Ezt az internetkapcsolat ideiglenes problémája vagy kiszolgálóhiba is okozhatja.", + "bundle_column_error.network.title": "Hálózati hiba", "bundle_column_error.retry": "Próbáld újra", - "bundle_column_error.title": "Hálózati hiba", + "bundle_column_error.return": "Vissza a kezdőlapra", + "bundle_column_error.routing.body": "A kért oldal nem található. Biztos, hogy a címsávban lévő webcím helyes?", + "bundle_column_error.routing.title": "404", "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áld újra", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "Névjegy", "column.blocks": "Letiltott felhasználók", "column.bookmarks": "Könyvjelzők", "column.community": "Helyi idővonal", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "Letiltás és jelentés", "confirmations.block.confirm": "Letiltás", "confirmations.block.message": "Biztos, hogy letiltod: {name}?", + "confirmations.cancel_follow_request.confirm": "Kérés visszavonása", + "confirmations.cancel_follow_request.message": "Biztos, hogy visszavonod a(z) {name} felhasználóra vonatkozó követési kérésedet?", "confirmations.delete.confirm": "Törlés", "confirmations.delete.message": "Biztos, hogy törölni szeretnéd ezt a bejegyzést?", "confirmations.delete_list.confirm": "Törlés", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Megjelölés olvasottként", "conversation.open": "Beszélgetés megtekintése", "conversation.with": "{names}-el/al", + "copypaste.copied": "Másolva", + "copypaste.copy": "Másolás", "directory.federated": "Az ismert fediverzumból", "directory.local": "Csak innen: {domain}", "directory.new_arrivals": "Új csatlakozók", "directory.recently_active": "Nemrég aktív", + "dismissable_banner.community_timeline": "Ezek a legfrissebb nyilvános bejegyzések, amelyeket a(z) {domain} kiszolgáló fiókjait használó emberek tették közzé.", + "dismissable_banner.dismiss": "Eltüntetés", + "dismissable_banner.explore_links": "Jelenleg ezekről a hírekről beszélgetnek az ezen és a decentralizált hálózat többi kiszolgálóján lévő emberek.", + "dismissable_banner.explore_statuses": "Jelenleg ezek a bejegyzések hódítanak teret ezen és a decentralizált hálózat egyéb kiszolgálóin.", + "dismissable_banner.explore_tags": "Jelenleg ezek a hashtagek hódítanak teret ezen és a decentralizált hálózat többi kiszolgálóján lévő emberek körében.", + "dismissable_banner.public_timeline": "Ezek a legfrissebb bejegyzések azoktól, akik a decentralizált hálózat más kiszolgálóin vannak, és ez a kiszolgáló tud róluk.", "embed.instructions": "Ágyazd be ezt a bejegyzést a weboldaladba az alábbi kód kimásolásával.", "embed.preview": "Így fog kinézni:", "emoji_button.activity": "Tevékenység", @@ -185,7 +223,7 @@ "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", + "empty_column.public": "Jelenleg itt nincs semmi! Írj valamit nyilvánosan vagy kövess más kiszolgálón levő felhasználókat, hogy megtöltsd.", "error.unexpected_crash.explanation": "Egy hiba vagy böngésző inkompatibilitás miatt ez az oldal nem jeleníthető meg rendesen.", "error.unexpected_crash.explanation_addons": "Ezt az oldalt nem lehet helyesen megjeleníteni. Ezt a hibát valószínűleg egy böngésző beépülő vagy egy automatikus fordító okozza.", "error.unexpected_crash.next_steps": "Próbáld frissíteni az oldalt. Ha ez nem segít, egy másik böngészőn vagy appon keresztül még mindig használhatod a Mastodont.", @@ -221,14 +259,14 @@ "follow_request.reject": "Elutasítás", "follow_requests.unlocked_explanation": "Bár a fiókod nincs zárolva, a(z) {domain} csapata úgy gondolta, hogy talán kézzel szeretnéd ellenőrizni a fiók követési kéréseit.", "generic.saved": "Elmentve", - "getting_started.developers": "Fejlesztőknek", - "getting_started.directory": "Profilok", + "getting_started.directory": "Névjegyzék", "getting_started.documentation": "Dokumentáció", + "getting_started.free_software_notice": "A Mastodon ingyenes, nyílt forráskódú szoftver. Megtekintheted a forrását, hozzájárulhatsz a fejlesztéséhez vagy jelenthetsz hibákat itt: {repository}", "getting_started.heading": "Első lépések", "getting_started.invite": "Mások meghívása", - "getting_started.open_source_notice": "A Mastodon nyílt forráskódú szoftver. Közreműködhetsz vagy problémákat jelenthetsz a GitHubon: {github}.", "getting_started.privacy_policy": "Adatvédelmi szabályzat", "getting_started.security": "Fiókbeállítások", + "getting_started.what_is_mastodon": "A Mastodonról", "hashtag.column_header.tag_mode.all": "és {additional}", "hashtag.column_header.tag_mode.any": "vagy {additional}", "hashtag.column_header.tag_mode.none": "{additional} nélkül", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Válaszok megjelenítése", "home.hide_announcements": "Közlemények elrejtése", "home.show_announcements": "Közlemények megjelenítése", + "interaction_modal.description.favourite": "Egy Mastodon fiókkal kedvencnek jelölheted ezt a bejegyzést, tudatva a szerzővel, hogy értékeled és elteszed későbbre.", + "interaction_modal.description.follow": "Egy Mastodon fiókkal bekövetheted {name} fiókot, hogy lásd a bejegyzéseit a saját hírfolyamodban.", + "interaction_modal.description.reblog": "Egy Mastodon fiókkal megtolhatod ezt a bejegyzést, hogy megoszd a saját követőiddel.", + "interaction_modal.description.reply": "Egy Mastodon fiókkal válaszolhatsz erre a bejegyzésre.", + "interaction_modal.on_another_server": "Másik kiszolgálón", + "interaction_modal.on_this_server": "Ezen a kiszolgálón", + "interaction_modal.other_server_instructions": "Csak másold be ezt az URL-t a kedvenc appod keresőjébe, vagy arra a webes felületre, ahol be vagy jelentkezve.", + "interaction_modal.preamble": "Mivel a Mastodon decentralizált, használhatod egy másik Mastodon kiszolgálón, vagy kompatibilis szolgáltatáson lévő fiókodat, ha ezen a kiszolgálón nincs fiókod.", + "interaction_modal.title.favourite": "{name} bejegyzésének megjelölése kedvencként", + "interaction_modal.title.follow": "{name} követése", + "interaction_modal.title.reblog": "{name} bejegyzésének megtolása", + "interaction_modal.title.reply": "Válasz {name} bejegyzésére", "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}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Időtartam", "mute_modal.hide_notifications": "Rejtsük el a felhasználótól származó értesítéseket?", "mute_modal.indefinite": "Határozatlan", - "navigation_bar.apps": "Mobil appok", + "navigation_bar.about": "Névjegy", + "navigation_bar.apps": "Töltsd le az appot", "navigation_bar.blocks": "Letiltott felhasználók", "navigation_bar.bookmarks": "Könyvjelzők", "navigation_bar.community_timeline": "Helyi idővonal", @@ -324,7 +375,7 @@ "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 kiszolgálóról", + "navigation_bar.info": "Névjegy", "navigation_bar.keyboard_shortcuts": "Gyorsbillentyűk", "navigation_bar.lists": "Listák", "navigation_bar.logout": "Kijelentkezés", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Kitűzött bejegyzések", "navigation_bar.preferences": "Beállítások", "navigation_bar.public_timeline": "Föderációs idővonal", + "navigation_bar.search": "Search", "navigation_bar.security": "Biztonság", + "not_signed_in_indicator.not_signed_in": "Az erőforrás eléréséhez be kell jelentkezned.", "notification.admin.report": "{name} jelentette: {target}", "notification.admin.sign_up": "{name} regisztrált", "notification.favourite": "{name} kedvencnek jelölte a bejegyzésedet", @@ -401,6 +454,8 @@ "privacy.public.short": "Nyilvános", "privacy.unlisted.long": "Mindenki számára látható, de kimarad a felfedezős funkciókból", "privacy.unlisted.short": "Listázatlan", + "privacy_policy.last_updated": "Utoljára frissítve: {date}", + "privacy_policy.title": "Adatvédelmi szabályzat", "refresh": "Frissítés", "regeneration_indicator.label": "Töltődik…", "regeneration_indicator.sublabel": "A saját idővonalad épp készül!", @@ -473,9 +528,15 @@ "search_results.statuses_fts_disabled": "Ezen a Mastodon szerveren nem engedélyezett a bejegyzések tartalom szerinti keresése.", "search_results.title": "Keresés erre: {q}", "search_results.total": "{count, number} {count, plural, one {találat} other {találat}}", + "server_banner.about_active_users": "Az elmúlt 30 napban ezt a kiszolgálót használók száma (Havi aktív felhasználók)", + "server_banner.active_users": "aktív felhasználó", + "server_banner.administered_by": "Adminisztrátor:", + "server_banner.introduction": "{domain} része egy decentralizált közösségi hálónak, melyet a {mastodon} hajt meg.", + "server_banner.learn_more": "Tudj meg többet", + "server_banner.server_stats": "Kiszolgálóstatisztika:", "sign_in_banner.create_account": "Fiók létrehozása", "sign_in_banner.sign_in": "Bejelentkezés", - "sign_in_banner.text": "Jelentkezz be profilok vagy hashtagek követéséhez, bejegyzések megosztásához, megválaszolásához, vagy kommunikálj a fiókodból más szerverekkel.", + "sign_in_banner.text": "Jelentkezz be profilok vagy hashtagek követéséhez, bejegyzések megosztásához, megválaszolásához, vagy kommunikálj a fiókodból más kiszolgálókkal.", "status.admin_account": "Moderációs felület megnyitása @{name} fiókhoz", "status.admin_status": "Bejegyzés megnyitása a moderációs felületen", "status.block": "@{name} letiltása", @@ -512,6 +573,7 @@ "status.reblogs.empty": "Senki sem tolta még meg ezt a bejegyzést. Ha valaki megteszi, itt fog megjelenni.", "status.redraft": "Törlés és újraírás", "status.remove_bookmark": "Könyvjelző eltávolítása", + "status.replied_to": "Replied to {name}", "status.reply": "Válasz", "status.replyAll": "Válasz a beszélgetésre", "status.report": "@{name} bejelentése", @@ -523,9 +585,8 @@ "status.show_more": "Többet", "status.show_more_all": "Többet mindenhol", "status.show_original": "Eredeti mutatása", - "status.show_thread": "Szál mutatása", "status.translate": "Fordítás", - "status.translated_from": "{lang} nyelvből fordítva", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Nem érhető el", "status.unmute_conversation": "Beszélgetés némításának feloldása", "status.unpin": "Kitűzés eltávolítása a profilodról", @@ -538,13 +599,12 @@ "tabs_bar.home": "Kezdőlap", "tabs_bar.local_timeline": "Helyi", "tabs_bar.notifications": "Értesítések", - "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", - "timeline_hint.remote_resource_not_displayed": "más szerverekről származó {resource} tartalmakat nem mutatjuk.", + "timeline_hint.remote_resource_not_displayed": "a más kiszolgálókról származó {resource} tartalmak nem jelennek meg.", "timeline_hint.resources.followers": "Követő", "timeline_hint.resources.follows": "Követett", "timeline_hint.resources.statuses": "Régi bejegyzések", diff --git a/app/javascript/mastodon/locales/hy.json b/app/javascript/mastodon/locales/hy.json index 524e06d6f..cd68f74d2 100644 --- a/app/javascript/mastodon/locales/hy.json +++ b/app/javascript/mastodon/locales/hy.json @@ -1,4 +1,17 @@ { + "about.blocks": "Moderated servers", + "about.contact": "Contact:", + "about.domain_blocks.comment": "Reason", + "about.domain_blocks.domain": "Domain", + "about.domain_blocks.preamble": "Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.", + "about.domain_blocks.severity": "Severity", + "about.domain_blocks.silenced.explanation": "You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.", + "about.domain_blocks.silenced.title": "Limited", + "about.domain_blocks.suspended.explanation": "No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.", + "about.domain_blocks.suspended.title": "Suspended", + "about.not_available": "This information has not been made available on this server.", + "about.powered_by": "Decentralized social media powered by {mastodon}", + "about.rules": "Server rules", "account.account_note_header": "Նշում", "account.add_or_remove_from_list": "Աւելացնել կամ հեռացնել ցանկերից", "account.badges.bot": "Բոտ", @@ -7,13 +20,16 @@ "account.block_domain": "Թաքցնել ամէնը հետեւեալ տիրոյթից՝ {domain}", "account.blocked": "Արգելափակուած է", "account.browse_more_on_origin_server": "Դիտել աւելին իրական պրոֆիլում", - "account.cancel_follow_request": "չեղարկել հետեւելու հայցը", + "account.cancel_follow_request": "Withdraw follow request", "account.direct": "Նամակ գրել @{name} -ին", "account.disable_notifications": "Ծանուցումները անջատել @{name} գրառումների համար", "account.domain_blocked": "Տիրոյթը արգելափակուած է", "account.edit_profile": "Խմբագրել անձնական էջը", "account.enable_notifications": "Ծանուցել ինձ @{name} գրառումների մասին", "account.endorse": "Ցուցադրել անձնական էջում", + "account.featured_tags.last_status_at": "Last post on {date}", + "account.featured_tags.last_status_never": "No posts", + "account.featured_tags.title": "{name}'s featured hashtags", "account.follow": "Հետեւել", "account.followers": "Հետեւողներ", "account.followers.empty": "Այս օգտատիրոջը դեռ ոչ մէկ չի հետեւում։", @@ -23,7 +39,7 @@ "account.follows.empty": "Այս օգտատէրը դեռ ոչ մէկի չի հետեւում։", "account.follows_you": "Հետեւում է քեզ", "account.hide_reblogs": "Թաքցնել @{name}֊ի տարածածները", - "account.joined": "Միացել է {date}-ից", + "account.joined_short": "Joined", "account.languages": "Change subscribed languages", "account.link_verified_on": "Սոյն յղման տիրապետումը ստուգուած է՝ {date}֊ին", "account.locked_info": "Սոյն հաշուի գաղտնիութեան մակարդակը նշուած է որպէս՝ փակ։ Հաշուի տէրն ընտրում է, թէ ով կարող է հետեւել իրեն։", @@ -63,12 +79,24 @@ "audio.hide": "Hide audio", "autosuggest_hashtag.per_week": "շաբաթը՝ {count}", "boost_modal.combo": "Կարող ես սեղմել {combo}՝ սա յաջորդ անգամ բաց թողնելու համար", - "bundle_column_error.body": "Այս բաղադրիչը բեռնելու ընթացքում ինչ֊որ բան խափանուեց։", + "bundle_column_error.copy_stacktrace": "Copy error report", + "bundle_column_error.error.body": "The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.", + "bundle_column_error.error.title": "Oh, no!", + "bundle_column_error.network.body": "There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.", + "bundle_column_error.network.title": "Network error", "bundle_column_error.retry": "Կրկին փորձել", - "bundle_column_error.title": "Ցանցային սխալ", + "bundle_column_error.return": "Go back home", + "bundle_column_error.routing.body": "The requested page could not be found. Are you sure the URL in the address bar is correct?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Փակել", "bundle_modal_error.message": "Այս բաղադրիչը բեռնելու ընթացքում ինչ֊որ բան խափանուեց։", "bundle_modal_error.retry": "Կրկին փորձել", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "About", "column.blocks": "Արգելափակուած օգտատէրեր", "column.bookmarks": "Էջանիշեր", "column.community": "Տեղական հոսք", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "Արգելափակել եւ բողոքել", "confirmations.block.confirm": "Արգելափակել", "confirmations.block.message": "Վստա՞հ ես, որ ուզում ես արգելափակել {name}֊ին։", + "confirmations.cancel_follow_request.confirm": "Withdraw request", + "confirmations.cancel_follow_request.message": "Are you sure you want to withdraw your request to follow {name}?", "confirmations.delete.confirm": "Ջնջել", "confirmations.delete.message": "Վստա՞հ ես, որ ուզում ես ջնջել այս գրառումը։", "confirmations.delete_list.confirm": "Ջնջել", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Նշել որպէս ընթերցուած", "conversation.open": "Դիտել խօսակցութիւնը", "conversation.with": "{names}-ի հետ", + "copypaste.copied": "Copied", + "copypaste.copy": "Copy", "directory.federated": "Յայտնի դաշնեզերքից", "directory.local": "{domain} տիրոյթից միայն", "directory.new_arrivals": "Նորեկներ", "directory.recently_active": "Վերջերս ակտիւ", + "dismissable_banner.community_timeline": "These are the most recent public posts from people whose accounts are hosted by {domain}.", + "dismissable_banner.dismiss": "Dismiss", + "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", + "dismissable_banner.explore_statuses": "These posts from this and other servers in the decentralized network are gaining traction on this server right now.", + "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", + "dismissable_banner.public_timeline": "These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.", "embed.instructions": "Այս գրառումը քո կայքում ներդնելու համար կարող ես պատճէնել ներքեւի կոդը։", "embed.preview": "Ահա, թէ ինչ տեսք կունենայ այն՝", "emoji_button.activity": "Զբաղմունքներ", @@ -221,14 +259,14 @@ "follow_request.reject": "Մերժել", "follow_requests.unlocked_explanation": "Այս հարցումը ուղարկուած է հաշուից, որի համար {domain}-ի անձնակազմը միացրել է ձեռքով ստուգում։", "generic.saved": "Պահպանուած է", - "getting_started.developers": "Մշակողներ", - "getting_started.directory": "Օգտատէրերի շտեմարան", + "getting_started.directory": "Directory", "getting_started.documentation": "Փաստաթղթեր", + "getting_started.free_software_notice": "Mastodon is free, open source software. You can view the source code, contribute or report issues at {repository}.", "getting_started.heading": "Ինչպէս սկսել", "getting_started.invite": "Հրաւիրել մարդկանց", - "getting_started.open_source_notice": "Մաստոդոնը բաց ելատեքստով ծրագրակազմ է։ Կարող ես ներդրում անել կամ վրէպներ զեկուցել ԳիթՀաբում՝ {github}։", "getting_started.privacy_policy": "Privacy Policy", "getting_started.security": "Հաշուի կարգաւորումներ", + "getting_started.what_is_mastodon": "About Mastodon", "hashtag.column_header.tag_mode.all": "եւ {additional}", "hashtag.column_header.tag_mode.any": "կամ {additional}", "hashtag.column_header.tag_mode.none": "առանց {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Ցուցադրել պատասխանները", "home.hide_announcements": "Թաքցնել յայտարարութիւնները", "home.show_announcements": "Ցուցադրել յայտարարութիւնները", + "interaction_modal.description.favourite": "With an account on Mastodon, you can favourite this post to let the author know you appreciate it and save it for later.", + "interaction_modal.description.follow": "With an account on Mastodon, you can follow {name} to receive their posts in your home feed.", + "interaction_modal.description.reblog": "With an account on Mastodon, you can boost this post to share it with your own followers.", + "interaction_modal.description.reply": "With an account on Mastodon, you can respond to this post.", + "interaction_modal.on_another_server": "On a different server", + "interaction_modal.on_this_server": "On this server", + "interaction_modal.other_server_instructions": "Simply copy and paste this URL into the search bar of your favourite app or the web interface where you are signed in.", + "interaction_modal.preamble": "Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one.", + "interaction_modal.title.favourite": "Favourite {name}'s post", + "interaction_modal.title.follow": "Follow {name}", + "interaction_modal.title.reblog": "Boost {name}'s post", + "interaction_modal.title.reply": "Reply to {name}'s post", "intervals.full.days": "{number, plural, one {# օր} other {# օր}}", "intervals.full.hours": "{number, plural, one {# ժամ} other {# ժամ}}", "intervals.full.minutes": "{number, plural, one {# րոպէ} other {# րոպէ}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Տեւողութիւն", "mute_modal.hide_notifications": "Թաքցնե՞լ ծանուցումներն այս օգտատիրոջից։", "mute_modal.indefinite": "Անժամկէտ", - "navigation_bar.apps": "Դիւրակիր յաւելուածներ", + "navigation_bar.about": "About", + "navigation_bar.apps": "Get the app", "navigation_bar.blocks": "Արգելափակուած օգտատէրեր", "navigation_bar.bookmarks": "Էջանիշեր", "navigation_bar.community_timeline": "Տեղական հոսք", @@ -324,7 +375,7 @@ "navigation_bar.filters": "Լռեցուած բառեր", "navigation_bar.follow_requests": "Հետեւելու հայցեր", "navigation_bar.follows_and_followers": "Հետեւածներ եւ հետեւողներ", - "navigation_bar.info": "Այս հանգոյցի մասին", + "navigation_bar.info": "About", "navigation_bar.keyboard_shortcuts": "Ստեղնաշարի կարճատներ", "navigation_bar.lists": "Ցանկեր", "navigation_bar.logout": "Դուրս գալ", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Ամրացուած գրառումներ", "navigation_bar.preferences": "Նախապատուութիւններ", "navigation_bar.public_timeline": "Դաշնային հոսք", + "navigation_bar.search": "Search", "navigation_bar.security": "Անվտանգութիւն", + "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", "notification.admin.report": "{name} reported {target}", "notification.admin.sign_up": "{name}-ը գրանցուած է", "notification.favourite": "{name} հաւանեց գրառումդ", @@ -401,6 +454,8 @@ "privacy.public.short": "Հրապարակային", "privacy.unlisted.long": "Visible for all, but opted-out of discovery features", "privacy.unlisted.short": "Ծածուկ", + "privacy_policy.last_updated": "Last updated {date}", + "privacy_policy.title": "Privacy Policy", "refresh": "Թարմացնել", "regeneration_indicator.label": "Բեռնւում է…", "regeneration_indicator.sublabel": "պատրաստւում է հիմնական հոսքդ", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "Այս հանգոյցում միացուած չէ ըստ բովանդակութեան գրառում փնտրելու հնարաւորութիւնը։", "search_results.title": "Search for {q}", "search_results.total": "{count, number} {count, plural, one {արդիւնք} other {արդիւնք}}", + "server_banner.about_active_users": "People using this server during the last 30 days (Monthly Active Users)", + "server_banner.active_users": "active users", + "server_banner.administered_by": "Administered by:", + "server_banner.introduction": "{domain} is part of the decentralized social network powered by {mastodon}.", + "server_banner.learn_more": "Learn more", + "server_banner.server_stats": "Server stats:", "sign_in_banner.create_account": "Create account", "sign_in_banner.sign_in": "Sign in", "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "Այս գրառումը ոչ մէկ դեռ չի տարածել։ Տարածողները կերեւան այստեղ, երբ տարածեն։", "status.redraft": "Ջնջել եւ վերակազմել", "status.remove_bookmark": "Հեռացնել էջանիշերից", + "status.replied_to": "Replied to {name}", "status.reply": "Պատասխանել", "status.replyAll": "Պատասխանել շղթային", "status.report": "Բողոքել @{name}֊ից", @@ -523,9 +585,8 @@ "status.show_more": "Աւելին", "status.show_more_all": "Ցուցադրել բոլոր նախազգուշացնումները", "status.show_original": "Show original", - "status.show_thread": "Բացել շղթան", "status.translate": "Translate", - "status.translated_from": "Translated from {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Անհասանելի", "status.unmute_conversation": "Ապալռեցնել խօսակցութիւնը", "status.unpin": "Հանել անձնական էջից", @@ -538,7 +599,6 @@ "tabs_bar.home": "Հիմնական", "tabs_bar.local_timeline": "Տեղական", "tabs_bar.notifications": "Ծանուցումներ", - "tabs_bar.search": "Փնտրել", "time_remaining.days": "{number, plural, one {մնաց # օր} other {մնաց # օր}}", "time_remaining.hours": "{number, plural, one {# ժամ} other {# ժամ}} անց", "time_remaining.minutes": "{number, plural, one {# րոպէ} other {# րոպէ}} անց", diff --git a/app/javascript/mastodon/locales/id.json b/app/javascript/mastodon/locales/id.json index 60a3d5770..fb86fda37 100644 --- a/app/javascript/mastodon/locales/id.json +++ b/app/javascript/mastodon/locales/id.json @@ -1,4 +1,17 @@ { + "about.blocks": "Moderated servers", + "about.contact": "Contact:", + "about.domain_blocks.comment": "Reason", + "about.domain_blocks.domain": "Domain", + "about.domain_blocks.preamble": "Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.", + "about.domain_blocks.severity": "Severity", + "about.domain_blocks.silenced.explanation": "You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.", + "about.domain_blocks.silenced.title": "Limited", + "about.domain_blocks.suspended.explanation": "No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.", + "about.domain_blocks.suspended.title": "Suspended", + "about.not_available": "This information has not been made available on this server.", + "about.powered_by": "Decentralized social media powered by {mastodon}", + "about.rules": "Server rules", "account.account_note_header": "Catatan", "account.add_or_remove_from_list": "Tambah atau Hapus dari daftar", "account.badges.bot": "בוט", @@ -7,13 +20,16 @@ "account.block_domain": "Blokir domain {domain}", "account.blocked": "Terblokir", "account.browse_more_on_origin_server": "Lihat lebih lanjut diprofil asli", - "account.cancel_follow_request": "Batalkan permintaan ikuti", + "account.cancel_follow_request": "Withdraw follow request", "account.direct": "Pesan Langsung @{name}", "account.disable_notifications": "Berhenti memberitahu saya ketika @{name} memposting", "account.domain_blocked": "Domain diblokir", "account.edit_profile": "Ubah profil", "account.enable_notifications": "Beritahu saya saat @{name} memposting", "account.endorse": "Tampilkan di profil", + "account.featured_tags.last_status_at": "Last post on {date}", + "account.featured_tags.last_status_never": "No posts", + "account.featured_tags.title": "{name}'s featured hashtags", "account.follow": "Ikuti", "account.followers": "Pengikut", "account.followers.empty": "Pengguna ini belum ada pengikut.", @@ -23,7 +39,7 @@ "account.follows.empty": "Pengguna ini belum mengikuti siapapun.", "account.follows_you": "Mengikuti anda", "account.hide_reblogs": "Sembunyikan boosts dari @{name}", - "account.joined": "Bergabung {date}", + "account.joined_short": "Joined", "account.languages": "Change subscribed languages", "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 mengikutinya.", @@ -63,12 +79,24 @@ "audio.hide": "Indonesia", "autosuggest_hashtag.per_week": "{count} per minggu", "boost_modal.combo": "Anda dapat menekan {combo} untuk melewati ini", - "bundle_column_error.body": "Kesalahan terjadi saat memuat komponen ini.", + "bundle_column_error.copy_stacktrace": "Copy error report", + "bundle_column_error.error.body": "The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.", + "bundle_column_error.error.title": "Oh, no!", + "bundle_column_error.network.body": "There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.", + "bundle_column_error.network.title": "Network error", "bundle_column_error.retry": "Coba lagi", - "bundle_column_error.title": "Kesalahan jaringan", + "bundle_column_error.return": "Go back home", + "bundle_column_error.routing.body": "The requested page could not be found. Are you sure the URL in the address bar is correct?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Tutup", "bundle_modal_error.message": "Kesalahan terjadi saat memuat komponen ini.", "bundle_modal_error.retry": "Coba lagi", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "About", "column.blocks": "Pengguna yang diblokir", "column.bookmarks": "Markah", "column.community": "Linimasa Lokal", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "Blokir & Laporkan", "confirmations.block.confirm": "Blokir", "confirmations.block.message": "Apa anda yakin ingin memblokir {name}?", + "confirmations.cancel_follow_request.confirm": "Withdraw request", + "confirmations.cancel_follow_request.message": "Are you sure you want to withdraw your request to follow {name}?", "confirmations.delete.confirm": "Hapus", "confirmations.delete.message": "Apa anda yakin untuk menghapus status ini?", "confirmations.delete_list.confirm": "Hapus", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Tandai sudah dibaca", "conversation.open": "Lihat percakapan", "conversation.with": "Dengan {names}", + "copypaste.copied": "Copied", + "copypaste.copy": "Copy", "directory.federated": "Dari fediverse yang dikenal", "directory.local": "Dari {domain} saja", "directory.new_arrivals": "Yang baru datang", "directory.recently_active": "Baru-baru ini aktif", + "dismissable_banner.community_timeline": "These are the most recent public posts from people whose accounts are hosted by {domain}.", + "dismissable_banner.dismiss": "Dismiss", + "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", + "dismissable_banner.explore_statuses": "These posts from this and other servers in the decentralized network are gaining traction on this server right now.", + "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", + "dismissable_banner.public_timeline": "These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.", "embed.instructions": "Sematkan kiriman ini di website anda dengan menyalin kode di bawah ini.", "embed.preview": "Tampilan akan seperti ini nantinya:", "emoji_button.activity": "Aktivitas", @@ -221,14 +259,14 @@ "follow_request.reject": "Tolak", "follow_requests.unlocked_explanation": "Meskipun akun Anda tidak dikunci, staf {domain} menyarankan Anda untuk meninjau permintaan mengikuti dari akun-akun ini secara manual.", "generic.saved": "Disimpan", - "getting_started.developers": "Pengembang", - "getting_started.directory": "Direktori profil", + "getting_started.directory": "Directory", "getting_started.documentation": "Dokumentasi", + "getting_started.free_software_notice": "Mastodon is free, open source software. You can view the source code, contribute or report issues at {repository}.", "getting_started.heading": "Mulai", "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.privacy_policy": "Privacy Policy", "getting_started.security": "Keamanan", + "getting_started.what_is_mastodon": "About Mastodon", "hashtag.column_header.tag_mode.all": "dan {additional}", "hashtag.column_header.tag_mode.any": "atau {additional}", "hashtag.column_header.tag_mode.none": "tanpa {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Tampilkan balasan", "home.hide_announcements": "Sembunyikan pengumuman", "home.show_announcements": "Tampilkan pengumuman", + "interaction_modal.description.favourite": "With an account on Mastodon, you can favourite this post to let the author know you appreciate it and save it for later.", + "interaction_modal.description.follow": "With an account on Mastodon, you can follow {name} to receive their posts in your home feed.", + "interaction_modal.description.reblog": "With an account on Mastodon, you can boost this post to share it with your own followers.", + "interaction_modal.description.reply": "With an account on Mastodon, you can respond to this post.", + "interaction_modal.on_another_server": "On a different server", + "interaction_modal.on_this_server": "On this server", + "interaction_modal.other_server_instructions": "Simply copy and paste this URL into the search bar of your favourite app or the web interface where you are signed in.", + "interaction_modal.preamble": "Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one.", + "interaction_modal.title.favourite": "Favourite {name}'s post", + "interaction_modal.title.follow": "Follow {name}", + "interaction_modal.title.reblog": "Boost {name}'s post", + "interaction_modal.title.reply": "Reply to {name}'s post", "intervals.full.days": "{number, plural, other {# hari}}", "intervals.full.hours": "{number, plural, other {# jam}}", "intervals.full.minutes": "{number, plural, other {# menit}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Durasi", "mute_modal.hide_notifications": "Sembunyikan notifikasi dari pengguna ini?", "mute_modal.indefinite": "Tak terbatas", - "navigation_bar.apps": "Aplikasi mobile", + "navigation_bar.about": "About", + "navigation_bar.apps": "Get the app", "navigation_bar.blocks": "Pengguna diblokir", "navigation_bar.bookmarks": "Markah", "navigation_bar.community_timeline": "Linimasa lokal", @@ -324,7 +375,7 @@ "navigation_bar.filters": "Kata yang dibisukan", "navigation_bar.follow_requests": "Permintaan mengikuti", "navigation_bar.follows_and_followers": "Ikuti dan pengikut", - "navigation_bar.info": "Informasi selengkapnya", + "navigation_bar.info": "About", "navigation_bar.keyboard_shortcuts": "Pintasan keyboard", "navigation_bar.lists": "Daftar", "navigation_bar.logout": "Keluar", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Toot tersemat", "navigation_bar.preferences": "Pengaturan", "navigation_bar.public_timeline": "Linimasa gabungan", + "navigation_bar.search": "Search", "navigation_bar.security": "Keamanan", + "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", "notification.admin.report": "{name} melaporkan {target}", "notification.admin.sign_up": "{name} mendaftar", "notification.favourite": "{name} menyukai status anda", @@ -401,6 +454,8 @@ "privacy.public.short": "Publik", "privacy.unlisted.long": "Terlihat oleh semua, tapi jangan tampilkan di fitur jelajah", "privacy.unlisted.short": "Tak Terdaftar", + "privacy_policy.last_updated": "Last updated {date}", + "privacy_policy.title": "Privacy Policy", "refresh": "Segarkan", "regeneration_indicator.label": "Memuat…", "regeneration_indicator.sublabel": "Linimasa anda sedang disiapkan!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "Pencarian toot berdasarkan konten tidak diaktifkan di server Mastadon ini.", "search_results.title": "Search for {q}", "search_results.total": "{count, number} {count, plural, one {hasil} other {hasil}}", + "server_banner.about_active_users": "People using this server during the last 30 days (Monthly Active Users)", + "server_banner.active_users": "active users", + "server_banner.administered_by": "Administered by:", + "server_banner.introduction": "{domain} is part of the decentralized social network powered by {mastodon}.", + "server_banner.learn_more": "Learn more", + "server_banner.server_stats": "Server stats:", "sign_in_banner.create_account": "Create account", "sign_in_banner.sign_in": "Sign in", "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "Belum ada yang mem-boost toot ini. Ketika seseorang melakukannya, maka akan muncul di sini.", "status.redraft": "Hapus & redraf", "status.remove_bookmark": "Hapus markah", + "status.replied_to": "Replied to {name}", "status.reply": "Balas", "status.replyAll": "Balas ke semua", "status.report": "Laporkan @{name}", @@ -523,9 +585,8 @@ "status.show_more": "Tampilkan semua", "status.show_more_all": "Tampilkan lebih banyak", "status.show_original": "Show original", - "status.show_thread": "Tampilkan utas", "status.translate": "Translate", - "status.translated_from": "Translated from {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Tak tersedia", "status.unmute_conversation": "Bunyikan percakapan", "status.unpin": "Hapus sematan dari profil", @@ -538,7 +599,6 @@ "tabs_bar.home": "Beranda", "tabs_bar.local_timeline": "Lokal", "tabs_bar.notifications": "Notifikasi", - "tabs_bar.search": "Cari", "time_remaining.days": "{number, plural, other {# hari}} tersisa", "time_remaining.hours": "{number, plural, other {# jam}} tersisa", "time_remaining.minutes": "{number, plural, other {# menit}} tersisa", diff --git a/app/javascript/mastodon/locales/io.json b/app/javascript/mastodon/locales/io.json index 297f60443..0d6e6365b 100644 --- a/app/javascript/mastodon/locales/io.json +++ b/app/javascript/mastodon/locales/io.json @@ -1,4 +1,17 @@ { + "about.blocks": "Jerata servili", + "about.contact": "Kontaktajo:", + "about.domain_blocks.comment": "Motivo", + "about.domain_blocks.domain": "Domeno", + "about.domain_blocks.preamble": "Mastodon generale permisas on vidar kontenajo e interagar kun uzanti de irga altra servilo en fediverso. Existas eceptioni quo facesis che ca partikulara servilo.", + "about.domain_blocks.severity": "Severeso", + "about.domain_blocks.silenced.explanation": "On generale ne vidar profili e kontenajo de ca servilo, se on ne reale trovar o voluntale juntar per sequar.", + "about.domain_blocks.silenced.title": "Limitizita", + "about.domain_blocks.suspended.explanation": "Nula informi de ca servili procedagesos o retenesos o interchanjesos, do irga interago o komuniko kun uzanti de ca servili esas neposibla.", + "about.domain_blocks.suspended.title": "Restriktita", + "about.not_available": "Ca informo ne igesis che ca servilo.", + "about.powered_by": "Necentraligita sociala ret quo povigesas da {mastodon}", + "about.rules": "Servilreguli", "account.account_note_header": "Noto", "account.add_or_remove_from_list": "Insertez o removez de listi", "account.badges.bot": "Boto", @@ -7,13 +20,16 @@ "account.block_domain": "Hide everything from {domain}", "account.blocked": "Restriktita", "account.browse_more_on_origin_server": "Videz pluse che originala profilo", - "account.cancel_follow_request": "Removez sequodemando", + "account.cancel_follow_request": "Desendez sequodemando", "account.direct": "Direct Message @{name}", "account.disable_notifications": "Cesez avizar me kande @{name} postas", "account.domain_blocked": "Domain hidden", "account.edit_profile": "Modifikar profilo", "account.enable_notifications": "Avizez me kande @{name} postas", "account.endorse": "Traito di profilo", + "account.featured_tags.last_status_at": "Antea posto ye {date}", + "account.featured_tags.last_status_never": "Nula posti", + "account.featured_tags.title": "Estalita hashtagi di {name}", "account.follow": "Sequar", "account.followers": "Sequanti", "account.followers.empty": "Nulu sequas ca uzanto til nun.", @@ -23,7 +39,7 @@ "account.follows.empty": "Ca uzanto ne sequa irgu til nun.", "account.follows_you": "Sequas tu", "account.hide_reblogs": "Celez busti de @{name}", - "account.joined": "Juntas ye {date}", + "account.joined_short": "Joined", "account.languages": "Chanjez abonita lingui", "account.link_verified_on": "Proprieteso di ca ligilo kontrolesis ye {date}", "account.locked_info": "La privatesostaco di ca konto fixesas quale lokata. Proprietato manue kontrolas personi qui povas sequar.", @@ -63,12 +79,24 @@ "audio.hide": "Celez audio", "autosuggest_hashtag.per_week": "{count} dum singla semano", "boost_modal.combo": "Tu povas presar sur {combo} por omisar co en la venonta foyo", - "bundle_column_error.body": "Nulo ne functionis dum chargar ca kompozaj.", + "bundle_column_error.copy_stacktrace": "Kopierorraporto", + "bundle_column_error.error.body": "La demandita pagino ne povas strukturigesar. Forsan ol esas eroro en kodexo hike o vidilkoncilieblesproblemo.", + "bundle_column_error.error.title": "Ach!", + "bundle_column_error.network.body": "Havas eroro kande probar montrar ca pagino. Forsan ol esas tempala problemo kun vua retkonekteso o ca servilo.", + "bundle_column_error.network.title": "Reteroro", "bundle_column_error.retry": "Probez itere", - "bundle_column_error.title": "Rederor", + "bundle_column_error.return": "Irez a hemo", + "bundle_column_error.routing.body": "Demandita pagino ne povas trovesar. Ka vu certe ke URL en situobuxo esar korekta?", + "bundle_column_error.routing.title": "Eroro di 404", "bundle_modal_error.close": "Klozez", "bundle_modal_error.message": "Nulo ne functionis dum chargar ca kompozaj.", "bundle_modal_error.retry": "Probez itere", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "Pri co", "column.blocks": "Blokusita uzeri", "column.bookmarks": "Libromarki", "column.community": "Lokala tempolineo", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "Restriktez e Raportizez", "confirmations.block.confirm": "Restriktez", "confirmations.block.message": "Ka vu certe volas restrikar {name}?", + "confirmations.cancel_follow_request.confirm": "Desendez demando", + "confirmations.cancel_follow_request.message": "Ka vu certe volas desendar vua demando di sequar {name}?", "confirmations.delete.confirm": "Efacez", "confirmations.delete.message": "Are you sure you want to delete this status?", "confirmations.delete_list.confirm": "Efacez", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Markizez quale lektita", "conversation.open": "Videz konverso", "conversation.with": "Kun {names}", + "copypaste.copied": "Kopiesis", + "copypaste.copy": "Kopiez", "directory.federated": "De savita fediverso", "directory.local": "De {domain} nur", "directory.new_arrivals": "Nova venanti", "directory.recently_active": "Recenta aktivo", + "dismissable_banner.community_timeline": "Co esas maxim recenta publika posti de personi quo havas konto quo hostigesas da {domain}.", + "dismissable_banner.dismiss": "Ignorez", + "dismissable_banner.explore_links": "Ca nova rakonti parolesas da personi che ca e altra servili di necentraligita situo nun.", + "dismissable_banner.explore_statuses": "Ca posti de ca e altra servili en la necentraligita situo bezonas plu famoza che ca servilo nun.", + "dismissable_banner.explore_tags": "Ca hashtagi bezonas plu famoza inter personi che ca e altra servili di la necentraligita situo nun.", + "dismissable_banner.public_timeline": "Co esas maxim recenta publika posti de personi en ca e altra servili di la necentraligita situo quo savesas da ca servilo.", "embed.instructions": "Embed this status on your website by copying the code below.", "embed.preview": "Co esas quon ol semblos tale:", "emoji_button.activity": "Ago", @@ -221,14 +259,14 @@ "follow_request.reject": "Refuzar", "follow_requests.unlocked_explanation": "Quankam vua konto ne klefklozesis, la {domain} laborero pensas ke vu forsan volas kontralar sequodemandi de ca konti manuale.", "generic.saved": "Sparesis", - "getting_started.developers": "Developeri", - "getting_started.directory": "Profilcheflisto", + "getting_started.directory": "Cheflisto", "getting_started.documentation": "Dokumentajo", + "getting_started.free_software_notice": "Mastodon esas libera fontoaperta softwaro. On povas vidar fontokodexo, kontribuar o reportigar problemi en {repository}.", "getting_started.heading": "Debuto", "getting_started.invite": "Invitez personi", - "getting_started.open_source_notice": "Mastodon esas programaro kun apertita kodexo. Tu povas kontributar o signalar problemi en GitHub ye {github}.", "getting_started.privacy_policy": "Privatesguidilo", "getting_started.security": "Kontoopcioni", + "getting_started.what_is_mastodon": "Pri Mastodon", "hashtag.column_header.tag_mode.all": "e {additional}", "hashtag.column_header.tag_mode.any": "o {additional}", "hashtag.column_header.tag_mode.none": "sen {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Montrar respondi", "home.hide_announcements": "Celez anunci", "home.show_announcements": "Montrez anunci", + "interaction_modal.description.favourite": "Per konto che Mastodon, vu povas favorizar ca posto por savigar postero ke vu gratitudizar lu e retenar por la futuro.", + "interaction_modal.description.follow": "Per konto che Mastodon, vu povas sequar {name} por ganar ola posti en vua hemniuzeto.", + "interaction_modal.description.reblog": "Per konto che Mastodon, vu povas bustizar ca posti por partigar kun sua sequanti.", + "interaction_modal.description.reply": "Per konto che Mastodon, vu povas respondar ca posto.", + "interaction_modal.on_another_server": "Che diferanta servilo", + "interaction_modal.on_this_server": "Che ca servilo", + "interaction_modal.other_server_instructions": "Jus kopiez e glutinar ca URL a trovbuxo di vua favorata softwaro o retintervizajo en vua ekirsituo.", + "interaction_modal.preamble": "Pro ke Mastodon esas necentraligita, on povas uzar vua havata konto quo hostigesas altra servilo di Mastodon o konciliebla metodo se on ne havas konto hike.", + "interaction_modal.title.favourite": "Favorata posto di {name}", + "interaction_modal.title.follow": "Sequez {name}", + "interaction_modal.title.reblog": "Bustizez posto di {name}", + "interaction_modal.title.reply": "Respondez posto di {name}", "intervals.full.days": "{number, plural, one {# dio} other {# dii}}", "intervals.full.hours": "{number, plural, one {# horo} other {# hori}}", "intervals.full.minutes": "{number, plural, one {# minuto} other {# minuti}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Durado", "mute_modal.hide_notifications": "Celez avizi de ca uzanto?", "mute_modal.indefinite": "Nedefinitiva", - "navigation_bar.apps": "Smartfonsoftwari", + "navigation_bar.about": "Pri co", + "navigation_bar.apps": "Ganez la softwaro", "navigation_bar.blocks": "Blokusita uzeri", "navigation_bar.bookmarks": "Libromarki", "navigation_bar.community_timeline": "Lokala tempolineo", @@ -324,7 +375,7 @@ "navigation_bar.filters": "Silencigita vorti", "navigation_bar.follow_requests": "Demandi di sequado", "navigation_bar.follows_and_followers": "Sequati e sequanti", - "navigation_bar.info": "Detaloza informi", + "navigation_bar.info": "Pri co", "navigation_bar.keyboard_shortcuts": "Rapidklavi", "navigation_bar.lists": "Listi", "navigation_bar.logout": "Ekirar", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Pinned toots", "navigation_bar.preferences": "Preferi", "navigation_bar.public_timeline": "Federata tempolineo", + "navigation_bar.search": "Search", "navigation_bar.security": "Sekureso", + "not_signed_in_indicator.not_signed_in": "Vu mustas enirar por acesar ca moyeno.", "notification.admin.report": "{name} raportizis {target}", "notification.admin.sign_up": "{name} registresis", "notification.favourite": "{name} favorizis tua mesajo", @@ -401,6 +454,8 @@ "privacy.public.short": "Publike", "privacy.unlisted.long": "Videbla da omnu ma voluntala ne inkluzas deskovrotraiti", "privacy.unlisted.short": "Ne enlistigota", + "privacy_policy.last_updated": "Antea novajo ye {date}", + "privacy_policy.title": "Privatesguidilo", "refresh": "Rifreshez", "regeneration_indicator.label": "Chargas…", "regeneration_indicator.sublabel": "Vua hemniuzeto preparesas!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.title": "Trovez {q}", "search_results.total": "{count, number} {count, plural, one {rezulto} other {rezulti}}", + "server_banner.about_active_users": "Personi quo uzas ca servilo dum antea 30 dii (monate aktiva uzanti)", + "server_banner.active_users": "aktiva uzanti", + "server_banner.administered_by": "Administresis da:", + "server_banner.introduction": "{domain} esas parto di necentraligita sociala ret quo povizesas da {mastodon}.", + "server_banner.learn_more": "Lernez plue", + "server_banner.server_stats": "Servilstatistiko:", "sign_in_banner.create_account": "Kreez konto", "sign_in_banner.sign_in": "Enirez", "sign_in_banner.text": "Enirez por sequar profili o hashtagi, favorizar, partigar e respondizar posti, o interagar de vua konto de diferanta servilo.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "No one has boosted this toot yet. When someone does, they will show up here.", "status.redraft": "Efacez e riskisigez", "status.remove_bookmark": "Efacez libromarko", + "status.replied_to": "Replied to {name}", "status.reply": "Respondar", "status.replyAll": "Respondar a filo", "status.report": "Denuncar @{name}", @@ -523,9 +585,8 @@ "status.show_more": "Montrar plue", "status.show_more_all": "Montrez pluse por omno", "status.show_original": "Montrez originalo", - "status.show_thread": "Montrez postaro", "status.translate": "Tradukez", - "status.translated_from": "Tradukesis de {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Nedisplonebla", "status.unmute_conversation": "Desilencigez konverso", "status.unpin": "Depinglagez de profilo", @@ -538,7 +599,6 @@ "tabs_bar.home": "Hemo", "tabs_bar.local_timeline": "Lokala", "tabs_bar.notifications": "Savigi", - "tabs_bar.search": "Trovez", "time_remaining.days": "{number, plural, one {# dio} other {# dii}} restas", "time_remaining.hours": "{number, plural, one {# horo} other {# hori}} restas", "time_remaining.minutes": "{number, plural, one {# minuto} other {# minuti}} restas", diff --git a/app/javascript/mastodon/locales/is.json b/app/javascript/mastodon/locales/is.json index e557010fb..e37c18b00 100644 --- a/app/javascript/mastodon/locales/is.json +++ b/app/javascript/mastodon/locales/is.json @@ -1,4 +1,17 @@ { + "about.blocks": "Netþjónar með efnisumsjón", + "about.contact": "Hafa samband:", + "about.domain_blocks.comment": "Ástæða", + "about.domain_blocks.domain": "Lén", + "about.domain_blocks.preamble": "Mastodon leyfir þér almennt að skoða og eiga við efni frá notendum frá hvaða vefþjóni sem er í vefþjónasambandinu. Þetta eru þær undantekningar sem hafa verið gerðar á þessum tiltekna vefþjóni.", + "about.domain_blocks.severity": "Mikilvægi", + "about.domain_blocks.silenced.explanation": "Þú munt almennt ekki sjá notandasnið og efni af þessum netþjóni nema þú flettir því upp sérstaklega eða veljir að fylgjast með því.", + "about.domain_blocks.silenced.title": "Takmarkað", + "about.domain_blocks.suspended.explanation": "Engin gögn frá þessum vefþjóni verða unnin, geymd eða skipst á, sem gerir samskipti við notendur frá þessum vefþjóni ómöguleg.", + "about.domain_blocks.suspended.title": "Í bið", + "about.not_available": "Þessar upplýsingar hafa ekki verið gerðar aðgengilegar á þessum netþjóni.", + "about.powered_by": "Dreihýstur samskiptamiðill keyrður með {mastodon}", + "about.rules": "Reglur netþjónsins", "account.account_note_header": "Minnispunktur", "account.add_or_remove_from_list": "Bæta við eða fjarlægja af listum", "account.badges.bot": "Vélmenni", @@ -7,13 +20,16 @@ "account.block_domain": "Útiloka lénið {domain}", "account.blocked": "Útilokaður", "account.browse_more_on_origin_server": "Skoða nánari upplýsingar á notandasniðinu", - "account.cancel_follow_request": "Hætta við beiðni um að fylgjas", + "account.cancel_follow_request": "Taka fylgjendabeiðni til baka", "account.direct": "Bein skilaboð til @{name}", "account.disable_notifications": "Hætta að láta mig vita þegar @{name} sendir inn", "account.domain_blocked": "Lén útilokað", "account.edit_profile": "Breyta notandasniði", "account.enable_notifications": "Láta mig vita þegar @{name} sendir inn", "account.endorse": "Birta á notandasniði", + "account.featured_tags.last_status_at": "Síðasta færsla þann {date}", + "account.featured_tags.last_status_never": "Engar færslur", + "account.featured_tags.title": "Myllumerki hjá {name} með aukið vægi", "account.follow": "Fylgjast með", "account.followers": "Fylgjendur", "account.followers.empty": "Ennþá fylgist enginn með þessum notanda.", @@ -23,7 +39,7 @@ "account.follows.empty": "Þessi notandi fylgist ennþá ekki með neinum.", "account.follows_you": "Fylgir þér", "account.hide_reblogs": "Fela endurbirtingar fyrir @{name}", - "account.joined": "Gerðist þátttakandi {date}", + "account.joined_short": "Joined", "account.languages": "Breyta tungumálum í áskrift", "account.link_verified_on": "Eignarhald á þessum tengli var athugað þann {date}", "account.locked_info": "Staða gagnaleyndar á þessum aðgangi er stillt á læsingu. Eigandinn yfirfer handvirkt hverjir geti fylgst með honum.", @@ -63,12 +79,24 @@ "audio.hide": "Fela hljóð", "autosuggest_hashtag.per_week": "{count} á viku", "boost_modal.combo": "Þú getur ýtt á {combo} til að sleppa þessu næst", - "bundle_column_error.body": "Eitthvað fór úrskeiðis við að hlaða inn þessari einingu.", - "bundle_column_error.retry": "Reyndu aftur", - "bundle_column_error.title": "Villa í netkerfi", + "bundle_column_error.copy_stacktrace": "Afrita villuskýrslu", + "bundle_column_error.error.body": "Umbeðna síðau var ekki hægt að myndgera. Það gæti verið vegna villu í kóðanum okkar eða vandamáls með samhæfni vafra.", + "bundle_column_error.error.title": "Ó-nei!", + "bundle_column_error.network.body": "Villa kom upp við að hlaða inn þessari síðu. Þetta gæti stafað af tímabundnum vandamálum með internettenginguna þína eða þennan netþjón.", + "bundle_column_error.network.title": "Villa í netkerfi", + "bundle_column_error.retry": "Reyna aftur", + "bundle_column_error.return": "Fara til baka á upphafssíðu", + "bundle_column_error.routing.body": "Umbeðin síða fannst ekki. Ertu viss um að slóðin í vistfangastikunni sé rétt?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Loka", "bundle_modal_error.message": "Eitthvað fór úrskeiðis við að hlaða inn þessari einingu.", "bundle_modal_error.retry": "Reyndu aftur", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "Um hugbúnaðinn", "column.blocks": "Útilokaðir notendur", "column.bookmarks": "Bókamerki", "column.community": "Staðvær tímalína", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "Útiloka og kæra", "confirmations.block.confirm": "Útiloka", "confirmations.block.message": "Ertu viss um að þú viljir loka á {name}?", + "confirmations.cancel_follow_request.confirm": "Taka beiðni til baka", + "confirmations.cancel_follow_request.message": "Ertu viss um að þú viljir taka til baka beiðnina um að fylgjast með {name}?", "confirmations.delete.confirm": "Eyða", "confirmations.delete.message": "Ertu viss um að þú viljir eyða þessari færslu?", "confirmations.delete_list.confirm": "Eyða", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Merkja sem lesið", "conversation.open": "Skoða samtal", "conversation.with": "Með {names}", + "copypaste.copied": "Afritað", + "copypaste.copy": "Afrita", "directory.federated": "Frá samtengdum vefþjónum", "directory.local": "Einungis frá {domain}", "directory.new_arrivals": "Nýkomnir", "directory.recently_active": "Nýleg virkni", + "dismissable_banner.community_timeline": "Þetta eru nýjustu opinberu færslurnar frá fólki sem er hýst á {domain}.", + "dismissable_banner.dismiss": "Hunsa", + "dismissable_banner.explore_links": "Þetta eru fréttafærslur sem í augnablikinu er verið að tala um af fólki á þessum og öðrum netþjónum á dreifhýsta netkerfinu.", + "dismissable_banner.explore_statuses": "Þessar færslur frá þessum og öðrum netþjónum á dreifhýsta netkerfinu eru að fá aukna athygli í þessu töluðum orðum.", + "dismissable_banner.explore_tags": "Þetta eru myllumerki sem í augnablikinu eru að fá aukna athygli hjá fólki á þessum og öðrum netþjónum á dreifhýsta netkerfinu.", + "dismissable_banner.public_timeline": "Þetta eru nýjustu opinberar færslur frá fólki á þessum og öðrum netþjónum á dreifhýsta netkerfinu sem þessi netþjónn veit um.", "embed.instructions": "Felldu þessa færslu inn í vefsvæðið þitt með því að afrita kóðann hér fyrir neðan.", "embed.preview": "Svona mun þetta líta út:", "emoji_button.activity": "Virkni", @@ -221,14 +259,14 @@ "follow_request.reject": "Hafna", "follow_requests.unlocked_explanation": "Jafnvel þótt aðgangurinn þinn sé ekki læstur, hafa umsjónarmenn {domain} ímyndað sér að þú gætir viljað yfirfara handvirkt fylgjendabeiðnir frá þessum notendum.", "generic.saved": "Vistað", - "getting_started.developers": "Forritarar", - "getting_started.directory": "Notandasniðamappa", + "getting_started.directory": "Mappa", "getting_started.documentation": "Hjálparskjöl", + "getting_started.free_software_notice": "Mastodon er frjáls, opinn hugbúnaður. Þú getur skoðað grunnkóðann, lagt þitt af mörkum eða tilkynnt vandamál á {repository}.", "getting_started.heading": "Komast í gang", "getting_started.invite": "Bjóða fólki", - "getting_started.open_source_notice": "Mastodon er opinn og frjáls hugbúnaður. Þú getur lagt þitt af mörkum eða tilkynnt um vandamál á GitHub á slóðinni {github}.", "getting_started.privacy_policy": "Persónuverndarstefna", "getting_started.security": "Stillingar notandaaðgangs", + "getting_started.what_is_mastodon": "Um Mastodon", "hashtag.column_header.tag_mode.all": "og {additional}", "hashtag.column_header.tag_mode.any": "eða {additional}", "hashtag.column_header.tag_mode.none": "án {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Birta svör", "home.hide_announcements": "Fela auglýsingar", "home.show_announcements": "Birta auglýsingar", + "interaction_modal.description.favourite": "Með notandaaðgangi á Mastodon geturðu sett þessa færslu í eftirlæti og þannig látið höfundinn vita að þú kunnir að meta hana og vistað hana til síðari tíma.", + "interaction_modal.description.follow": "Með notandaaðgangi á Mastodon geturðu fylgst með {name} og fengið færslur frá viðkomandi í heimastreymið þitt.", + "interaction_modal.description.reblog": "Með notandaaðgangi á Mastodon geturðu endurbirt þessa færslu til að deila henni með þeim sem fylgjast með þér.", + "interaction_modal.description.reply": "Með notandaaðgangi á Mastodon geturðu svarað þessari færslu.", + "interaction_modal.on_another_server": "Á öðrum netþjóni", + "interaction_modal.on_this_server": "Á þessum netþjóni", + "interaction_modal.other_server_instructions": "Þú einfaldlega afritar þessa slóð og límir hana inn í veffanga-/leitarstiku eftirlætisforritsins þíns eða í vefviðmótið þar sem þú ert skráð/ur inn.", + "interaction_modal.preamble": "Þar sem Mastodon er dreifhýst kerfi, þá geturðu notað aðgang sem er hýstur á öðrum Mastodon-þjóni eða öðru samhæfðu kerfi, ef þú ert ekki með notandaaðgang á þessum hér.", + "interaction_modal.title.favourite": "Setja færsluna frá {name} í eftirlæti", + "interaction_modal.title.follow": "Fylgjast með {name}", + "interaction_modal.title.reblog": "Endurbirta færsluna frá {name}", + "interaction_modal.title.reply": "Svara færslunni frá {name}", "intervals.full.days": "{number, plural, one {# dagur} other {# dagar}}", "intervals.full.hours": "{number, plural, one {# klukkustund} other {# klukkustundir}}", "intervals.full.minutes": "{number, plural, one {# mínúta} other {# mínútur}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Lengd", "mute_modal.hide_notifications": "Fela tilkynningar frá þessum notanda?", "mute_modal.indefinite": "Óendanlegt", - "navigation_bar.apps": "Farsímaforrit", + "navigation_bar.about": "Um hugbúnaðinn", + "navigation_bar.apps": "Ná í forritið", "navigation_bar.blocks": "Útilokaðir notendur", "navigation_bar.bookmarks": "Bókamerki", "navigation_bar.community_timeline": "Staðvær tímalína", @@ -324,7 +375,7 @@ "navigation_bar.filters": "Þögguð orð", "navigation_bar.follow_requests": "Beiðnir um að fylgjast með", "navigation_bar.follows_and_followers": "Fylgist með og fylgjendur", - "navigation_bar.info": "Um þennan vefþjón", + "navigation_bar.info": "Um hugbúnaðinn", "navigation_bar.keyboard_shortcuts": "Flýtilyklar", "navigation_bar.lists": "Listar", "navigation_bar.logout": "Útskráning", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Festar færslur", "navigation_bar.preferences": "Kjörstillingar", "navigation_bar.public_timeline": "Sameiginleg tímalína", + "navigation_bar.search": "Search", "navigation_bar.security": "Öryggi", + "not_signed_in_indicator.not_signed_in": "Þú þarft að skrá þig inn til að nota þetta tilfang.", "notification.admin.report": "{name} kærði {target}", "notification.admin.sign_up": "{name} skráði sig", "notification.favourite": "{name} setti færslu þína í eftirlæti", @@ -401,6 +454,8 @@ "privacy.public.short": "Opinbert", "privacy.unlisted.long": "Sýnilegt öllum, en ekki tekið með í uppgötvunareiginleikum", "privacy.unlisted.short": "Óskráð", + "privacy_policy.last_updated": "Síðast uppfært {date}", + "privacy_policy.title": "Persónuverndarstefna", "refresh": "Endurlesa", "regeneration_indicator.label": "Hleð inn…", "regeneration_indicator.sublabel": "Verið er að útbúa heimastreymið þitt!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "Að leita í efni færslna er ekki virkt á þessum Mastodon-þjóni.", "search_results.title": "Leita að {q}", "search_results.total": "{count, number} {count, plural, one {niðurstaða} other {niðurstöður}}", + "server_banner.about_active_users": "Folk sem hefur notað þennan netþjón síðustu 30 daga (virkir notendur í mánuðinum)", + "server_banner.active_users": "virkir notendur", + "server_banner.administered_by": "Stýrt af:", + "server_banner.introduction": "{domain} er hluti af dreifhýsta samfélagsnetinu sem keyrt er af {mastodon}.", + "server_banner.learn_more": "Kanna nánar", + "server_banner.server_stats": "Tölfræði þjóns:", "sign_in_banner.create_account": "Búa til notandaaðgang", "sign_in_banner.sign_in": "Skrá inn", "sign_in_banner.text": "Skráðu þig inn til að fylgjast með notendum eða myllumerkjum, svara færslum, deila þeim eða setja í eftirlæti, eða eiga í samskiptum á aðgangnum þínum á öðrum netþjónum.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "Enginn hefur ennþá endurbirt þessa færslu. Þegar einhver gerir það, mun það birtast hér.", "status.redraft": "Eyða og endurvinna drög", "status.remove_bookmark": "Fjarlægja bókamerki", + "status.replied_to": "Replied to {name}", "status.reply": "Svara", "status.replyAll": "Svara þræði", "status.report": "Kæra @{name}", @@ -523,9 +585,8 @@ "status.show_more": "Sýna meira", "status.show_more_all": "Sýna meira fyrir allt", "status.show_original": "Sýna upprunalega", - "status.show_thread": "Birta þráð", "status.translate": "Þýða", - "status.translated_from": "Þýtt úr {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Ekki tiltækt", "status.unmute_conversation": "Hætta að þagga niður í samtali", "status.unpin": "Losa af notandasniði", @@ -538,7 +599,6 @@ "tabs_bar.home": "Heim", "tabs_bar.local_timeline": "Staðvært", "tabs_bar.notifications": "Tilkynningar", - "tabs_bar.search": "Leita", "time_remaining.days": "{number, plural, one {# dagur} other {# dagar}} eftir", "time_remaining.hours": "{number, plural, one {# klukkustund} other {# klukkustundir}} eftir", "time_remaining.minutes": "{number, plural, one {# mínúta} other {# mínútur}} eftir", diff --git a/app/javascript/mastodon/locales/it.json b/app/javascript/mastodon/locales/it.json index a680aed7e..52ac4693d 100644 --- a/app/javascript/mastodon/locales/it.json +++ b/app/javascript/mastodon/locales/it.json @@ -1,4 +1,17 @@ { + "about.blocks": "Server moderati", + "about.contact": "Contatto:", + "about.domain_blocks.comment": "Motivo", + "about.domain_blocks.domain": "Dominio", + "about.domain_blocks.preamble": "Mastodon, generalmente, ti consente di visualizzare i contenuti e interagire con gli utenti da qualsiasi altro server nel fediverso. Queste sono le eccezioni che sono state fatte su questo particolare server.", + "about.domain_blocks.severity": "Gravità", + "about.domain_blocks.silenced.explanation": "Generalmente non vedrai i profili e i contenuti di questo server, a meno che tu non lo cerchi esplicitamente o che tu scelga di seguirlo.", + "about.domain_blocks.silenced.title": "Silenziato", + "about.domain_blocks.suspended.explanation": "Nessun dato proveniente da questo server verrà elaborato, conservato o scambiato, rendendo impossibile qualsiasi interazione o comunicazione con gli utenti da questo server.", + "about.domain_blocks.suspended.title": "Sospeso", + "about.not_available": "Queste informazioni non sono state rese disponibili su questo server.", + "about.powered_by": "Social media decentralizzati alimentati da {mastodon}", + "about.rules": "Regole del server", "account.account_note_header": "Le tue note sull'utente", "account.add_or_remove_from_list": "Aggiungi o togli dalle liste", "account.badges.bot": "Bot", @@ -7,13 +20,16 @@ "account.block_domain": "Blocca dominio {domain}", "account.blocked": "Bloccato", "account.browse_more_on_origin_server": "Sfoglia di più sul profilo originale", - "account.cancel_follow_request": "Annulla richiesta di seguire", + "account.cancel_follow_request": "Annulla la richiesta di seguire", "account.direct": "Messaggio diretto a @{name}", "account.disable_notifications": "Smetti di avvisarmi quando @{name} pubblica un post", "account.domain_blocked": "Dominio bloccato", "account.edit_profile": "Modifica profilo", "account.enable_notifications": "Avvisami quando @{name} pubblica un post", "account.endorse": "Metti in evidenza sul profilo", + "account.featured_tags.last_status_at": "Ultimo post il {date}", + "account.featured_tags.last_status_never": "Nessun post", + "account.featured_tags.title": "Hashtag in evidenza di {name}", "account.follow": "Segui", "account.followers": "Follower", "account.followers.empty": "Nessuno segue ancora questo utente.", @@ -23,7 +39,7 @@ "account.follows.empty": "Questo utente non segue nessuno ancora.", "account.follows_you": "Ti segue", "account.hide_reblogs": "Nascondi condivisioni da @{name}", - "account.joined": "Su questa istanza dal {date}", + "account.joined_short": "Joined", "account.languages": "Cambia le lingue di cui ricevere i post", "account.link_verified_on": "La proprietà di questo link è stata controllata il {date}", "account.locked_info": "Questo è un account privato. Il proprietario approva manualmente chi può seguirlo.", @@ -63,12 +79,24 @@ "audio.hide": "Nascondi audio", "autosuggest_hashtag.per_week": "{count} per settimana", "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.copy_stacktrace": "Copia rapporto di errore", + "bundle_column_error.error.body": "La pagina richiesta non può essere visualizzata. Potrebbe essere a causa di un bug nel nostro codice o di un problema di compatibilità del browser.", + "bundle_column_error.error.title": "Oh, no!", + "bundle_column_error.network.body": "C'è stato un errore durante il caricamento di questa pagina. Potrebbe essere dovuto a un problema temporaneo con la tua connessione internet o a questo server.", + "bundle_column_error.network.title": "Errore di rete", "bundle_column_error.retry": "Riprova", - "bundle_column_error.title": "Errore di rete", + "bundle_column_error.return": "Torna alla pagina home", + "bundle_column_error.routing.body": "La pagina richiesta non è stata trovata. Sei sicuro che l'URL nella barra degli indirizzi è corretta?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Chiudi", "bundle_modal_error.message": "Qualcosa è andato storto durante il caricamento di questo componente.", "bundle_modal_error.retry": "Riprova", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "Informazioni su", "column.blocks": "Utenti bloccati", "column.bookmarks": "Segnalibri", "column.community": "Timeline locale", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "Blocca & Segnala", "confirmations.block.confirm": "Blocca", "confirmations.block.message": "Sei sicuro di voler bloccare {name}?", + "confirmations.cancel_follow_request.confirm": "Annulla la richiesta", + "confirmations.cancel_follow_request.message": "Sei sicuro di voler annullare la tua richiesta per seguire {name}?", "confirmations.delete.confirm": "Cancella", "confirmations.delete.message": "Sei sicuro di voler cancellare questo post?", "confirmations.delete_list.confirm": "Cancella", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Segna come letto", "conversation.open": "Visualizza conversazione", "conversation.with": "Con {names}", + "copypaste.copied": "Copiato", + "copypaste.copy": "Copia", "directory.federated": "Da un fediverse noto", "directory.local": "Solo da {domain}", "directory.new_arrivals": "Nuovi arrivi", "directory.recently_active": "Attivo di recente", + "dismissable_banner.community_timeline": "Questi sono i posti pubblici più recenti di persone i cui account sono ospitati da {domain}.", + "dismissable_banner.dismiss": "Ignora", + "dismissable_banner.explore_links": "Queste notizie sono in fase di discussione da parte di persone su questo e altri server della rete decentralizzata, in questo momento.", + "dismissable_banner.explore_statuses": "Questi post, da questo e da altri server nella rete decentralizzata, stanno guadagnando popolarità su questo server in questo momento.", + "dismissable_banner.explore_tags": "Questi hashtag stanno guadagnando popolarità tra le persone su questo e altri server della rete decentralizzata, in questo momento.", + "dismissable_banner.public_timeline": "Questi sono i post pubblici più recenti di persone, su questo e altri server della rete decentralizzata che questo server conosce.", "embed.instructions": "Incorpora questo post sul tuo sito web copiando il codice sotto.", "embed.preview": "Ecco come apparirà:", "emoji_button.activity": "Attività", @@ -195,7 +233,7 @@ "explore.search_results": "Risultati della ricerca", "explore.suggested_follows": "Per te", "explore.title": "Esplora", - "explore.trending_links": "Novità", + "explore.trending_links": "Notizie", "explore.trending_statuses": "Post", "explore.trending_tags": "Hashtag", "filter_modal.added.context_mismatch_explanation": "La categoria di questo filtro non si applica al contesto in cui hai acceduto a questo post. Se desideri che il post sia filtrato anche in questo contesto, dovrai modificare il filtro.", @@ -221,14 +259,14 @@ "follow_request.reject": "Rifiuta", "follow_requests.unlocked_explanation": "Benché il tuo account non sia privato, lo staff di {domain} ha pensato che potresti voler approvare manualmente le richieste di follow da questi account.", "generic.saved": "Salvato", - "getting_started.developers": "Sviluppatori", - "getting_started.directory": "Directory dei profili", + "getting_started.directory": "Directory", "getting_started.documentation": "Documentazione", + "getting_started.free_software_notice": "Mastodon è un software libero e open source. È possibile visualizzare il codice sorgente, contribuire o segnalare problemi a {repository}.", "getting_started.heading": "Come iniziare", "getting_started.invite": "Invita qualcuno", - "getting_started.open_source_notice": "Mastodon è un software open source. Puoi contribuire o segnalare errori su GitHub all'indirizzo {github}.", "getting_started.privacy_policy": "Politica sulla Privacy", "getting_started.security": "Sicurezza", + "getting_started.what_is_mastodon": "Informazioni su Mastodon", "hashtag.column_header.tag_mode.all": "e {additional}", "hashtag.column_header.tag_mode.any": "o {additional}", "hashtag.column_header.tag_mode.none": "senza {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Mostra risposte", "home.hide_announcements": "Nascondi annunci", "home.show_announcements": "Mostra annunci", + "interaction_modal.description.favourite": "Con un account su Mastodon, puoi aggiungere questo post ai preferiti per far sapere all'autore che lo apprezzi e salvarlo per dopo.", + "interaction_modal.description.follow": "Con un account su Mastodon, puoi seguire {name} per ricevere i suoi post nel tuo home feed.", + "interaction_modal.description.reblog": "Con un account su Mastodon, puoi condividere questo post per rendere partecipi i tuoi seguaci.", + "interaction_modal.description.reply": "Con un account su Mastodon, è possibile rispondere a questo post.", + "interaction_modal.on_another_server": "Su un altro server", + "interaction_modal.on_this_server": "Su questo server", + "interaction_modal.other_server_instructions": "Basta copiare e incollare questo URL nella barra di ricerca della tua app preferita o nell'interfaccia web in cui hai effettuato l'accesso.", + "interaction_modal.preamble": "Poiché Mastodon è decentralizzato, è possibile utilizzare il proprio account esistente ospitato da un altro server Mastodon o piattaforma compatibile se non si dispone di un account su questo.", + "interaction_modal.title.favourite": "Post preferito di {name}", + "interaction_modal.title.follow": "Segui {name}", + "interaction_modal.title.reblog": "Condividi il post di {name}", + "interaction_modal.title.reply": "Rispondi al post di {name}", "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}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Durata", "mute_modal.hide_notifications": "Nascondere le notifiche da quest'utente?", "mute_modal.indefinite": "Per sempre", - "navigation_bar.apps": "App per dispositivi mobili", + "navigation_bar.about": "Informazioni su", + "navigation_bar.apps": "Scarica l'app", "navigation_bar.blocks": "Utenti bloccati", "navigation_bar.bookmarks": "Segnalibri", "navigation_bar.community_timeline": "Timeline locale", @@ -324,7 +375,7 @@ "navigation_bar.filters": "Parole silenziate", "navigation_bar.follow_requests": "Richieste di seguirti", "navigation_bar.follows_and_followers": "Seguiti e seguaci", - "navigation_bar.info": "Informazioni su questo server", + "navigation_bar.info": "Informazioni su", "navigation_bar.keyboard_shortcuts": "Tasti di scelta rapida", "navigation_bar.lists": "Liste", "navigation_bar.logout": "Esci", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Post fissati in cima", "navigation_bar.preferences": "Impostazioni", "navigation_bar.public_timeline": "Timeline federata", + "navigation_bar.search": "Search", "navigation_bar.security": "Sicurezza", + "not_signed_in_indicator.not_signed_in": "Devi effetturare il login per accedere a questa funzione.", "notification.admin.report": "{name} ha segnalato {target}", "notification.admin.sign_up": "{name} si è iscritto", "notification.favourite": "{name} ha apprezzato il tuo post", @@ -401,6 +454,8 @@ "privacy.public.short": "Pubblico", "privacy.unlisted.long": "Visibile a tutti, ma escluso dalle funzioni di scoperta", "privacy.unlisted.short": "Non elencato", + "privacy_policy.last_updated": "Ultimo aggiornamento {date}", + "privacy_policy.title": "Politica sulla privacy", "refresh": "Aggiorna", "regeneration_indicator.label": "Caricamento in corso…", "regeneration_indicator.sublabel": "Stiamo preparando il tuo home feed!", @@ -473,8 +528,14 @@ "search_results.statuses_fts_disabled": "La ricerca di post per il loro contenuto non è abilitata su questo server Mastodon.", "search_results.title": "Ricerca: {q}", "search_results.total": "{count} {count, plural, one {risultato} other {risultati}}", + "server_banner.about_active_users": "Persone che usano questo server negli ultimi 30 giorni (utenti attivi mensili)", + "server_banner.active_users": "utenti attivi", + "server_banner.administered_by": "Amministrato da:", + "server_banner.introduction": "{domain} fa parte del social network decentralizzato alimentato da {mastodon}.", + "server_banner.learn_more": "Scopri di più", + "server_banner.server_stats": "Statistiche del server:", "sign_in_banner.create_account": "Crea un account", - "sign_in_banner.sign_in": "Registrati", + "sign_in_banner.sign_in": "Accedi", "sign_in_banner.text": "Accedi per seguire profili o hashtag, segnare come preferiti, condividere e rispondere ai post o interagire dal tuo account su un server diverso.", "status.admin_account": "Apri interfaccia di moderazione per @{name}", "status.admin_status": "Apri questo post nell'interfaccia di moderazione", @@ -512,6 +573,7 @@ "status.reblogs.empty": "Nessuno ha ancora condiviso questo post. Quando qualcuno lo farà, comparirà qui.", "status.redraft": "Cancella e riscrivi", "status.remove_bookmark": "Elimina segnalibro", + "status.replied_to": "Replied to {name}", "status.reply": "Rispondi", "status.replyAll": "Rispondi alla conversazione", "status.report": "Segnala @{name}", @@ -523,9 +585,8 @@ "status.show_more": "Mostra di più", "status.show_more_all": "Mostra di più per tutti", "status.show_original": "Mostra originale", - "status.show_thread": "Mostra conversazione", "status.translate": "Traduci", - "status.translated_from": "Tradotto da {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Non disponibile", "status.unmute_conversation": "Annulla silenzia conversazione", "status.unpin": "Non fissare in cima al profilo", @@ -538,7 +599,6 @@ "tabs_bar.home": "Home", "tabs_bar.local_timeline": "Locale", "tabs_bar.notifications": "Notifiche", - "tabs_bar.search": "Cerca", "time_remaining.days": "{number, plural, one {# giorno} other {# giorni}} left", "time_remaining.hours": "{number, plural, one {# ora} other {# ore}} left", "time_remaining.minutes": "{number, plural, one {# minuto} other {# minuti}} left", diff --git a/app/javascript/mastodon/locales/ja.json b/app/javascript/mastodon/locales/ja.json index 2af9192c3..ba6246048 100644 --- a/app/javascript/mastodon/locales/ja.json +++ b/app/javascript/mastodon/locales/ja.json @@ -1,4 +1,17 @@ { + "about.blocks": "制限中のサーバー", + "about.contact": "連絡先", + "about.domain_blocks.comment": "制限理由", + "about.domain_blocks.domain": "ドメイン", + "about.domain_blocks.preamble": "Mastodonでは連合先のどのようなサーバーのユーザーとも交流できます。ただし次のサーバーには例外が設定されています。", + "about.domain_blocks.severity": "重大性", + "about.domain_blocks.silenced.explanation": "You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.", + "about.domain_blocks.silenced.title": "制限", + "about.domain_blocks.suspended.explanation": "これらのサーバーからのデータは処理されず、保存や変換もされません。該当するユーザーとの交流もできません。", + "about.domain_blocks.suspended.title": "停止済み", + "about.not_available": "この情報はこのサーバーでは利用できません。", + "about.powered_by": "{mastodon}による分散型ソーシャルメディア", + "about.rules": "サーバーのルール", "account.account_note_header": "メモ", "account.add_or_remove_from_list": "リストから追加または外す", "account.badges.bot": "Bot", @@ -7,13 +20,16 @@ "account.block_domain": "{domain}全体をブロック", "account.blocked": "ブロック済み", "account.browse_more_on_origin_server": "リモートで表示", - "account.cancel_follow_request": "フォローリクエストを取り消す", + "account.cancel_follow_request": "フォローリクエストの取り消し", "account.direct": "@{name}さんにダイレクトメッセージ", "account.disable_notifications": "@{name}さんの投稿時の通知を停止", "account.domain_blocked": "ドメインブロック中", "account.edit_profile": "プロフィール編集", "account.enable_notifications": "@{name}さんの投稿時に通知", "account.endorse": "プロフィールで紹介する", + "account.featured_tags.last_status_at": "最終投稿 {date}", + "account.featured_tags.last_status_never": "投稿がありません", + "account.featured_tags.title": "{name}の注目ハッシュタグ", "account.follow": "フォロー", "account.followers": "フォロワー", "account.followers.empty": "まだ誰もフォローしていません。", @@ -23,8 +39,8 @@ "account.follows.empty": "まだ誰もフォローしていません。", "account.follows_you": "フォローされています", "account.hide_reblogs": "@{name}さんからのブーストを非表示", - "account.joined": "{date} に登録", - "account.languages": "Change subscribed languages", + "account.joined_short": "Joined", + "account.languages": "購読言語の変更", "account.link_verified_on": "このリンクの所有権は{date}に確認されました", "account.locked_info": "このアカウントは承認制アカウントです。相手が承認するまでフォローは完了しません。", "account.media": "メディア", @@ -63,12 +79,24 @@ "audio.hide": "音声を閉じる", "autosuggest_hashtag.per_week": "{count} 回 / 週", "boost_modal.combo": "次からは{combo}を押せばスキップできます", - "bundle_column_error.body": "コンポーネントの読み込み中に問題が発生しました。", + "bundle_column_error.copy_stacktrace": "Copy error report", + "bundle_column_error.error.body": "The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.", + "bundle_column_error.error.title": "Oh, no!", + "bundle_column_error.network.body": "There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.", + "bundle_column_error.network.title": "Network error", "bundle_column_error.retry": "再試行", - "bundle_column_error.title": "ネットワークエラー", + "bundle_column_error.return": "Go back home", + "bundle_column_error.routing.body": "The requested page could not be found. Are you sure the URL in the address bar is correct?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "閉じる", "bundle_modal_error.message": "コンポーネントの読み込み中に問題が発生しました。", "bundle_modal_error.retry": "再試行", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "About", "column.blocks": "ブロックしたユーザー", "column.bookmarks": "ブックマーク", "column.community": "ローカルタイムライン", @@ -125,6 +153,8 @@ "confirmations.block.block_and_report": "ブロックし通報", "confirmations.block.confirm": "ブロック", "confirmations.block.message": "本当に{name}さんをブロックしますか?", + "confirmations.cancel_follow_request.confirm": "フォローリクエストを取り消す", + "confirmations.cancel_follow_request.message": "{name}に対するフォローリクエストを取り消しますか?", "confirmations.delete.confirm": "削除", "confirmations.delete.message": "本当に削除しますか?", "confirmations.delete_list.confirm": "削除", @@ -148,10 +178,18 @@ "conversation.mark_as_read": "既読にする", "conversation.open": "会話を表示", "conversation.with": "{names}", + "copypaste.copied": "コピーしました", + "copypaste.copy": "コピー", "directory.federated": "既知の連合より", "directory.local": "{domain} のみ", "directory.new_arrivals": "新着順", "directory.recently_active": "最近の活動順", + "dismissable_banner.community_timeline": "これらは{domain}がホストしている人たちの最新の公開投稿です。", + "dismissable_banner.dismiss": "閉じる", + "dismissable_banner.explore_links": "これらのニュース記事は現在分散型ネットワークの他のサーバーの人たちに話されています。", + "dismissable_banner.explore_statuses": "分散型ネットワーク内の他のサーバーのこれらの投稿は現在このサーバー上で注目されています。", + "dismissable_banner.explore_tags": "これらのハッシュタグは現在分散型ネットワークの他のサーバーの人たちに話されています。", + "dismissable_banner.public_timeline": "これらの投稿はこのサーバーが知っている分散型ネットワークの他のサーバーの人たちの最新の公開投稿です。", "embed.instructions": "下記のコードをコピーしてウェブサイトに埋め込みます。", "embed.preview": "表示例:", "emoji_button.activity": "活動", @@ -225,14 +263,14 @@ "follow_request.reject": "拒否", "follow_requests.unlocked_explanation": "あなたのアカウントは承認制ではありませんが、{domain}のスタッフはこれらのアカウントからのフォローリクエストの確認が必要であると判断しました。", "generic.saved": "保存しました", - "getting_started.developers": "開発", "getting_started.directory": "ディレクトリ", "getting_started.documentation": "ドキュメント", + "getting_started.free_software_notice": "Mastodonは自由なオープンソースソフトウェアです。{repository}でソースコードを確認したりコントリビュートしたり不具合の報告ができます。", "getting_started.heading": "スタート", "getting_started.invite": "招待", - "getting_started.open_source_notice": "Mastodonはオープンソースソフトウェアです。誰でもGitHub ({github}) から開発に参加したり、問題を報告したりできます。", "getting_started.privacy_policy": "プライバシーポリシー", "getting_started.security": "アカウント設定", + "getting_started.what_is_mastodon": "Mastodonについて", "hashtag.column_header.tag_mode.all": "と{additional}", "hashtag.column_header.tag_mode.any": "か{additional}", "hashtag.column_header.tag_mode.none": "({additional} を除く)", @@ -249,6 +287,18 @@ "home.column_settings.show_replies": "返信表示", "home.hide_announcements": "お知らせを隠す", "home.show_announcements": "お知らせを表示", + "interaction_modal.description.favourite": "Mastodonのアカウントでこの投稿をお気に入りに入れて投稿者に感謝を知らせたり保存することができます。", + "interaction_modal.description.follow": "Mastodonのアカウントで{name}さんをフォローしてホームフィードで投稿を受け取れます。", + "interaction_modal.description.reblog": "Mastodonのアカウントでこの投稿をブーストして自分のフォロワーに共有できます。", + "interaction_modal.description.reply": "Mastodonのアカウントでこの投稿に反応できます。", + "interaction_modal.on_another_server": "別のサーバー", + "interaction_modal.on_this_server": "このサーバー", + "interaction_modal.other_server_instructions": "このURLをコピーしてお気に入りのアプリの検索バーやログインしているWeb UIに貼り付けるだけです。", + "interaction_modal.preamble": "Mastodonは分散化されているためアカウントを持っていなくても別のMastodonサーバーまたは互換性のあるプラットフォームでホストされているアカウントを使用できます。", + "interaction_modal.title.favourite": "{name}さんの投稿をお気に入り", + "interaction_modal.title.follow": "{name}さんをフォロー", + "interaction_modal.title.reblog": "{name}さんの投稿をブースト", + "interaction_modal.title.reply": "{name}さんの投稿にリプライ", "intervals.full.days": "{number}日", "intervals.full.hours": "{number}時間", "intervals.full.minutes": "{number}分", @@ -314,6 +364,7 @@ "mute_modal.duration": "ミュートする期間", "mute_modal.hide_notifications": "このユーザーからの通知を隠しますか?", "mute_modal.indefinite": "無期限", + "navigation_bar.about": "About", "navigation_bar.apps": "アプリ", "navigation_bar.blocks": "ブロックしたユーザー", "navigation_bar.bookmarks": "ブックマーク", @@ -328,7 +379,7 @@ "navigation_bar.filters": "フィルター設定", "navigation_bar.follow_requests": "フォローリクエスト", "navigation_bar.follows_and_followers": "フォロー・フォロワー", - "navigation_bar.info": "このサーバーについて", + "navigation_bar.info": "About", "navigation_bar.keyboard_shortcuts": "キーボードショートカット", "navigation_bar.lists": "リスト", "navigation_bar.logout": "ログアウト", @@ -337,8 +388,9 @@ "navigation_bar.pins": "固定した投稿", "navigation_bar.preferences": "ユーザー設定", "navigation_bar.public_timeline": "連合タイムライン", - "navigation_bar.misc": "その他", + "navigation_bar.search": "Search", "navigation_bar.security": "セキュリティ", + "not_signed_in_indicator.not_signed_in": "この機能を使うにはログインする必要があります。", "notification.admin.report": "{name}さんが{target}さんを通報しました", "notification.admin.sign_up": "{name}さんがサインアップしました", "notification.favourite": "{name}さんがあなたの投稿をお気に入りに登録しました", @@ -406,6 +458,8 @@ "privacy.public.short": "公開", "privacy.unlisted.long": "誰でも閲覧可、サイレント", "privacy.unlisted.short": "未収載", + "privacy_policy.last_updated": "{date}に更新", + "privacy_policy.title": "プライバシーポリシー", "refresh": "更新", "regeneration_indicator.label": "読み込み中…", "regeneration_indicator.sublabel": "ホームタイムラインは準備中です!", @@ -478,9 +532,15 @@ "search_results.statuses_fts_disabled": "このサーバーでは投稿本文の検索は利用できません。", "search_results.title": "『{q}』の検索結果", "search_results.total": "{count, number}件の結果", + "server_banner.about_active_users": "過去30日間にこのサーバーを使用している人 (月間アクティブユーザー)", + "server_banner.active_users": "人のアクティブユーザー", + "server_banner.administered_by": "管理者", + "server_banner.introduction": "{domain}は{mastodon}を使った分散型ソーシャルネットワークの一部です。", + "server_banner.learn_more": "もっと詳しく", + "server_banner.server_stats": "サーバーの情報", "sign_in_banner.create_account": "アカウント作成", "sign_in_banner.sign_in": "ログイン", - "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", + "sign_in_banner.text": "ログインしてプロファイルやハッシュタグ、お気に入りをフォローしたり、投稿を共有したり、返信したり、別のサーバーのアカウントと交流したりできます。", "status.admin_account": "@{name}さんのモデレーション画面を開く", "status.admin_status": "この投稿をモデレーション画面で開く", "status.block": "@{name}さんをブロック", @@ -517,6 +577,7 @@ "status.reblogs.empty": "まだ誰もブーストしていません。ブーストされるとここに表示されます。", "status.redraft": "削除して下書きに戻す", "status.remove_bookmark": "ブックマークを削除", + "status.replied_to": "Replied to {name}", "status.reply": "返信", "status.replyAll": "全員に返信", "status.report": "@{name}さんを通報", @@ -528,22 +589,20 @@ "status.show_more": "もっと見る", "status.show_more_all": "全て見る", "status.show_original": "原文を表示", - "status.show_thread": "スレッドを表示", "status.translate": "翻訳", - "status.translated_from": "{lang}からの翻訳", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "利用できません", "status.unmute_conversation": "会話のミュートを解除", "status.unpin": "プロフィールへの固定を解除", - "subscribed_languages.lead": "Only posts in selected languages will appear on your home and list timelines after the change. Select none to receive posts in all languages.", + "subscribed_languages.lead": "選択した言語の投稿だけがホームとリストのタイムラインに表示されます。全ての言語の投稿を受け取る場合は全てのチェックを外して下さい。", "subscribed_languages.save": "変更を保存", - "subscribed_languages.target": "Change subscribed languages for {target}", + "subscribed_languages.target": "{target}さんの購読言語を変更します", "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}日", "time_remaining.hours": "残り{number}時間", "time_remaining.minutes": "残り{number}分", @@ -553,7 +612,7 @@ "timeline_hint.resources.followers": "フォロワー", "timeline_hint.resources.follows": "フォロー", "timeline_hint.resources.statuses": "以前の投稿", - "trends.counter_by_accounts": "{count, plural, one {{counter} person} other {{counter} people}} in the past {days, plural, one {day} other {{days} days}}", + "trends.counter_by_accounts": "過去{days, plural, one {{days}日} other {{days}日}}に{count, plural, one {{counter}人} other {{counter} 人}}", "trends.trending_now": "トレンドタグ", "ui.beforeunload": "Mastodonから離れると送信前の投稿は失われます。", "units.short.billion": "{count}B", diff --git a/app/javascript/mastodon/locales/ka.json b/app/javascript/mastodon/locales/ka.json index 519021235..be6709e0b 100644 --- a/app/javascript/mastodon/locales/ka.json +++ b/app/javascript/mastodon/locales/ka.json @@ -1,4 +1,17 @@ { + "about.blocks": "Moderated servers", + "about.contact": "Contact:", + "about.domain_blocks.comment": "Reason", + "about.domain_blocks.domain": "Domain", + "about.domain_blocks.preamble": "Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.", + "about.domain_blocks.severity": "Severity", + "about.domain_blocks.silenced.explanation": "You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.", + "about.domain_blocks.silenced.title": "Limited", + "about.domain_blocks.suspended.explanation": "No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.", + "about.domain_blocks.suspended.title": "Suspended", + "about.not_available": "This information has not been made available on this server.", + "about.powered_by": "Decentralized social media powered by {mastodon}", + "about.rules": "Server rules", "account.account_note_header": "Note", "account.add_or_remove_from_list": "Add or Remove from lists", "account.badges.bot": "ბოტი", @@ -7,13 +20,16 @@ "account.block_domain": "დაიმალოს ყველაფერი დომენიდან {domain}", "account.blocked": "დაიბლოკა", "account.browse_more_on_origin_server": "Browse more on the original profile", - "account.cancel_follow_request": "Cancel follow request", + "account.cancel_follow_request": "Withdraw follow request", "account.direct": "პირდაპირი წერილი @{name}-ს", "account.disable_notifications": "Stop notifying me when @{name} posts", "account.domain_blocked": "დომენი დამალულია", "account.edit_profile": "პროფილის ცვლილება", "account.enable_notifications": "Notify me when @{name} posts", "account.endorse": "გამორჩევა პროფილზე", + "account.featured_tags.last_status_at": "Last post on {date}", + "account.featured_tags.last_status_never": "No posts", + "account.featured_tags.title": "{name}'s featured hashtags", "account.follow": "გაყოლა", "account.followers": "მიმდევრები", "account.followers.empty": "No one follows this user yet.", @@ -23,7 +39,7 @@ "account.follows.empty": "This user doesn't follow anyone yet.", "account.follows_you": "მოგყვებათ", "account.hide_reblogs": "დაიმალოს ბუსტები @{name}-სგან", - "account.joined": "Joined {date}", + "account.joined_short": "Joined", "account.languages": "Change subscribed languages", "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.", @@ -63,12 +79,24 @@ "audio.hide": "Hide audio", "autosuggest_hashtag.per_week": "კვირაში {count}", "boost_modal.combo": "შეგიძლიათ დააჭიროთ {combo}-ს რათა შემდეგ ჯერზე გამოტოვოთ ეს", - "bundle_column_error.body": "ამ კომპონენტის ჩატვირთვისას რაღაც აირია.", + "bundle_column_error.copy_stacktrace": "Copy error report", + "bundle_column_error.error.body": "The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.", + "bundle_column_error.error.title": "Oh, no!", + "bundle_column_error.network.body": "There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.", + "bundle_column_error.network.title": "Network error", "bundle_column_error.retry": "სცადეთ კიდევ ერთხელ", - "bundle_column_error.title": "ქსელის შეცდომა", + "bundle_column_error.return": "Go back home", + "bundle_column_error.routing.body": "The requested page could not be found. Are you sure the URL in the address bar is correct?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "დახურვა", "bundle_modal_error.message": "ამ კომპონენტის ჩატვირთვისას რაღაც აირია.", "bundle_modal_error.retry": "სცადეთ კიდევ ერთხელ", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "About", "column.blocks": "დაბლოკილი მომხმარებლები", "column.bookmarks": "Bookmarks", "column.community": "ლოკალური თაიმლაინი", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "Block & Report", "confirmations.block.confirm": "ბლოკი", "confirmations.block.message": "დარწმუნებული ხართ, გსურთ დაბლოკოთ {name}?", + "confirmations.cancel_follow_request.confirm": "Withdraw request", + "confirmations.cancel_follow_request.message": "Are you sure you want to withdraw your request to follow {name}?", "confirmations.delete.confirm": "გაუქმება", "confirmations.delete.message": "დარწმუნებული ხართ, გსურთ გააუქმოთ ეს სტატუსი?", "confirmations.delete_list.confirm": "გაუქმება", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Mark as read", "conversation.open": "View conversation", "conversation.with": "With {names}", + "copypaste.copied": "Copied", + "copypaste.copy": "Copy", "directory.federated": "From known fediverse", "directory.local": "From {domain} only", "directory.new_arrivals": "New arrivals", "directory.recently_active": "Recently active", + "dismissable_banner.community_timeline": "These are the most recent public posts from people whose accounts are hosted by {domain}.", + "dismissable_banner.dismiss": "Dismiss", + "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", + "dismissable_banner.explore_statuses": "These posts from this and other servers in the decentralized network are gaining traction on this server right now.", + "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", + "dismissable_banner.public_timeline": "These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.", "embed.instructions": "ეს სტატუსი ჩასვით თქვენს ვებ-საიტზე შემდეგი კოდის კოპირებით.", "embed.preview": "ესაა თუ როგორც გამოჩნდება:", "emoji_button.activity": "აქტივობა", @@ -221,14 +259,14 @@ "follow_request.reject": "უარყოფა", "follow_requests.unlocked_explanation": "Even though your account is not locked, the {domain} staff thought you might want to review follow requests from these accounts manually.", "generic.saved": "Saved", - "getting_started.developers": "დეველოპერები", - "getting_started.directory": "Profile directory", + "getting_started.directory": "Directory", "getting_started.documentation": "დოკუმენტაცია", + "getting_started.free_software_notice": "Mastodon is free, open source software. You can view the source code, contribute or report issues at {repository}.", "getting_started.heading": "დაწყება", "getting_started.invite": "ხალხის მოწვევა", - "getting_started.open_source_notice": "მასტოდონი ღია პროგრამაა. შეგიძლიათ შეუწყოთ ხელი ან შექმნათ პრობემის რეპორტი {github}-ზე.", "getting_started.privacy_policy": "Privacy Policy", "getting_started.security": "უსაფრთხოება", + "getting_started.what_is_mastodon": "About Mastodon", "hashtag.column_header.tag_mode.all": "and {additional}", "hashtag.column_header.tag_mode.any": "or {additional}", "hashtag.column_header.tag_mode.none": "without {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "პასუხების ჩვენება", "home.hide_announcements": "Hide announcements", "home.show_announcements": "Show announcements", + "interaction_modal.description.favourite": "With an account on Mastodon, you can favourite this post to let the author know you appreciate it and save it for later.", + "interaction_modal.description.follow": "With an account on Mastodon, you can follow {name} to receive their posts in your home feed.", + "interaction_modal.description.reblog": "With an account on Mastodon, you can boost this post to share it with your own followers.", + "interaction_modal.description.reply": "With an account on Mastodon, you can respond to this post.", + "interaction_modal.on_another_server": "On a different server", + "interaction_modal.on_this_server": "On this server", + "interaction_modal.other_server_instructions": "Simply copy and paste this URL into the search bar of your favourite app or the web interface where you are signed in.", + "interaction_modal.preamble": "Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one.", + "interaction_modal.title.favourite": "Favourite {name}'s post", + "interaction_modal.title.follow": "Follow {name}", + "interaction_modal.title.reblog": "Boost {name}'s post", + "interaction_modal.title.reply": "Reply to {name}'s post", "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}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Duration", "mute_modal.hide_notifications": "დავმალოთ შეტყობინებები ამ მომხმარებლისგან?", "mute_modal.indefinite": "Indefinite", - "navigation_bar.apps": "Mobile apps", + "navigation_bar.about": "About", + "navigation_bar.apps": "Get the app", "navigation_bar.blocks": "დაბლოკილი მომხმარებლები", "navigation_bar.bookmarks": "Bookmarks", "navigation_bar.community_timeline": "ლოკალური თაიმლაინი", @@ -324,7 +375,7 @@ "navigation_bar.filters": "გაჩუმებული სიტყვები", "navigation_bar.follow_requests": "დადევნების მოთხოვნები", "navigation_bar.follows_and_followers": "Follows and followers", - "navigation_bar.info": "ამ ინსტანციის შესახებ", + "navigation_bar.info": "About", "navigation_bar.keyboard_shortcuts": "ცხელი კლავიშები", "navigation_bar.lists": "სიები", "navigation_bar.logout": "გასვლა", @@ -333,7 +384,9 @@ "navigation_bar.pins": "აპინული ტუტები", "navigation_bar.preferences": "პრეფერენსიები", "navigation_bar.public_timeline": "ფედერალური თაიმლაინი", + "navigation_bar.search": "Search", "navigation_bar.security": "უსაფრთხოება", + "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", "notification.admin.report": "{name} reported {target}", "notification.admin.sign_up": "{name} signed up", "notification.favourite": "{name}-მა თქვენი სტატუსი აქცია ფავორიტად", @@ -401,6 +454,8 @@ "privacy.public.short": "საჯარო", "privacy.unlisted.long": "Visible for all, but opted-out of discovery features", "privacy.unlisted.short": "ჩამოუთვლელი", + "privacy_policy.last_updated": "Last updated {date}", + "privacy_policy.title": "Privacy Policy", "refresh": "Refresh", "regeneration_indicator.label": "იტვირთება…", "regeneration_indicator.sublabel": "თქვენი სახლის ლენტა მზადდება!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.title": "Search for {q}", "search_results.total": "{count, number} {count, plural, one {result} other {results}}", + "server_banner.about_active_users": "People using this server during the last 30 days (Monthly Active Users)", + "server_banner.active_users": "active users", + "server_banner.administered_by": "Administered by:", + "server_banner.introduction": "{domain} is part of the decentralized social network powered by {mastodon}.", + "server_banner.learn_more": "Learn more", + "server_banner.server_stats": "Server stats:", "sign_in_banner.create_account": "Create account", "sign_in_banner.sign_in": "Sign in", "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "No one has boosted this toot yet. When someone does, they will show up here.", "status.redraft": "გაუქმდეს და გადანაწილდეს", "status.remove_bookmark": "Remove bookmark", + "status.replied_to": "Replied to {name}", "status.reply": "პასუხი", "status.replyAll": "უპასუხე თემას", "status.report": "დაარეპორტე @{name}", @@ -523,9 +585,8 @@ "status.show_more": "აჩვენე მეტი", "status.show_more_all": "აჩვენე მეტი ყველაზე", "status.show_original": "Show original", - "status.show_thread": "Show thread", "status.translate": "Translate", - "status.translated_from": "Translated from {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Not available", "status.unmute_conversation": "საუბარზე გაჩუმების მოშორება", "status.unpin": "პროფილიდან პინის მოშორება", @@ -538,7 +599,6 @@ "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", diff --git a/app/javascript/mastodon/locales/kab.json b/app/javascript/mastodon/locales/kab.json index 2bcef42c7..d693216af 100644 --- a/app/javascript/mastodon/locales/kab.json +++ b/app/javascript/mastodon/locales/kab.json @@ -1,4 +1,17 @@ { + "about.blocks": "Moderated servers", + "about.contact": "Contact:", + "about.domain_blocks.comment": "Reason", + "about.domain_blocks.domain": "Domain", + "about.domain_blocks.preamble": "Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.", + "about.domain_blocks.severity": "Severity", + "about.domain_blocks.silenced.explanation": "You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.", + "about.domain_blocks.silenced.title": "Limited", + "about.domain_blocks.suspended.explanation": "No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.", + "about.domain_blocks.suspended.title": "Suspended", + "about.not_available": "This information has not been made available on this server.", + "about.powered_by": "Decentralized social media powered by {mastodon}", + "about.rules": "Server rules", "account.account_note_header": "Tazmilt", "account.add_or_remove_from_list": "Rnu neɣ kkes seg tebdarin", "account.badges.bot": "Aṛubut", @@ -7,13 +20,16 @@ "account.block_domain": "Ffer kra i d-yekkan seg {domain}", "account.blocked": "Yettusewḥel", "account.browse_more_on_origin_server": "Snirem ugar deg umeɣnu aneẓli", - "account.cancel_follow_request": "Sefsex asuter n uḍfar", + "account.cancel_follow_request": "Withdraw follow request", "account.direct": "Izen usrid i @{name}", "account.disable_notifications": "Ḥbes ur iyi-d-ttazen ara ilɣa mi ara d-isuffeɣ @{name}", "account.domain_blocked": "Taɣult yeffren", "account.edit_profile": "Ẓreg amaɣnu", "account.enable_notifications": "Azen-iyi-d ilɣa mi ara d-isuffeɣ @{name}", "account.endorse": "Welleh fell-as deg umaɣnu-inek", + "account.featured_tags.last_status_at": "Last post on {date}", + "account.featured_tags.last_status_never": "No posts", + "account.featured_tags.title": "{name}'s featured hashtags", "account.follow": "Ḍfer", "account.followers": "Imeḍfaren", "account.followers.empty": "Ar tura, ulac yiwen i yeṭṭafaṛen amseqdac-agi.", @@ -23,7 +39,7 @@ "account.follows.empty": "Ar tura, amseqdac-agi ur yeṭṭafaṛ yiwen.", "account.follows_you": "Yeṭṭafaṛ-ik", "account.hide_reblogs": "Ffer ayen i ibeṭṭu @{name}", - "account.joined": "Yerna-d {date}", + "account.joined_short": "Joined", "account.languages": "Change subscribed languages", "account.link_verified_on": "Taɣara n useɣwen-a tettwasenqed ass n {date}", "account.locked_info": "Amiḍan-agi uslig isekweṛ. D bab-is kan i izemren ad yeǧǧ, s ufus-is, win ara t-iḍefṛen.", @@ -33,13 +49,13 @@ "account.mute": "Sgugem @{name}", "account.mute_notifications": "Sgugem tilɣa sγur @{name}", "account.muted": "Yettwasgugem", - "account.posts": "Tijewwaqin", - "account.posts_with_replies": "Tijewwaqin akked tririyin", + "account.posts": "Tisuffaɣ", + "account.posts_with_replies": "Tisuffaɣ d tririyin", "account.report": "Cetki ɣef @{name}", "account.requested": "Di laɛḍil ad yettwaqbel. Ssit i wakken ad yefsex usuter n uḍfar", "account.share": "Bḍu amaɣnu n @{name}", "account.show_reblogs": "Ssken-d inebḍa n @{name}", - "account.statuses_counter": "{count, plural, one {{counter} ajewwaq} other {{counter} ijewwaqen}}", + "account.statuses_counter": "{count, plural, one {{counter} n tsuffeɣt} other {{counter} n tsuffaɣ}}", "account.unblock": "Serreḥ i @{name}", "account.unblock_domain": "Ssken-d {domain}", "account.unblock_short": "Unblock", @@ -63,16 +79,28 @@ "audio.hide": "Hide audio", "autosuggest_hashtag.per_week": "{count} i yimalas", "boost_modal.combo": "Tzemreḍ ad tetekkiḍ ɣef {combo} akken ad tessurfeḍ aya tikelt-nniḍen", - "bundle_column_error.body": "Tella-d kra n tuccḍa mi d-yettali ugbur-agi.", + "bundle_column_error.copy_stacktrace": "Copy error report", + "bundle_column_error.error.body": "The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.", + "bundle_column_error.error.title": "Oh, no!", + "bundle_column_error.network.body": "There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.", + "bundle_column_error.network.title": "Network error", "bundle_column_error.retry": "Ɛreḍ tikelt-nniḍen", - "bundle_column_error.title": "Tuccḍa deg uẓeṭṭa", + "bundle_column_error.return": "Go back home", + "bundle_column_error.routing.body": "The requested page could not be found. Are you sure the URL in the address bar is correct?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Mdel", "bundle_modal_error.message": "Tella-d kra n tuccḍa mi d-yettali ugbur-agi.", "bundle_modal_error.retry": "Ɛreḍ tikelt-nniḍen", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "Γef", "column.blocks": "Imiḍanen yettusḥebsen", "column.bookmarks": "Ticraḍ", "column.community": "Tasuddemt tadigant", - "column.direct": "Direct messages", + "column.direct": "Iznan usriden", "column.directory": "Inig deg imaɣnuten", "column.domain_blocks": "Taɣulin yeffren", "column.favourites": "Ismenyifen", @@ -94,8 +122,8 @@ "community.column_settings.local_only": "Adigan kan", "community.column_settings.media_only": "Allal n teywalt kan", "community.column_settings.remote_only": "Anmeggag kan", - "compose.language.change": "Change language", - "compose.language.search": "Search languages...", + "compose.language.change": "Beddel tutlayt", + "compose.language.search": "Nadi tutlayin …", "compose_form.direct_message_warning_learn_more": "Issin ugar", "compose_form.encryption_warning": "Posts on Mastodon are not end-to-end encrypted. Do not share any dangerous information over Mastodon.", "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.", @@ -113,14 +141,16 @@ "compose_form.save_changes": "Sekles ibeddilen", "compose_form.sensitive.hide": "Creḍ allal n teywalt d anafri", "compose_form.sensitive.marked": "Allal n teywalt yettwacreḍ d anafri", - "compose_form.sensitive.unmarked": "Allal n teywalt ur yettwacreḍ ara d anafri", - "compose_form.spoiler.marked": "Aḍris yeffer deffir n walɣu", - "compose_form.spoiler.unmarked": "Aḍris ur yettwaffer ara", - "compose_form.spoiler_placeholder": "Aru alɣu-inek da", + "compose_form.sensitive.unmarked": "{count, plural, one {Amidya ur yettwacreḍ ara d anafri} other {Imidyaten ur ttwacreḍen ara d inafriyen}}", + "compose_form.spoiler.marked": "Kkes aḍris yettwaffren deffir n walɣu", + "compose_form.spoiler.unmarked": "Rnu aḍris yettwaffren deffir n walɣu", + "compose_form.spoiler_placeholder": "Aru alɣu-inek·inem da", "confirmation_modal.cancel": "Sefsex", "confirmations.block.block_and_report": "Sewḥel & sewɛed", "confirmations.block.confirm": "Sewḥel", "confirmations.block.message": "Tebγiḍ s tidet ad tesḥebseḍ {name}?", + "confirmations.cancel_follow_request.confirm": "Withdraw request", + "confirmations.cancel_follow_request.message": "Are you sure you want to withdraw your request to follow {name}?", "confirmations.delete.confirm": "Kkes", "confirmations.delete.message": "Tebɣiḍ s tidet ad tekkseḍ tasuffeɣt-agi?", "confirmations.delete_list.confirm": "Kkes", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Creḍ yettwaɣṛa", "conversation.open": "Ssken adiwenni", "conversation.with": "Akked {names}", + "copypaste.copied": "Copied", + "copypaste.copy": "Nγel", "directory.federated": "Deg fedivers yettwasnen", "directory.local": "Seg {domain} kan", "directory.new_arrivals": "Imaynuten id yewḍen", "directory.recently_active": "Yermed xas melmi kan", + "dismissable_banner.community_timeline": "These are the most recent public posts from people whose accounts are hosted by {domain}.", + "dismissable_banner.dismiss": "Dismiss", + "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", + "dismissable_banner.explore_statuses": "These posts from this and other servers in the decentralized network are gaining traction on this server right now.", + "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", + "dismissable_banner.public_timeline": "These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.", "embed.instructions": "Ẓẓu addad-agi deg usmel-inek s wenγal n tangalt yellan sdaw-agi.", "embed.preview": "Akka ara d-iban:", "emoji_button.activity": "Aqeddic", @@ -194,7 +232,7 @@ "errors.unexpected_crash.report_issue": "Mmel ugur", "explore.search_results": "Search results", "explore.suggested_follows": "I kečč·kem", - "explore.title": "Explore", + "explore.title": "Snirem", "explore.trending_links": "News", "explore.trending_statuses": "Tisuffaɣ", "explore.trending_tags": "Ihacṭagen", @@ -221,14 +259,14 @@ "follow_request.reject": "Agi", "follow_requests.unlocked_explanation": "Even though your account is not locked, the {domain} staff thought you might want to review follow requests from these accounts manually.", "generic.saved": "Yettwasekles", - "getting_started.developers": "Ineflayen", - "getting_started.directory": "Akaram n imaɣnuten", + "getting_started.directory": "Directory", "getting_started.documentation": "Amnir", + "getting_started.free_software_notice": "Mastodon is free, open source software. You can view the source code, contribute or report issues at {repository}.", "getting_started.heading": "Bdu", "getting_started.invite": "Snebgi-d imdanen", - "getting_started.open_source_notice": "Maṣṭudun d aseɣzan s uɣbalu yeldin. Tzemreḍ ad tɛiwneḍ neɣ ad temmleḍ uguren deg GitHub {github}.", "getting_started.privacy_policy": "Privacy Policy", "getting_started.security": "Iɣewwaṛen n umiḍan", + "getting_started.what_is_mastodon": "About Mastodon", "hashtag.column_header.tag_mode.all": "d {additional}", "hashtag.column_header.tag_mode.any": "neɣ {additional}", "hashtag.column_header.tag_mode.none": "war {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Ssken-d tiririyin", "home.hide_announcements": "Ffer ulɣuyen", "home.show_announcements": "Ssken-d ulɣuyen", + "interaction_modal.description.favourite": "With an account on Mastodon, you can favourite this post to let the author know you appreciate it and save it for later.", + "interaction_modal.description.follow": "With an account on Mastodon, you can follow {name} to receive their posts in your home feed.", + "interaction_modal.description.reblog": "With an account on Mastodon, you can boost this post to share it with your own followers.", + "interaction_modal.description.reply": "With an account on Mastodon, you can respond to this post.", + "interaction_modal.on_another_server": "On a different server", + "interaction_modal.on_this_server": "On this server", + "interaction_modal.other_server_instructions": "Simply copy and paste this URL into the search bar of your favourite app or the web interface where you are signed in.", + "interaction_modal.preamble": "Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one.", + "interaction_modal.title.favourite": "Favourite {name}'s post", + "interaction_modal.title.follow": "Follow {name}", + "interaction_modal.title.reblog": "Boost {name}'s post", + "interaction_modal.title.reply": "Reply to {name}'s post", "intervals.full.days": "{number, plural, one {# n wass} other {# n wussan}}", "intervals.full.hours": "{number, plural, one {# n usarag} other {# n yesragen}}", "intervals.full.minutes": "{number, plural, one {# n tesdat} other {# n tesdatin}}", @@ -310,12 +360,13 @@ "mute_modal.duration": "Tanzagt", "mute_modal.hide_notifications": "Tebɣiḍ ad teffreḍ talɣutin n umseqdac-a?", "mute_modal.indefinite": "Ur yettwasbadu ara", - "navigation_bar.apps": "Isnasen izirazen", + "navigation_bar.about": "Γef", + "navigation_bar.apps": "Get the app", "navigation_bar.blocks": "Imseqdacen yettusḥebsen", "navigation_bar.bookmarks": "Ticraḍ", "navigation_bar.community_timeline": "Tasuddemt tadigant", "navigation_bar.compose": "Aru tajewwiqt tamaynut", - "navigation_bar.direct": "Direct messages", + "navigation_bar.direct": "Iznan usridden", "navigation_bar.discover": "Ẓer", "navigation_bar.domain_blocks": "Tiɣula yeffren", "navigation_bar.edit_profile": "Ẓreg amaɣnu", @@ -324,7 +375,7 @@ "navigation_bar.filters": "Awalen i yettwasgugmen", "navigation_bar.follow_requests": "Isuturen n teḍfeṛt", "navigation_bar.follows_and_followers": "Imeḍfaṛen akked wid i teṭṭafaṛeḍ", - "navigation_bar.info": "Ɣef uqeddac-agi", + "navigation_bar.info": "Γef", "navigation_bar.keyboard_shortcuts": "Inegzumen n unasiw", "navigation_bar.lists": "Tibdarin", "navigation_bar.logout": "Ffeɣ", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Tijewwiqin yettwasentḍen", "navigation_bar.preferences": "Imenyafen", "navigation_bar.public_timeline": "Tasuddemt tazayezt tamatut", + "navigation_bar.search": "Search", "navigation_bar.security": "Taɣellist", + "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", "notification.admin.report": "{name} reported {target}", "notification.admin.sign_up": "{name} signed up", "notification.favourite": "{name} yesmenyef tasuffeɣt-ik·im", @@ -401,6 +454,8 @@ "privacy.public.short": "Azayez", "privacy.unlisted.long": "Visible for all, but opted-out of discovery features", "privacy.unlisted.short": "War tabdert", + "privacy_policy.last_updated": "Last updated {date}", + "privacy_policy.title": "Privacy Policy", "refresh": "Smiren", "regeneration_indicator.label": "Yessalay-d…", "regeneration_indicator.sublabel": "Tasuddemt tagejdant ara d-tettwaheggay!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "Anadi ɣef tjewwiqin s ugbur-nsent ur yermid ara deg uqeddac-agi n Maṣṭudun.", "search_results.title": "Search for {q}", "search_results.total": "{count, number} {count, plural, one {n ugemmuḍ} other {n yigemmuḍen}}", + "server_banner.about_active_users": "People using this server during the last 30 days (Monthly Active Users)", + "server_banner.active_users": "active users", + "server_banner.administered_by": "Administered by:", + "server_banner.introduction": "{domain} is part of the decentralized social network powered by {mastodon}.", + "server_banner.learn_more": "Issin ugar", + "server_banner.server_stats": "Server stats:", "sign_in_banner.create_account": "Create account", "sign_in_banner.sign_in": "Sign in", "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", @@ -488,7 +549,7 @@ "status.direct": "Izen usrid i @{name}", "status.edit": "Ẓreg", "status.edited": "Tettwaẓreg deg {date}", - "status.edited_x_times": "Edited {count, plural, one {{count} time} other {{count} times}}", + "status.edited_x_times": "Tettwaẓreg {count, plural, one {{count} n tikkelt} other {{count} n tikkal}}", "status.embed": "Seddu", "status.favourite": "Rnu ɣer yismenyifen", "status.filter": "Filter this post", @@ -512,6 +573,7 @@ "status.reblogs.empty": "Ula yiwen ur yebḍi tajewwiqt-agi ar tura. Ticki yebḍa-tt yiwen, ad d-iban da.", "status.redraft": "Kkes tɛiwdeḍ tira", "status.remove_bookmark": "Kkes tacreḍt", + "status.replied_to": "Replied to {name}", "status.reply": "Err", "status.replyAll": "Err i lxiḍ", "status.report": "Cetki ɣef @{name}", @@ -523,14 +585,13 @@ "status.show_more": "Ssken-d ugar", "status.show_more_all": "Ẓerr ugar lebda", "status.show_original": "Show original", - "status.show_thread": "Ssken-d lxiḍ", - "status.translate": "Translate", - "status.translated_from": "Translated from {lang}", + "status.translate": "Suqel", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Ulac-it", "status.unmute_conversation": "Kkes asgugem n udiwenni", "status.unpin": "Kkes asenteḍ seg umaɣnu", "subscribed_languages.lead": "Only posts in selected languages will appear on your home and list timelines after the change. Select none to receive posts in all languages.", - "subscribed_languages.save": "Save changes", + "subscribed_languages.save": "Sekles ibeddilen", "subscribed_languages.target": "Change subscribed languages for {target}", "suggestions.dismiss": "Sefsex asumer", "suggestions.header": "Ahat ad tcelgeḍ deg…", @@ -538,7 +599,6 @@ "tabs_bar.home": "Agejdan", "tabs_bar.local_timeline": "Adigan", "tabs_bar.notifications": "Tilɣa", - "tabs_bar.search": "Nadi", "time_remaining.days": "Mazal {number, plural, one {# n wass} other {# n wussan}}", "time_remaining.hours": "Mazal {number, plural, one {# n usrag} other {# n yesragen}}", "time_remaining.minutes": "Mazal {number, plural, one {# n tesdat} other {# n tesdatin}}", diff --git a/app/javascript/mastodon/locales/kk.json b/app/javascript/mastodon/locales/kk.json index bc8b068db..157ca66da 100644 --- a/app/javascript/mastodon/locales/kk.json +++ b/app/javascript/mastodon/locales/kk.json @@ -1,4 +1,17 @@ { + "about.blocks": "Moderated servers", + "about.contact": "Contact:", + "about.domain_blocks.comment": "Reason", + "about.domain_blocks.domain": "Domain", + "about.domain_blocks.preamble": "Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.", + "about.domain_blocks.severity": "Severity", + "about.domain_blocks.silenced.explanation": "You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.", + "about.domain_blocks.silenced.title": "Limited", + "about.domain_blocks.suspended.explanation": "No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.", + "about.domain_blocks.suspended.title": "Suspended", + "about.not_available": "This information has not been made available on this server.", + "about.powered_by": "Decentralized social media powered by {mastodon}", + "about.rules": "Server rules", "account.account_note_header": "Жазба", "account.add_or_remove_from_list": "Тізімге қосу немесе жою", "account.badges.bot": "Бот", @@ -7,13 +20,16 @@ "account.block_domain": "Домендегі барлығын бұғатта {domain}", "account.blocked": "Бұғатталды", "account.browse_more_on_origin_server": "Толығырақ оригинал профилінде қара", - "account.cancel_follow_request": "Жазылуға сұранымды қайтару", + "account.cancel_follow_request": "Withdraw follow request", "account.direct": "Жеке хат @{name}", "account.disable_notifications": "Stop notifying me when @{name} posts", "account.domain_blocked": "Домен жабық", "account.edit_profile": "Профильді өңдеу", "account.enable_notifications": "Notify me when @{name} posts", "account.endorse": "Профильде рекомендеу", + "account.featured_tags.last_status_at": "Last post on {date}", + "account.featured_tags.last_status_never": "No posts", + "account.featured_tags.title": "{name}'s featured hashtags", "account.follow": "Жазылу", "account.followers": "Оқырмандар", "account.followers.empty": "Әлі ешкім жазылмаған.", @@ -23,7 +39,7 @@ "account.follows.empty": "Ешкімге жазылмапты.", "account.follows_you": "Сізге жазылыпты", "account.hide_reblogs": "@{name} атты қолданушының әрекеттерін жасыру", - "account.joined": "Joined {date}", + "account.joined_short": "Joined", "account.languages": "Change subscribed languages", "account.link_verified_on": "Сілтеме меншігі расталған күн {date}", "account.locked_info": "Бұл қолданушы өзі туралы мәліметтерді жасырған. Тек жазылғандар ғана көре алады.", @@ -63,12 +79,24 @@ "audio.hide": "Hide audio", "autosuggest_hashtag.per_week": "{count} аптасына", "boost_modal.combo": "Келесіде өткізіп жіберу үшін басыңыз {combo}", - "bundle_column_error.body": "Бұл компонентті жүктеген кезде бір қате пайда болды.", + "bundle_column_error.copy_stacktrace": "Copy error report", + "bundle_column_error.error.body": "The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.", + "bundle_column_error.error.title": "Oh, no!", + "bundle_column_error.network.body": "There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.", + "bundle_column_error.network.title": "Network error", "bundle_column_error.retry": "Қайтадан көріңіз", - "bundle_column_error.title": "Желі қатесі", + "bundle_column_error.return": "Go back home", + "bundle_column_error.routing.body": "The requested page could not be found. Are you sure the URL in the address bar is correct?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Жабу", "bundle_modal_error.message": "Бұл компонентті жүктеген кезде бір қате пайда болды.", "bundle_modal_error.retry": "Қайтадан көріңіз", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "About", "column.blocks": "Бұғатталғандар", "column.bookmarks": "Бетбелгілер", "column.community": "Жергілікті желі", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "Блок және Шағым", "confirmations.block.confirm": "Бұғаттау", "confirmations.block.message": "{name} атты қолданушыны бұғаттайтыныңызға сенімдісіз бе?", + "confirmations.cancel_follow_request.confirm": "Withdraw request", + "confirmations.cancel_follow_request.message": "Are you sure you want to withdraw your request to follow {name}?", "confirmations.delete.confirm": "Өшіру", "confirmations.delete.message": "Бұл жазбаны өшіресіз бе?", "confirmations.delete_list.confirm": "Өшіру", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Оқылды деп белгіле", "conversation.open": "Пікірталасты қарау", "conversation.with": "{names} атты", + "copypaste.copied": "Copied", + "copypaste.copy": "Copy", "directory.federated": "Танымал желіден", "directory.local": "Тек {domain} доменінен", "directory.new_arrivals": "Жаңадан келгендер", "directory.recently_active": "Жақында кіргендер", + "dismissable_banner.community_timeline": "These are the most recent public posts from people whose accounts are hosted by {domain}.", + "dismissable_banner.dismiss": "Dismiss", + "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", + "dismissable_banner.explore_statuses": "These posts from this and other servers in the decentralized network are gaining traction on this server right now.", + "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", + "dismissable_banner.public_timeline": "These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.", "embed.instructions": "Төмендегі кодты көшіріп алу арқылы жазбаны басқа сайттарға да орналастыра аласыз.", "embed.preview": "Былай көрінетін болады:", "emoji_button.activity": "Белсенділік", @@ -221,14 +259,14 @@ "follow_request.reject": "Қабылдамау", "follow_requests.unlocked_explanation": "Even though your account is not locked, the {domain} staff thought you might want to review follow requests from these accounts manually.", "generic.saved": "Сақталды", - "getting_started.developers": "Жасаушылар тобы", - "getting_started.directory": "Профильдер каталогы", + "getting_started.directory": "Directory", "getting_started.documentation": "Құжаттама", + "getting_started.free_software_notice": "Mastodon is free, open source software. You can view the source code, contribute or report issues at {repository}.", "getting_started.heading": "Желіде", "getting_started.invite": "Адам шақыру", - "getting_started.open_source_notice": "Mastodon - ашық кодты құрылым. Түзету енгізу немесе ұсыныстарды GitHub арқылы жасаңыз {github}.", "getting_started.privacy_policy": "Privacy Policy", "getting_started.security": "Қауіпсіздік", + "getting_started.what_is_mastodon": "About Mastodon", "hashtag.column_header.tag_mode.all": "және {additional}", "hashtag.column_header.tag_mode.any": "немесе {additional}", "hashtag.column_header.tag_mode.none": "{additional} болмай", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Жауаптарды көрсету", "home.hide_announcements": "Анонстарды жасыр", "home.show_announcements": "Анонстарды көрсет", + "interaction_modal.description.favourite": "With an account on Mastodon, you can favourite this post to let the author know you appreciate it and save it for later.", + "interaction_modal.description.follow": "With an account on Mastodon, you can follow {name} to receive their posts in your home feed.", + "interaction_modal.description.reblog": "With an account on Mastodon, you can boost this post to share it with your own followers.", + "interaction_modal.description.reply": "With an account on Mastodon, you can respond to this post.", + "interaction_modal.on_another_server": "On a different server", + "interaction_modal.on_this_server": "On this server", + "interaction_modal.other_server_instructions": "Simply copy and paste this URL into the search bar of your favourite app or the web interface where you are signed in.", + "interaction_modal.preamble": "Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one.", + "interaction_modal.title.favourite": "Favourite {name}'s post", + "interaction_modal.title.follow": "Follow {name}", + "interaction_modal.title.reblog": "Boost {name}'s post", + "interaction_modal.title.reply": "Reply to {name}'s post", "intervals.full.days": "{number, plural, one {# күн} other {# күн}}", "intervals.full.hours": "{number, plural, one {# сағат} other {# сағат}}", "intervals.full.minutes": "{number, plural, one {# минут} other {# минут}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Duration", "mute_modal.hide_notifications": "Бұл қолданушы ескертпелерін жасырамыз ба?", "mute_modal.indefinite": "Indefinite", - "navigation_bar.apps": "Мобиль қосымшалар", + "navigation_bar.about": "About", + "navigation_bar.apps": "Get the app", "navigation_bar.blocks": "Бұғатталғандар", "navigation_bar.bookmarks": "Бетбелгілер", "navigation_bar.community_timeline": "Жергілікті желі", @@ -324,7 +375,7 @@ "navigation_bar.filters": "Үнсіз сөздер", "navigation_bar.follow_requests": "Жазылуға сұранғандар", "navigation_bar.follows_and_followers": "Жазылымдар және оқырмандар", - "navigation_bar.info": "Сервер туралы", + "navigation_bar.info": "About", "navigation_bar.keyboard_shortcuts": "Ыстық пернелер", "navigation_bar.lists": "Тізімдер", "navigation_bar.logout": "Шығу", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Жабыстырылғандар", "navigation_bar.preferences": "Басымдықтар", "navigation_bar.public_timeline": "Жаһандық желі", + "navigation_bar.search": "Search", "navigation_bar.security": "Қауіпсіздік", + "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", "notification.admin.report": "{name} reported {target}", "notification.admin.sign_up": "{name} signed up", "notification.favourite": "{name} жазбаңызды таңдаулыға қосты", @@ -401,6 +454,8 @@ "privacy.public.short": "Ашық", "privacy.unlisted.long": "Visible for all, but opted-out of discovery features", "privacy.unlisted.short": "Тізімсіз", + "privacy_policy.last_updated": "Last updated {date}", + "privacy_policy.title": "Privacy Policy", "refresh": "Жаңарту", "regeneration_indicator.label": "Жүктеу…", "regeneration_indicator.sublabel": "Жергілікті желі құрылуда!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "Mastodon серверінде постты толық мәтінмен іздей алмайсыз.", "search_results.title": "Search for {q}", "search_results.total": "{count, number} {count, plural, one {нәтиже} other {нәтиже}}", + "server_banner.about_active_users": "People using this server during the last 30 days (Monthly Active Users)", + "server_banner.active_users": "active users", + "server_banner.administered_by": "Administered by:", + "server_banner.introduction": "{domain} is part of the decentralized social network powered by {mastodon}.", + "server_banner.learn_more": "Learn more", + "server_banner.server_stats": "Server stats:", "sign_in_banner.create_account": "Create account", "sign_in_banner.sign_in": "Sign in", "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "Бұл жазбаны әлі ешкім бөліспеді. Біреу бөліскен кезде осында көрінеді.", "status.redraft": "Өшіру & қайта қарастыру", "status.remove_bookmark": "Бетбелгілерден алып тастау", + "status.replied_to": "Replied to {name}", "status.reply": "Жауап", "status.replyAll": "Тақырыпқа жауап", "status.report": "Шағым @{name}", @@ -523,9 +585,8 @@ "status.show_more": "Толығырақ", "status.show_more_all": "Бәрін толығымен", "status.show_original": "Show original", - "status.show_thread": "Желіні көрсет", "status.translate": "Translate", - "status.translated_from": "Translated from {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Қолжетімді емес", "status.unmute_conversation": "Пікірталасты үнсіз қылмау", "status.unpin": "Профильден алып тастау", @@ -538,7 +599,6 @@ "tabs_bar.home": "Басты бет", "tabs_bar.local_timeline": "Жергілікті", "tabs_bar.notifications": "Ескертпелер", - "tabs_bar.search": "Іздеу", "time_remaining.days": "{number, plural, one {# күн} other {# күн}}", "time_remaining.hours": "{number, plural, one {# сағат} other {# сағат}}", "time_remaining.minutes": "{number, plural, one {# минут} other {# минут}}", diff --git a/app/javascript/mastodon/locales/kn.json b/app/javascript/mastodon/locales/kn.json index 80c82f157..3e2baf887 100644 --- a/app/javascript/mastodon/locales/kn.json +++ b/app/javascript/mastodon/locales/kn.json @@ -1,4 +1,17 @@ { + "about.blocks": "Moderated servers", + "about.contact": "Contact:", + "about.domain_blocks.comment": "Reason", + "about.domain_blocks.domain": "Domain", + "about.domain_blocks.preamble": "Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.", + "about.domain_blocks.severity": "Severity", + "about.domain_blocks.silenced.explanation": "You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.", + "about.domain_blocks.silenced.title": "Limited", + "about.domain_blocks.suspended.explanation": "No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.", + "about.domain_blocks.suspended.title": "Suspended", + "about.not_available": "This information has not been made available on this server.", + "about.powered_by": "Decentralized social media powered by {mastodon}", + "about.rules": "Server rules", "account.account_note_header": "ಟಿಪ್ಪಣಿ", "account.add_or_remove_from_list": "ಪಟ್ಟಿಗೆ ಸೇರಿಸು ಅಥವ ಪಟ್ಟಿಯಿಂದ ತೆಗೆದುಹಾಕು", "account.badges.bot": "Bot", @@ -7,13 +20,16 @@ "account.block_domain": "Hide everything from {domain}", "account.blocked": "Blocked", "account.browse_more_on_origin_server": "Browse more on the original profile", - "account.cancel_follow_request": "Cancel follow request", + "account.cancel_follow_request": "Withdraw follow request", "account.direct": "Direct message @{name}", "account.disable_notifications": "Stop notifying me when @{name} posts", "account.domain_blocked": "Domain hidden", "account.edit_profile": "Edit profile", "account.enable_notifications": "Notify me when @{name} posts", "account.endorse": "Feature on profile", + "account.featured_tags.last_status_at": "Last post on {date}", + "account.featured_tags.last_status_never": "No posts", + "account.featured_tags.title": "{name}'s featured hashtags", "account.follow": "ಹಿಂಬಾಲಿಸಿ", "account.followers": "ಹಿಂಬಾಲಕರು", "account.followers.empty": "No one follows this user yet.", @@ -23,7 +39,7 @@ "account.follows.empty": "This user doesn't follow anyone yet.", "account.follows_you": "Follows you", "account.hide_reblogs": "Hide boosts from @{name}", - "account.joined": "Joined {date}", + "account.joined_short": "Joined", "account.languages": "Change subscribed languages", "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.", @@ -63,12 +79,24 @@ "audio.hide": "Hide audio", "autosuggest_hashtag.per_week": "{count} per week", "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.copy_stacktrace": "Copy error report", + "bundle_column_error.error.body": "The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.", + "bundle_column_error.error.title": "Oh, no!", + "bundle_column_error.network.body": "There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.", + "bundle_column_error.network.title": "Network error", "bundle_column_error.retry": "ಮರಳಿ ಪ್ರಯತ್ನಿಸಿ", - "bundle_column_error.title": "Network error", + "bundle_column_error.return": "Go back home", + "bundle_column_error.routing.body": "The requested page could not be found. Are you sure the URL in the address bar is correct?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Close", "bundle_modal_error.message": "Something went wrong while loading this component.", "bundle_modal_error.retry": "Try again", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "About", "column.blocks": "Blocked users", "column.bookmarks": "Bookmarks", "column.community": "Local timeline", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "Block & Report", "confirmations.block.confirm": "Block", "confirmations.block.message": "Are you sure you want to block {name}?", + "confirmations.cancel_follow_request.confirm": "Withdraw request", + "confirmations.cancel_follow_request.message": "Are you sure you want to withdraw your request to follow {name}?", "confirmations.delete.confirm": "Delete", "confirmations.delete.message": "Are you sure you want to delete this status?", "confirmations.delete_list.confirm": "Delete", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Mark as read", "conversation.open": "View conversation", "conversation.with": "With {names}", + "copypaste.copied": "Copied", + "copypaste.copy": "Copy", "directory.federated": "From known fediverse", "directory.local": "From {domain} only", "directory.new_arrivals": "New arrivals", "directory.recently_active": "Recently active", + "dismissable_banner.community_timeline": "These are the most recent public posts from people whose accounts are hosted by {domain}.", + "dismissable_banner.dismiss": "Dismiss", + "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", + "dismissable_banner.explore_statuses": "These posts from this and other servers in the decentralized network are gaining traction on this server right now.", + "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", + "dismissable_banner.public_timeline": "These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.", "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", @@ -221,14 +259,14 @@ "follow_request.reject": "Reject", "follow_requests.unlocked_explanation": "Even though your account is not locked, the {domain} staff thought you might want to review follow requests from these accounts manually.", "generic.saved": "Saved", - "getting_started.developers": "Developers", - "getting_started.directory": "Profile directory", + "getting_started.directory": "Directory", "getting_started.documentation": "Documentation", + "getting_started.free_software_notice": "Mastodon is free, open source software. You can view the source code, contribute or report issues at {repository}.", "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.privacy_policy": "Privacy Policy", "getting_started.security": "Security", + "getting_started.what_is_mastodon": "About Mastodon", "hashtag.column_header.tag_mode.all": "and {additional}", "hashtag.column_header.tag_mode.any": "or {additional}", "hashtag.column_header.tag_mode.none": "without {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Show replies", "home.hide_announcements": "Hide announcements", "home.show_announcements": "Show announcements", + "interaction_modal.description.favourite": "With an account on Mastodon, you can favourite this post to let the author know you appreciate it and save it for later.", + "interaction_modal.description.follow": "With an account on Mastodon, you can follow {name} to receive their posts in your home feed.", + "interaction_modal.description.reblog": "With an account on Mastodon, you can boost this post to share it with your own followers.", + "interaction_modal.description.reply": "With an account on Mastodon, you can respond to this post.", + "interaction_modal.on_another_server": "On a different server", + "interaction_modal.on_this_server": "On this server", + "interaction_modal.other_server_instructions": "Simply copy and paste this URL into the search bar of your favourite app or the web interface where you are signed in.", + "interaction_modal.preamble": "Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one.", + "interaction_modal.title.favourite": "Favourite {name}'s post", + "interaction_modal.title.follow": "Follow {name}", + "interaction_modal.title.reblog": "Boost {name}'s post", + "interaction_modal.title.reply": "Reply to {name}'s post", "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}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Duration", "mute_modal.hide_notifications": "Hide notifications from this user?", "mute_modal.indefinite": "Indefinite", - "navigation_bar.apps": "Mobile apps", + "navigation_bar.about": "About", + "navigation_bar.apps": "Get the app", "navigation_bar.blocks": "Blocked users", "navigation_bar.bookmarks": "Bookmarks", "navigation_bar.community_timeline": "Local timeline", @@ -324,7 +375,7 @@ "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.info": "About", "navigation_bar.keyboard_shortcuts": "Hotkeys", "navigation_bar.lists": "Lists", "navigation_bar.logout": "Logout", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Pinned toots", "navigation_bar.preferences": "Preferences", "navigation_bar.public_timeline": "Federated timeline", + "navigation_bar.search": "Search", "navigation_bar.security": "Security", + "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", "notification.admin.report": "{name} reported {target}", "notification.admin.sign_up": "{name} signed up", "notification.favourite": "{name} favourited your status", @@ -401,6 +454,8 @@ "privacy.public.short": "Public", "privacy.unlisted.long": "Visible for all, but opted-out of discovery features", "privacy.unlisted.short": "Unlisted", + "privacy_policy.last_updated": "Last updated {date}", + "privacy_policy.title": "Privacy Policy", "refresh": "Refresh", "regeneration_indicator.label": "Loading…", "regeneration_indicator.sublabel": "Your home feed is being prepared!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.title": "Search for {q}", "search_results.total": "{count, number} {count, plural, one {result} other {results}}", + "server_banner.about_active_users": "People using this server during the last 30 days (Monthly Active Users)", + "server_banner.active_users": "active users", + "server_banner.administered_by": "Administered by:", + "server_banner.introduction": "{domain} is part of the decentralized social network powered by {mastodon}.", + "server_banner.learn_more": "Learn more", + "server_banner.server_stats": "Server stats:", "sign_in_banner.create_account": "Create account", "sign_in_banner.sign_in": "Sign in", "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "No one has boosted this toot yet. When someone does, they will show up here.", "status.redraft": "Delete & re-draft", "status.remove_bookmark": "Remove bookmark", + "status.replied_to": "Replied to {name}", "status.reply": "Reply", "status.replyAll": "Reply to thread", "status.report": "Report @{name}", @@ -523,9 +585,8 @@ "status.show_more": "Show more", "status.show_more_all": "Show more for all", "status.show_original": "Show original", - "status.show_thread": "Show thread", "status.translate": "Translate", - "status.translated_from": "Translated from {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Not available", "status.unmute_conversation": "Unmute conversation", "status.unpin": "Unpin from profile", @@ -538,7 +599,6 @@ "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", diff --git a/app/javascript/mastodon/locales/ko.json b/app/javascript/mastodon/locales/ko.json index 394bce9f0..af818e304 100644 --- a/app/javascript/mastodon/locales/ko.json +++ b/app/javascript/mastodon/locales/ko.json @@ -1,4 +1,17 @@ { + "about.blocks": "제한된 서버들", + "about.contact": "연락처:", + "about.domain_blocks.comment": "사유", + "about.domain_blocks.domain": "도메인", + "about.domain_blocks.preamble": "마스토돈은 일반적으로 연합우주에 있는 어떤 서버의 사용자와도 게시물을 보고 응답을 할 수 있도록 허용합니다. 다음 항목들은 특정한 서버에 대해 만들어 진 예외사항입니다.", + "about.domain_blocks.severity": "심각도", + "about.domain_blocks.silenced.explanation": "명시적으로 찾아보거나 팔로우를 하기 전까지는, 이 서버에 있는 프로필이나 게시물 등을 일반적으로 볼 수 없습니다.", + "about.domain_blocks.silenced.title": "제한됨", + "about.domain_blocks.suspended.explanation": "이 서버의 어떤 데이터도 처리되거나, 저장 되거나 공유되지 않고, 이 서버의 어떤 유저와도 상호작용 하거나 대화할 수 없습니다.", + "about.domain_blocks.suspended.title": "정지됨", + "about.not_available": "이 정보는 이 서버에서 사용할 수 없습니다.", + "about.powered_by": "{mastodon}에 의해 구동되는 분산화된 소셜 미디어", + "about.rules": "서버 규칙", "account.account_note_header": "노트", "account.add_or_remove_from_list": "리스트에 추가 혹은 삭제", "account.badges.bot": "봇", @@ -14,6 +27,9 @@ "account.edit_profile": "프로필 편집", "account.enable_notifications": "@{name} 의 게시물 알림 켜기", "account.endorse": "프로필에 추천하기", + "account.featured_tags.last_status_at": "{date}에 마지막으로 게시", + "account.featured_tags.last_status_never": "게시물 없음", + "account.featured_tags.title": "{name} 님의 추천 해시태그", "account.follow": "팔로우", "account.followers": "팔로워", "account.followers.empty": "아직 아무도 이 사용자를 팔로우하고 있지 않습니다.", @@ -23,7 +39,7 @@ "account.follows.empty": "이 사용자는 아직 아무도 팔로우하고 있지 않습니다.", "account.follows_you": "날 팔로우합니다", "account.hide_reblogs": "@{name}의 부스트를 숨기기", - "account.joined": "{date}에 가입함", + "account.joined_short": "Joined", "account.languages": "구독한 언어 변경", "account.link_verified_on": "{date}에 이 링크의 소유권이 확인 됨", "account.locked_info": "이 계정의 프라이버시 설정은 잠금으로 설정되어 있습니다. 계정 소유자가 수동으로 팔로워를 승인합니다.", @@ -63,12 +79,24 @@ "audio.hide": "소리 숨기기", "autosuggest_hashtag.per_week": "주간 {count}회", "boost_modal.combo": "다음엔 {combo}를 눌러서 이 과정을 건너뛸 수 있습니다", - "bundle_column_error.body": "컴포넌트를 불러오는 과정에서 문제가 발생했습니다.", + "bundle_column_error.copy_stacktrace": "에러 리포트 복사하기", + "bundle_column_error.error.body": "요청한 페이지를 렌더링 할 수 없습니다. 저희의 코드에 버그가 있거나, 브라우저 호환성 문제일 수 있습니다.", + "bundle_column_error.error.title": "으악, 안돼!", + "bundle_column_error.network.body": "이 페이지를 불러오는 중 오류가 발생했습니다. 일시적으로 서버와의 연결이 불안정한 문제일 수도 있습니다.", + "bundle_column_error.network.title": "네트워크 오류", "bundle_column_error.retry": "다시 시도", - "bundle_column_error.title": "네트워크 에러", + "bundle_column_error.return": "홈으로 돌아가기", + "bundle_column_error.routing.body": "요청하신 페이지를 찾을 수 없습니다. 주소창에 적힌 URL이 확실히 맞나요?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "닫기", "bundle_modal_error.message": "컴포넌트를 불러오는 과정에서 문제가 발생했습니다.", "bundle_modal_error.retry": "다시 시도", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "정보", "column.blocks": "차단한 사용자", "column.bookmarks": "보관함", "column.community": "로컬 타임라인", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "차단하고 신고하기", "confirmations.block.confirm": "차단", "confirmations.block.message": "정말로 {name}를 차단하시겠습니까?", + "confirmations.cancel_follow_request.confirm": "요청 무시", + "confirmations.cancel_follow_request.message": "정말 {name}님에 대한 팔로우 요청을 취소하시겠습니까?", "confirmations.delete.confirm": "삭제", "confirmations.delete.message": "정말로 이 게시물을 삭제하시겠습니까?", "confirmations.delete_list.confirm": "삭제", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "읽은 상태로 표시", "conversation.open": "대화 보기", "conversation.with": "{names} 님과", + "copypaste.copied": "복사됨", + "copypaste.copy": "복사", "directory.federated": "알려진 연합우주로부터", "directory.local": "{domain}에서만", "directory.new_arrivals": "새로운 사람들", "directory.recently_active": "최근 활동", + "dismissable_banner.community_timeline": "여기 있는 것들은 계정이 {domain}에 있는 사람들의 최근 공개 게시물들입니다.", + "dismissable_banner.dismiss": "지우기", + "dismissable_banner.explore_links": "이 뉴스들은 이 서버와 분산화된 네트워크의 다른 서버에서 사람들이 지금 많이 이야기 하고 있는 것입니다.", + "dismissable_banner.explore_statuses": "이 게시물들은 이 서버와 분산화된 네트워크의 다른 서버에서 지금 인기를 끌고 있는 것들입니다.", + "dismissable_banner.explore_tags": "이 해시태그들은 이 서버와 분산화된 네트워크의 다른 서버에서 사람들의 인기를 끌고 있는 것들입니다.", + "dismissable_banner.public_timeline": "이 게시물들은 이 서버와 이 서버가 알고있는 분산화된 네트워크의 다른 서버에서 사람들이 게시한 최근 공개 게시물들입니다.", "embed.instructions": "아래의 코드를 복사하여 대화를 원하는 곳으로 공유하세요.", "embed.preview": "다음과 같이 표시됩니다:", "emoji_button.activity": "활동", @@ -221,14 +259,14 @@ "follow_request.reject": "거부", "follow_requests.unlocked_explanation": "당신의 계정이 잠기지 않았다고 할 지라도, {domain}의 스탭은 당신이 이 계정들로부터의 팔로우 요청을 수동으로 확인하길 원한다고 생각했습니다.", "generic.saved": "저장됨", - "getting_started.developers": "개발자", - "getting_started.directory": "프로필 책자", + "getting_started.directory": "디렉토리", "getting_started.documentation": "문서", + "getting_started.free_software_notice": "마스토돈은 자유 오픈소스 소프트웨어입니다. {repository}에서 소스코드를 열람할 수 있으며, 기여를 하거나 이슈를 작성할 수도 있습니다.", "getting_started.heading": "시작", "getting_started.invite": "초대", - "getting_started.open_source_notice": "Mastodon은 오픈 소스 소프트웨어입니다. 누구나 GitHub({github})에서 개발에 참여하거나, 문제를 보고할 수 있습니다.", "getting_started.privacy_policy": "개인정보 처리방침", "getting_started.security": "계정 설정", + "getting_started.what_is_mastodon": "마스토돈에 대하여", "hashtag.column_header.tag_mode.all": "그리고 {additional}", "hashtag.column_header.tag_mode.any": "또는 {additional}", "hashtag.column_header.tag_mode.none": "{additional}를 제외하고", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "답글 표시", "home.hide_announcements": "공지사항 숨기기", "home.show_announcements": "공지사항 보기", + "interaction_modal.description.favourite": "마스토돈 계정을 통해, 게시물을 마음에 들어 하는 것으로 작성자에게 호의를 표하고 나중에 보기 위해 저장할 수 있습니다.", + "interaction_modal.description.follow": "마스토돈 계정을 통해, {name} 님을 팔로우 하고 그의 게시물을 홈 피드에서 받아 볼 수 있습니다.", + "interaction_modal.description.reblog": "마스토돈 계정을 통해, 이 게시물을 부스트 하고 자신의 팔로워들에게 공유할 수 있습니다.", + "interaction_modal.description.reply": "마스토돈 계정을 통해, 이 게시물에 응답할 수 있습니다.", + "interaction_modal.on_another_server": "다른 서버에", + "interaction_modal.on_this_server": "이 서버에서", + "interaction_modal.other_server_instructions": "단순하게 이 URL을 당신이 좋아하는 앱이나 로그인 한 웹 인터페이스의 검색창에 복사/붙여넣기 하세요.", + "interaction_modal.preamble": "마스토돈은 분산화 되어 있기 때문에, 이곳에 계정이 없더라도 다른 곳에서 운영되는 마스토돈 서버나 호환 되는 플랫폼에 있는 계정을 사용할 수 있습니다.", + "interaction_modal.title.favourite": "{name} 님의 게시물을 마음에 들어하기", + "interaction_modal.title.follow": "{name} 님을 팔로우", + "interaction_modal.title.reblog": "{name} 님의 게시물을 부스트", + "interaction_modal.title.reply": "{name} 님의 게시물에 답글", "intervals.full.days": "{number} 일", "intervals.full.hours": "{number} 시간", "intervals.full.minutes": "{number} 분", @@ -310,7 +360,8 @@ "mute_modal.duration": "기간", "mute_modal.hide_notifications": "이 사용자로부터의 알림을 숨기시겠습니까?", "mute_modal.indefinite": "무기한", - "navigation_bar.apps": "모바일 앱", + "navigation_bar.about": "정보", + "navigation_bar.apps": "앱 다운로드하기", "navigation_bar.blocks": "차단한 사용자", "navigation_bar.bookmarks": "보관함", "navigation_bar.community_timeline": "로컬 타임라인", @@ -324,7 +375,7 @@ "navigation_bar.filters": "뮤트한 단어", "navigation_bar.follow_requests": "팔로우 요청", "navigation_bar.follows_and_followers": "팔로우와 팔로워", - "navigation_bar.info": "이 서버에 대해서", + "navigation_bar.info": "정보", "navigation_bar.keyboard_shortcuts": "단축키", "navigation_bar.lists": "리스트", "navigation_bar.logout": "로그아웃", @@ -333,7 +384,9 @@ "navigation_bar.pins": "고정된 게시물", "navigation_bar.preferences": "사용자 설정", "navigation_bar.public_timeline": "연합 타임라인", + "navigation_bar.search": "Search", "navigation_bar.security": "보안", + "not_signed_in_indicator.not_signed_in": "이 정보에 접근하려면 로그인을 해야 합니다.", "notification.admin.report": "{name} 님이 {target}를 신고했습니다", "notification.admin.sign_up": "{name} 님이 가입했습니다", "notification.favourite": "{name} 님이 당신의 게시물을 마음에 들어합니다", @@ -401,6 +454,8 @@ "privacy.public.short": "공개", "privacy.unlisted.long": "모두가 볼 수 있지만, 발견하기 기능에서는 제외됨", "privacy.unlisted.short": "타임라인에 비표시", + "privacy_policy.last_updated": "{date}에 마지막으로 업데이트됨", + "privacy_policy.title": "개인정보 정책", "refresh": "새로고침", "regeneration_indicator.label": "불러오는 중…", "regeneration_indicator.sublabel": "당신의 홈 피드가 준비되는 중입니다!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "이 마스토돈 서버에선 게시물의 내용을 통한 검색이 활성화 되어 있지 않습니다.", "search_results.title": "{q}에 대한 검색", "search_results.total": "{count, number}건의 결과", + "server_banner.about_active_users": "30일 동안 이 서버를 사용한 사람들 (월간 활성 이용자)", + "server_banner.active_users": "활성 사용자", + "server_banner.administered_by": "관리자:", + "server_banner.introduction": "{domain}은 마스토돈으로 운영되는 탈중앙화 된 소셜 네트워크의 일부입니다.", + "server_banner.learn_more": "더 알아보기", + "server_banner.server_stats": "서버 통계:", "sign_in_banner.create_account": "계정 생성", "sign_in_banner.sign_in": "로그인", "sign_in_banner.text": "로그인을 통해 프로필이나 해시태그를 팔로우하거나 마음에 들어하거나 공유하고 답글을 달 수 있습니다, 혹은 다른 서버에 있는 본인의 계정을 통해 참여할 수도 있습니다.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "아직 아무도 이 게시물을 부스트하지 않았습니다. 부스트 한 사람들이 여기에 표시 됩니다.", "status.redraft": "지우고 다시 쓰기", "status.remove_bookmark": "보관한 게시물 삭제", + "status.replied_to": "Replied to {name}", "status.reply": "답장", "status.replyAll": "글타래에 답장", "status.report": "신고", @@ -523,9 +585,8 @@ "status.show_more": "더 보기", "status.show_more_all": "모두 펼치기", "status.show_original": "원본 보기", - "status.show_thread": "글타래 보기", "status.translate": "번역", - "status.translated_from": "{lang}에서 번역됨", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "사용할 수 없음", "status.unmute_conversation": "이 대화의 뮤트 해제하기", "status.unpin": "고정 해제", @@ -538,7 +599,6 @@ "tabs_bar.home": "홈", "tabs_bar.local_timeline": "로컬", "tabs_bar.notifications": "알림", - "tabs_bar.search": "검색", "time_remaining.days": "{number} 일 남음", "time_remaining.hours": "{number} 시간 남음", "time_remaining.minutes": "{number} 분 남음", diff --git a/app/javascript/mastodon/locales/ku.json b/app/javascript/mastodon/locales/ku.json index bdfafa980..246b46407 100644 --- a/app/javascript/mastodon/locales/ku.json +++ b/app/javascript/mastodon/locales/ku.json @@ -1,4 +1,17 @@ { + "about.blocks": "Rajekarên çavdêrkirî", + "about.contact": "Têkilî:", + "about.domain_blocks.comment": "Sedem", + "about.domain_blocks.domain": "Navper", + "about.domain_blocks.preamble": "Mastodon bi gelemperî dihêle ku tu naverokê bibînî û bi bikarhênerên ji rajekareke din a li fendiverse re têkilî dayne. Ev awaretyên ku li ser vê rajekara taybetî hatine çêkirin ev in.", + "about.domain_blocks.severity": "Asta girîngiyê", + "about.domain_blocks.silenced.explanation": "Heye ku tu bi awayekî vekirî lê negerî an jî bi şopandinê hilnebijêrî, tu yêbi giştî profîl û naverok ji vê rajekarê nebînî.", + "about.domain_blocks.silenced.title": "Sînorkirî", + "about.domain_blocks.suspended.explanation": "Dê tu daneya ji van rajekaran neyê berhev kirin, tomarkirin an jî guhertin, ku têkilî an danûstendinek bi bikarhênerên van rajekaran re tune dike.", + "about.domain_blocks.suspended.title": "Hatiye rawestandin", + "about.not_available": "Ev zanyarî li ser vê rajekarê nehatine peydakirin.", + "about.powered_by": "Medyaya civakî ya nenavendî bi hêzdariya {mastodon}", + "about.rules": "Rêbazên rajekar", "account.account_note_header": "Nîşe", "account.add_or_remove_from_list": "Tevlî bike an rake ji rêzokê", "account.badges.bot": "Bot", @@ -7,13 +20,16 @@ "account.block_domain": "{domain} navpar asteng bike", "account.blocked": "Astengkirî", "account.browse_more_on_origin_server": "Li pelên resen bêhtir bigere", - "account.cancel_follow_request": "Daxwaza şopandinê rake", + "account.cancel_follow_request": "Daxwaza şopandinê vekişîne", "account.direct": "Peyamekê bişîne @{name}", "account.disable_notifications": "Êdî min agahdar neke gava @{name} diweşîne", "account.domain_blocked": "Navper hate astengkirin", "account.edit_profile": "Profîlê serrast bike", "account.enable_notifications": "Min agahdar bike gava @{name} diweşîne", "account.endorse": "Taybetiyên li ser profîl", + "account.featured_tags.last_status_at": "Şandiya dawî di {date} de", + "account.featured_tags.last_status_never": "Şandî tune ne", + "account.featured_tags.title": "{name}'s hashtagên taybet", "account.follow": "Bişopîne", "account.followers": "Şopîner", "account.followers.empty": "Kesekî hin ev bikarhêner neşopandiye.", @@ -23,7 +39,7 @@ "account.follows.empty": "Ev bikarhêner hin kesekî heya niha neşopandiye.", "account.follows_you": "Te dişopîne", "account.hide_reblogs": "Bilindkirinên ji @{name} veşêre", - "account.joined": "Di {date} de tevlî bû", + "account.joined_short": "Joined", "account.languages": "Zimanên beşdarbûyî biguherîne", "account.link_verified_on": "Xwedaniya li vê girêdanê di {date} de hatiye kontrolkirin", "account.locked_info": "Rewşa vê ajimêrê wek kilîtkirî hatiye sazkirin. Xwediyê ajimêrê, bi destan dinirxîne şopandinê dinirxîne.", @@ -63,12 +79,24 @@ "audio.hide": "Dengê veşêre", "autosuggest_hashtag.per_week": "Her hefte {count}", "boost_modal.combo": "Ji bo derbas bî carekî din de pêlê {combo} bike", - "bundle_column_error.body": "Di dema barkirina vê hêmanê de tiştek çewt çê bû.", + "bundle_column_error.copy_stacktrace": "Rapora çewtiyê jê bigire", + "bundle_column_error.error.body": "Rûpela xwestî nehate pêşkêşkirin. Dibe ku ew ji ber şaşetiyeke koda me, an jî pirsgirêkeke lihevhatina gerokê be.", + "bundle_column_error.error.title": "Ax, na!", + "bundle_column_error.network.body": "Di dema hewldana barkirina vê rûpelê de çewtiyek derket. Ev dibe ku ji ber pirsgirêkeke demkî ya girêdana înternetê te be an jî ev rajekar be.", + "bundle_column_error.network.title": "Çewtiya torê", "bundle_column_error.retry": "Dîsa biceribîne", - "bundle_column_error.title": "Çewtiya torê", + "bundle_column_error.return": "Vegere rûpela sereke", + "bundle_column_error.routing.body": "Rûpela xwestî nehate dîtin. Tu bawerî ku girêdana di kodika lêgerînê de rast e?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Bigire", "bundle_modal_error.message": "Di dema barkirina vê hêmanê de tiştek çewt çê bû.", "bundle_modal_error.retry": "Dîsa bicerbîne", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "Derbar", "column.blocks": "Bikarhênerên astengkirî", "column.bookmarks": "Şûnpel", "column.community": "Demnameya herêmî", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "Asteng bike & ragihîne", "confirmations.block.confirm": "Asteng bike", "confirmations.block.message": "Ma tu dixwazî ku {name} asteng bikî?", + "confirmations.cancel_follow_request.confirm": "Daxwazê vekişîne", + "confirmations.cancel_follow_request.message": "Tu dixwazî daxwaza xwe ya şopandina {name} vekşînî?", "confirmations.delete.confirm": "Jê bibe", "confirmations.delete.message": "Ma tu dixwazî vê şandiyê jê bibî?", "confirmations.delete_list.confirm": "Jê bibe", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Wekî xwendî nîşan bide", "conversation.open": "Axaftinê nîşan bide", "conversation.with": "Bi {names} re", + "copypaste.copied": "Hate jêgirtin", + "copypaste.copy": "Jê bigire", "directory.federated": "Ji fediversên naskirî", "directory.local": "Tenê ji {domain}", "directory.new_arrivals": "Kesên ku nû hatine", "directory.recently_active": "Di demên dawî de çalak", + "dismissable_banner.community_timeline": "Ev şandiyên giştî yên herî dawî ji kesên ku ajimêrê wan ji aliyê {domain} ve têne pêşkêşkirin.", + "dismissable_banner.dismiss": "Paşguh bike", + "dismissable_banner.explore_links": "Ev çîrokên nûçeyan niha li ser vê û rajekarên din ên tora nenavendî ji aliyê mirovan ve têne axaftin.", + "dismissable_banner.explore_statuses": "Ev şandiyên ji vê û rajekarên din ên di tora nenavendî de niha li ser vê rajekarê balê dikşînin.", + "dismissable_banner.explore_tags": "Ev hashtagên ji vê û rajekarên din ên di tora nenavendî de niha li ser vê rajekarê balê dikşînin.", + "dismissable_banner.public_timeline": "Ev şandiyên gelemperî herî dawî yên mirovên li ser vê û rajekarên din ên tora nenavendî ne ku ev rajekar pê tê nasîn.", "embed.instructions": "Bi jêgirtina koda jêrîn vê şandiyê li ser malpera xwe bicîh bikin.", "embed.preview": "Wa ye wê wusa xuya bike:", "emoji_button.activity": "Çalakî", @@ -221,14 +259,14 @@ "follow_request.reject": "Nepejirîne", "follow_requests.unlocked_explanation": "Tevlî ku ajimêra te ne kilît kiriye, karmendên {domain} digotin qey tu dixwazî ku pêşdîtina daxwazên şopandinê bi destan bike.", "generic.saved": "Tomarkirî", - "getting_started.developers": "Pêşdebir", - "getting_started.directory": "Rêgeha profîlê", + "getting_started.directory": "Rêgeh", "getting_started.documentation": "Pelbend", + "getting_started.free_software_notice": "Mastodon belaş, nermalava çavkaniya vekirî ye. Tu dikarî koda çavkaniyê bibînî, beşdar bibî an pirsgirêkan ragihînî li ser {repository}.", "getting_started.heading": "Destpêkirin", "getting_started.invite": "Kesan vexwîne", - "getting_started.open_source_notice": "Mastodon nermalava çavkaniya vekirî ye. Tu dikarî pirsgirêkan li ser GitHub-ê ragihînî di {github} de an jî dikarî tevkariyê bikî.", "getting_started.privacy_policy": "Politîka taybetiyê", "getting_started.security": "Sazkariyên ajimêr", + "getting_started.what_is_mastodon": "Derbarê Mastodon", "hashtag.column_header.tag_mode.all": "û {additional}", "hashtag.column_header.tag_mode.any": "an {additional}", "hashtag.column_header.tag_mode.none": "bêyî {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Bersivan nîşan bide", "home.hide_announcements": "Reklaman veşêre", "home.show_announcements": "Reklaman nîşan bide", + "interaction_modal.description.favourite": "Bi ajimêrek li ser Mastodon re, tu dikarî vê şandiyê bijarte bikî da ku nivîskar bizanibe ku tu wê/î re rêzê digirî û wê ji bo paşê biparêzî.", + "interaction_modal.description.follow": "Bi ajimêrekê li ser Mastodon, tu dikarî {name} bişopînî da ku şandiyan li ser rojeva rûpela xwe bi dest bixe.", + "interaction_modal.description.reblog": "Bi ajimêrekê li ser Mastodon, tu dikarî vê şandiyê bilind bikî da ku wê bi şopînerên xwe re parve bikî.", + "interaction_modal.description.reply": "Bi ajimêrekê li ser Mastodon, tu dikarî bersiva vê şandiyê bidî.", + "interaction_modal.on_another_server": "Li ser rajekareke cuda", + "interaction_modal.on_this_server": "Li ser ev rajekar", + "interaction_modal.other_server_instructions": "Tenê vê girêdanê jê bigire û pêve bike di darika lêgerînê ya sepana xwe ya bijarte an navrûya bikarhêneriyê tevnê ya ku tu tê de ye.", + "interaction_modal.preamble": "Ji ber ku Mastodon nenavendî ye, tu dikarî ajimêrê xwe ya heyî ku ji aliyê rajekarek din a Mastodon an platformek lihevhatî ve hatî pêşkêşkirin bi kar bînî ku ajimêrê te li ser vê yekê tune be.", + "interaction_modal.title.favourite": "Şandiyê {name} bijarte bike", + "interaction_modal.title.follow": "{name} bişopîne", + "interaction_modal.title.reblog": "Şandiyê {name} bilind bike", + "interaction_modal.title.reply": "Bersivê bide şandiyê {name}", "intervals.full.days": "{number, plural, one {# roj} other {# roj}}", "intervals.full.hours": "{number, plural, one {# demjimêr} other {# demjimêr}}\n \n", "intervals.full.minutes": "{number, plural, one {# xulek} other {# xulek}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Dem", "mute_modal.hide_notifications": "Agahdariyan ji ev bikarhêner veşêre?", "mute_modal.indefinite": "Nediyar", - "navigation_bar.apps": "Sepana mobayil", + "navigation_bar.about": "Derbar", + "navigation_bar.apps": "Sepanê bi dest bixe", "navigation_bar.blocks": "Bikarhênerên astengkirî", "navigation_bar.bookmarks": "Şûnpel", "navigation_bar.community_timeline": "Demnameya herêmî", @@ -324,7 +375,7 @@ "navigation_bar.filters": "Peyvên bêdengkirî", "navigation_bar.follow_requests": "Daxwazên şopandinê", "navigation_bar.follows_and_followers": "Şopandin û şopîner", - "navigation_bar.info": "Derbarê vî rajekarî", + "navigation_bar.info": "Derbar", "navigation_bar.keyboard_shortcuts": "Kurte bişkok", "navigation_bar.lists": "Rêzok", "navigation_bar.logout": "Derkeve", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Şandiya derzîkirî", "navigation_bar.preferences": "Sazkarî", "navigation_bar.public_timeline": "Demnameya giştî", + "navigation_bar.search": "Search", "navigation_bar.security": "Ewlehî", + "not_signed_in_indicator.not_signed_in": "Divê tu têketinê bikî da ku tu bigihîjî vê çavkaniyê.", "notification.admin.report": "{name} hate ragihandin {target}", "notification.admin.sign_up": "{name} tomar bû", "notification.favourite": "{name} şandiya te hez kir", @@ -401,6 +454,8 @@ "privacy.public.short": "Gelemperî", "privacy.unlisted.long": "Ji bo hemûyan xuyabar e, lê ji taybetmendiyên vekolînê veqetiya ye", "privacy.unlisted.short": "Nerêzok", + "privacy_policy.last_updated": "Rojanekirina dawî {date}", + "privacy_policy.title": "Politîka taybetiyê", "refresh": "Nû bike", "regeneration_indicator.label": "Tê barkirin…", "regeneration_indicator.sublabel": "Naveroka rûpela sereke ya te tê amedekirin!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "Di vê rajekara Mastodonê da lêgerîna şandîyên li gorî naveroka wan ne çalak e.", "search_results.title": "Li {q} bigere", "search_results.total": "{count, number} {count, plural, one {encam} other {encam}}", + "server_banner.about_active_users": "Kesên ku di van 30 rojên dawî de vê rajekarê bi kar tînin (Bikarhênerên Çalak ên Mehane)", + "server_banner.active_users": "bikarhênerên çalak", + "server_banner.administered_by": "Tê bi rêvebirin ji aliyê:", + "server_banner.introduction": "{domain} beşek ji tora civakî ya nenavendî ye bi hêzdariya {mastodon}.", + "server_banner.learn_more": "Bêtir fêr bibe", + "server_banner.server_stats": "Amarên rajekar:", "sign_in_banner.create_account": "Ajimêr biafirîne", "sign_in_banner.sign_in": "Têkeve", "sign_in_banner.text": "Têkeve ji bo şopandina profîlan an hashtagan, bijarte, parvekirin û bersivdana şandiyan, an ji ajimêrê xwe li ser rajekarek cuda têkilî deyine.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "Kesekî hin ev şandî bilind nekiriye. Gava kesek bilind bike, ew ên li vir werin xuyakirin.", "status.redraft": "Jê bibe & ji nû ve reşnivîs bike", "status.remove_bookmark": "Şûnpêlê jê rake", + "status.replied_to": "Replied to {name}", "status.reply": "Bersivê bide", "status.replyAll": "Mijarê bibersivîne", "status.report": "@{name} ragihîne", @@ -523,9 +585,8 @@ "status.show_more": "Bêtir nîşan bide", "status.show_more_all": "Bêtir nîşan bide bo hemûyan", "status.show_original": "A resen nîşan bide", - "status.show_thread": "Mijarê nîşan bide", "status.translate": "Wergerîne", - "status.translated_from": "Ji {lang} hate wergerandin", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Tune ye", "status.unmute_conversation": "Axaftinê bêdeng neke", "status.unpin": "Şandiya derzîkirî ji profîlê rake", @@ -538,7 +599,6 @@ "tabs_bar.home": "Rûpela sereke", "tabs_bar.local_timeline": "Herêmî", "tabs_bar.notifications": "Agahdarî", - "tabs_bar.search": "Bigere", "time_remaining.days": "{number, plural, one {# roj} other {# roj}} maye", "time_remaining.hours": "{number, plural, one {# demjimêr} other {# demjimêr}} maye", "time_remaining.minutes": "{number, plural, one {# xulek} other {# xulek}} maye", diff --git a/app/javascript/mastodon/locales/kw.json b/app/javascript/mastodon/locales/kw.json index c7abf77f1..8ace3826a 100644 --- a/app/javascript/mastodon/locales/kw.json +++ b/app/javascript/mastodon/locales/kw.json @@ -1,4 +1,17 @@ { + "about.blocks": "Moderated servers", + "about.contact": "Contact:", + "about.domain_blocks.comment": "Reason", + "about.domain_blocks.domain": "Domain", + "about.domain_blocks.preamble": "Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.", + "about.domain_blocks.severity": "Severity", + "about.domain_blocks.silenced.explanation": "You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.", + "about.domain_blocks.silenced.title": "Limited", + "about.domain_blocks.suspended.explanation": "No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.", + "about.domain_blocks.suspended.title": "Suspended", + "about.not_available": "This information has not been made available on this server.", + "about.powered_by": "Decentralized social media powered by {mastodon}", + "about.rules": "Server rules", "account.account_note_header": "Noten", "account.add_or_remove_from_list": "Keworra po Dilea a rolyow", "account.badges.bot": "Bot", @@ -7,13 +20,16 @@ "account.block_domain": "Lettya gorfarth {domain}", "account.blocked": "Lettys", "account.browse_more_on_origin_server": "Peuri moy y'n profil derowel", - "account.cancel_follow_request": "Dilea govyn holya", + "account.cancel_follow_request": "Withdraw follow request", "account.direct": "Messach didro dhe @{name}", "account.disable_notifications": "Hedhi ow gwarnya pan wra @{name} postya", "account.domain_blocked": "Gorfarth lettys", "account.edit_profile": "Golegi profil", "account.enable_notifications": "Gwra ow gwarnya pan wra @{name} postya", "account.endorse": "Diskwedhes yn profil", + "account.featured_tags.last_status_at": "Last post on {date}", + "account.featured_tags.last_status_never": "No posts", + "account.featured_tags.title": "{name}'s featured hashtags", "account.follow": "Holya", "account.followers": "Holyoryon", "account.followers.empty": "Ny wra nagonan holya'n devnydhyer ma hwath.", @@ -23,7 +39,7 @@ "account.follows.empty": "Ny wra'n devnydhyer ma holya nagonan hwath.", "account.follows_you": "Y'th hol", "account.hide_reblogs": "Kudha kenerthow a @{name}", - "account.joined": "Joined {date}", + "account.joined_short": "Joined", "account.languages": "Change subscribed languages", "account.link_verified_on": "Perghenogeth an kolm ma a veu checkys dhe {date}", "account.locked_info": "Studh privetter an akont ma yw alhwedhys. An perghen a wra dasweles dre leuv piw a yll aga holya.", @@ -63,12 +79,24 @@ "audio.hide": "Hide audio", "autosuggest_hashtag.per_week": "{count} an seythen", "boost_modal.combo": "Hwi a yll gwaska {combo} dhe woheles hemma an nessa tro", - "bundle_column_error.body": "Neppyth eth yn kamm ow karga'n elven ma.", + "bundle_column_error.copy_stacktrace": "Copy error report", + "bundle_column_error.error.body": "The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.", + "bundle_column_error.error.title": "Oh, no!", + "bundle_column_error.network.body": "There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.", + "bundle_column_error.network.title": "Network error", "bundle_column_error.retry": "Assayewgh arta", - "bundle_column_error.title": "Gwall ròsweyth", + "bundle_column_error.return": "Go back home", + "bundle_column_error.routing.body": "The requested page could not be found. Are you sure the URL in the address bar is correct?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Degea", "bundle_modal_error.message": "Neppyth eth yn kamm ow karga'n elven ma.", "bundle_modal_error.retry": "Assayewgh arta", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "About", "column.blocks": "Devnydhyoryon lettys", "column.bookmarks": "Folennosow", "column.community": "Amserlin leel", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "Lettya & Reportya", "confirmations.block.confirm": "Lettya", "confirmations.block.message": "Owgh hwi sur a vynnes lettya {name}?", + "confirmations.cancel_follow_request.confirm": "Withdraw request", + "confirmations.cancel_follow_request.message": "Are you sure you want to withdraw your request to follow {name}?", "confirmations.delete.confirm": "Dilea", "confirmations.delete.message": "Owgh hwi sur a vynnes dilea'n post ma?", "confirmations.delete_list.confirm": "Dilea", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Merkya vel redys", "conversation.open": "Gweles kesklapp", "conversation.with": "Gans {names}", + "copypaste.copied": "Copied", + "copypaste.copy": "Copy", "directory.federated": "A geffrysvys godhvedhys", "directory.local": "A {domain} hepken", "directory.new_arrivals": "Devedhyansow nowydh", "directory.recently_active": "Bew a-gynsow", + "dismissable_banner.community_timeline": "These are the most recent public posts from people whose accounts are hosted by {domain}.", + "dismissable_banner.dismiss": "Dismiss", + "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", + "dismissable_banner.explore_statuses": "These posts from this and other servers in the decentralized network are gaining traction on this server right now.", + "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", + "dismissable_banner.public_timeline": "These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.", "embed.instructions": "Stagewgh an post ma a-berth yn agas gwiasva ow tasskrifa'n kod a-wòles.", "embed.preview": "Ottomma fatel hevel:", "emoji_button.activity": "Gwrians", @@ -221,14 +259,14 @@ "follow_request.reject": "Denagha", "follow_requests.unlocked_explanation": "Kyn na vo agas akont alhwedhys, an meni {domain} a wrug tybi y fia da genowgh dasweles govynnow holya a'n akontys ma dre leuv.", "generic.saved": "Gwithys", - "getting_started.developers": "Displegyoryon", - "getting_started.directory": "Menegva profilys", + "getting_started.directory": "Directory", "getting_started.documentation": "Dogvenva", + "getting_started.free_software_notice": "Mastodon is free, open source software. You can view the source code, contribute or report issues at {repository}.", "getting_started.heading": "Dhe dhalleth", "getting_started.invite": "Gelwel tus", - "getting_started.open_source_notice": "Mastodon yw medhelweyth a fenten ygor. Hwi a yll kevri po reportya kudynnow dre GitHub dhe {github}.", "getting_started.privacy_policy": "Privacy Policy", "getting_started.security": "Dewisyow akont", + "getting_started.what_is_mastodon": "About Mastodon", "hashtag.column_header.tag_mode.all": "ha(g) {additional}", "hashtag.column_header.tag_mode.any": "po {additional}", "hashtag.column_header.tag_mode.none": "heb {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Diskwedhes gorthebow", "home.hide_announcements": "Kudha deklaryansow", "home.show_announcements": "Diskwedhes deklaryansow", + "interaction_modal.description.favourite": "With an account on Mastodon, you can favourite this post to let the author know you appreciate it and save it for later.", + "interaction_modal.description.follow": "With an account on Mastodon, you can follow {name} to receive their posts in your home feed.", + "interaction_modal.description.reblog": "With an account on Mastodon, you can boost this post to share it with your own followers.", + "interaction_modal.description.reply": "With an account on Mastodon, you can respond to this post.", + "interaction_modal.on_another_server": "On a different server", + "interaction_modal.on_this_server": "On this server", + "interaction_modal.other_server_instructions": "Simply copy and paste this URL into the search bar of your favourite app or the web interface where you are signed in.", + "interaction_modal.preamble": "Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one.", + "interaction_modal.title.favourite": "Favourite {name}'s post", + "interaction_modal.title.follow": "Follow {name}", + "interaction_modal.title.reblog": "Boost {name}'s post", + "interaction_modal.title.reply": "Reply to {name}'s post", "intervals.full.days": "{number, plural, one {# jydh} other {# a jydhyow}}", "intervals.full.hours": "{number, plural, one {# our} other {# our}}", "intervals.full.minutes": "{number, plural, one {# vynysen} other {# a vynysennow}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Duryans", "mute_modal.hide_notifications": "Kudha gwarnyansow a'n devnydhyer ma?", "mute_modal.indefinite": "Andhevri", - "navigation_bar.apps": "Appys klapkodh", + "navigation_bar.about": "About", + "navigation_bar.apps": "Get the app", "navigation_bar.blocks": "Devnydhyoryon lettys", "navigation_bar.bookmarks": "Folennosow", "navigation_bar.community_timeline": "Amserlin leel", @@ -324,7 +375,7 @@ "navigation_bar.filters": "Geryow tawhes", "navigation_bar.follow_requests": "Govynnow holya", "navigation_bar.follows_and_followers": "Holyansow ha holyoryon", - "navigation_bar.info": "A-dro dhe'n leuren ma", + "navigation_bar.info": "About", "navigation_bar.keyboard_shortcuts": "Buanellow", "navigation_bar.lists": "Rolyow", "navigation_bar.logout": "Digelmi", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Postow fastys", "navigation_bar.preferences": "Erviransow", "navigation_bar.public_timeline": "Amserlin geffrysys", + "navigation_bar.search": "Search", "navigation_bar.security": "Diogeledh", + "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", "notification.admin.report": "{name} reported {target}", "notification.admin.sign_up": "{name} signed up", "notification.favourite": "{name} a wrug merkya agas post vel drudh", @@ -401,6 +454,8 @@ "privacy.public.short": "Poblek", "privacy.unlisted.long": "Visible for all, but opted-out of discovery features", "privacy.unlisted.short": "Anrelys", + "privacy_policy.last_updated": "Last updated {date}", + "privacy_policy.title": "Privacy Policy", "refresh": "Daskarga", "regeneration_indicator.label": "Ow karga…", "regeneration_indicator.sublabel": "Yma agas lin dre ow pos pareusys!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "Nyns yw hwilas postow der aga dalgh gweythresys y'n leuren Mastodon ma.", "search_results.title": "Search for {q}", "search_results.total": "{count, number} {count, plural, one {sewyans} other {sewyans}}", + "server_banner.about_active_users": "People using this server during the last 30 days (Monthly Active Users)", + "server_banner.active_users": "active users", + "server_banner.administered_by": "Administered by:", + "server_banner.introduction": "{domain} is part of the decentralized social network powered by {mastodon}.", + "server_banner.learn_more": "Learn more", + "server_banner.server_stats": "Server stats:", "sign_in_banner.create_account": "Create account", "sign_in_banner.sign_in": "Sign in", "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "Ny wrug nagonan kenertha'n post ma hwath. Pan wra, hynn a wra omdhiskwedhes omma.", "status.redraft": "Dilea ha daskynskrifa", "status.remove_bookmark": "Dilea folennos", + "status.replied_to": "Replied to {name}", "status.reply": "Gorthebi", "status.replyAll": "Gorthebi orth neusen", "status.report": "Reportya @{name}", @@ -523,9 +585,8 @@ "status.show_more": "Diskwedhes moy", "status.show_more_all": "Diskwedhes moy rag puptra", "status.show_original": "Show original", - "status.show_thread": "Diskwedhes neusen", "status.translate": "Translate", - "status.translated_from": "Translated from {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Ankavadow", "status.unmute_conversation": "Antawhe kesklapp", "status.unpin": "Anfastya a brofil", @@ -538,7 +599,6 @@ "tabs_bar.home": "Tre", "tabs_bar.local_timeline": "Leel", "tabs_bar.notifications": "Gwarnyansow", - "tabs_bar.search": "Hwilas", "time_remaining.days": "{number, plural, one {# jydh} other {# a jydhyow}} gesys", "time_remaining.hours": "{number, plural, one {# our} other {# our}} gesys", "time_remaining.minutes": "{number, plural, one {# vynysen} other {# a vynysennow}} gesys", diff --git a/app/javascript/mastodon/locales/lt.json b/app/javascript/mastodon/locales/lt.json index 0573a9ef5..be61374e9 100644 --- a/app/javascript/mastodon/locales/lt.json +++ b/app/javascript/mastodon/locales/lt.json @@ -1,4 +1,17 @@ { + "about.blocks": "Moderated servers", + "about.contact": "Contact:", + "about.domain_blocks.comment": "Reason", + "about.domain_blocks.domain": "Domain", + "about.domain_blocks.preamble": "Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.", + "about.domain_blocks.severity": "Severity", + "about.domain_blocks.silenced.explanation": "You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.", + "about.domain_blocks.silenced.title": "Limited", + "about.domain_blocks.suspended.explanation": "No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.", + "about.domain_blocks.suspended.title": "Suspended", + "about.not_available": "This information has not been made available on this server.", + "about.powered_by": "Decentralized social media powered by {mastodon}", + "about.rules": "Server rules", "account.account_note_header": "Pastaba", "account.add_or_remove_from_list": "Add or Remove from lists", "account.badges.bot": "Bot", @@ -7,13 +20,16 @@ "account.block_domain": "Hide everything from {domain}", "account.blocked": "Blocked", "account.browse_more_on_origin_server": "Browse more on the original profile", - "account.cancel_follow_request": "Cancel follow request", + "account.cancel_follow_request": "Withdraw follow request", "account.direct": "Direct message @{name}", "account.disable_notifications": "Stop notifying me when @{name} posts", "account.domain_blocked": "Domain hidden", "account.edit_profile": "Edit profile", "account.enable_notifications": "Notify me when @{name} posts", "account.endorse": "Feature on profile", + "account.featured_tags.last_status_at": "Last post on {date}", + "account.featured_tags.last_status_never": "No posts", + "account.featured_tags.title": "{name}'s featured hashtags", "account.follow": "Sekti", "account.followers": "Followers", "account.followers.empty": "No one follows this user yet.", @@ -23,7 +39,7 @@ "account.follows.empty": "This user doesn't follow anyone yet.", "account.follows_you": "Follows you", "account.hide_reblogs": "Hide boosts from @{name}", - "account.joined": "Joined {date}", + "account.joined_short": "Joined", "account.languages": "Change subscribed languages", "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.", @@ -63,12 +79,24 @@ "audio.hide": "Hide audio", "autosuggest_hashtag.per_week": "{count} per week", "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.copy_stacktrace": "Copy error report", + "bundle_column_error.error.body": "The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.", + "bundle_column_error.error.title": "Oh, no!", + "bundle_column_error.network.body": "There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.", + "bundle_column_error.network.title": "Network error", "bundle_column_error.retry": "Try again", - "bundle_column_error.title": "Tinklo klaida", + "bundle_column_error.return": "Go back home", + "bundle_column_error.routing.body": "The requested page could not be found. Are you sure the URL in the address bar is correct?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Close", "bundle_modal_error.message": "Something went wrong while loading this component.", "bundle_modal_error.retry": "Try again", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "About", "column.blocks": "Blocked users", "column.bookmarks": "Bookmarks", "column.community": "Local timeline", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "Block & Report", "confirmations.block.confirm": "Block", "confirmations.block.message": "Are you sure you want to block {name}?", + "confirmations.cancel_follow_request.confirm": "Withdraw request", + "confirmations.cancel_follow_request.message": "Are you sure you want to withdraw your request to follow {name}?", "confirmations.delete.confirm": "Delete", "confirmations.delete.message": "Are you sure you want to delete this status?", "confirmations.delete_list.confirm": "Delete", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Mark as read", "conversation.open": "View conversation", "conversation.with": "With {names}", + "copypaste.copied": "Copied", + "copypaste.copy": "Copy", "directory.federated": "From known fediverse", "directory.local": "From {domain} only", "directory.new_arrivals": "New arrivals", "directory.recently_active": "Recently active", + "dismissable_banner.community_timeline": "These are the most recent public posts from people whose accounts are hosted by {domain}.", + "dismissable_banner.dismiss": "Dismiss", + "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", + "dismissable_banner.explore_statuses": "These posts from this and other servers in the decentralized network are gaining traction on this server right now.", + "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", + "dismissable_banner.public_timeline": "These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.", "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", @@ -221,14 +259,14 @@ "follow_request.reject": "Reject", "follow_requests.unlocked_explanation": "Even though your account is not locked, the {domain} staff thought you might want to review follow requests from these accounts manually.", "generic.saved": "Saved", - "getting_started.developers": "Developers", - "getting_started.directory": "Profile directory", + "getting_started.directory": "Directory", "getting_started.documentation": "Documentation", + "getting_started.free_software_notice": "Mastodon is free, open source software. You can view the source code, contribute or report issues at {repository}.", "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.privacy_policy": "Privacy Policy", "getting_started.security": "Security", + "getting_started.what_is_mastodon": "About Mastodon", "hashtag.column_header.tag_mode.all": "and {additional}", "hashtag.column_header.tag_mode.any": "or {additional}", "hashtag.column_header.tag_mode.none": "without {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Show replies", "home.hide_announcements": "Hide announcements", "home.show_announcements": "Show announcements", + "interaction_modal.description.favourite": "With an account on Mastodon, you can favourite this post to let the author know you appreciate it and save it for later.", + "interaction_modal.description.follow": "With an account on Mastodon, you can follow {name} to receive their posts in your home feed.", + "interaction_modal.description.reblog": "With an account on Mastodon, you can boost this post to share it with your own followers.", + "interaction_modal.description.reply": "With an account on Mastodon, you can respond to this post.", + "interaction_modal.on_another_server": "On a different server", + "interaction_modal.on_this_server": "On this server", + "interaction_modal.other_server_instructions": "Simply copy and paste this URL into the search bar of your favourite app or the web interface where you are signed in.", + "interaction_modal.preamble": "Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one.", + "interaction_modal.title.favourite": "Favourite {name}'s post", + "interaction_modal.title.follow": "Follow {name}", + "interaction_modal.title.reblog": "Boost {name}'s post", + "interaction_modal.title.reply": "Reply to {name}'s post", "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}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Duration", "mute_modal.hide_notifications": "Hide notifications from this user?", "mute_modal.indefinite": "Indefinite", - "navigation_bar.apps": "Mobile apps", + "navigation_bar.about": "About", + "navigation_bar.apps": "Get the app", "navigation_bar.blocks": "Blocked users", "navigation_bar.bookmarks": "Bookmarks", "navigation_bar.community_timeline": "Local timeline", @@ -324,7 +375,7 @@ "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.info": "About", "navigation_bar.keyboard_shortcuts": "Hotkeys", "navigation_bar.lists": "Lists", "navigation_bar.logout": "Logout", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Pinned toots", "navigation_bar.preferences": "Preferences", "navigation_bar.public_timeline": "Federated timeline", + "navigation_bar.search": "Search", "navigation_bar.security": "Security", + "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", "notification.admin.report": "{name} reported {target}", "notification.admin.sign_up": "{name} signed up", "notification.favourite": "{name} favourited your status", @@ -401,6 +454,8 @@ "privacy.public.short": "Public", "privacy.unlisted.long": "Visible for all, but opted-out of discovery features", "privacy.unlisted.short": "Unlisted", + "privacy_policy.last_updated": "Last updated {date}", + "privacy_policy.title": "Privacy Policy", "refresh": "Refresh", "regeneration_indicator.label": "Loading…", "regeneration_indicator.sublabel": "Your home feed is being prepared!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.title": "Search for {q}", "search_results.total": "{count, number} {count, plural, one {result} other {results}}", + "server_banner.about_active_users": "People using this server during the last 30 days (Monthly Active Users)", + "server_banner.active_users": "active users", + "server_banner.administered_by": "Administered by:", + "server_banner.introduction": "{domain} is part of the decentralized social network powered by {mastodon}.", + "server_banner.learn_more": "Learn more", + "server_banner.server_stats": "Server stats:", "sign_in_banner.create_account": "Create account", "sign_in_banner.sign_in": "Sign in", "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "No one has boosted this toot yet. When someone does, they will show up here.", "status.redraft": "Delete & re-draft", "status.remove_bookmark": "Remove bookmark", + "status.replied_to": "Replied to {name}", "status.reply": "Reply", "status.replyAll": "Reply to thread", "status.report": "Report @{name}", @@ -523,9 +585,8 @@ "status.show_more": "Show more", "status.show_more_all": "Show more for all", "status.show_original": "Show original", - "status.show_thread": "Show thread", "status.translate": "Translate", - "status.translated_from": "Translated from {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Not available", "status.unmute_conversation": "Unmute conversation", "status.unpin": "Unpin from profile", @@ -538,7 +599,6 @@ "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", diff --git a/app/javascript/mastodon/locales/lv.json b/app/javascript/mastodon/locales/lv.json index be34219f3..cd1c486cc 100644 --- a/app/javascript/mastodon/locales/lv.json +++ b/app/javascript/mastodon/locales/lv.json @@ -1,4 +1,17 @@ { + "about.blocks": "Moderētie serveri", + "about.contact": "Kontakts:", + "about.domain_blocks.comment": "Iemesls", + "about.domain_blocks.domain": "Domēns", + "about.domain_blocks.preamble": "Mastodon parasti ļauj apskatīt saturu un mijiedarboties ar lietotājiem no jebkura cita federācijas servera. Šie ir izņēmumi, kas veikti šajā konkrētajā serverī.", + "about.domain_blocks.severity": "Nozīmīgums", + "about.domain_blocks.silenced.explanation": "Parasti tu neredzēsi profilus un saturu no šī servera, ja vien tu nepārprotami izvēlēsies to pārskatīt vai sekot.", + "about.domain_blocks.silenced.title": "Ierobežotās", + "about.domain_blocks.suspended.explanation": "Nekādi dati no šī servera netiks apstrādāti, uzglabāti vai apmainīti, padarot neiespējamu mijiedarbību vai saziņu ar lietotājiem no šī servera.", + "about.domain_blocks.suspended.title": "Apturētie", + "about.not_available": "Šī informācija šajā serverī nav bijusi pieejama.", + "about.powered_by": "Decentralizētu sociālo multividi nodrošina {mastodon}", + "about.rules": "Servera noteikumi", "account.account_note_header": "Piezīme", "account.add_or_remove_from_list": "Pievienot vai noņemt no saraksta", "account.badges.bot": "Bots", @@ -7,13 +20,16 @@ "account.block_domain": "Bloķēt domēnu {domain}", "account.blocked": "Bloķēts", "account.browse_more_on_origin_server": "Pārlūkot vairāk sākotnējā profilā", - "account.cancel_follow_request": "Atcelt sekošanas pieprasījumu", + "account.cancel_follow_request": "Atsaukt sekošanas pieprasījumu", "account.direct": "Privāta ziņa @{name}", "account.disable_notifications": "Pārtraukt man paziņot, kad @{name} publicē ierakstu", "account.domain_blocked": "Domēns ir bloķēts", "account.edit_profile": "Rediģēt profilu", "account.enable_notifications": "Man paziņot, kad @{name} publicē ierakstu", "account.endorse": "Izcelts profilā", + "account.featured_tags.last_status_at": "Beidzamā ziņa {date}", + "account.featured_tags.last_status_never": "Publikāciju nav", + "account.featured_tags.title": "{name} piedāvātie haštagi", "account.follow": "Sekot", "account.followers": "Sekotāji", "account.followers.empty": "Šim lietotājam patreiz nav sekotāju.", @@ -23,7 +39,7 @@ "account.follows.empty": "Šis lietotājs pagaidām nevienam neseko.", "account.follows_you": "Seko tev", "account.hide_reblogs": "Paslēpt paceltos ierakstus no lietotāja @{name}", - "account.joined": "Pievienojās {date}", + "account.joined_short": "Joined", "account.languages": "Mainīt abonētās valodas", "account.link_verified_on": "Šīs saites piederība ir pārbaudīta {date}", "account.locked_info": "Šī konta privātuma statuss ir slēgts. Īpašnieks izskatīs, kurš viņam drīkst sekot.", @@ -32,7 +48,7 @@ "account.moved_to": "{name} ir pārcelts uz:", "account.mute": "Apklusināt @{name}", "account.mute_notifications": "Nerādīt paziņojumus no @{name}", - "account.muted": "Apklusināts", + "account.muted": "Noklusināts", "account.posts": "Ziņas", "account.posts_with_replies": "Ziņas un atbildes", "account.report": "Ziņot par lietotāju @{name}", @@ -63,12 +79,24 @@ "audio.hide": "Slēpt audio", "autosuggest_hashtag.per_week": "{count} nedēļā", "boost_modal.combo": "Nospied {combo} lai izlaistu šo nākamreiz", - "bundle_column_error.body": "Kaut kas nogāja greizi ielādējot šo komponenti.", + "bundle_column_error.copy_stacktrace": "Kopēt kļūdu ziņojumu", + "bundle_column_error.error.body": "Pieprasīto lapu nevarēja atveidot. Tas varētu būt saistīts ar kļūdu mūsu kodā vai pārlūkprogrammas saderības problēma.", + "bundle_column_error.error.title": "Ak, nē!", + "bundle_column_error.network.body": "Mēģinot ielādēt šo lapu, radās kļūda. Tas varētu būt saistīts ar īslaicīgu interneta savienojuma vai šī servera problēmu.", + "bundle_column_error.network.title": "Tīkla kļūda", "bundle_column_error.retry": "Mēģini vēlreiz", - "bundle_column_error.title": "Tīkla kļūda", + "bundle_column_error.return": "Atgriezties", + "bundle_column_error.routing.body": "Pieprasīto lapu nevarēja atrast. Vai esi pārliecināts, ka URL adreses joslā ir pareizs?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Aizvērt", "bundle_modal_error.message": "Kaut kas nogāja greizi ielādējot šo komponenti.", "bundle_modal_error.retry": "Mēģini vēlreiz", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "Par", "column.blocks": "Bloķētie lietotāji", "column.bookmarks": "Grāmatzīmes", "column.community": "Vietējā ziņu līnija", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "Bloķēt un ziņot", "confirmations.block.confirm": "Bloķēt", "confirmations.block.message": "Vai tiešām vēlies bloķēt lietotāju {name}?", + "confirmations.cancel_follow_request.confirm": "Atsaukt pieprasījumu", + "confirmations.cancel_follow_request.message": "Vai tiešām vēlies atsaukt pieprasījumu sekot {name}?", "confirmations.delete.confirm": "Dzēst", "confirmations.delete.message": "Vai tiešām vēlaties dzēst šo ziņu?", "confirmations.delete_list.confirm": "Dzēst", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Atzīmēt kā izlasītu", "conversation.open": "Skatīt sarunu", "conversation.with": "Ar {names}", + "copypaste.copied": "Nokopēts", + "copypaste.copy": "Kopēt", "directory.federated": "No pazīstamas federācijas", "directory.local": "Tikai no {domain}", "directory.new_arrivals": "Jaunpienācēji", "directory.recently_active": "Nesen aktīvs", + "dismissable_banner.community_timeline": "Šīs ir jaunākās publiskās ziņas no personām, kuru kontus mitina {domain}.", + "dismissable_banner.dismiss": "Atcelt", + "dismissable_banner.explore_links": "Par šiem jaunumiem šobrīd runā cilvēki šajā un citos decentralizētā tīkla serveros.", + "dismissable_banner.explore_statuses": "Šīs ziņas no šī un citiem decentralizētajā tīkla serveriem šobrīd gūst panākumus šajā serverī.", + "dismissable_banner.explore_tags": "Šie tēmturi šobrīd kļūst arvien populārāki cilvēku vidū šajā un citos decentralizētā tīkla serveros.", + "dismissable_banner.public_timeline": "Šīs ir jaunākās publiskās ziņas no cilvēkiem šajā un citos decentralizētā tīkla serveros, par kuriem šis serveris zina.", "embed.instructions": "Iestrādā šo ziņu savā mājaslapā, kopējot zemāk redzmo kodu.", "embed.preview": "Tas izskatīsies šādi:", "emoji_button.activity": "Aktivitāte", @@ -221,14 +259,14 @@ "follow_request.reject": "Noraidīt", "follow_requests.unlocked_explanation": "Lai gan tavs konts nav bloķēts, {domain} darbinieki iedomājās, ka, iespējams, vēlēsies pārskatīt pieprasījumus no šiem kontiem.", "generic.saved": "Saglabāts", - "getting_started.developers": "Izstrādātāji", - "getting_started.directory": "Profila direktorija", + "getting_started.directory": "Direktorija", "getting_started.documentation": "Dokumentācija", + "getting_started.free_software_notice": "Mastodon ir bezmaksas atvērtā pirmkoda programmatūra. Tu vari apskatīt pirmkodu, sniegt savu ieguldījumu vai ziņot par problēmām vietnē {repository}.", "getting_started.heading": "Darba sākšana", "getting_started.invite": "Uzaicini cilvēkus", - "getting_started.open_source_notice": "Mastodon ir atvērtā koda programmatūra. Tu vari dot savu ieguldījumu vai arī ziņot par problēmām {github}.", "getting_started.privacy_policy": "Privātuma Politika", "getting_started.security": "Konta iestatījumi", + "getting_started.what_is_mastodon": "Par Mastodon", "hashtag.column_header.tag_mode.all": "un {additional}", "hashtag.column_header.tag_mode.any": "vai {additional}", "hashtag.column_header.tag_mode.none": "bez {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Rādīt atbildes", "home.hide_announcements": "Slēpt paziņojumus", "home.show_announcements": "Rādīt paziņojumus", + "interaction_modal.description.favourite": "Izmantojot kontu pakalpojumā Mastodon, vari pievienot šo ziņu izlasei, lai informētu autoru, ka to novērtē un saglabā vēlākai lasīšanai.", + "interaction_modal.description.follow": "Izmantojot Mastodon kontu, tu vari sekot lietotājam {name}, lai saņemtu viņa ziņas savā mājas plūsmā.", + "interaction_modal.description.reblog": "Izmantojot kontu Mastodon, vari atbalstīt šo ziņu, lai kopīgotu to ar saviem sekotājiem.", + "interaction_modal.description.reply": "Izmantojot kontu Mastodon, tu vari atbildēt uz šo ziņu.", + "interaction_modal.on_another_server": "Citā serverī", + "interaction_modal.on_this_server": "Šajā serverī", + "interaction_modal.other_server_instructions": "Vienkārši nokopē un ielīmē šo URL savas iecienītākās lietotnes meklēšanas joslā vai tīmekļa saskarnē, kurā esi pierakstījies.", + "interaction_modal.preamble": "Tā kā Mastodon ir decentralizēts, tu vari izmantot savu esošo kontu, ko mitina cits Mastodon serveris vai saderīga platforma, ja tev nav konta šajā serverī.", + "interaction_modal.title.favourite": "Pievienot {name} ziņu izlasei", + "interaction_modal.title.follow": "Sekot {name}", + "interaction_modal.title.reblog": "Atbalstīt {name} ziņu", + "interaction_modal.title.reply": "Atbildēt uz {name} ziņu", "intervals.full.days": "{number, plural, one {# diena} other {# dienas}}", "intervals.full.hours": "{number, plural, one {# stunda} other {# stundas}}", "intervals.full.minutes": "{number, plural, one {# minūte} other {# minūtes}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Ilgums", "mute_modal.hide_notifications": "Slēpt paziņojumus no šī lietotāja?", "mute_modal.indefinite": "Nenoteikts", - "navigation_bar.apps": "Mobilās lietotnes", + "navigation_bar.about": "Par", + "navigation_bar.apps": "Iegūt lietotni", "navigation_bar.blocks": "Bloķētie lietotāji", "navigation_bar.bookmarks": "Grāmatzīmes", "navigation_bar.community_timeline": "Vietējā ziņu lenta", @@ -324,7 +375,7 @@ "navigation_bar.filters": "Klusināti vārdi", "navigation_bar.follow_requests": "Sekošanas pieprasījumi", "navigation_bar.follows_and_followers": "Man seko un sekotāji", - "navigation_bar.info": "Par šo serveri", + "navigation_bar.info": "Par", "navigation_bar.keyboard_shortcuts": "Ātrie taustiņi", "navigation_bar.lists": "Saraksti", "navigation_bar.logout": "Iziet", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Piespraustās ziņas", "navigation_bar.preferences": "Iestatījumi", "navigation_bar.public_timeline": "Apvienotā ziņu lenta", + "navigation_bar.search": "Search", "navigation_bar.security": "Drošība", + "not_signed_in_indicator.not_signed_in": "Lai piekļūtu šim resursam, tev ir jāpierakstās.", "notification.admin.report": "{name} ziņoja par {target}", "notification.admin.sign_up": "{name} ir pierakstījies", "notification.favourite": "{name} izcēla tavu ziņu", @@ -401,6 +454,8 @@ "privacy.public.short": "Publisks", "privacy.unlisted.long": "Redzama visiem, bet atteicās no atklāšanas funkcijām", "privacy.unlisted.short": "Neminētie", + "privacy_policy.last_updated": "Pēdējo reizi atjaunināta {date}", + "privacy_policy.title": "Privātuma Politika", "refresh": "Atsvaidzināt", "regeneration_indicator.label": "Ielādē…", "regeneration_indicator.sublabel": "Tiek gatavota tava plūsma!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "Šajā Mastodon serverī nav iespējota ziņu meklēšana pēc to satura.", "search_results.title": "Meklēt {q}", "search_results.total": "{count, number} {count, plural, one {rezultāts} other {rezultāti}}", + "server_banner.about_active_users": "Cilvēki, kas izmantojuši šo serveri pēdējo 30 dienu laikā (aktīvie lietotāji mēnesī)", + "server_banner.active_users": "aktīvie lietotāji", + "server_banner.administered_by": "Administrē:", + "server_banner.introduction": "{domain} ir daļa no decentralizētā sociālā tīkla, ko nodrošina {mastodon}.", + "server_banner.learn_more": "Uzzināt vairāk", + "server_banner.server_stats": "Servera statistika:", "sign_in_banner.create_account": "Izveidot kontu", "sign_in_banner.sign_in": "Pierakstīties", "sign_in_banner.text": "Pieraksties, lai sekotu profiliem vai atsaucēm, pievienotu izlasei, kopīgotu ziņas un atbildētu uz tām vai mijiedarbotos no sava konta citā serverī.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "Neviens šo ziņojumu vel nav paaugstinājis. Kad būs, tie parādīsies šeit.", "status.redraft": "Dzēst un pārrakstīt", "status.remove_bookmark": "Noņemt grāmatzīmi", + "status.replied_to": "Replied to {name}", "status.reply": "Atbildēt", "status.replyAll": "Atbildēt uz tematu", "status.report": "Ziņot par @{name}", @@ -523,9 +585,8 @@ "status.show_more": "Rādīt vairāk", "status.show_more_all": "Rādīt vairāk visiem", "status.show_original": "Rādīt oriģinālu", - "status.show_thread": "Rādīt tematu", "status.translate": "Tulkot", - "status.translated_from": "Tulkot no {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Nav pieejams", "status.unmute_conversation": "Atvērt sarunu", "status.unpin": "Noņemt no profila", @@ -538,7 +599,6 @@ "tabs_bar.home": "Sākums", "tabs_bar.local_timeline": "Vietējā", "tabs_bar.notifications": "Paziņojumi", - "tabs_bar.search": "Meklēt", "time_remaining.days": "Atlikušas {number, plural, one {# diena} other {# dienas}}", "time_remaining.hours": "Atlikušas {number, plural, one {# stunda} other {# stundas}}", "time_remaining.minutes": "Atlikušas {number, plural, one {# minūte} other {# minūtes}}", diff --git a/app/javascript/mastodon/locales/mk.json b/app/javascript/mastodon/locales/mk.json index 02a8e20a5..2cbe5a50e 100644 --- a/app/javascript/mastodon/locales/mk.json +++ b/app/javascript/mastodon/locales/mk.json @@ -1,4 +1,17 @@ { + "about.blocks": "Moderated servers", + "about.contact": "Contact:", + "about.domain_blocks.comment": "Reason", + "about.domain_blocks.domain": "Domain", + "about.domain_blocks.preamble": "Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.", + "about.domain_blocks.severity": "Severity", + "about.domain_blocks.silenced.explanation": "You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.", + "about.domain_blocks.silenced.title": "Limited", + "about.domain_blocks.suspended.explanation": "No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.", + "about.domain_blocks.suspended.title": "Suspended", + "about.not_available": "This information has not been made available on this server.", + "about.powered_by": "Decentralized social media powered by {mastodon}", + "about.rules": "Server rules", "account.account_note_header": "Note", "account.add_or_remove_from_list": "Додади или одстрани од листа", "account.badges.bot": "Бот", @@ -7,13 +20,16 @@ "account.block_domain": "Сокријај се од {domain}", "account.blocked": "Блокиран", "account.browse_more_on_origin_server": "Browse more on the original profile", - "account.cancel_follow_request": "Одкажи барање за следење", + "account.cancel_follow_request": "Withdraw follow request", "account.direct": "Директна порана @{name}", "account.disable_notifications": "Stop notifying me when @{name} posts", "account.domain_blocked": "Скриен домен", "account.edit_profile": "Измени профил", "account.enable_notifications": "Notify me when @{name} posts", "account.endorse": "Карактеристики на профилот", + "account.featured_tags.last_status_at": "Last post on {date}", + "account.featured_tags.last_status_never": "No posts", + "account.featured_tags.title": "{name}'s featured hashtags", "account.follow": "Следи", "account.followers": "Следбеници", "account.followers.empty": "Никој не го следи овој корисник сеуште.", @@ -23,7 +39,7 @@ "account.follows.empty": "Корисникот не следи никој сеуште.", "account.follows_you": "Те следи тебе", "account.hide_reblogs": "Сокриј буст од @{name}", - "account.joined": "Joined {date}", + "account.joined_short": "Joined", "account.languages": "Change subscribed languages", "account.link_verified_on": "Сопстевноста на овај линк беше проверен на {date}", "account.locked_info": "Статусот на приватност на овај корисник е сетиран како заклучен. Корисникот одлучува кој можи да го следи него.", @@ -63,12 +79,24 @@ "audio.hide": "Hide audio", "autosuggest_hashtag.per_week": "{count} неделно", "boost_modal.combo": "Кликни {combo} за да го прескокниш ова нареден пат", - "bundle_column_error.body": "Се случи проблем при вчитувањето.", + "bundle_column_error.copy_stacktrace": "Copy error report", + "bundle_column_error.error.body": "The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.", + "bundle_column_error.error.title": "Oh, no!", + "bundle_column_error.network.body": "There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.", + "bundle_column_error.network.title": "Network error", "bundle_column_error.retry": "Обидете се повторно", - "bundle_column_error.title": "Мрежна грешка", + "bundle_column_error.return": "Go back home", + "bundle_column_error.routing.body": "The requested page could not be found. Are you sure the URL in the address bar is correct?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Затвори", "bundle_modal_error.message": "Настана грешка при прикажувањето на оваа веб-страница.", "bundle_modal_error.retry": "Обидете се повторно", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "About", "column.blocks": "Блокирани корисници", "column.bookmarks": "Bookmarks", "column.community": "Локална временска зона", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "Блокирај и Пријави", "confirmations.block.confirm": "Блокирај", "confirmations.block.message": "Сигурни сте дека дека го блокирате {name}?", + "confirmations.cancel_follow_request.confirm": "Withdraw request", + "confirmations.cancel_follow_request.message": "Are you sure you want to withdraw your request to follow {name}?", "confirmations.delete.confirm": "Избриши", "confirmations.delete.message": "Сигурни сте дека го бришите статусот?", "confirmations.delete_list.confirm": "Избриши", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Означете како прочитано", "conversation.open": "Прегледај разговор", "conversation.with": "Со {names}", + "copypaste.copied": "Copied", + "copypaste.copy": "Copy", "directory.federated": "Од познати fediverse", "directory.local": "Само од {domain}", "directory.new_arrivals": "New arrivals", "directory.recently_active": "Recently active", + "dismissable_banner.community_timeline": "These are the most recent public posts from people whose accounts are hosted by {domain}.", + "dismissable_banner.dismiss": "Dismiss", + "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", + "dismissable_banner.explore_statuses": "These posts from this and other servers in the decentralized network are gaining traction on this server right now.", + "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", + "dismissable_banner.public_timeline": "These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.", "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": "Активност", @@ -221,14 +259,14 @@ "follow_request.reject": "Одбиј", "follow_requests.unlocked_explanation": "Even though your account is not locked, the {domain} staff thought you might want to review follow requests from these accounts manually.", "generic.saved": "Saved", - "getting_started.developers": "Програмери", - "getting_started.directory": "Профил директориум", + "getting_started.directory": "Directory", "getting_started.documentation": "Документација", + "getting_started.free_software_notice": "Mastodon is free, open source software. You can view the source code, contribute or report issues at {repository}.", "getting_started.heading": "Започни", "getting_started.invite": "Покани луѓе", - "getting_started.open_source_notice": "Мастодон е софтвер со отворен код. Можете да придонесувате или пријавувате проблеми во GitHub на {github}.", "getting_started.privacy_policy": "Privacy Policy", "getting_started.security": "Поставки на сметката", + "getting_started.what_is_mastodon": "About Mastodon", "hashtag.column_header.tag_mode.all": "и {additional}", "hashtag.column_header.tag_mode.any": "или {additional}", "hashtag.column_header.tag_mode.none": "без {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Прикажи одговори", "home.hide_announcements": "Hide announcements", "home.show_announcements": "Show announcements", + "interaction_modal.description.favourite": "With an account on Mastodon, you can favourite this post to let the author know you appreciate it and save it for later.", + "interaction_modal.description.follow": "With an account on Mastodon, you can follow {name} to receive their posts in your home feed.", + "interaction_modal.description.reblog": "With an account on Mastodon, you can boost this post to share it with your own followers.", + "interaction_modal.description.reply": "With an account on Mastodon, you can respond to this post.", + "interaction_modal.on_another_server": "On a different server", + "interaction_modal.on_this_server": "On this server", + "interaction_modal.other_server_instructions": "Simply copy and paste this URL into the search bar of your favourite app or the web interface where you are signed in.", + "interaction_modal.preamble": "Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one.", + "interaction_modal.title.favourite": "Favourite {name}'s post", + "interaction_modal.title.follow": "Follow {name}", + "interaction_modal.title.reblog": "Boost {name}'s post", + "interaction_modal.title.reply": "Reply to {name}'s post", "intervals.full.days": "{number, plural, one {# ден} other {# дена}}", "intervals.full.hours": "{number, plural, one {# час} other {# часа}}", "intervals.full.minutes": "{number, plural, one {# минута} other {# минути}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Duration", "mute_modal.hide_notifications": "Hide notifications from this user?", "mute_modal.indefinite": "Indefinite", - "navigation_bar.apps": "Mobile apps", + "navigation_bar.about": "About", + "navigation_bar.apps": "Get the app", "navigation_bar.blocks": "Blocked users", "navigation_bar.bookmarks": "Bookmarks", "navigation_bar.community_timeline": "Local timeline", @@ -324,7 +375,7 @@ "navigation_bar.filters": "Замолќени зборови", "navigation_bar.follow_requests": "Следи покани", "navigation_bar.follows_and_followers": "Следења и следбеници", - "navigation_bar.info": "За овој сервер", + "navigation_bar.info": "About", "navigation_bar.keyboard_shortcuts": "Кратенки", "navigation_bar.lists": "Листи", "navigation_bar.logout": "Одјави се", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Pinned toots", "navigation_bar.preferences": "Preferences", "navigation_bar.public_timeline": "Федеративен времеплов", + "navigation_bar.search": "Search", "navigation_bar.security": "Безбедност", + "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", "notification.admin.report": "{name} reported {target}", "notification.admin.sign_up": "{name} signed up", "notification.favourite": "{name} favourited your status", @@ -401,6 +454,8 @@ "privacy.public.short": "Јавно", "privacy.unlisted.long": "Visible for all, but opted-out of discovery features", "privacy.unlisted.short": "Необјавено", + "privacy_policy.last_updated": "Last updated {date}", + "privacy_policy.title": "Privacy Policy", "refresh": "Освежи", "regeneration_indicator.label": "Вчитување…", "regeneration_indicator.sublabel": "Вашиот новости се подготвуваат!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.title": "Search for {q}", "search_results.total": "{count, number} {count, plural, one {result} other {results}}", + "server_banner.about_active_users": "People using this server during the last 30 days (Monthly Active Users)", + "server_banner.active_users": "active users", + "server_banner.administered_by": "Administered by:", + "server_banner.introduction": "{domain} is part of the decentralized social network powered by {mastodon}.", + "server_banner.learn_more": "Learn more", + "server_banner.server_stats": "Server stats:", "sign_in_banner.create_account": "Create account", "sign_in_banner.sign_in": "Sign in", "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "No one has boosted this toot yet. When someone does, they will show up here.", "status.redraft": "Delete & re-draft", "status.remove_bookmark": "Remove bookmark", + "status.replied_to": "Replied to {name}", "status.reply": "Reply", "status.replyAll": "Reply to thread", "status.report": "Report @{name}", @@ -523,9 +585,8 @@ "status.show_more": "Show more", "status.show_more_all": "Show more for all", "status.show_original": "Show original", - "status.show_thread": "Show thread", "status.translate": "Translate", - "status.translated_from": "Translated from {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Not available", "status.unmute_conversation": "Unmute conversation", "status.unpin": "Unpin from profile", @@ -538,7 +599,6 @@ "tabs_bar.home": "Дома", "tabs_bar.local_timeline": "Локално", "tabs_bar.notifications": "Нотификации", - "tabs_bar.search": "Барај", "time_remaining.days": "{number, plural, one {# ден} other {# дена}} {number, plural, one {остана} other {останаа}}", "time_remaining.hours": "{number, plural, one {# час} other {# часа}} {number, plural, one {остана} other {останаа}}", "time_remaining.minutes": "{number, plural, one {# минута} other {# минути}} {number, plural, one {остана} other {останаа}}", diff --git a/app/javascript/mastodon/locales/ml.json b/app/javascript/mastodon/locales/ml.json index 9707275a6..b7f92c715 100644 --- a/app/javascript/mastodon/locales/ml.json +++ b/app/javascript/mastodon/locales/ml.json @@ -1,4 +1,17 @@ { + "about.blocks": "Moderated servers", + "about.contact": "Contact:", + "about.domain_blocks.comment": "Reason", + "about.domain_blocks.domain": "Domain", + "about.domain_blocks.preamble": "Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.", + "about.domain_blocks.severity": "Severity", + "about.domain_blocks.silenced.explanation": "You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.", + "about.domain_blocks.silenced.title": "Limited", + "about.domain_blocks.suspended.explanation": "No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.", + "about.domain_blocks.suspended.title": "Suspended", + "about.not_available": "This information has not been made available on this server.", + "about.powered_by": "Decentralized social media powered by {mastodon}", + "about.rules": "Server rules", "account.account_note_header": "കുറിപ്പ്", "account.add_or_remove_from_list": "പട്ടികയിൽ ചേർക്കുകയോ/മാറ്റുകയോ ചെയ്യുക", "account.badges.bot": "റോബോട്ട്", @@ -7,13 +20,16 @@ "account.block_domain": "{domain} എന്ന മേഖല തടയുക", "account.blocked": "തടഞ്ഞു", "account.browse_more_on_origin_server": "യഥാർത്ഥ പ്രൊഫൈലിലേക്ക് പോവുക", - "account.cancel_follow_request": "പിന്തുടരാനുള്ള അപേക്ഷ നിരസിക്കുക", + "account.cancel_follow_request": "Withdraw follow request", "account.direct": "@{name}-ന്(ക്ക്) നേരിട്ട് സന്ദേശം അയക്കുക", "account.disable_notifications": "@{name} പോസ്റ്റുചെയ്യുന്നത് എന്നെ അറിയിക്കുന്നത് നിർത്തുക", "account.domain_blocked": "മേഖല തടഞ്ഞു", "account.edit_profile": "പ്രൊഫൈൽ തിരുത്തുക", "account.enable_notifications": "@{name} പോസ്റ്റ് ചെയ്യുമ്പോൾ എന്നെ അറിയിക്കുക", "account.endorse": "പ്രൊഫൈലിൽ പ്രകടമാക്കുക", + "account.featured_tags.last_status_at": "Last post on {date}", + "account.featured_tags.last_status_never": "No posts", + "account.featured_tags.title": "{name}'s featured hashtags", "account.follow": "പിന്തുടരുക", "account.followers": "പിന്തുടരുന്നവർ", "account.followers.empty": "ഈ ഉപയോക്താവിനെ ആരും ഇതുവരെ പിന്തുടരുന്നില്ല.", @@ -23,7 +39,7 @@ "account.follows.empty": "ഈ ഉപയോക്താവ് ആരേയും ഇതുവരെ പിന്തുടരുന്നില്ല.", "account.follows_you": "നിങ്ങളെ പിന്തുടരുന്നു", "account.hide_reblogs": "@{name} ബൂസ്റ്റ് ചെയ്തവ മറയ്കുക", - "account.joined": "{date} ൽ ചേർന്നു", + "account.joined_short": "Joined", "account.languages": "Change subscribed languages", "account.link_verified_on": "ഈ ലിങ്കിന്റെ ഉടമസ്തത {date} ഇൽ ഉറപ്പാക്കിയതാണ്", "account.locked_info": "ഈ അംഗത്വത്തിന്റെ സ്വകാര്യതാ നിലപാട് അനുസരിച്ച് പിന്തുടരുന്നവരെ തിരഞ്ഞെടുക്കാനുള്ള വിവേചനാധികാരം ഉടമസ്ഥനിൽ നിഷിപ്തമായിരിക്കുന്നു.", @@ -63,12 +79,24 @@ "audio.hide": "Hide audio", "autosuggest_hashtag.per_week": "ആഴ്ച തോറും {count}", "boost_modal.combo": "അടുത്ത തവണ ഇത് ഒഴിവാക്കുവാൻ {combo} ഞെക്കാവുന്നതാണ്", - "bundle_column_error.body": "ഈ ഘടകം പ്രദശിപ്പിക്കുമ്പോൾ എന്തോ കുഴപ്പം സംഭവിച്ചു.", + "bundle_column_error.copy_stacktrace": "Copy error report", + "bundle_column_error.error.body": "The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.", + "bundle_column_error.error.title": "Oh, no!", + "bundle_column_error.network.body": "There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.", + "bundle_column_error.network.title": "Network error", "bundle_column_error.retry": "വീണ്ടും ശ്രമിക്കുക", - "bundle_column_error.title": "ശൃംഖലയിലെ പിഴവ്", + "bundle_column_error.return": "Go back home", + "bundle_column_error.routing.body": "The requested page could not be found. Are you sure the URL in the address bar is correct?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "അടയ്ക്കുക", "bundle_modal_error.message": "ഈ വെബ്പേജ് പ്രദർശിപ്പിക്കുമ്പോൾ എന്തോ കുഴപ്പം സംഭവിച്ചു.", "bundle_modal_error.retry": "വീണ്ടും ശ്രമിക്കുക", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "About", "column.blocks": "തടയപ്പെട്ട ഉപയോക്താക്കൾ", "column.bookmarks": "ബുക്ക്മാർക്കുകൾ", "column.community": "പ്രാദേശികമായ സമയരേഖ", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "തടയുകയും റിപ്പോർട്ടും ചെയ്യുക", "confirmations.block.confirm": "തടയുക", "confirmations.block.message": "{name} തടയാൻ നിങ്ങൾ ആഗ്രഹിക്കുന്നുണ്ടോ?", + "confirmations.cancel_follow_request.confirm": "Withdraw request", + "confirmations.cancel_follow_request.message": "Are you sure you want to withdraw your request to follow {name}?", "confirmations.delete.confirm": "മായ്ക്കുക", "confirmations.delete.message": "ഈ ടൂട്ട് ഇല്ലാതാക്കണം എന്ന് നിങ്ങൾക്ക് ഉറപ്പാണോ?", "confirmations.delete_list.confirm": "മായ്ക്കുക", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "വായിച്ചതായി അടയാളപ്പെടുത്തുക", "conversation.open": "സംഭാഷണം കാണുക", "conversation.with": "{names} കൂടെ", + "copypaste.copied": "Copied", + "copypaste.copy": "Copy", "directory.federated": "അറിയപ്പെടുന്ന ഫെഡിവേഴ്സ്ൽ നിന്ന്", "directory.local": "{domain} ൽ നിന്ന് മാത്രം", "directory.new_arrivals": "പുതിയ വരവുകൾ", "directory.recently_active": "അടുത്തിടെയായി സജീവമായ", + "dismissable_banner.community_timeline": "These are the most recent public posts from people whose accounts are hosted by {domain}.", + "dismissable_banner.dismiss": "Dismiss", + "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", + "dismissable_banner.explore_statuses": "These posts from this and other servers in the decentralized network are gaining traction on this server right now.", + "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", + "dismissable_banner.public_timeline": "These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.", "embed.instructions": "ചുവടെയുള്ള കോഡ് പകർത്തിക്കൊണ്ട് നിങ്ങളുടെ വെബ്സൈറ്റിൽ ഈ ടൂട്ട് ഉൾച്ചേർക്കുക.", "embed.preview": "ഇത് ഇങ്ങനെ കാണപ്പെടും:", "emoji_button.activity": "പ്രവര്ത്തനം", @@ -221,14 +259,14 @@ "follow_request.reject": "നിരസിക്കുക", "follow_requests.unlocked_explanation": "Even though your account is not locked, the {domain} staff thought you might want to review follow requests from these accounts manually.", "generic.saved": "സംരക്ഷിച്ചു", - "getting_started.developers": "വികസിപ്പിക്കുന്നവർ", - "getting_started.directory": "പ്രൊഫൈൽ ഡയറക്ടറി", + "getting_started.directory": "Directory", "getting_started.documentation": "രേഖാ സമാഹരണം", + "getting_started.free_software_notice": "Mastodon is free, open source software. You can view the source code, contribute or report issues at {repository}.", "getting_started.heading": "തുടക്കം കുറിക്കുക", "getting_started.invite": "ആളുകളെ ക്ഷണിക്കുക", - "getting_started.open_source_notice": "മാസ്റ്റഡോൺ ഒരു സ്വതന്ത്ര സോഫ്ട്വെയർ ആണ്. നിങ്ങൾക്ക് {github} GitHub ൽ സംഭാവന ചെയ്യുകയോ പ്രശ്നങ്ങൾ അറിയിക്കുകയോ ചെയ്യാം.", "getting_started.privacy_policy": "Privacy Policy", "getting_started.security": "അംഗത്വ ക്രമീകരണങ്ങൾ", + "getting_started.what_is_mastodon": "About Mastodon", "hashtag.column_header.tag_mode.all": "{additional} ഉം കൂടെ", "hashtag.column_header.tag_mode.any": "അല്ലെങ്കിൽ {additional}", "hashtag.column_header.tag_mode.none": "{additional} ഇല്ലാതെ", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "മറുപടികൾ കാണിക്കുക", "home.hide_announcements": "പ്രഖ്യാപനങ്ങൾ മറയ്ക്കുക", "home.show_announcements": "പ്രഖ്യാപനങ്ങൾ കാണിക്കുക", + "interaction_modal.description.favourite": "With an account on Mastodon, you can favourite this post to let the author know you appreciate it and save it for later.", + "interaction_modal.description.follow": "With an account on Mastodon, you can follow {name} to receive their posts in your home feed.", + "interaction_modal.description.reblog": "With an account on Mastodon, you can boost this post to share it with your own followers.", + "interaction_modal.description.reply": "With an account on Mastodon, you can respond to this post.", + "interaction_modal.on_another_server": "On a different server", + "interaction_modal.on_this_server": "On this server", + "interaction_modal.other_server_instructions": "Simply copy and paste this URL into the search bar of your favourite app or the web interface where you are signed in.", + "interaction_modal.preamble": "Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one.", + "interaction_modal.title.favourite": "Favourite {name}'s post", + "interaction_modal.title.follow": "Follow {name}", + "interaction_modal.title.reblog": "Boost {name}'s post", + "interaction_modal.title.reply": "Reply to {name}'s post", "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}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "കാലാവധി", "mute_modal.hide_notifications": "Hide notifications from this user?", "mute_modal.indefinite": "അനിശ്ചിതകാല", - "navigation_bar.apps": "മൊബൈൽ ആപ്പുകൾ", + "navigation_bar.about": "About", + "navigation_bar.apps": "Get the app", "navigation_bar.blocks": "തടയപ്പെട്ട ഉപയോക്താക്കൾ", "navigation_bar.bookmarks": "ബുക്ക്മാർക്കുകൾ", "navigation_bar.community_timeline": "പ്രാദേശിക സമയരേഖ", @@ -324,7 +375,7 @@ "navigation_bar.filters": "Muted words", "navigation_bar.follow_requests": "പിന്തുടരാനുള്ള അഭ്യർത്ഥനകൾ", "navigation_bar.follows_and_followers": "Follows and followers", - "navigation_bar.info": "ഈ സെർവറിനെക്കുറിച്ച്", + "navigation_bar.info": "About", "navigation_bar.keyboard_shortcuts": "Hotkeys", "navigation_bar.lists": "ലിസ്റ്റുകൾ", "navigation_bar.logout": "ലോഗൗട്ട്", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Pinned toots", "navigation_bar.preferences": "ക്രമീകരണങ്ങൾ", "navigation_bar.public_timeline": "Federated timeline", + "navigation_bar.search": "Search", "navigation_bar.security": "സുരക്ഷ", + "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", "notification.admin.report": "{name} reported {target}", "notification.admin.sign_up": "{name} signed up", "notification.favourite": "{name} favourited your status", @@ -401,6 +454,8 @@ "privacy.public.short": "എല്ലാവര്ക്കും", "privacy.unlisted.long": "Visible for all, but opted-out of discovery features", "privacy.unlisted.short": "Unlisted", + "privacy_policy.last_updated": "Last updated {date}", + "privacy_policy.title": "Privacy Policy", "refresh": "പുതുക്കുക", "regeneration_indicator.label": "ലഭ്യമാക്കുന്നു…", "regeneration_indicator.sublabel": "നിങ്ങളുടെ ഹോം ഫീഡ് തയാറാക്കുന്നു!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.title": "Search for {q}", "search_results.total": "{count, number} {count, plural, one {result} other {results}}", + "server_banner.about_active_users": "People using this server during the last 30 days (Monthly Active Users)", + "server_banner.active_users": "active users", + "server_banner.administered_by": "Administered by:", + "server_banner.introduction": "{domain} is part of the decentralized social network powered by {mastodon}.", + "server_banner.learn_more": "Learn more", + "server_banner.server_stats": "Server stats:", "sign_in_banner.create_account": "Create account", "sign_in_banner.sign_in": "Sign in", "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "No one has boosted this toot yet. When someone does, they will show up here.", "status.redraft": "ഇല്ലാതാക്കുക & വീണ്ടും ഡ്രാഫ്റ്റ് ചെയ്യുക", "status.remove_bookmark": "ബുക്ക്മാർക്ക് നീക്കംചെയ്യുക", + "status.replied_to": "Replied to {name}", "status.reply": "മറുപടി", "status.replyAll": "Reply to thread", "status.report": "@{name}--നെ റിപ്പോർട്ട് ചെയ്യുക", @@ -523,9 +585,8 @@ "status.show_more": "കൂടുതകൽ കാണിക്കുക", "status.show_more_all": "എല്ലാവർക്കുമായി കൂടുതൽ കാണിക്കുക", "status.show_original": "Show original", - "status.show_thread": "ത്രെഡ് കാണിക്കുക", "status.translate": "Translate", - "status.translated_from": "Translated from {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "ലഭ്യമല്ല", "status.unmute_conversation": "Unmute conversation", "status.unpin": "Unpin from profile", @@ -538,7 +599,6 @@ "tabs_bar.home": "ഹോം", "tabs_bar.local_timeline": "പ്രാദേശികം", "tabs_bar.notifications": "അറിയിപ്പുകൾ", - "tabs_bar.search": "തിരയുക", "time_remaining.days": "{number, plural, one {# ദിവസം} other {# ദിവസങ്ങൾ}} ബാക്കി", "time_remaining.hours": "{number, plural, one {# മണിക്കൂർ} other {# മണിക്കൂർ}} ശേഷിക്കുന്നു", "time_remaining.minutes": "{number, plural, one {# minute} other {# minutes}} left", diff --git a/app/javascript/mastodon/locales/mr.json b/app/javascript/mastodon/locales/mr.json index f3fa37c02..ea2345ecf 100644 --- a/app/javascript/mastodon/locales/mr.json +++ b/app/javascript/mastodon/locales/mr.json @@ -1,4 +1,17 @@ { + "about.blocks": "Moderated servers", + "about.contact": "Contact:", + "about.domain_blocks.comment": "Reason", + "about.domain_blocks.domain": "Domain", + "about.domain_blocks.preamble": "Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.", + "about.domain_blocks.severity": "Severity", + "about.domain_blocks.silenced.explanation": "You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.", + "about.domain_blocks.silenced.title": "Limited", + "about.domain_blocks.suspended.explanation": "No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.", + "about.domain_blocks.suspended.title": "Suspended", + "about.not_available": "This information has not been made available on this server.", + "about.powered_by": "Decentralized social media powered by {mastodon}", + "about.rules": "Server rules", "account.account_note_header": "Note", "account.add_or_remove_from_list": "यादीत घाला किंवा यादीतून काढून टाका", "account.badges.bot": "स्वयंचलित खाते", @@ -7,13 +20,16 @@ "account.block_domain": "{domain} पासून सर्व लपवा", "account.blocked": "ब्लॉक केले आहे", "account.browse_more_on_origin_server": "Browse more on the original profile", - "account.cancel_follow_request": "अनुयायी होण्याची विनंती रद्द करा", + "account.cancel_follow_request": "Withdraw follow request", "account.direct": "थेट संदेश @{name}", "account.disable_notifications": "Stop notifying me when @{name} posts", "account.domain_blocked": "Domain hidden", "account.edit_profile": "प्रोफाइल एडिट करा", "account.enable_notifications": "Notify me when @{name} posts", "account.endorse": "Feature on profile", + "account.featured_tags.last_status_at": "Last post on {date}", + "account.featured_tags.last_status_never": "No posts", + "account.featured_tags.title": "{name}'s featured hashtags", "account.follow": "अनुयायी व्हा", "account.followers": "अनुयायी", "account.followers.empty": "ह्या वापरकर्त्याचा आतापर्यंत कोणी अनुयायी नाही.", @@ -23,7 +39,7 @@ "account.follows.empty": "हा वापरकर्ता अजूनपर्यंत कोणाचा अनुयायी नाही.", "account.follows_you": "तुमचा अनुयायी आहे", "account.hide_reblogs": "@{name} पासून सर्व बूस्ट लपवा", - "account.joined": "Joined {date}", + "account.joined_short": "Joined", "account.languages": "Change subscribed languages", "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.", @@ -63,12 +79,24 @@ "audio.hide": "Hide audio", "autosuggest_hashtag.per_week": "{count} प्रतिसप्ताह", "boost_modal.combo": "You can press {combo} to skip this next time", - "bundle_column_error.body": "हा घटक लोड करतांना काहीतरी चुकले आहे.", + "bundle_column_error.copy_stacktrace": "Copy error report", + "bundle_column_error.error.body": "The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.", + "bundle_column_error.error.title": "Oh, no!", + "bundle_column_error.network.body": "There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.", + "bundle_column_error.network.title": "Network error", "bundle_column_error.retry": "पुन्हा प्रयत्न करा", - "bundle_column_error.title": "नेटवर्क त्रुटी", + "bundle_column_error.return": "Go back home", + "bundle_column_error.routing.body": "The requested page could not be found. Are you sure the URL in the address bar is correct?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "बंद करा", "bundle_modal_error.message": "हा घटक लोड करतांना काहीतरी चुकले आहे.", "bundle_modal_error.retry": "पुन्हा प्रयत्न करा", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "About", "column.blocks": "ब्लॉक केलेले खातेधारक", "column.bookmarks": "Bookmarks", "column.community": "Local timeline", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "Block & Report", "confirmations.block.confirm": "Block", "confirmations.block.message": "Are you sure you want to block {name}?", + "confirmations.cancel_follow_request.confirm": "Withdraw request", + "confirmations.cancel_follow_request.message": "Are you sure you want to withdraw your request to follow {name}?", "confirmations.delete.confirm": "हटवा", "confirmations.delete.message": "हे स्टेटस तुम्हाला नक्की हटवायचंय?", "confirmations.delete_list.confirm": "हटवा", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Mark as read", "conversation.open": "View conversation", "conversation.with": "With {names}", + "copypaste.copied": "Copied", + "copypaste.copy": "Copy", "directory.federated": "From known fediverse", "directory.local": "From {domain} only", "directory.new_arrivals": "New arrivals", "directory.recently_active": "Recently active", + "dismissable_banner.community_timeline": "These are the most recent public posts from people whose accounts are hosted by {domain}.", + "dismissable_banner.dismiss": "Dismiss", + "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", + "dismissable_banner.explore_statuses": "These posts from this and other servers in the decentralized network are gaining traction on this server right now.", + "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", + "dismissable_banner.public_timeline": "These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.", "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", @@ -221,14 +259,14 @@ "follow_request.reject": "Reject", "follow_requests.unlocked_explanation": "Even though your account is not locked, the {domain} staff thought you might want to review follow requests from these accounts manually.", "generic.saved": "Saved", - "getting_started.developers": "Developers", - "getting_started.directory": "Profile directory", + "getting_started.directory": "Directory", "getting_started.documentation": "Documentation", + "getting_started.free_software_notice": "Mastodon is free, open source software. You can view the source code, contribute or report issues at {repository}.", "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.privacy_policy": "Privacy Policy", "getting_started.security": "Security", + "getting_started.what_is_mastodon": "About Mastodon", "hashtag.column_header.tag_mode.all": "and {additional}", "hashtag.column_header.tag_mode.any": "or {additional}", "hashtag.column_header.tag_mode.none": "without {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Show replies", "home.hide_announcements": "Hide announcements", "home.show_announcements": "Show announcements", + "interaction_modal.description.favourite": "With an account on Mastodon, you can favourite this post to let the author know you appreciate it and save it for later.", + "interaction_modal.description.follow": "With an account on Mastodon, you can follow {name} to receive their posts in your home feed.", + "interaction_modal.description.reblog": "With an account on Mastodon, you can boost this post to share it with your own followers.", + "interaction_modal.description.reply": "With an account on Mastodon, you can respond to this post.", + "interaction_modal.on_another_server": "On a different server", + "interaction_modal.on_this_server": "On this server", + "interaction_modal.other_server_instructions": "Simply copy and paste this URL into the search bar of your favourite app or the web interface where you are signed in.", + "interaction_modal.preamble": "Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one.", + "interaction_modal.title.favourite": "Favourite {name}'s post", + "interaction_modal.title.follow": "Follow {name}", + "interaction_modal.title.reblog": "Boost {name}'s post", + "interaction_modal.title.reply": "Reply to {name}'s post", "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}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Duration", "mute_modal.hide_notifications": "Hide notifications from this user?", "mute_modal.indefinite": "Indefinite", - "navigation_bar.apps": "Mobile apps", + "navigation_bar.about": "About", + "navigation_bar.apps": "Get the app", "navigation_bar.blocks": "Blocked users", "navigation_bar.bookmarks": "Bookmarks", "navigation_bar.community_timeline": "Local timeline", @@ -324,7 +375,7 @@ "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.info": "About", "navigation_bar.keyboard_shortcuts": "Hotkeys", "navigation_bar.lists": "Lists", "navigation_bar.logout": "Logout", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Pinned toots", "navigation_bar.preferences": "Preferences", "navigation_bar.public_timeline": "Federated timeline", + "navigation_bar.search": "Search", "navigation_bar.security": "Security", + "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", "notification.admin.report": "{name} reported {target}", "notification.admin.sign_up": "{name} signed up", "notification.favourite": "{name} favourited your status", @@ -401,6 +454,8 @@ "privacy.public.short": "Public", "privacy.unlisted.long": "Visible for all, but opted-out of discovery features", "privacy.unlisted.short": "Unlisted", + "privacy_policy.last_updated": "Last updated {date}", + "privacy_policy.title": "Privacy Policy", "refresh": "Refresh", "regeneration_indicator.label": "Loading…", "regeneration_indicator.sublabel": "Your home feed is being prepared!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.title": "Search for {q}", "search_results.total": "{count, number} {count, plural, one {result} other {results}}", + "server_banner.about_active_users": "People using this server during the last 30 days (Monthly Active Users)", + "server_banner.active_users": "active users", + "server_banner.administered_by": "Administered by:", + "server_banner.introduction": "{domain} is part of the decentralized social network powered by {mastodon}.", + "server_banner.learn_more": "Learn more", + "server_banner.server_stats": "Server stats:", "sign_in_banner.create_account": "Create account", "sign_in_banner.sign_in": "Sign in", "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "No one has boosted this toot yet. When someone does, they will show up here.", "status.redraft": "Delete & re-draft", "status.remove_bookmark": "Remove bookmark", + "status.replied_to": "Replied to {name}", "status.reply": "Reply", "status.replyAll": "Reply to thread", "status.report": "Report @{name}", @@ -523,9 +585,8 @@ "status.show_more": "Show more", "status.show_more_all": "Show more for all", "status.show_original": "Show original", - "status.show_thread": "Show thread", "status.translate": "Translate", - "status.translated_from": "Translated from {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Not available", "status.unmute_conversation": "Unmute conversation", "status.unpin": "Unpin from profile", @@ -538,7 +599,6 @@ "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", diff --git a/app/javascript/mastodon/locales/ms.json b/app/javascript/mastodon/locales/ms.json index 9972e8bb8..de0c50480 100644 --- a/app/javascript/mastodon/locales/ms.json +++ b/app/javascript/mastodon/locales/ms.json @@ -1,4 +1,17 @@ { + "about.blocks": "Moderated servers", + "about.contact": "Contact:", + "about.domain_blocks.comment": "Reason", + "about.domain_blocks.domain": "Domain", + "about.domain_blocks.preamble": "Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.", + "about.domain_blocks.severity": "Severity", + "about.domain_blocks.silenced.explanation": "You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.", + "about.domain_blocks.silenced.title": "Limited", + "about.domain_blocks.suspended.explanation": "No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.", + "about.domain_blocks.suspended.title": "Suspended", + "about.not_available": "This information has not been made available on this server.", + "about.powered_by": "Decentralized social media powered by {mastodon}", + "about.rules": "Server rules", "account.account_note_header": "Catatan", "account.add_or_remove_from_list": "Tambah atau Buang dari senarai", "account.badges.bot": "Bot", @@ -7,13 +20,16 @@ "account.block_domain": "Sekat domain {domain}", "account.blocked": "Disekat", "account.browse_more_on_origin_server": "Layari selebihnya di profil asal", - "account.cancel_follow_request": "Batalkan permintaan ikutan", + "account.cancel_follow_request": "Withdraw follow request", "account.direct": "Mesej terus @{name}", "account.disable_notifications": "Berhenti memaklumi saya apabila @{name} mengirim hantaran", "account.domain_blocked": "Domain disekat", "account.edit_profile": "Sunting profil", "account.enable_notifications": "Maklumi saya apabila @{name} mengirim hantaran", "account.endorse": "Tampilkan di profil", + "account.featured_tags.last_status_at": "Last post on {date}", + "account.featured_tags.last_status_never": "No posts", + "account.featured_tags.title": "{name}'s featured hashtags", "account.follow": "Ikuti", "account.followers": "Pengikut", "account.followers.empty": "Belum ada yang mengikuti pengguna ini.", @@ -23,7 +39,7 @@ "account.follows.empty": "Pengguna ini belum mengikuti sesiapa.", "account.follows_you": "Mengikuti anda", "account.hide_reblogs": "Sembunyikan galakan daripada @{name}", - "account.joined": "Sertai pada {date}", + "account.joined_short": "Joined", "account.languages": "Change subscribed languages", "account.link_verified_on": "Pemilikan pautan ini telah disemak pada {date}", "account.locked_info": "Status privasi akaun ini dikunci. Pemiliknya menyaring sendiri siapa yang boleh mengikutinya.", @@ -63,12 +79,24 @@ "audio.hide": "Hide audio", "autosuggest_hashtag.per_week": "{count} seminggu", "boost_modal.combo": "Anda boleh tekan {combo} untuk melangkauinya pada waktu lain", - "bundle_column_error.body": "Terdapat kesilapan ketika memuatkan komponen ini.", + "bundle_column_error.copy_stacktrace": "Copy error report", + "bundle_column_error.error.body": "The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.", + "bundle_column_error.error.title": "Oh, no!", + "bundle_column_error.network.body": "There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.", + "bundle_column_error.network.title": "Network error", "bundle_column_error.retry": "Cuba lagi", - "bundle_column_error.title": "Ralat rangkaian", + "bundle_column_error.return": "Go back home", + "bundle_column_error.routing.body": "The requested page could not be found. Are you sure the URL in the address bar is correct?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Tutup", "bundle_modal_error.message": "Ada yang tidak kena semasa memuatkan komponen ini.", "bundle_modal_error.retry": "Cuba lagi", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "About", "column.blocks": "Pengguna yang disekat", "column.bookmarks": "Tanda buku", "column.community": "Garis masa tempatan", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "Sekat & Lapor", "confirmations.block.confirm": "Sekat", "confirmations.block.message": "Adakah anda pasti anda ingin menyekat {name}?", + "confirmations.cancel_follow_request.confirm": "Withdraw request", + "confirmations.cancel_follow_request.message": "Are you sure you want to withdraw your request to follow {name}?", "confirmations.delete.confirm": "Padam", "confirmations.delete.message": "Adakah anda pasti anda ingin memadam hantaran ini?", "confirmations.delete_list.confirm": "Padam", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Tanda sudah dibaca", "conversation.open": "Lihat perbualan", "conversation.with": "Dengan {names}", + "copypaste.copied": "Copied", + "copypaste.copy": "Copy", "directory.federated": "Dari fediverse yang diketahui", "directory.local": "Dari {domain} sahaja", "directory.new_arrivals": "Ketibaan baharu", "directory.recently_active": "Aktif baru-baru ini", + "dismissable_banner.community_timeline": "These are the most recent public posts from people whose accounts are hosted by {domain}.", + "dismissable_banner.dismiss": "Dismiss", + "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", + "dismissable_banner.explore_statuses": "These posts from this and other servers in the decentralized network are gaining traction on this server right now.", + "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", + "dismissable_banner.public_timeline": "These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.", "embed.instructions": "Benam hantaran ini di laman sesawang anda dengan menyalin kod berikut.", "embed.preview": "Begini rupanya nanti:", "emoji_button.activity": "Aktiviti", @@ -221,14 +259,14 @@ "follow_request.reject": "Tolak", "follow_requests.unlocked_explanation": "Walaupun akaun anda tidak dikunci, kakitangan {domain} merasakan anda mungkin ingin menyemak permintaan ikutan daripada akaun ini secara manual.", "generic.saved": "Disimpan", - "getting_started.developers": "Pembangun", - "getting_started.directory": "Direktori profil", + "getting_started.directory": "Directory", "getting_started.documentation": "Pendokumenan", + "getting_started.free_software_notice": "Mastodon is free, open source software. You can view the source code, contribute or report issues at {repository}.", "getting_started.heading": "Mari bermula", "getting_started.invite": "Undang orang", - "getting_started.open_source_notice": "Mastodon itu perisian bersumber terbuka. Anda boleh menyumbang atau melaporkan masalah di GitHub menerusi {github}.", "getting_started.privacy_policy": "Privacy Policy", "getting_started.security": "Tetapan akaun", + "getting_started.what_is_mastodon": "About Mastodon", "hashtag.column_header.tag_mode.all": "dan {additional}", "hashtag.column_header.tag_mode.any": "atau {additional}", "hashtag.column_header.tag_mode.none": "tanpa {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Tunjukkan balasan", "home.hide_announcements": "Sembunyikan pengumuman", "home.show_announcements": "Tunjukkan pengumuman", + "interaction_modal.description.favourite": "With an account on Mastodon, you can favourite this post to let the author know you appreciate it and save it for later.", + "interaction_modal.description.follow": "With an account on Mastodon, you can follow {name} to receive their posts in your home feed.", + "interaction_modal.description.reblog": "With an account on Mastodon, you can boost this post to share it with your own followers.", + "interaction_modal.description.reply": "With an account on Mastodon, you can respond to this post.", + "interaction_modal.on_another_server": "On a different server", + "interaction_modal.on_this_server": "On this server", + "interaction_modal.other_server_instructions": "Simply copy and paste this URL into the search bar of your favourite app or the web interface where you are signed in.", + "interaction_modal.preamble": "Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one.", + "interaction_modal.title.favourite": "Favourite {name}'s post", + "interaction_modal.title.follow": "Follow {name}", + "interaction_modal.title.reblog": "Boost {name}'s post", + "interaction_modal.title.reply": "Reply to {name}'s post", "intervals.full.days": "{number, plural, other {# hari}}", "intervals.full.hours": "{number, plural, other {# jam}}", "intervals.full.minutes": "{number, plural, other {# minit}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Tempoh", "mute_modal.hide_notifications": "Sembunyikan pemberitahuan daripada pengguna ini?", "mute_modal.indefinite": "Tidak tentu", - "navigation_bar.apps": "Aplikasi mudah alih", + "navigation_bar.about": "About", + "navigation_bar.apps": "Get the app", "navigation_bar.blocks": "Pengguna yang disekat", "navigation_bar.bookmarks": "Tanda buku", "navigation_bar.community_timeline": "Garis masa tempatan", @@ -324,7 +375,7 @@ "navigation_bar.filters": "Perkataan yang dibisukan", "navigation_bar.follow_requests": "Permintaan ikutan", "navigation_bar.follows_and_followers": "Ikutan dan pengikut", - "navigation_bar.info": "Perihal pelayan ini", + "navigation_bar.info": "About", "navigation_bar.keyboard_shortcuts": "Kekunci pantas", "navigation_bar.lists": "Senarai", "navigation_bar.logout": "Log keluar", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Hantaran disemat", "navigation_bar.preferences": "Keutamaan", "navigation_bar.public_timeline": "Garis masa bersekutu", + "navigation_bar.search": "Search", "navigation_bar.security": "Keselamatan", + "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", "notification.admin.report": "{name} reported {target}", "notification.admin.sign_up": "{name} signed up", "notification.favourite": "{name} menggemari hantaran anda", @@ -401,6 +454,8 @@ "privacy.public.short": "Awam", "privacy.unlisted.long": "Visible for all, but opted-out of discovery features", "privacy.unlisted.short": "Tidak tersenarai", + "privacy_policy.last_updated": "Last updated {date}", + "privacy_policy.title": "Privacy Policy", "refresh": "Muat semula", "regeneration_indicator.label": "Memuatkan…", "regeneration_indicator.sublabel": "Suapan rumah anda sedang disediakan!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "Menggelintar hantaran menggunakan kandungannya tidak didayakan di pelayan Mastodon ini.", "search_results.title": "Search for {q}", "search_results.total": "{count, number} {count, plural, other {hasil}}", + "server_banner.about_active_users": "People using this server during the last 30 days (Monthly Active Users)", + "server_banner.active_users": "active users", + "server_banner.administered_by": "Administered by:", + "server_banner.introduction": "{domain} is part of the decentralized social network powered by {mastodon}.", + "server_banner.learn_more": "Learn more", + "server_banner.server_stats": "Server stats:", "sign_in_banner.create_account": "Create account", "sign_in_banner.sign_in": "Sign in", "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "Tiada sesiapa yang menggalak hantaran ini. Apabila ada yang menggalak, ia akan muncul di sini.", "status.redraft": "Padam & rangka semula", "status.remove_bookmark": "Buang tanda buku", + "status.replied_to": "Replied to {name}", "status.reply": "Balas", "status.replyAll": "Balas ke bebenang", "status.report": "Laporkan @{name}", @@ -523,9 +585,8 @@ "status.show_more": "Tunjukkan lebih", "status.show_more_all": "Tunjukkan lebih untuk semua", "status.show_original": "Show original", - "status.show_thread": "Tunjuk bebenang", "status.translate": "Translate", - "status.translated_from": "Translated from {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Tidak tersedia", "status.unmute_conversation": "Nyahbisukan perbualan", "status.unpin": "Nyahsemat daripada profil", @@ -538,7 +599,6 @@ "tabs_bar.home": "Laman utama", "tabs_bar.local_timeline": "Tempatan", "tabs_bar.notifications": "Pemberitahuan", - "tabs_bar.search": "Cari", "time_remaining.days": "Tinggal {number, plural, other {# hari}}", "time_remaining.hours": "Tinggal {number, plural, other {# jam}}", "time_remaining.minutes": "Tinggal {number, plural, other {# minit}}", diff --git a/app/javascript/mastodon/locales/nl.json b/app/javascript/mastodon/locales/nl.json index 8b9a420ce..253d5ec02 100644 --- a/app/javascript/mastodon/locales/nl.json +++ b/app/javascript/mastodon/locales/nl.json @@ -1,4 +1,17 @@ { + "about.blocks": "Gemodereerde servers", + "about.contact": "Contact:", + "about.domain_blocks.comment": "Reden", + "about.domain_blocks.domain": "Domein", + "about.domain_blocks.preamble": "In het algemeen kun je met Mastodon berichten ontvangen van, en interactie hebben met gebruikers van elke server in de fediverse. Dit zijn de uitzonderingen die op deze specifieke server gelden.", + "about.domain_blocks.severity": "Zwaarte", + "about.domain_blocks.silenced.explanation": "In het algemeen zie je geen berichten en accounts van deze server, tenzij je berichten expliciet opzoekt of ervoor kiest om een account van deze server te volgen.", + "about.domain_blocks.silenced.title": "Beperkt", + "about.domain_blocks.suspended.explanation": "Er worden geen gegevens van deze server verwerkt, opgeslagen of uitgewisseld, wat interactie of communicatie met gebruikers van deze server onmogelijk maakt.", + "about.domain_blocks.suspended.title": "Opgeschort", + "about.not_available": "Deze informatie is door deze server niet openbaar gemaakt.", + "about.powered_by": "Gedecentraliseerde sociale media, mogelijk gemaakt door {mastodon}", + "about.rules": "Serverregels", "account.account_note_header": "Opmerking", "account.add_or_remove_from_list": "Toevoegen of verwijderen vanuit lijsten", "account.badges.bot": "Bot", @@ -14,6 +27,9 @@ "account.edit_profile": "Profiel bewerken", "account.enable_notifications": "Geef een melding wanneer @{name} een bericht plaatst", "account.endorse": "Op profiel weergeven", + "account.featured_tags.last_status_at": "Laatste bericht op {date}", + "account.featured_tags.last_status_never": "Geen berichten", + "account.featured_tags.title": "Uitgelichte hashtags van {name}", "account.follow": "Volgen", "account.followers": "Volgers", "account.followers.empty": "Niemand volgt nog deze gebruiker.", @@ -23,7 +39,7 @@ "account.follows.empty": "Deze gebruiker volgt nog niemand.", "account.follows_you": "Volgt jou", "account.hide_reblogs": "Boosts van @{name} verbergen", - "account.joined": "Geregistreerd op {date}", + "account.joined_short": "Joined", "account.languages": "Getoonde talen wijzigen", "account.link_verified_on": "Eigendom van deze link is gecontroleerd op {date}", "account.locked_info": "De privacystatus van dit account is op besloten gezet. De eigenaar bepaalt handmatig wie diegene kan volgen.", @@ -63,12 +79,24 @@ "audio.hide": "Audio verbergen", "autosuggest_hashtag.per_week": "{count} per week", "boost_modal.combo": "Je kunt {combo} klikken om dit de volgende keer over te slaan", - "bundle_column_error.body": "Tijdens het laden van dit onderdeel is er iets fout gegaan.", + "bundle_column_error.copy_stacktrace": "Foutrapportage kopiëren", + "bundle_column_error.error.body": "De opgevraagde pagina kon niet worden aangemaakt. Dit kan het gevolg zijn van onze broncode of van een verouderde webbrowser.", + "bundle_column_error.error.title": "Oh nee!", + "bundle_column_error.network.body": "Er is een fout opgetreden tijdens het laden van deze pagina. Dit kan veroorzaakt zijn door een tijdelijk probleem met je internetverbinding of met deze server.", + "bundle_column_error.network.title": "Netwerkfout", "bundle_column_error.retry": "Opnieuw proberen", - "bundle_column_error.title": "Netwerkfout", + "bundle_column_error.return": "Terug naar start", + "bundle_column_error.routing.body": "De opgevraagde pagina kon niet worden gevonden. Weet je zeker dat de URL in de adresbalk de juiste is?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Sluiten", "bundle_modal_error.message": "Tijdens het laden van dit onderdeel is er iets fout gegaan.", "bundle_modal_error.retry": "Opnieuw proberen", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "Over", "column.blocks": "Geblokkeerde gebruikers", "column.bookmarks": "Bladwijzers", "column.community": "Lokale tijdlijn", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "Blokkeren en rapporteren", "confirmations.block.confirm": "Blokkeren", "confirmations.block.message": "Weet je het zeker dat je {name} wilt blokkeren?", + "confirmations.cancel_follow_request.confirm": "Verzoek annuleren", + "confirmations.cancel_follow_request.message": "Weet je zeker dat je jouw verzoek om {name} te volgen wilt annuleren?", "confirmations.delete.confirm": "Verwijderen", "confirmations.delete.message": "Weet je het zeker dat je dit bericht wilt verwijderen?", "confirmations.delete_list.confirm": "Verwijderen", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Als gelezen markeren", "conversation.open": "Gesprek tonen", "conversation.with": "Met {names}", + "copypaste.copied": "Gekopieerd", + "copypaste.copy": "Kopiëren", "directory.federated": "Fediverse (wat bekend is)", "directory.local": "Alleen {domain}", "directory.new_arrivals": "Nieuwe accounts", "directory.recently_active": "Onlangs actief", + "dismissable_banner.community_timeline": "Dit zijn de meest recente openbare berichten van accounts op {domain}. Je kunt onder 'instellingen > voorkeuren > overig' kiezen welke talen je wilt zien.", + "dismissable_banner.dismiss": "Sluiten", + "dismissable_banner.explore_links": "Deze nieuwsberichten winnen aan populariteit op deze en andere servers binnen het decentrale netwerk.", + "dismissable_banner.explore_statuses": "Deze berichten winnen aan populariteit op deze en andere servers binnen het decentrale netwerk.", + "dismissable_banner.explore_tags": "Deze hashtags winnen aan populariteit op deze en andere servers binnen het decentrale netwerk.", + "dismissable_banner.public_timeline": "Dit zijn de meest recente openbare berichten van accounts op deze en andere servers binnen het decentrale netwerk. Je kunt onder 'instellingen > voorkeuren > overig' kiezen welke talen je wilt zien.", "embed.instructions": "Embed dit bericht op jouw website door de onderstaande code te kopiëren.", "embed.preview": "Zo komt het eruit te zien:", "emoji_button.activity": "Activiteiten", @@ -198,11 +236,11 @@ "explore.trending_links": "Nieuws", "explore.trending_statuses": "Berichten", "explore.trending_tags": "Hashtags", - "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.", + "filter_modal.added.context_mismatch_explanation": "Deze filtercategorie is niet van toepassing op de context waarin je dit bericht hebt benaderd. Als je wilt dat het bericht ook in deze context wordt gefilterd, moet je het filter bewerken.", "filter_modal.added.context_mismatch_title": "Context komt niet overeen!", - "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.", + "filter_modal.added.expired_explanation": "Deze filtercategorie is verlopen. Je moet de vervaldatum wijzigen om de categorie toe te kunnen passen.", "filter_modal.added.expired_title": "Filter verlopen!", - "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.", + "filter_modal.added.review_and_configure": "Ga naar {settings_link} om deze filtercategorie opnieuw te bekijken en verder te configureren.", "filter_modal.added.review_and_configure_title": "Filterinstellingen", "filter_modal.added.settings_link": "instellingspagina", "filter_modal.added.short_explanation": "Dit bericht is toegevoegd aan de volgende filtercategorie: {title}.", @@ -216,19 +254,19 @@ "filter_modal.title.status": "Een bericht filteren", "follow_recommendations.done": "Klaar", "follow_recommendations.heading": "Volg mensen waarvan je graag berichten wil zien! Hier zijn enkele aanbevelingen.", - "follow_recommendations.lead": "Berichten van mensen die je volgt zullen in chronologische volgorde onder start verschijnen. Wees niet bang om hierin fouten te maken, want je kunt mensen op elk moment net zo eenvoudig ontvolgen!", + "follow_recommendations.lead": "Berichten van mensen die je volgt zullen in chronologische volgorde op jouw starttijdlijn verschijnen. Wees niet bang om hierin fouten te maken, want je kunt mensen op elk moment net zo eenvoudig ontvolgen!", "follow_request.authorize": "Goedkeuren", "follow_request.reject": "Afwijzen", "follow_requests.unlocked_explanation": "Ook al is jouw account niet besloten, de medewerkers van {domain} denken dat jij misschien de volgende volgverzoeken handmatig wil controleren.", "generic.saved": "Opgeslagen", - "getting_started.developers": "Ontwikkelaars", "getting_started.directory": "Gebruikersgids", "getting_started.documentation": "Documentatie", + "getting_started.free_software_notice": "Mastodon is vrije, opensourcesoftware. Je kunt de broncode bekijken, bijdragen of bugs rapporteren op {repository}.", "getting_started.heading": "Aan de slag", "getting_started.invite": "Mensen uitnodigen", - "getting_started.open_source_notice": "Mastodon is vrije software. Je kunt bijdragen of problemen melden op GitHub via {github}.", "getting_started.privacy_policy": "Privacybeleid", "getting_started.security": "Accountinstellingen", + "getting_started.what_is_mastodon": "Over Mastodon", "hashtag.column_header.tag_mode.all": "en {additional}", "hashtag.column_header.tag_mode.any": "of {additional}", "hashtag.column_header.tag_mode.none": "zonder {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Reacties tonen", "home.hide_announcements": "Mededelingen verbergen", "home.show_announcements": "Mededelingen tonen", + "interaction_modal.description.favourite": "Je kunt met een Mastodon-account dit bericht als favoriet markeren, om die gebruiker te laten weten dat je het bericht waardeert en om het op te slaan.", + "interaction_modal.description.follow": "Je kunt met een Mastodon-account {name} volgen, om zo diens berichten op jouw starttijdlijn te ontvangen.", + "interaction_modal.description.reblog": "Je kunt met een Mastodon-account dit bericht boosten, om het zo met jouw volgers te delen.", + "interaction_modal.description.reply": "Je kunt met een Mastodon-account op dit bericht reageren.", + "interaction_modal.on_another_server": "Op een andere server", + "interaction_modal.on_this_server": "Op deze server", + "interaction_modal.other_server_instructions": "Kopieer en plak eenvoudig deze URL in het zoekveld van de door jou gebruikte app of in de webinterface van de server waarop je bent ingelogd.", + "interaction_modal.preamble": "Mastodon is gedecentraliseerd. Daarom heb je geen account op deze Mastodon-server nodig, wanneer je al een account op een andere Mastodon-server of compatibel platform hebt.", + "interaction_modal.title.favourite": "Bericht van {name} als favoriet markeren", + "interaction_modal.title.follow": "{name} volgen", + "interaction_modal.title.reblog": "Bericht van {name} boosten", + "interaction_modal.title.reply": "Op het bericht van {name} reageren", "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}}", @@ -261,7 +311,7 @@ "keyboard_shortcuts.favourites": "Favorieten tonen", "keyboard_shortcuts.federated": "Globale tijdlijn tonen", "keyboard_shortcuts.heading": "Sneltoetsen", - "keyboard_shortcuts.home": "Start tonen", + "keyboard_shortcuts.home": "Starttijdlijn tonen", "keyboard_shortcuts.hotkey": "Sneltoets", "keyboard_shortcuts.legend": "Deze legenda tonen", "keyboard_shortcuts.local": "Lokale tijdlijn tonen", @@ -310,7 +360,8 @@ "mute_modal.duration": "Duur", "mute_modal.hide_notifications": "Verberg meldingen van deze persoon?", "mute_modal.indefinite": "Voor onbepaalde tijd", - "navigation_bar.apps": "Mobiele apps", + "navigation_bar.about": "Over", + "navigation_bar.apps": "App downloaden", "navigation_bar.blocks": "Geblokkeerde gebruikers", "navigation_bar.bookmarks": "Bladwijzers", "navigation_bar.community_timeline": "Lokale tijdlijn", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Vastgemaakte berichten", "navigation_bar.preferences": "Instellingen", "navigation_bar.public_timeline": "Globale tijdlijn", + "navigation_bar.search": "Search", "navigation_bar.security": "Beveiliging", + "not_signed_in_indicator.not_signed_in": "Je moet inloggen om toegang tot deze informatie te krijgen.", "notification.admin.report": "{name} heeft {target} geapporteerd", "notification.admin.sign_up": "{name} heeft zich geregistreerd", "notification.favourite": "{name} markeerde jouw bericht als favoriet", @@ -401,9 +454,11 @@ "privacy.public.short": "Openbaar", "privacy.unlisted.long": "Voor iedereen zichtbaar, maar niet onder trends, hashtags en op openbare tijdlijnen", "privacy.unlisted.short": "Minder openbaar", + "privacy_policy.last_updated": "Laatst bijgewerkt op {date}", + "privacy_policy.title": "Privacybeleid", "refresh": "Vernieuwen", "regeneration_indicator.label": "Aan het laden…", - "regeneration_indicator.sublabel": "Jouw tijdlijn wordt aangemaakt!", + "regeneration_indicator.sublabel": "Jouw starttijdlijn wordt aangemaakt!", "relative_time.days": "{number}d", "relative_time.full.days": "{number, plural, one {# dag} other {# dagen}} geleden", "relative_time.full.hours": "{number, plural, one {# uur} other {# uur}} geleden", @@ -473,11 +528,17 @@ "search_results.statuses_fts_disabled": "Het zoeken in berichten is op deze Mastodon-server niet ingeschakeld.", "search_results.title": "Naar {q} zoeken", "search_results.total": "{count, number} {count, plural, one {resultaat} other {resultaten}}", - "sign_in_banner.create_account": "Account registreren", + "server_banner.about_active_users": "Aantal gebruikers tijdens de afgelopen 30 dagen (MAU)", + "server_banner.active_users": "actieve gebruikers", + "server_banner.administered_by": "Beheerd door:", + "server_banner.introduction": "{domain} is onderdeel van het gedecentraliseerde sociale netwerk {mastodon}.", + "server_banner.learn_more": "Meer leren", + "server_banner.server_stats": "Serverstats:", + "sign_in_banner.create_account": "Registreren", "sign_in_banner.sign_in": "Inloggen", "sign_in_banner.text": "Inloggen om accounts of hashtags te volgen, op berichten te reageren, berichten te delen, of om interactie te hebben met jouw account op een andere server.", "status.admin_account": "Moderatie-omgeving van @{name} openen", - "status.admin_status": "Dit bericht in de moderatie-omgeving openen", + "status.admin_status": "Dit bericht in de moderatie-omgeving tonen", "status.block": "@{name} blokkeren", "status.bookmark": "Bladwijzer toevoegen", "status.cancel_reblog_private": "Niet langer boosten", @@ -512,6 +573,7 @@ "status.reblogs.empty": "Niemand heeft dit bericht nog geboost. Wanneer iemand dit doet, valt dat hier te zien.", "status.redraft": "Verwijderen en herschrijven", "status.remove_bookmark": "Bladwijzer verwijderen", + "status.replied_to": "Replied to {name}", "status.reply": "Reageren", "status.replyAll": "Reageer op iedereen", "status.report": "@{name} rapporteren", @@ -523,13 +585,12 @@ "status.show_more": "Meer tonen", "status.show_more_all": "Alles meer tonen", "status.show_original": "Origineel bekijken", - "status.show_thread": "Gesprek tonen", "status.translate": "Vertalen", - "status.translated_from": "Vertaald uit het {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Niet beschikbaar", "status.unmute_conversation": "Gesprek niet langer negeren", "status.unpin": "Van profielpagina losmaken", - "subscribed_languages.lead": "Na de wijziging worden alleen berichten van geselecteerde talen op jouw starttijden en in lijsten weergegeven.", + "subscribed_languages.lead": "Na de wijziging worden alleen berichten van geselecteerde talen op jouw starttijdlijn en in lijsten weergegeven.", "subscribed_languages.save": "Wijzigingen opslaan", "subscribed_languages.target": "Getoonde talen voor {target} wijzigen", "suggestions.dismiss": "Aanbeveling verwerpen", @@ -538,7 +599,6 @@ "tabs_bar.home": "Start", "tabs_bar.local_timeline": "Lokaal", "tabs_bar.notifications": "Meldingen", - "tabs_bar.search": "Zoeken", "time_remaining.days": "{number, plural, one {# dag} other {# dagen}} te gaan", "time_remaining.hours": "{number, plural, one {# uur} other {# uur}} te gaan", "time_remaining.minutes": "{number, plural, one {# minuut} other {# minuten}} te gaan", @@ -548,7 +608,7 @@ "timeline_hint.resources.followers": "Volgers", "timeline_hint.resources.follows": "Volgend", "timeline_hint.resources.statuses": "Oudere berichten", - "trends.counter_by_accounts": "{count, plural, one {{counter} person} other {{counter} people}} in the past {days, plural, one {day} other {{days} days}}", + "trends.counter_by_accounts": "{count, plural, one {{counter} persoon} other {{counter} mensen}} {days, plural, one {in het afgelopen etmaal} other {in de afgelopen {days} dagen}}", "trends.trending_now": "Huidige trends", "ui.beforeunload": "Je concept gaat verloren wanneer je Mastodon verlaat.", "units.short.billion": "{count} mrd.", @@ -572,7 +632,7 @@ "upload_modal.description_placeholder": "Pa's wijze lynx bezag vroom het fikse aquaduct", "upload_modal.detect_text": "Tekst in een afbeelding detecteren", "upload_modal.edit_media": "Media bewerken", - "upload_modal.hint": "Klik of sleep de cirkel in de voorvertoning naar een centraal punt dat op elke thumbnail zichtbaar moet blijven.", + "upload_modal.hint": "Klik of sleep de cirkel in de voorvertoning naar een centraal focuspunt dat op elke thumbnail zichtbaar moet blijven.", "upload_modal.preparing_ocr": "OCR voorbereiden…", "upload_modal.preview_label": "Voorvertoning ({ratio})", "upload_progress.label": "Uploaden...", diff --git a/app/javascript/mastodon/locales/nn.json b/app/javascript/mastodon/locales/nn.json index f5d012f70..6d08e430a 100644 --- a/app/javascript/mastodon/locales/nn.json +++ b/app/javascript/mastodon/locales/nn.json @@ -1,4 +1,17 @@ { + "about.blocks": "Moderated servers", + "about.contact": "Contact:", + "about.domain_blocks.comment": "Reason", + "about.domain_blocks.domain": "Domain", + "about.domain_blocks.preamble": "Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.", + "about.domain_blocks.severity": "Severity", + "about.domain_blocks.silenced.explanation": "You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.", + "about.domain_blocks.silenced.title": "Limited", + "about.domain_blocks.suspended.explanation": "No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.", + "about.domain_blocks.suspended.title": "Suspended", + "about.not_available": "This information has not been made available on this server.", + "about.powered_by": "Decentralized social media powered by {mastodon}", + "about.rules": "Server rules", "account.account_note_header": "Merknad", "account.add_or_remove_from_list": "Legg til eller tak vekk frå listene", "account.badges.bot": "Robot", @@ -7,13 +20,16 @@ "account.block_domain": "Skjul alt frå {domain}", "account.blocked": "Blokkert", "account.browse_more_on_origin_server": "Sjå gjennom meir på den opphavlege profilen", - "account.cancel_follow_request": "Fjern fylgjeførespurnad", + "account.cancel_follow_request": "Withdraw follow request", "account.direct": "Send melding til @{name}", "account.disable_notifications": "Slutt å varsle meg når @{name} legger ut innlegg", "account.domain_blocked": "Domenet er gøymt", "account.edit_profile": "Rediger profil", "account.enable_notifications": "Varsle meg når @{name} legger ut innlegg", "account.endorse": "Framhev på profil", + "account.featured_tags.last_status_at": "Last post on {date}", + "account.featured_tags.last_status_never": "No posts", + "account.featured_tags.title": "{name}'s featured hashtags", "account.follow": "Fylg", "account.followers": "Fylgjarar", "account.followers.empty": "Ingen fylgjer denne brukaren enno.", @@ -23,7 +39,7 @@ "account.follows.empty": "Denne brukaren fylgjer ikkje nokon enno.", "account.follows_you": "Fylgjer deg", "account.hide_reblogs": "Gøym fremhevingar frå @{name}", - "account.joined": "Vart med {date}", + "account.joined_short": "Joined", "account.languages": "Change subscribed languages", "account.link_verified_on": "Eigarskap for denne lenkja vart sist sjekka {date}", "account.locked_info": "Denne kontoen er privat. Eigaren kan sjølv velja kven som kan fylgja han.", @@ -63,12 +79,24 @@ "audio.hide": "Hide audio", "autosuggest_hashtag.per_week": "{count} per veke", "boost_modal.combo": "Du kan trykkja {combo} for å hoppa over dette neste gong", - "bundle_column_error.body": "Noko gjekk gale mens denne komponenten vart lasta ned.", + "bundle_column_error.copy_stacktrace": "Copy error report", + "bundle_column_error.error.body": "The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.", + "bundle_column_error.error.title": "Oh, no!", + "bundle_column_error.network.body": "There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.", + "bundle_column_error.network.title": "Network error", "bundle_column_error.retry": "Prøv igjen", - "bundle_column_error.title": "Nettverksfeil", + "bundle_column_error.return": "Go back home", + "bundle_column_error.routing.body": "The requested page could not be found. Are you sure the URL in the address bar is correct?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Lat att", "bundle_modal_error.message": "Noko gjekk gale under lastinga av denne komponenten.", "bundle_modal_error.retry": "Prøv igjen", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "About", "column.blocks": "Blokkerte brukarar", "column.bookmarks": "Bokmerke", "column.community": "Lokal tidsline", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "Blokker & rapporter", "confirmations.block.confirm": "Blokker", "confirmations.block.message": "Er du sikker på at du vil blokkera {name}?", + "confirmations.cancel_follow_request.confirm": "Withdraw request", + "confirmations.cancel_follow_request.message": "Are you sure you want to withdraw your request to follow {name}?", "confirmations.delete.confirm": "Slett", "confirmations.delete.message": "Er du sikker på at du vil sletta denne statusen?", "confirmations.delete_list.confirm": "Slett", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Merk som lese", "conversation.open": "Sjå samtale", "conversation.with": "Med {names}", + "copypaste.copied": "Copied", + "copypaste.copy": "Copy", "directory.federated": "Frå kjent fedivers", "directory.local": "Berre frå {domain}", "directory.new_arrivals": "Nyankommne", "directory.recently_active": "Nyleg aktive", + "dismissable_banner.community_timeline": "These are the most recent public posts from people whose accounts are hosted by {domain}.", + "dismissable_banner.dismiss": "Dismiss", + "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", + "dismissable_banner.explore_statuses": "These posts from this and other servers in the decentralized network are gaining traction on this server right now.", + "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", + "dismissable_banner.public_timeline": "These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.", "embed.instructions": "Bygg inn denne statusen på nettsida di ved å kopiera koden under.", "embed.preview": "Slik bid det å sjå ut:", "emoji_button.activity": "Aktivitet", @@ -221,14 +259,14 @@ "follow_request.reject": "Avvis", "follow_requests.unlocked_explanation": "Sjølv om kontoen din ikkje er låst tenkte {domain} tilsette at du ville gå gjennom førespurnadar frå desse kontoane manuelt.", "generic.saved": "Lagra", - "getting_started.developers": "Utviklarar", - "getting_started.directory": "Profilkatalog", + "getting_started.directory": "Directory", "getting_started.documentation": "Dokumentasjon", + "getting_started.free_software_notice": "Mastodon is free, open source software. You can view the source code, contribute or report issues at {repository}.", "getting_started.heading": "Kom i gang", "getting_started.invite": "Byd folk inn", - "getting_started.open_source_notice": "Mastodon er fri programvare. Du kan bidraga eller rapportera problem med GitHub på {github}.", "getting_started.privacy_policy": "Privacy Policy", "getting_started.security": "Kontoinnstillingar", + "getting_started.what_is_mastodon": "About Mastodon", "hashtag.column_header.tag_mode.all": "og {additional}", "hashtag.column_header.tag_mode.any": "eller {additional}", "hashtag.column_header.tag_mode.none": "utan {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Vis svar", "home.hide_announcements": "Skjul kunngjeringar", "home.show_announcements": "Vis kunngjeringar", + "interaction_modal.description.favourite": "With an account on Mastodon, you can favourite this post to let the author know you appreciate it and save it for later.", + "interaction_modal.description.follow": "With an account on Mastodon, you can follow {name} to receive their posts in your home feed.", + "interaction_modal.description.reblog": "With an account on Mastodon, you can boost this post to share it with your own followers.", + "interaction_modal.description.reply": "With an account on Mastodon, you can respond to this post.", + "interaction_modal.on_another_server": "On a different server", + "interaction_modal.on_this_server": "On this server", + "interaction_modal.other_server_instructions": "Simply copy and paste this URL into the search bar of your favourite app or the web interface where you are signed in.", + "interaction_modal.preamble": "Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one.", + "interaction_modal.title.favourite": "Favourite {name}'s post", + "interaction_modal.title.follow": "Follow {name}", + "interaction_modal.title.reblog": "Boost {name}'s post", + "interaction_modal.title.reply": "Reply to {name}'s post", "intervals.full.days": "{number, plural, one {# dag} other {# dagar}}", "intervals.full.hours": "{number, plural, one {# time} other {# timar}}", "intervals.full.minutes": "{number, plural, one {# minutt} other {# minutt}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Varighet", "mute_modal.hide_notifications": "Gøyme varsel frå denne brukaren?", "mute_modal.indefinite": "På ubestemt tid", - "navigation_bar.apps": "Mobilappar", + "navigation_bar.about": "About", + "navigation_bar.apps": "Get the app", "navigation_bar.blocks": "Blokkerte brukarar", "navigation_bar.bookmarks": "Bokmerke", "navigation_bar.community_timeline": "Lokal tidsline", @@ -324,7 +375,7 @@ "navigation_bar.filters": "Målbundne ord", "navigation_bar.follow_requests": "Fylgjeførespurnader", "navigation_bar.follows_and_followers": "Fylgje og fylgjarar", - "navigation_bar.info": "Om denne tenaren", + "navigation_bar.info": "About", "navigation_bar.keyboard_shortcuts": "Snøggtastar", "navigation_bar.lists": "Lister", "navigation_bar.logout": "Logg ut", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Festa tut", "navigation_bar.preferences": "Innstillingar", "navigation_bar.public_timeline": "Føderert tidsline", + "navigation_bar.search": "Search", "navigation_bar.security": "Tryggleik", + "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", "notification.admin.report": "{name} rapporterte {target}", "notification.admin.sign_up": "{name} signed up", "notification.favourite": "{name} merkte statusen din som favoritt", @@ -401,6 +454,8 @@ "privacy.public.short": "Offentleg", "privacy.unlisted.long": "Visible for all, but opted-out of discovery features", "privacy.unlisted.short": "Uoppført", + "privacy_policy.last_updated": "Last updated {date}", + "privacy_policy.title": "Privacy Policy", "refresh": "Oppdater", "regeneration_indicator.label": "Lastar…", "regeneration_indicator.sublabel": "Heimetidslinja di vert førebudd!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "På denne Matsodon-tenaren kan du ikkje søkja på tut etter innhaldet deira.", "search_results.title": "Search for {q}", "search_results.total": "{count, number} {count, plural, one {treff} other {treff}}", + "server_banner.about_active_users": "People using this server during the last 30 days (Monthly Active Users)", + "server_banner.active_users": "active users", + "server_banner.administered_by": "Administered by:", + "server_banner.introduction": "{domain} is part of the decentralized social network powered by {mastodon}.", + "server_banner.learn_more": "Learn more", + "server_banner.server_stats": "Server stats:", "sign_in_banner.create_account": "Create account", "sign_in_banner.sign_in": "Sign in", "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "Ingen har framheva dette tutet enno. Om nokon gjer, så dukkar det opp her.", "status.redraft": "Slett & skriv på nytt", "status.remove_bookmark": "Fjern bokmerke", + "status.replied_to": "Replied to {name}", "status.reply": "Svar", "status.replyAll": "Svar til tråd", "status.report": "Rapporter @{name}", @@ -523,9 +585,8 @@ "status.show_more": "Vis meir", "status.show_more_all": "Vis meir for alle", "status.show_original": "Show original", - "status.show_thread": "Vis tråd", "status.translate": "Translate", - "status.translated_from": "Translated from {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Ikkje tilgjengeleg", "status.unmute_conversation": "Opphev målbinding av samtalen", "status.unpin": "Løys frå profil", @@ -538,7 +599,6 @@ "tabs_bar.home": "Heim", "tabs_bar.local_timeline": "Lokal", "tabs_bar.notifications": "Varsel", - "tabs_bar.search": "Søk", "time_remaining.days": "{number, plural, one {# dag} other {# dagar}} igjen", "time_remaining.hours": "{number, plural, one {# time} other {# timar}} igjen", "time_remaining.minutes": "{number, plural, one {# minutt} other {# minutt}} igjen", diff --git a/app/javascript/mastodon/locales/no.json b/app/javascript/mastodon/locales/no.json index 5ede22d71..f408fad68 100644 --- a/app/javascript/mastodon/locales/no.json +++ b/app/javascript/mastodon/locales/no.json @@ -1,4 +1,17 @@ { + "about.blocks": "Moderated servers", + "about.contact": "Contact:", + "about.domain_blocks.comment": "Reason", + "about.domain_blocks.domain": "Domain", + "about.domain_blocks.preamble": "Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.", + "about.domain_blocks.severity": "Severity", + "about.domain_blocks.silenced.explanation": "You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.", + "about.domain_blocks.silenced.title": "Limited", + "about.domain_blocks.suspended.explanation": "No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.", + "about.domain_blocks.suspended.title": "Suspended", + "about.not_available": "This information has not been made available on this server.", + "about.powered_by": "Decentralized social media powered by {mastodon}", + "about.rules": "Server rules", "account.account_note_header": "Notis", "account.add_or_remove_from_list": "Legg til eller fjern fra lister", "account.badges.bot": "Bot", @@ -7,13 +20,16 @@ "account.block_domain": "Skjul alt fra {domain}", "account.blocked": "Blokkert", "account.browse_more_on_origin_server": "Bla mer på den opprinnelige profilen", - "account.cancel_follow_request": "Avbryt følge forespørsel", + "account.cancel_follow_request": "Withdraw follow request", "account.direct": "Direct Message @{name}", "account.disable_notifications": "Slutt å varsle meg når @{name} legger ut innlegg", "account.domain_blocked": "Domenet skjult", "account.edit_profile": "Rediger profil", "account.enable_notifications": "Varsle meg når @{name} legger ut innlegg", "account.endorse": "Vis frem på profilen", + "account.featured_tags.last_status_at": "Last post on {date}", + "account.featured_tags.last_status_never": "No posts", + "account.featured_tags.title": "{name}'s featured hashtags", "account.follow": "Følg", "account.followers": "Følgere", "account.followers.empty": "Ingen følger denne brukeren ennå.", @@ -23,7 +39,7 @@ "account.follows.empty": "Denne brukeren følger ikke noen enda.", "account.follows_you": "Følger deg", "account.hide_reblogs": "Skjul fremhevinger fra @{name}", - "account.joined": "Ble med den {date}", + "account.joined_short": "Joined", "account.languages": "Change subscribed languages", "account.link_verified_on": "Eierskap av denne lenken ble sjekket {date}", "account.locked_info": "Denne kontoens personvernstatus er satt til låst. Eieren vurderer manuelt hvem som kan følge dem.", @@ -63,12 +79,24 @@ "audio.hide": "Hide audio", "autosuggest_hashtag.per_week": "{count} per uke", "boost_modal.combo": "You kan trykke {combo} for å hoppe over dette neste gang", - "bundle_column_error.body": "Noe gikk galt mens denne komponenten lastet.", + "bundle_column_error.copy_stacktrace": "Copy error report", + "bundle_column_error.error.body": "The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.", + "bundle_column_error.error.title": "Oh, no!", + "bundle_column_error.network.body": "There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.", + "bundle_column_error.network.title": "Network error", "bundle_column_error.retry": "Prøv igjen", - "bundle_column_error.title": "Nettverksfeil", + "bundle_column_error.return": "Go back home", + "bundle_column_error.routing.body": "The requested page could not be found. Are you sure the URL in the address bar is correct?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Lukk", "bundle_modal_error.message": "Noe gikk galt da denne komponenten lastet.", "bundle_modal_error.retry": "Prøv igjen", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "About", "column.blocks": "Blokkerte brukere", "column.bookmarks": "Bokmerker", "column.community": "Lokal tidslinje", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "Blokker og rapporter", "confirmations.block.confirm": "Blokkèr", "confirmations.block.message": "Er du sikker på at du vil blokkere {name}?", + "confirmations.cancel_follow_request.confirm": "Withdraw request", + "confirmations.cancel_follow_request.message": "Are you sure you want to withdraw your request to follow {name}?", "confirmations.delete.confirm": "Slett", "confirmations.delete.message": "Er du sikker på at du vil slette denne statusen?", "confirmations.delete_list.confirm": "Slett", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Marker som lest", "conversation.open": "Vis samtale", "conversation.with": "Med {names}", + "copypaste.copied": "Copied", + "copypaste.copy": "Copy", "directory.federated": "Fra det kjente strømiverset", "directory.local": "Kun fra {domain}", "directory.new_arrivals": "Nye ankomster", "directory.recently_active": "Nylig aktiv", + "dismissable_banner.community_timeline": "These are the most recent public posts from people whose accounts are hosted by {domain}.", + "dismissable_banner.dismiss": "Dismiss", + "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", + "dismissable_banner.explore_statuses": "These posts from this and other servers in the decentralized network are gaining traction on this server right now.", + "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", + "dismissable_banner.public_timeline": "These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.", "embed.instructions": "Kopier koden under for å bygge inn denne statusen på hjemmesiden din.", "embed.preview": "Slik kommer det til å se ut:", "emoji_button.activity": "Aktivitet", @@ -221,14 +259,14 @@ "follow_request.reject": "Avvis", "follow_requests.unlocked_explanation": "Selv om kontoen din ikke er låst, tror {domain} ansatte at du kanskje vil gjennomgå forespørsler fra disse kontoene manuelt.", "generic.saved": "Lagret", - "getting_started.developers": "Utviklere", - "getting_started.directory": "Profilmappe", + "getting_started.directory": "Directory", "getting_started.documentation": "Dokumentasjon", + "getting_started.free_software_notice": "Mastodon is free, open source software. You can view the source code, contribute or report issues at {repository}.", "getting_started.heading": "Kom i gang", "getting_started.invite": "Inviter folk", - "getting_started.open_source_notice": "Mastodon er fri programvare. Du kan bidra eller rapportere problemer på GitHub på {github}.", "getting_started.privacy_policy": "Privacy Policy", "getting_started.security": "Kontoinnstillinger", + "getting_started.what_is_mastodon": "About Mastodon", "hashtag.column_header.tag_mode.all": "og {additional}", "hashtag.column_header.tag_mode.any": "eller {additional}", "hashtag.column_header.tag_mode.none": "uten {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Vis svar", "home.hide_announcements": "Skjul kunngjøring", "home.show_announcements": "Vis kunngjøring", + "interaction_modal.description.favourite": "With an account on Mastodon, you can favourite this post to let the author know you appreciate it and save it for later.", + "interaction_modal.description.follow": "With an account on Mastodon, you can follow {name} to receive their posts in your home feed.", + "interaction_modal.description.reblog": "With an account on Mastodon, you can boost this post to share it with your own followers.", + "interaction_modal.description.reply": "With an account on Mastodon, you can respond to this post.", + "interaction_modal.on_another_server": "On a different server", + "interaction_modal.on_this_server": "On this server", + "interaction_modal.other_server_instructions": "Simply copy and paste this URL into the search bar of your favourite app or the web interface where you are signed in.", + "interaction_modal.preamble": "Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one.", + "interaction_modal.title.favourite": "Favourite {name}'s post", + "interaction_modal.title.follow": "Follow {name}", + "interaction_modal.title.reblog": "Boost {name}'s post", + "interaction_modal.title.reply": "Reply to {name}'s post", "intervals.full.days": "{number, plural,one {# dag} other {# dager}}", "intervals.full.hours": "{number, plural, one {# time} other {# timer}}", "intervals.full.minutes": "{number, plural, one {# minutt} other {# minutter}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Varighet", "mute_modal.hide_notifications": "Skjul varslinger fra denne brukeren?", "mute_modal.indefinite": "På ubestemt tid", - "navigation_bar.apps": "Mobilapper", + "navigation_bar.about": "About", + "navigation_bar.apps": "Get the app", "navigation_bar.blocks": "Blokkerte brukere", "navigation_bar.bookmarks": "Bokmerker", "navigation_bar.community_timeline": "Lokal tidslinje", @@ -324,7 +375,7 @@ "navigation_bar.filters": "Stilnede ord", "navigation_bar.follow_requests": "Følgeforespørsler", "navigation_bar.follows_and_followers": "Følginger og følgere", - "navigation_bar.info": "Utvidet informasjon", + "navigation_bar.info": "About", "navigation_bar.keyboard_shortcuts": "Tastatursnarveier", "navigation_bar.lists": "Lister", "navigation_bar.logout": "Logg ut", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Festa tuter", "navigation_bar.preferences": "Innstillinger", "navigation_bar.public_timeline": "Felles tidslinje", + "navigation_bar.search": "Search", "navigation_bar.security": "Sikkerhet", + "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", "notification.admin.report": "{name} reported {target}", "notification.admin.sign_up": "{name} signed up", "notification.favourite": "{name} likte din status", @@ -401,6 +454,8 @@ "privacy.public.short": "Offentlig", "privacy.unlisted.long": "Visible for all, but opted-out of discovery features", "privacy.unlisted.short": "Uoppført", + "privacy_policy.last_updated": "Last updated {date}", + "privacy_policy.title": "Privacy Policy", "refresh": "Oppfrisk", "regeneration_indicator.label": "Laster…", "regeneration_indicator.sublabel": "Dine startside forberedes!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "Å søke i tuter etter innhold er ikke skrudd på i denne Mastodon-tjeneren.", "search_results.title": "Search for {q}", "search_results.total": "{count, number} {count, plural, one {resultat} other {resultater}}", + "server_banner.about_active_users": "People using this server during the last 30 days (Monthly Active Users)", + "server_banner.active_users": "active users", + "server_banner.administered_by": "Administered by:", + "server_banner.introduction": "{domain} is part of the decentralized social network powered by {mastodon}.", + "server_banner.learn_more": "Learn more", + "server_banner.server_stats": "Server stats:", "sign_in_banner.create_account": "Create account", "sign_in_banner.sign_in": "Sign in", "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "Ingen har fremhevet denne tuten enda. Når noen gjør det, vil de dukke opp her.", "status.redraft": "Slett og drøft på nytt", "status.remove_bookmark": "Fjern bokmerke", + "status.replied_to": "Replied to {name}", "status.reply": "Svar", "status.replyAll": "Svar til samtale", "status.report": "Rapporter @{name}", @@ -523,9 +585,8 @@ "status.show_more": "Vis mer", "status.show_more_all": "Vis mer for alle", "status.show_original": "Show original", - "status.show_thread": "Vis tråden", "status.translate": "Translate", - "status.translated_from": "Translated from {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Ikke tilgjengelig", "status.unmute_conversation": "Ikke demp samtale", "status.unpin": "Angre festing på profilen", @@ -538,7 +599,6 @@ "tabs_bar.home": "Hjem", "tabs_bar.local_timeline": "Lokal", "tabs_bar.notifications": "Varslinger", - "tabs_bar.search": "Søk", "time_remaining.days": "{number, plural,one {# dag} other {# dager}} igjen", "time_remaining.hours": "{number, plural, one {# time} other {# timer}} igjen", "time_remaining.minutes": "{number, plural, one {# minutt} other {# minutter}} igjen", diff --git a/app/javascript/mastodon/locales/oc.json b/app/javascript/mastodon/locales/oc.json index cfe5364dd..754f38f21 100644 --- a/app/javascript/mastodon/locales/oc.json +++ b/app/javascript/mastodon/locales/oc.json @@ -1,4 +1,17 @@ { + "about.blocks": "Moderated servers", + "about.contact": "Contact:", + "about.domain_blocks.comment": "Reason", + "about.domain_blocks.domain": "Domain", + "about.domain_blocks.preamble": "Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.", + "about.domain_blocks.severity": "Severity", + "about.domain_blocks.silenced.explanation": "You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.", + "about.domain_blocks.silenced.title": "Limited", + "about.domain_blocks.suspended.explanation": "No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.", + "about.domain_blocks.suspended.title": "Suspended", + "about.not_available": "This information has not been made available on this server.", + "about.powered_by": "Decentralized social media powered by {mastodon}", + "about.rules": "Server rules", "account.account_note_header": "Nòta", "account.add_or_remove_from_list": "Ajustar o tirar de las listas", "account.badges.bot": "Robòt", @@ -7,13 +20,16 @@ "account.block_domain": "Tot amagar del domeni {domain}", "account.blocked": "Blocat", "account.browse_more_on_origin_server": "Navigar sul perfil original", - "account.cancel_follow_request": "Anullar la demanda de seguiment", + "account.cancel_follow_request": "Withdraw follow request", "account.direct": "Escriure un MP a @{name}", "account.disable_notifications": "Quitar de m’avisar quand @{name} publica quicòm", "account.domain_blocked": "Domeni amagat", "account.edit_profile": "Modificar lo perfil", "account.enable_notifications": "M’avisar quand @{name} publica quicòm", "account.endorse": "Mostrar pel perfil", + "account.featured_tags.last_status_at": "Last post on {date}", + "account.featured_tags.last_status_never": "No posts", + "account.featured_tags.title": "{name}'s featured hashtags", "account.follow": "Sègre", "account.followers": "Seguidors", "account.followers.empty": "Degun sèc pas aqueste utilizaire pel moment.", @@ -23,7 +39,7 @@ "account.follows.empty": "Aqueste utilizaire sèc pas degun pel moment.", "account.follows_you": "Vos sèc", "account.hide_reblogs": "Rescondre los partatges de @{name}", - "account.joined": "Arribèt en {date}", + "account.joined_short": "Joined", "account.languages": "Change subscribed languages", "account.link_verified_on": "La proprietat d’aqueste ligam foguèt verificada lo {date}", "account.locked_info": "L’estatut de privacitat del compte es configurat sus clavat. Lo proprietari causís qual pòt sègre son compte.", @@ -63,12 +79,24 @@ "audio.hide": "Hide audio", "autosuggest_hashtag.per_week": "{count} per setmana", "boost_modal.combo": "Podètz botar {combo} per passar aquò lo còp que ven", - "bundle_column_error.body": "Quicòm a fach mèuca pendent lo cargament d’aqueste compausant.", + "bundle_column_error.copy_stacktrace": "Copy error report", + "bundle_column_error.error.body": "The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.", + "bundle_column_error.error.title": "Oh, no!", + "bundle_column_error.network.body": "There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.", + "bundle_column_error.network.title": "Network error", "bundle_column_error.retry": "Tornar ensajar", - "bundle_column_error.title": "Error de ret", + "bundle_column_error.return": "Go back home", + "bundle_column_error.routing.body": "The requested page could not be found. Are you sure the URL in the address bar is correct?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Tampar", "bundle_modal_error.message": "Quicòm a fach mèuca pendent lo cargament d’aqueste compausant.", "bundle_modal_error.retry": "Tornar ensajar", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "About", "column.blocks": "Personas blocadas", "column.bookmarks": "Marcadors", "column.community": "Flux public local", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "Blocar e senhalar", "confirmations.block.confirm": "Blocar", "confirmations.block.message": "Volètz vertadièrament blocar {name} ?", + "confirmations.cancel_follow_request.confirm": "Withdraw request", + "confirmations.cancel_follow_request.message": "Are you sure you want to withdraw your request to follow {name}?", "confirmations.delete.confirm": "Escafar", "confirmations.delete.message": "Volètz vertadièrament escafar l’estatut ?", "confirmations.delete_list.confirm": "Suprimir", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Marcar coma legida", "conversation.open": "Veire la conversacion", "conversation.with": "Amb {names}", + "copypaste.copied": "Copied", + "copypaste.copy": "Copy", "directory.federated": "Del fediverse conegut", "directory.local": "Solament de {domain}", "directory.new_arrivals": "Nòus-venguts", "directory.recently_active": "Actius fa res", + "dismissable_banner.community_timeline": "These are the most recent public posts from people whose accounts are hosted by {domain}.", + "dismissable_banner.dismiss": "Dismiss", + "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", + "dismissable_banner.explore_statuses": "These posts from this and other servers in the decentralized network are gaining traction on this server right now.", + "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", + "dismissable_banner.public_timeline": "These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.", "embed.instructions": "Embarcar aqueste estatut per lo far veire sus un site Internet en copiar lo còdi çai-jos.", "embed.preview": "Semblarà aquò :", "emoji_button.activity": "Activitats", @@ -221,14 +259,14 @@ "follow_request.reject": "Regetar", "follow_requests.unlocked_explanation": "Encara que vòstre compte siasque pas verrolhat, la còla de {domain} pensèt que volriatz benlèu repassar las demandas d’abonament d’aquestes comptes.", "generic.saved": "Enregistrat", - "getting_started.developers": "Desvelopaires", - "getting_started.directory": "Annuari de perfils", + "getting_started.directory": "Directory", "getting_started.documentation": "Documentacion", + "getting_started.free_software_notice": "Mastodon is free, open source software. You can view the source code, contribute or report issues at {repository}.", "getting_started.heading": "Per començar", "getting_started.invite": "Convidar de mond", - "getting_started.open_source_notice": "Mastodon es un logicial liure. Podètz contribuir e mandar vòstres comentaris e rapòrt de bug via {github} sus GitHub.", "getting_started.privacy_policy": "Privacy Policy", "getting_started.security": "Seguretat", + "getting_started.what_is_mastodon": "About Mastodon", "hashtag.column_header.tag_mode.all": "e {additional}", "hashtag.column_header.tag_mode.any": "o {additional}", "hashtag.column_header.tag_mode.none": "sens {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Mostrar las responsas", "home.hide_announcements": "Rescondre las anóncias", "home.show_announcements": "Mostrar las anóncias", + "interaction_modal.description.favourite": "With an account on Mastodon, you can favourite this post to let the author know you appreciate it and save it for later.", + "interaction_modal.description.follow": "With an account on Mastodon, you can follow {name} to receive their posts in your home feed.", + "interaction_modal.description.reblog": "With an account on Mastodon, you can boost this post to share it with your own followers.", + "interaction_modal.description.reply": "With an account on Mastodon, you can respond to this post.", + "interaction_modal.on_another_server": "On a different server", + "interaction_modal.on_this_server": "On this server", + "interaction_modal.other_server_instructions": "Simply copy and paste this URL into the search bar of your favourite app or the web interface where you are signed in.", + "interaction_modal.preamble": "Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one.", + "interaction_modal.title.favourite": "Favourite {name}'s post", + "interaction_modal.title.follow": "Follow {name}", + "interaction_modal.title.reblog": "Boost {name}'s post", + "interaction_modal.title.reply": "Reply to {name}'s post", "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}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Durada", "mute_modal.hide_notifications": "Rescondre las notificacions d’aquesta persona ?", "mute_modal.indefinite": "Cap de data de fin", - "navigation_bar.apps": "Aplicacions mobil", + "navigation_bar.about": "About", + "navigation_bar.apps": "Get the app", "navigation_bar.blocks": "Personas blocadas", "navigation_bar.bookmarks": "Marcadors", "navigation_bar.community_timeline": "Flux public local", @@ -324,7 +375,7 @@ "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.info": "About", "navigation_bar.keyboard_shortcuts": "Acorchis clavièr", "navigation_bar.lists": "Listas", "navigation_bar.logout": "Desconnexion", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Tuts penjats", "navigation_bar.preferences": "Preferéncias", "navigation_bar.public_timeline": "Flux public global", + "navigation_bar.search": "Search", "navigation_bar.security": "Seguretat", + "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", "notification.admin.report": "{name} reported {target}", "notification.admin.sign_up": "{name} se marquèt", "notification.favourite": "{name} a ajustat a sos favorits", @@ -401,6 +454,8 @@ "privacy.public.short": "Public", "privacy.unlisted.long": "Visible for all, but opted-out of discovery features", "privacy.unlisted.short": "Pas-listat", + "privacy_policy.last_updated": "Last updated {date}", + "privacy_policy.title": "Privacy Policy", "refresh": "Actualizar", "regeneration_indicator.label": "Cargament…", "regeneration_indicator.sublabel": "Sèm a preparar vòstre flux d’acuèlh !", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "La recèrca de tuts per lor contengut es pas activada sus aqueste servidor Mastodon.", "search_results.title": "Search for {q}", "search_results.total": "{count, number} {count, plural, one {resultat} other {resultats}}", + "server_banner.about_active_users": "People using this server during the last 30 days (Monthly Active Users)", + "server_banner.active_users": "active users", + "server_banner.administered_by": "Administered by:", + "server_banner.introduction": "{domain} is part of the decentralized social network powered by {mastodon}.", + "server_banner.learn_more": "Learn more", + "server_banner.server_stats": "Server stats:", "sign_in_banner.create_account": "Create account", "sign_in_banner.sign_in": "Sign in", "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "Degun a pas encara partejat aqueste tut. Quand qualqu’un o farà, apareisserà aquí.", "status.redraft": "Escafar e tornar formular", "status.remove_bookmark": "Suprimir lo marcador", + "status.replied_to": "Replied to {name}", "status.reply": "Respondre", "status.replyAll": "Respondre a la conversacion", "status.report": "Senhalar @{name}", @@ -523,9 +585,8 @@ "status.show_more": "Desplegar", "status.show_more_all": "Los desplegar totes", "status.show_original": "Show original", - "status.show_thread": "Mostrar lo fil", "status.translate": "Translate", - "status.translated_from": "Translated from {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Pas disponible", "status.unmute_conversation": "Tornar mostrar la conversacion", "status.unpin": "Tirar del perfil", @@ -538,7 +599,6 @@ "tabs_bar.home": "Acuèlh", "tabs_bar.local_timeline": "Flux public local", "tabs_bar.notifications": "Notificacions", - "tabs_bar.search": "Recèrcas", "time_remaining.days": "demòra{number, plural, one { # jorn} other {n # jorns}}", "time_remaining.hours": "demòra{number, plural, one { # ora} other {n # oras}}", "time_remaining.minutes": "demòra{number, plural, one { # minuta} other {n # minutas}}", diff --git a/app/javascript/mastodon/locales/pa.json b/app/javascript/mastodon/locales/pa.json index de4e76507..cc0fa7069 100644 --- a/app/javascript/mastodon/locales/pa.json +++ b/app/javascript/mastodon/locales/pa.json @@ -1,4 +1,17 @@ { + "about.blocks": "Moderated servers", + "about.contact": "Contact:", + "about.domain_blocks.comment": "Reason", + "about.domain_blocks.domain": "Domain", + "about.domain_blocks.preamble": "Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.", + "about.domain_blocks.severity": "Severity", + "about.domain_blocks.silenced.explanation": "You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.", + "about.domain_blocks.silenced.title": "Limited", + "about.domain_blocks.suspended.explanation": "No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.", + "about.domain_blocks.suspended.title": "Suspended", + "about.not_available": "This information has not been made available on this server.", + "about.powered_by": "Decentralized social media powered by {mastodon}", + "about.rules": "Server rules", "account.account_note_header": "Note", "account.add_or_remove_from_list": "Add or Remove from lists", "account.badges.bot": "Bot", @@ -7,13 +20,16 @@ "account.block_domain": "Block domain {domain}", "account.blocked": "Blocked", "account.browse_more_on_origin_server": "Browse more on the original profile", - "account.cancel_follow_request": "Cancel follow request", + "account.cancel_follow_request": "Withdraw follow request", "account.direct": "Direct message @{name}", "account.disable_notifications": "Stop notifying me when @{name} posts", "account.domain_blocked": "Domain blocked", "account.edit_profile": "Edit profile", "account.enable_notifications": "Notify me when @{name} posts", "account.endorse": "Feature on profile", + "account.featured_tags.last_status_at": "Last post on {date}", + "account.featured_tags.last_status_never": "No posts", + "account.featured_tags.title": "{name}'s featured hashtags", "account.follow": "Follow", "account.followers": "Followers", "account.followers.empty": "No one follows this user yet.", @@ -23,7 +39,7 @@ "account.follows.empty": "This user doesn't follow anyone yet.", "account.follows_you": "Follows you", "account.hide_reblogs": "Hide boosts from @{name}", - "account.joined": "Joined {date}", + "account.joined_short": "Joined", "account.languages": "Change subscribed languages", "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.", @@ -63,12 +79,24 @@ "audio.hide": "Hide audio", "autosuggest_hashtag.per_week": "{count} per week", "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.copy_stacktrace": "Copy error report", + "bundle_column_error.error.body": "The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.", + "bundle_column_error.error.title": "Oh, no!", + "bundle_column_error.network.body": "There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.", + "bundle_column_error.network.title": "Network error", "bundle_column_error.retry": "Try again", - "bundle_column_error.title": "Network error", + "bundle_column_error.return": "Go back home", + "bundle_column_error.routing.body": "The requested page could not be found. Are you sure the URL in the address bar is correct?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Close", "bundle_modal_error.message": "Something went wrong while loading this component.", "bundle_modal_error.retry": "Try again", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "About", "column.blocks": "Blocked users", "column.bookmarks": "Bookmarks", "column.community": "Local timeline", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "Block & Report", "confirmations.block.confirm": "Block", "confirmations.block.message": "Are you sure you want to block {name}?", + "confirmations.cancel_follow_request.confirm": "Withdraw request", + "confirmations.cancel_follow_request.message": "Are you sure you want to withdraw your request to follow {name}?", "confirmations.delete.confirm": "Delete", "confirmations.delete.message": "Are you sure you want to delete this status?", "confirmations.delete_list.confirm": "Delete", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Mark as read", "conversation.open": "View conversation", "conversation.with": "With {names}", + "copypaste.copied": "Copied", + "copypaste.copy": "Copy", "directory.federated": "From known fediverse", "directory.local": "From {domain} only", "directory.new_arrivals": "New arrivals", "directory.recently_active": "Recently active", + "dismissable_banner.community_timeline": "These are the most recent public posts from people whose accounts are hosted by {domain}.", + "dismissable_banner.dismiss": "Dismiss", + "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", + "dismissable_banner.explore_statuses": "These posts from this and other servers in the decentralized network are gaining traction on this server right now.", + "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", + "dismissable_banner.public_timeline": "These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.", "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", @@ -221,14 +259,14 @@ "follow_request.reject": "Reject", "follow_requests.unlocked_explanation": "Even though your account is not locked, the {domain} staff thought you might want to review follow requests from these accounts manually.", "generic.saved": "Saved", - "getting_started.developers": "Developers", - "getting_started.directory": "Profile directory", + "getting_started.directory": "Directory", "getting_started.documentation": "Documentation", + "getting_started.free_software_notice": "Mastodon is free, open source software. You can view the source code, contribute or report issues at {repository}.", "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.privacy_policy": "Privacy Policy", "getting_started.security": "Security", + "getting_started.what_is_mastodon": "About Mastodon", "hashtag.column_header.tag_mode.all": "and {additional}", "hashtag.column_header.tag_mode.any": "or {additional}", "hashtag.column_header.tag_mode.none": "without {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Show replies", "home.hide_announcements": "Hide announcements", "home.show_announcements": "Show announcements", + "interaction_modal.description.favourite": "With an account on Mastodon, you can favourite this post to let the author know you appreciate it and save it for later.", + "interaction_modal.description.follow": "With an account on Mastodon, you can follow {name} to receive their posts in your home feed.", + "interaction_modal.description.reblog": "With an account on Mastodon, you can boost this post to share it with your own followers.", + "interaction_modal.description.reply": "With an account on Mastodon, you can respond to this post.", + "interaction_modal.on_another_server": "On a different server", + "interaction_modal.on_this_server": "On this server", + "interaction_modal.other_server_instructions": "Simply copy and paste this URL into the search bar of your favourite app or the web interface where you are signed in.", + "interaction_modal.preamble": "Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one.", + "interaction_modal.title.favourite": "Favourite {name}'s post", + "interaction_modal.title.follow": "Follow {name}", + "interaction_modal.title.reblog": "Boost {name}'s post", + "interaction_modal.title.reply": "Reply to {name}'s post", "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}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Duration", "mute_modal.hide_notifications": "Hide notifications from this user?", "mute_modal.indefinite": "Indefinite", - "navigation_bar.apps": "Mobile apps", + "navigation_bar.about": "About", + "navigation_bar.apps": "Get the app", "navigation_bar.blocks": "Blocked users", "navigation_bar.bookmarks": "Bookmarks", "navigation_bar.community_timeline": "Local timeline", @@ -324,7 +375,7 @@ "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.info": "About", "navigation_bar.keyboard_shortcuts": "Hotkeys", "navigation_bar.lists": "Lists", "navigation_bar.logout": "Logout", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Pinned toots", "navigation_bar.preferences": "Preferences", "navigation_bar.public_timeline": "Federated timeline", + "navigation_bar.search": "Search", "navigation_bar.security": "Security", + "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", "notification.admin.report": "{name} reported {target}", "notification.admin.sign_up": "{name} signed up", "notification.favourite": "{name} favourited your status", @@ -401,6 +454,8 @@ "privacy.public.short": "Public", "privacy.unlisted.long": "Visible for all, but opted-out of discovery features", "privacy.unlisted.short": "Unlisted", + "privacy_policy.last_updated": "Last updated {date}", + "privacy_policy.title": "Privacy Policy", "refresh": "Refresh", "regeneration_indicator.label": "Loading…", "regeneration_indicator.sublabel": "Your home feed is being prepared!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.title": "Search for {q}", "search_results.total": "{count, number} {count, plural, one {result} other {results}}", + "server_banner.about_active_users": "People using this server during the last 30 days (Monthly Active Users)", + "server_banner.active_users": "active users", + "server_banner.administered_by": "Administered by:", + "server_banner.introduction": "{domain} is part of the decentralized social network powered by {mastodon}.", + "server_banner.learn_more": "Learn more", + "server_banner.server_stats": "Server stats:", "sign_in_banner.create_account": "Create account", "sign_in_banner.sign_in": "Sign in", "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "No one has boosted this toot yet. When someone does, they will show up here.", "status.redraft": "Delete & re-draft", "status.remove_bookmark": "Remove bookmark", + "status.replied_to": "Replied to {name}", "status.reply": "Reply", "status.replyAll": "Reply to thread", "status.report": "Report @{name}", @@ -523,9 +585,8 @@ "status.show_more": "Show more", "status.show_more_all": "Show more for all", "status.show_original": "Show original", - "status.show_thread": "Show thread", "status.translate": "Translate", - "status.translated_from": "Translated from {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Not available", "status.unmute_conversation": "Unmute conversation", "status.unpin": "Unpin from profile", @@ -538,7 +599,6 @@ "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", diff --git a/app/javascript/mastodon/locales/pl.json b/app/javascript/mastodon/locales/pl.json index 6087d9d54..2049ede0f 100644 --- a/app/javascript/mastodon/locales/pl.json +++ b/app/javascript/mastodon/locales/pl.json @@ -1,4 +1,17 @@ { + "about.blocks": "Serwery moderowane", + "about.contact": "Kontakt:", + "about.domain_blocks.comment": "Powód", + "about.domain_blocks.domain": "Domena", + "about.domain_blocks.preamble": "Normalnie Mastodon pozwala ci przeglądać i reagować na treści od innych użytkowników z jakiegokolwiek serwera w fediwersum. To są wyjątki, które zostały stworzone na tym konkretnym serwerze.", + "about.domain_blocks.severity": "Priorytet", + "about.domain_blocks.silenced.explanation": "Zazwyczaj nie zobaczysz profili i treści z tego serwera, chyba że wyraźnie go poszukasz lub zdecydujesz się go obserwować.", + "about.domain_blocks.silenced.title": "Ograniczone", + "about.domain_blocks.suspended.explanation": "Żadne dane z tego serwera nie będą przetwarzane, przechowywane lub wymieniane, co uniemożliwia jakąkolwiek interakcję lub komunikację z użytkownikami z tego serwera.", + "about.domain_blocks.suspended.title": "Zawieszono", + "about.not_available": "Ta informacja nie została udostępniona na tym serwerze.", + "about.powered_by": "Zdecentralizowane media społecznościowe w technologii {mastodon}", + "about.rules": "Regulamin serwera", "account.account_note_header": "Notatka", "account.add_or_remove_from_list": "Dodaj lub usuń z list", "account.badges.bot": "Bot", @@ -7,13 +20,16 @@ "account.block_domain": "Blokuj wszystko z {domain}", "account.blocked": "Zablokowany(-a)", "account.browse_more_on_origin_server": "Zobacz więcej na oryginalnym profilu", - "account.cancel_follow_request": "Zrezygnuj z prośby o możliwość śledzenia", + "account.cancel_follow_request": "Wycofaj żądanie obserwowania", "account.direct": "Wyślij wiadomość bezpośrednią do @{name}", "account.disable_notifications": "Przestań powiadamiać mnie o wpisach @{name}", "account.domain_blocked": "Ukryto domenę", "account.edit_profile": "Edytuj profil", "account.enable_notifications": "Powiadamiaj mnie o wpisach @{name}", "account.endorse": "Wyróżnij na profilu", + "account.featured_tags.last_status_at": "Ostatni post {date}", + "account.featured_tags.last_status_never": "Brak postów", + "account.featured_tags.title": "Polecane hasztagi {name}", "account.follow": "Śledź", "account.followers": "Śledzący", "account.followers.empty": "Nikt jeszcze nie śledzi tego użytkownika.", @@ -23,7 +39,7 @@ "account.follows.empty": "Ten użytkownik nie śledzi jeszcze nikogo.", "account.follows_you": "Śledzi Cię", "account.hide_reblogs": "Ukryj podbicia od @{name}", - "account.joined": "Dołączył(a) {date}", + "account.joined_short": "Joined", "account.languages": "Zmień subskrybowane języki", "account.link_verified_on": "Własność tego odnośnika została potwierdzona {date}", "account.locked_info": "To konto jest prywatne. Właściciel ręcznie wybiera kto może go śledzić.", @@ -63,12 +79,24 @@ "audio.hide": "Ukryj dźwięk", "autosuggest_hashtag.per_week": "{count} co tydzień", "boost_modal.combo": "Naciśnij {combo}, aby pominąć to następnym razem", - "bundle_column_error.body": "Coś poszło nie tak podczas ładowania tego składnika.", + "bundle_column_error.copy_stacktrace": "Skopiuj raport o błędzie", + "bundle_column_error.error.body": "Nie można zrenderować żądanej strony. Może to być spowodowane błędem w naszym kodzie lub problemami z kompatybilnością przeglądarki.", + "bundle_column_error.error.title": "O nie!", + "bundle_column_error.network.body": "Wystąpił błąd podczas próby załadowania tej strony. Może to być spowodowane tymczasowym problemem z połączeniem z internetem lub serwerem.", + "bundle_column_error.network.title": "Błąd sieci", "bundle_column_error.retry": "Spróbuj ponownie", - "bundle_column_error.title": "Błąd sieci", + "bundle_column_error.return": "Wróć do strony głównej", + "bundle_column_error.routing.body": "Żądana strona nie została znaleziona. Czy na pewno adres URL w pasku adresu jest poprawny?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Zamknij", "bundle_modal_error.message": "Coś poszło nie tak podczas ładowania tego składnika.", "bundle_modal_error.retry": "Spróbuj ponownie", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "O...", "column.blocks": "Zablokowani użytkownicy", "column.bookmarks": "Zakładki", "column.community": "Lokalna oś czasu", @@ -125,6 +153,8 @@ "confirmations.block.block_and_report": "Zablokuj i zgłoś", "confirmations.block.confirm": "Zablokuj", "confirmations.block.message": "Czy na pewno chcesz zablokować {name}?", + "confirmations.cancel_follow_request.confirm": "Wycofaj żądanie", + "confirmations.cancel_follow_request.message": "Czy na pewno chcesz wycofać zgłoszenie śledzenia {name}?", "confirmations.delete.confirm": "Usuń", "confirmations.delete.message": "Czy na pewno chcesz usunąć ten wpis?", "confirmations.delete_list.confirm": "Usuń", @@ -148,10 +178,18 @@ "conversation.mark_as_read": "Oznacz jako przeczytane", "conversation.open": "Zobacz rozmowę", "conversation.with": "Z {names}", + "copypaste.copied": "Skopiowano", + "copypaste.copy": "Kopiuj", "directory.federated": "Ze znanego fediwersum", "directory.local": "Tylko z {domain}", "directory.new_arrivals": "Nowości", "directory.recently_active": "Ostatnio aktywne", + "dismissable_banner.community_timeline": "To są najnowsze wpisy publiczne od osób, które mają założone konta na {domain}.", + "dismissable_banner.dismiss": "Schowaj", + "dismissable_banner.explore_links": "Te wiadomości obecnie są komentowane przez osoby z tego serwera i pozostałych w zdecentralizowanej sieci.", + "dismissable_banner.explore_statuses": "Obecnie te wpisy z tego serwera i pozostałych serwerów w zdecentralizowanej sieci zyskują popularność na tym serwerze.", + "dismissable_banner.explore_tags": "Te hasztagi obecnie zyskują popularność wśród osób z tego serwera i pozostałych w zdecentralizowanej sieci.", + "dismissable_banner.public_timeline": "To są najnowsze publiczne wpisy od osób z tego i innych serwerów zdecentralizowanej sieci, o których ten serwer wie.", "embed.instructions": "Osadź ten wpis na swojej stronie wklejając poniższy kod.", "embed.preview": "Tak będzie to wyglądać:", "emoji_button.activity": "Aktywność", @@ -225,14 +263,14 @@ "follow_request.reject": "Odrzuć", "follow_requests.unlocked_explanation": "Mimo że Twoje konto nie jest zablokowane, zespół {domain} uznał że możesz chcieć ręcznie przejrzeć prośby o możliwość śledzenia.", "generic.saved": "Zapisano", - "getting_started.developers": "Dla programistów", - "getting_started.directory": "Katalog profilów", + "getting_started.directory": "Katalog", "getting_started.documentation": "Dokumentacja", + "getting_started.free_software_notice": "Mastodon jest darmowym, otwartym oprogramowaniem. Możesz zobaczyć kod źródłowy, wnieść wkład lub zgłosić problemy na {repository}.", "getting_started.heading": "Rozpocznij", "getting_started.invite": "Zaproś znajomych", - "getting_started.open_source_notice": "Mastodon jest oprogramowaniem o otwartym źródle. Możesz pomóc w rozwoju lub zgłaszać błędy na GitHubie tutaj: {github}.", "getting_started.privacy_policy": "Polityka prywatności", "getting_started.security": "Bezpieczeństwo", + "getting_started.what_is_mastodon": "O Mastodon", "hashtag.column_header.tag_mode.all": "i {additional}", "hashtag.column_header.tag_mode.any": "lub {additional}", "hashtag.column_header.tag_mode.none": "bez {additional}", @@ -249,6 +287,18 @@ "home.column_settings.show_replies": "Pokazuj odpowiedzi", "home.hide_announcements": "Ukryj ogłoszenia", "home.show_announcements": "Pokaż ogłoszenia", + "interaction_modal.description.favourite": "Mając konto na Mastodonie, możesz dodawać wpisy do ulubionych by dać znać jego autorowi, że podoba Ci się ten wpis i zachować go na później.", + "interaction_modal.description.follow": "Mając konto na Mastodonie, możesz śledzić {name} by widzieć jego wpisy na swojej głównej osi czasu.", + "interaction_modal.description.reblog": "Mając konto na Mastodonie, możesz podbić ten wpis i udostępnić go Twoim obserwującym.", + "interaction_modal.description.reply": "Mając konto na Mastodonie, możesz odpowiedzieć na ten wpis.", + "interaction_modal.on_another_server": "Na innym serwerze", + "interaction_modal.on_this_server": "Na tym serwerze", + "interaction_modal.other_server_instructions": "Wystarczy skopiować i wkleić ten adres URL do swojej ulubionej aplikacji lub przegąldarki www gdzie jesteś zalogowany/a.", + "interaction_modal.preamble": "Ponieważ Mastodon jest zdecentralizowany, możesz użyć swojego istniejącego konta z innego serwera Mastodona lub innej kompatybilnej usługi, jeśli nie masz konta na tym serwerze.", + "interaction_modal.title.favourite": "Ulubiony wpis {name}", + "interaction_modal.title.follow": "Śledź {name}", + "interaction_modal.title.reblog": "Podbij wpis {name}", + "interaction_modal.title.reply": "Odpowiedz na post {name}", "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}}", @@ -314,7 +364,8 @@ "mute_modal.duration": "Czas", "mute_modal.hide_notifications": "Chcesz ukryć powiadomienia od tego użytkownika?", "mute_modal.indefinite": "Nieokreślony", - "navigation_bar.apps": "Aplikacje mobilne", + "navigation_bar.about": "O...", + "navigation_bar.apps": "Pobierz aplikację", "navigation_bar.blocks": "Zablokowani użytkownicy", "navigation_bar.bookmarks": "Zakładki", "navigation_bar.community_timeline": "Lokalna oś czasu", @@ -328,7 +379,7 @@ "navigation_bar.filters": "Wyciszone słowa", "navigation_bar.follow_requests": "Prośby o śledzenie", "navigation_bar.follows_and_followers": "Śledzeni i śledzący", - "navigation_bar.info": "Szczegółowe informacje", + "navigation_bar.info": "O nas", "navigation_bar.keyboard_shortcuts": "Skróty klawiszowe", "navigation_bar.lists": "Listy", "navigation_bar.logout": "Wyloguj", @@ -338,7 +389,9 @@ "navigation_bar.pins": "Przypięte wpisy", "navigation_bar.preferences": "Preferencje", "navigation_bar.public_timeline": "Globalna oś czasu", + "navigation_bar.search": "Search", "navigation_bar.security": "Bezpieczeństwo", + "not_signed_in_indicator.not_signed_in": "Musisz się zalogować, aby otrzymać dostęp do tego zasobu.", "notification.admin.report": "{name} zgłosił {target}", "notification.admin.sign_up": "Użytkownik {name} zarejestrował się", "notification.favourite": "{name} dodał(a) Twój wpis do ulubionych", @@ -406,6 +459,8 @@ "privacy.public.short": "Publiczny", "privacy.unlisted.long": "Widoczne dla każdego, z wyłączeniem funkcji odkrywania", "privacy.unlisted.short": "Niewidoczny", + "privacy_policy.last_updated": "Data ostatniej aktualizacji: {date}", + "privacy_policy.title": "Polityka prywatności", "refresh": "Odśwież", "regeneration_indicator.label": "Ładuję…", "regeneration_indicator.sublabel": "Twoja oś czasu jest przygotowywana!", @@ -478,9 +533,15 @@ "search_results.statuses_fts_disabled": "Szukanie wpisów przy pomocy ich zawartości nie jest włączone na tym serwerze Mastodona.", "search_results.title": "Wyszukiwanie {q}", "search_results.total": "{count, number} {count, plural, one {wynik} few {wyniki} many {wyników} other {wyników}}", + "server_banner.about_active_users": "Osoby korzystające z tego serwera w ciągu ostatnich 30 dni (Miesięcznie aktywni użytkownicy)", + "server_banner.active_users": "aktywni użytkownicy", + "server_banner.administered_by": "Zarzdzane przez:", + "server_banner.introduction": "{domain} jest częścią zdecentralizowanej sieci społecznościowej wspieranej przez {mastodon}.", + "server_banner.learn_more": "Dowiedz się więcej", + "server_banner.server_stats": "Statystyki serwera:", "sign_in_banner.create_account": "Załóż konto", "sign_in_banner.sign_in": "Zaloguj się", - "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", + "sign_in_banner.text": "Zaloguj się, aby obserwować profile lub hasztagi, jak również dodawaj wpisy do ulubionych, udostępniaj je dalej i odpowiadaj na nie lub wchodź w interakcje z kontem na innym serwerze.", "status.admin_account": "Otwórz interfejs moderacyjny dla @{name}", "status.admin_status": "Otwórz ten wpis w interfejsie moderacyjnym", "status.block": "Zablokuj @{name}", @@ -517,6 +578,7 @@ "status.reblogs.empty": "Nikt nie podbił jeszcze tego wpisu. Gdy ktoś to zrobi, pojawi się tutaj.", "status.redraft": "Usuń i przeredaguj", "status.remove_bookmark": "Usuń zakładkę", + "status.replied_to": "Replied to {name}", "status.reply": "Odpowiedz", "status.replyAll": "Odpowiedz na wątek", "status.report": "Zgłoś @{name}", @@ -528,9 +590,8 @@ "status.show_more": "Rozwiń", "status.show_more_all": "Rozwiń wszystkie", "status.show_original": "Pokaż oryginał", - "status.show_thread": "Pokaż wątek", "status.translate": "Przetłumacz", - "status.translated_from": "Przetłumaczone z {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Niedostępne", "status.unmute_conversation": "Cofnij wyciszenie konwersacji", "status.unpin": "Odepnij z profilu", @@ -543,7 +604,6 @@ "tabs_bar.home": "Strona główna", "tabs_bar.local_timeline": "Lokalne", "tabs_bar.notifications": "Powiadomienia", - "tabs_bar.search": "Szukaj", "time_remaining.days": "{number, plural, one {Pozostał # dzień} few {Pozostały # dni} many {Pozostało # dni} other {Pozostało # dni}}", "time_remaining.hours": "{number, plural, one {Pozostała # godzina} few {Pozostały # godziny} many {Pozostało # godzin} other {Pozostało # godzin}}", "time_remaining.minutes": "{number, plural, one {Pozostała # minuta} few {Pozostały # minuty} many {Pozostało # minut} other {Pozostało # minut}}", diff --git a/app/javascript/mastodon/locales/pt-BR.json b/app/javascript/mastodon/locales/pt-BR.json index eb5d25785..a4d7701ff 100644 --- a/app/javascript/mastodon/locales/pt-BR.json +++ b/app/javascript/mastodon/locales/pt-BR.json @@ -1,4 +1,17 @@ { + "about.blocks": "Moderated servers", + "about.contact": "Contact:", + "about.domain_blocks.comment": "Reason", + "about.domain_blocks.domain": "Domain", + "about.domain_blocks.preamble": "Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.", + "about.domain_blocks.severity": "Severity", + "about.domain_blocks.silenced.explanation": "You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.", + "about.domain_blocks.silenced.title": "Limited", + "about.domain_blocks.suspended.explanation": "No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.", + "about.domain_blocks.suspended.title": "Suspended", + "about.not_available": "This information has not been made available on this server.", + "about.powered_by": "Decentralized social media powered by {mastodon}", + "about.rules": "Server rules", "account.account_note_header": "Nota", "account.add_or_remove_from_list": "Adicionar ou remover de listas", "account.badges.bot": "Robô", @@ -7,13 +20,16 @@ "account.block_domain": "Bloquear domínio {domain}", "account.blocked": "Bloqueado", "account.browse_more_on_origin_server": "Veja mais no perfil original", - "account.cancel_follow_request": "Cancelar solicitação", + "account.cancel_follow_request": "Withdraw follow request", "account.direct": "Enviar toot direto para @{name}", "account.disable_notifications": "Cancelar notificações de @{name}", "account.domain_blocked": "Domínio bloqueado", "account.edit_profile": "Editar perfil", "account.enable_notifications": "Notificar novos toots de @{name}", "account.endorse": "Recomendar", + "account.featured_tags.last_status_at": "Last post on {date}", + "account.featured_tags.last_status_never": "No posts", + "account.featured_tags.title": "{name}'s featured hashtags", "account.follow": "Seguir", "account.followers": "Seguidores", "account.followers.empty": "Nada aqui.", @@ -23,7 +39,7 @@ "account.follows.empty": "Nada aqui.", "account.follows_you": "te segue", "account.hide_reblogs": "Ocultar boosts de @{name}", - "account.joined": "Entrou em {date}", + "account.joined_short": "Joined", "account.languages": "Change subscribed languages", "account.link_verified_on": "link verificado em {date}", "account.locked_info": "Trancado. Seguir requer aprovação manual do perfil.", @@ -63,12 +79,24 @@ "audio.hide": "Hide audio", "autosuggest_hashtag.per_week": "{count} por semana", "boost_modal.combo": "Pressione {combo} para pular isso na próxima vez", - "bundle_column_error.body": "Erro ao carregar este componente.", + "bundle_column_error.copy_stacktrace": "Copy error report", + "bundle_column_error.error.body": "The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.", + "bundle_column_error.error.title": "Oh, no!", + "bundle_column_error.network.body": "There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.", + "bundle_column_error.network.title": "Network error", "bundle_column_error.retry": "Tente novamente", - "bundle_column_error.title": "Erro de rede", + "bundle_column_error.return": "Go back home", + "bundle_column_error.routing.body": "The requested page could not be found. Are you sure the URL in the address bar is correct?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Fechar", "bundle_modal_error.message": "Erro ao carregar este componente.", "bundle_modal_error.retry": "Tente novamente", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "About", "column.blocks": "Usuários bloqueados", "column.bookmarks": "Salvos", "column.community": "Linha local", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "Bloquear e denunciar", "confirmations.block.confirm": "Bloquear", "confirmations.block.message": "Você tem certeza de que deseja bloquear {name}?", + "confirmations.cancel_follow_request.confirm": "Withdraw request", + "confirmations.cancel_follow_request.message": "Are you sure you want to withdraw your request to follow {name}?", "confirmations.delete.confirm": "Excluir", "confirmations.delete.message": "Você tem certeza de que deseja excluir este toot?", "confirmations.delete_list.confirm": "Excluir", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Marcar como lida", "conversation.open": "Ver conversa", "conversation.with": "Com {names}", + "copypaste.copied": "Copied", + "copypaste.copy": "Copy", "directory.federated": "Do fediverso conhecido", "directory.local": "Somente de {domain}", "directory.new_arrivals": "Acabaram de chegar", "directory.recently_active": "Ativos recentemente", + "dismissable_banner.community_timeline": "These are the most recent public posts from people whose accounts are hosted by {domain}.", + "dismissable_banner.dismiss": "Dismiss", + "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", + "dismissable_banner.explore_statuses": "These posts from this and other servers in the decentralized network are gaining traction on this server right now.", + "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", + "dismissable_banner.public_timeline": "These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.", "embed.instructions": "Incorpore este toot no seu site ao copiar o código abaixo.", "embed.preview": "Aqui está como vai ficar:", "emoji_button.activity": "Atividade", @@ -221,14 +259,14 @@ "follow_request.reject": "Recusar", "follow_requests.unlocked_explanation": "Apesar de seu perfil não ser trancado, {domain} exige que você revise a solicitação para te seguir destes perfis manualmente.", "generic.saved": "Salvo", - "getting_started.developers": "Desenvolvedores", - "getting_started.directory": "Centro de usuários", + "getting_started.directory": "Directory", "getting_started.documentation": "Documentação", + "getting_started.free_software_notice": "Mastodon is free, open source software. You can view the source code, contribute or report issues at {repository}.", "getting_started.heading": "Primeiros passos", "getting_started.invite": "Convidar pessoas", - "getting_started.open_source_notice": "Mastodon é um software de código aberto. Você pode contribuir ou reportar problemas na página do projeto no GitHub em {github}.", "getting_started.privacy_policy": "Privacy Policy", "getting_started.security": "Configurações da conta", + "getting_started.what_is_mastodon": "About Mastodon", "hashtag.column_header.tag_mode.all": "e {additional}", "hashtag.column_header.tag_mode.any": "ou {additional}", "hashtag.column_header.tag_mode.none": "sem {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Mostrar respostas", "home.hide_announcements": "Ocultar comunicados", "home.show_announcements": "Mostrar comunicados", + "interaction_modal.description.favourite": "With an account on Mastodon, you can favourite this post to let the author know you appreciate it and save it for later.", + "interaction_modal.description.follow": "With an account on Mastodon, you can follow {name} to receive their posts in your home feed.", + "interaction_modal.description.reblog": "With an account on Mastodon, you can boost this post to share it with your own followers.", + "interaction_modal.description.reply": "With an account on Mastodon, you can respond to this post.", + "interaction_modal.on_another_server": "On a different server", + "interaction_modal.on_this_server": "On this server", + "interaction_modal.other_server_instructions": "Simply copy and paste this URL into the search bar of your favourite app or the web interface where you are signed in.", + "interaction_modal.preamble": "Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one.", + "interaction_modal.title.favourite": "Favourite {name}'s post", + "interaction_modal.title.follow": "Follow {name}", + "interaction_modal.title.reblog": "Boost {name}'s post", + "interaction_modal.title.reply": "Reply to {name}'s post", "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}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Duração", "mute_modal.hide_notifications": "Ocultar notificações deste usuário?", "mute_modal.indefinite": "Indefinido", - "navigation_bar.apps": "Aplicativos", + "navigation_bar.about": "About", + "navigation_bar.apps": "Get the app", "navigation_bar.blocks": "Usuários bloqueados", "navigation_bar.bookmarks": "Salvos", "navigation_bar.community_timeline": "Linha do tempo local", @@ -324,7 +375,7 @@ "navigation_bar.filters": "Palavras filtradas", "navigation_bar.follow_requests": "Seguidores pendentes", "navigation_bar.follows_and_followers": "Segue e seguidores", - "navigation_bar.info": "Sobre este servidor", + "navigation_bar.info": "About", "navigation_bar.keyboard_shortcuts": "Atalhos de teclado", "navigation_bar.lists": "Listas", "navigation_bar.logout": "Sair", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Toots fixados", "navigation_bar.preferences": "Preferências", "navigation_bar.public_timeline": "Linha global", + "navigation_bar.search": "Search", "navigation_bar.security": "Segurança", + "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", "notification.admin.report": "{name} denunciou {target}", "notification.admin.sign_up": "{name} se inscreveu", "notification.favourite": "{name} favoritou teu toot", @@ -401,6 +454,8 @@ "privacy.public.short": "Público", "privacy.unlisted.long": "Visível para todos, mas desativou os recursos de descoberta", "privacy.unlisted.short": "Não-listado", + "privacy_policy.last_updated": "Last updated {date}", + "privacy_policy.title": "Privacy Policy", "refresh": "Atualizar", "regeneration_indicator.label": "Carregando…", "regeneration_indicator.sublabel": "Sua página inicial está sendo preparada!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "Pesquisar toots por seu conteúdo não está ativado nesta instância Mastodon.", "search_results.title": "Search for {q}", "search_results.total": "{count, number} {count, plural, one {resultado} other {resultados}}", + "server_banner.about_active_users": "People using this server during the last 30 days (Monthly Active Users)", + "server_banner.active_users": "active users", + "server_banner.administered_by": "Administered by:", + "server_banner.introduction": "{domain} is part of the decentralized social network powered by {mastodon}.", + "server_banner.learn_more": "Learn more", + "server_banner.server_stats": "Server stats:", "sign_in_banner.create_account": "Create account", "sign_in_banner.sign_in": "Sign in", "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "Nada aqui. Quando alguém der boost, o usuário aparecerá aqui.", "status.redraft": "Excluir e rascunhar", "status.remove_bookmark": "Remover do Salvos", + "status.replied_to": "Replied to {name}", "status.reply": "Responder", "status.replyAll": "Responder a conversa", "status.report": "Denunciar @{name}", @@ -523,9 +585,8 @@ "status.show_more": "Mostrar mais", "status.show_more_all": "Mostrar mais em tudo", "status.show_original": "Show original", - "status.show_thread": "Mostrar conversa", "status.translate": "Translate", - "status.translated_from": "Translated from {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Não disponível", "status.unmute_conversation": "Dessilenciar conversa", "status.unpin": "Desafixar", @@ -538,7 +599,6 @@ "tabs_bar.home": "Página inicial", "tabs_bar.local_timeline": "Linha local", "tabs_bar.notifications": "Notificações", - "tabs_bar.search": "Pesquisar", "time_remaining.days": "{number, plural, one {# dia restante} other {# dias restantes}}", "time_remaining.hours": "{number, plural, one {# hora restante} other {# horas restantes}}", "time_remaining.minutes": "{number, plural, one {# minuto restante} other {# minutos restantes}}", diff --git a/app/javascript/mastodon/locales/pt-PT.json b/app/javascript/mastodon/locales/pt-PT.json index 654588545..ef8f4f086 100644 --- a/app/javascript/mastodon/locales/pt-PT.json +++ b/app/javascript/mastodon/locales/pt-PT.json @@ -1,4 +1,17 @@ { + "about.blocks": "Servidores moderados", + "about.contact": "Contacto:", + "about.domain_blocks.comment": "Motivo", + "about.domain_blocks.domain": "Domínio", + "about.domain_blocks.preamble": "Mastodon geralmente permite que veja e interaja com o conteúdo de utilizadores de qualquer outra instância no fediverso. Estas são as exceções desta instância em específico.", + "about.domain_blocks.severity": "Severidade", + "about.domain_blocks.silenced.explanation": "Geralmente não verá perfis e conteúdo deste servidor, a menos que os procure explicitamente ou opte por os seguir.", + "about.domain_blocks.silenced.title": "Limitados", + "about.domain_blocks.suspended.explanation": "Nenhum dado dessas instâncias será processado, armazenado ou trocado, tornando qualquer interação ou comunicação com os utilizadores dessas instâncias impossível.", + "about.domain_blocks.suspended.title": "Supensos", + "about.not_available": "Esta informação não foi disponibilizada neste servidor.", + "about.powered_by": "Rede social descentralizada baseada no {mastodon}", + "about.rules": "Regras da instância", "account.account_note_header": "Nota", "account.add_or_remove_from_list": "Adicionar ou remover das listas", "account.badges.bot": "Robô", @@ -7,13 +20,16 @@ "account.block_domain": "Esconder tudo do domínio {domain}", "account.blocked": "Bloqueado(a)", "account.browse_more_on_origin_server": "Encontrar mais no perfil original", - "account.cancel_follow_request": "Cancelar pedido para seguir", + "account.cancel_follow_request": "Retirar pedido para seguir", "account.direct": "Enviar mensagem direta para @{name}", "account.disable_notifications": "Parar de me notificar das publicações de @{name}", "account.domain_blocked": "Domínio bloqueado", "account.edit_profile": "Editar perfil", "account.enable_notifications": "Notificar-me das publicações de @{name}", "account.endorse": "Destacar no perfil", + "account.featured_tags.last_status_at": "Última publicação em {date}", + "account.featured_tags.last_status_never": "Sem publicações", + "account.featured_tags.title": "Hashtags destacadas por {name}", "account.follow": "Seguir", "account.followers": "Seguidores", "account.followers.empty": "Ainda ninguém segue este utilizador.", @@ -23,7 +39,7 @@ "account.follows.empty": "Este utilizador ainda não segue ninguém.", "account.follows_you": "Segue-te", "account.hide_reblogs": "Esconder partilhas de @{name}", - "account.joined": "Ingressou em {date}", + "account.joined_short": "Joined", "account.languages": "Alterar idiomas subscritos", "account.link_verified_on": "A posse deste link foi verificada em {date}", "account.locked_info": "Esta conta é privada. O proprietário revê manualmente quem a pode seguir.", @@ -63,12 +79,24 @@ "audio.hide": "Ocultar áudio", "autosuggest_hashtag.per_week": "{count} por semana", "boost_modal.combo": "Pode clicar {combo} para não voltar a ver", - "bundle_column_error.body": "Algo de errado aconteceu enquanto este componente era carregado.", + "bundle_column_error.copy_stacktrace": "Copiar relatório de erros", + "bundle_column_error.error.body": "A página solicitada não pôde ser renderizada. Isto pode ser devido a uma falha no nosso código ou a um problema de compatibilidade com o navegador.", + "bundle_column_error.error.title": "Oh, não!", + "bundle_column_error.network.body": "Houve um erro ao tentar carregar esta página. Isto pode ocorrer devido a um problema temporário com a sua conexão à internet ou a este servidor.", + "bundle_column_error.network.title": "Erro de rede", "bundle_column_error.retry": "Tente de novo", - "bundle_column_error.title": "Erro de rede", + "bundle_column_error.return": "Voltar à página inicial", + "bundle_column_error.routing.body": "A página solicitada não foi encontrada. Tem a certeza que o URL na barra de endereços está correto?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Fechar", "bundle_modal_error.message": "Algo de errado aconteceu enquanto este componente era carregado.", "bundle_modal_error.retry": "Tente de novo", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "Sobre", "column.blocks": "Utilizadores Bloqueados", "column.bookmarks": "Itens salvos", "column.community": "Cronologia local", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "Bloquear e Denunciar", "confirmations.block.confirm": "Bloquear", "confirmations.block.message": "De certeza que queres bloquear {name}?", + "confirmations.cancel_follow_request.confirm": "Retirar pedido", + "confirmations.cancel_follow_request.message": "Tem a certeza que pretende retirar o pedido para seguir {name}?", "confirmations.delete.confirm": "Eliminar", "confirmations.delete.message": "De certeza que quer eliminar esta publicação?", "confirmations.delete_list.confirm": "Eliminar", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Marcar como lida", "conversation.open": "Ver conversa", "conversation.with": "Com {names}", + "copypaste.copied": "Copiado", + "copypaste.copy": "Copiar", "directory.federated": "Do fediverso conhecido", "directory.local": "Apenas de {domain}", "directory.new_arrivals": "Recém chegados", "directory.recently_active": "Com actividade recente", + "dismissable_banner.community_timeline": "Estas são as publicações públicas mais recentes de pessoas cujas contas são hospedadas por {domain}.", + "dismissable_banner.dismiss": "Descartar", + "dismissable_banner.explore_links": "Essas histórias de notícias estão, no momento, a ser faladas por pessoas neste e noutros servidores da rede descentralizada.", + "dismissable_banner.explore_statuses": "Estas publicações, deste e de outros servidores na rede descentralizada, estão, neste momento, a ganhar atenção neste servidor.", + "dismissable_banner.explore_tags": "Estas hashtags estão, neste momento, a ganhar atenção entre as pessoas neste e outros servidores da rede descentralizada.", + "dismissable_banner.public_timeline": "Estas são as publicações públicas mais recentes de pessoas neste e outros servidores da rede descentralizada que esse servidor conhece.", "embed.instructions": "Incorpore esta publicação no seu site copiando o código abaixo.", "embed.preview": "Podes ver aqui como irá ficar:", "emoji_button.activity": "Actividade", @@ -221,14 +259,14 @@ "follow_request.reject": "Rejeitar", "follow_requests.unlocked_explanation": "Apesar de a sua não ser privada, a administração de {domain} pensa que poderá querer rever manualmente os pedidos de seguimento dessas contas.", "generic.saved": "Salvo", - "getting_started.developers": "Responsáveis pelo desenvolvimento", - "getting_started.directory": "Diretório de perfis", + "getting_started.directory": "Diretório", "getting_started.documentation": "Documentação", + "getting_started.free_software_notice": "O Mastodon é um software gratuito, de código aberto. Pode ver o código-fonte, contribuir ou reportar problemas em {repository}.", "getting_started.heading": "Primeiros passos", "getting_started.invite": "Convidar pessoas", - "getting_started.open_source_notice": "Mastodon é um software de código aberto. Podes contribuir ou reportar problemas no GitHub do projeto: {github}.", "getting_started.privacy_policy": "Política de Privacidade", "getting_started.security": "Segurança", + "getting_started.what_is_mastodon": "Sobre Mastodon", "hashtag.column_header.tag_mode.all": "e {additional}", "hashtag.column_header.tag_mode.any": "ou {additional}", "hashtag.column_header.tag_mode.none": "sem {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Mostrar respostas", "home.hide_announcements": "Ocultar anúncios", "home.show_announcements": "Exibir anúncios", + "interaction_modal.description.favourite": "Com uma conta no Mastodon, pode adicionar esta publicação aos favoritos para que o autor saiba que gostou e salvá-la para mais tarde.", + "interaction_modal.description.follow": "Com uma conta no Mastodon, pode seguir {name} para receber as suas publicações na sua página inicial.", + "interaction_modal.description.reblog": "Com uma conta no Mastodon, pode impulsionar esta publicação para compartilhá-lo com os seus seguidores.", + "interaction_modal.description.reply": "Com uma conta no Mastodon, pode responder a esta publicação.", + "interaction_modal.on_another_server": "Num servidor diferente", + "interaction_modal.on_this_server": "Neste servidor", + "interaction_modal.other_server_instructions": "Basta copiar e colar este URL na barra de pesquisa do seu aplicativo favorito ou na interface web onde está conectado.", + "interaction_modal.preamble": "Uma vez que o Mastodon é descentralizado, pode utilizar a sua conta existente, hospedada em outro servidor Mastodon ou plataforma compatível, se não tiver uma conta neste servidor.", + "interaction_modal.title.favourite": "Adicionar a publicação de {name} aos favoritos", + "interaction_modal.title.follow": "Seguir {name}", + "interaction_modal.title.reblog": "Impulsionar a publicação de {name}", + "interaction_modal.title.reply": "Responder à publicação de {name}", "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}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Duração", "mute_modal.hide_notifications": "Esconder notificações deste utilizador?", "mute_modal.indefinite": "Indefinidamente", - "navigation_bar.apps": "Aplicações móveis", + "navigation_bar.about": "Sobre", + "navigation_bar.apps": "Obtém a aplicação", "navigation_bar.blocks": "Utilizadores bloqueados", "navigation_bar.bookmarks": "Itens salvos", "navigation_bar.community_timeline": "Cronologia local", @@ -324,7 +375,7 @@ "navigation_bar.filters": "Palavras silenciadas", "navigation_bar.follow_requests": "Seguidores pendentes", "navigation_bar.follows_and_followers": "Seguindo e seguidores", - "navigation_bar.info": "Sobre esta instância", + "navigation_bar.info": "Sobre", "navigation_bar.keyboard_shortcuts": "Atalhos de teclado", "navigation_bar.lists": "Listas", "navigation_bar.logout": "Sair", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Toots afixados", "navigation_bar.preferences": "Preferências", "navigation_bar.public_timeline": "Cronologia federada", + "navigation_bar.search": "Search", "navigation_bar.security": "Segurança", + "not_signed_in_indicator.not_signed_in": "Necessita de iniciar sessão para utilizar esta funcionalidade.", "notification.admin.report": "{name} denunciou {target}", "notification.admin.sign_up": "{name} inscreveu-se", "notification.favourite": "{name} adicionou a tua publicação aos favoritos", @@ -401,6 +454,8 @@ "privacy.public.short": "Público", "privacy.unlisted.long": "Visível para todos, mas não incluir em funcionalidades de divulgação", "privacy.unlisted.short": "Não listar", + "privacy_policy.last_updated": "Última atualização em {date}", + "privacy_policy.title": "Política de Privacidade", "refresh": "Actualizar", "regeneration_indicator.label": "A carregar…", "regeneration_indicator.sublabel": "A tua página inicial está a ser preparada!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "A pesquisa de toots pelo seu conteúdo não está disponível nesta instância Mastodon.", "search_results.title": "Pesquisar por {q}", "search_results.total": "{count, number} {count, plural, one {resultado} other {resultados}}", + "server_banner.about_active_users": "Pessoas que utilizaram este servidor nos últimos 30 dias (Utilizadores Ativos Mensais)", + "server_banner.active_users": "utilizadores ativos", + "server_banner.administered_by": "Administrado por:", + "server_banner.introduction": "{domain} faz parte da rede social descentralizada baseada no {mastodon}.", + "server_banner.learn_more": "Saber mais", + "server_banner.server_stats": "Estatísticas do servidor:", "sign_in_banner.create_account": "Criar conta", "sign_in_banner.sign_in": "Iniciar sessão", "sign_in_banner.text": "Inicie sessão para seguir perfis ou hashtags, favoritos, partilhar e responder às publicações ou interagir através da sua conta noutro servidor.", @@ -512,6 +573,7 @@ "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.remove_bookmark": "Remover dos itens salvos", + "status.replied_to": "Replied to {name}", "status.reply": "Responder", "status.replyAll": "Responder à conversa", "status.report": "Denunciar @{name}", @@ -523,9 +585,8 @@ "status.show_more": "Mostrar mais", "status.show_more_all": "Mostrar mais para todas", "status.show_original": "Mostrar original", - "status.show_thread": "Mostrar conversa", "status.translate": "Traduzir", - "status.translated_from": "Traduzido de {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Não disponível", "status.unmute_conversation": "Deixar de silenciar esta conversa", "status.unpin": "Não fixar no perfil", @@ -538,7 +599,6 @@ "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", diff --git a/app/javascript/mastodon/locales/ro.json b/app/javascript/mastodon/locales/ro.json index 2ecc84218..06f28fb49 100644 --- a/app/javascript/mastodon/locales/ro.json +++ b/app/javascript/mastodon/locales/ro.json @@ -1,4 +1,17 @@ { + "about.blocks": "Moderated servers", + "about.contact": "Contact:", + "about.domain_blocks.comment": "Reason", + "about.domain_blocks.domain": "Domain", + "about.domain_blocks.preamble": "Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.", + "about.domain_blocks.severity": "Severity", + "about.domain_blocks.silenced.explanation": "You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.", + "about.domain_blocks.silenced.title": "Limited", + "about.domain_blocks.suspended.explanation": "No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.", + "about.domain_blocks.suspended.title": "Suspended", + "about.not_available": "This information has not been made available on this server.", + "about.powered_by": "Decentralized social media powered by {mastodon}", + "about.rules": "Server rules", "account.account_note_header": "Notă", "account.add_or_remove_from_list": "Adaugă sau elimină din liste", "account.badges.bot": "Robot", @@ -7,13 +20,16 @@ "account.block_domain": "Blochează domeniul {domain}", "account.blocked": "Blocat", "account.browse_more_on_origin_server": "Vezi mai multe pe profilul original", - "account.cancel_follow_request": "Anulează cererea de abonare", + "account.cancel_follow_request": "Withdraw follow request", "account.direct": "Trimite-i un mesaj direct lui @{name}", "account.disable_notifications": "Nu îmi mai trimite notificări când postează @{name}", "account.domain_blocked": "Domeniu blocat", "account.edit_profile": "Modifică profilul", "account.enable_notifications": "Trimite-mi o notificare când postează @{name}", "account.endorse": "Promovează pe profil", + "account.featured_tags.last_status_at": "Last post on {date}", + "account.featured_tags.last_status_never": "No posts", + "account.featured_tags.title": "{name}'s featured hashtags", "account.follow": "Abonează-te", "account.followers": "Abonați", "account.followers.empty": "Acest utilizator încă nu are abonați.", @@ -23,7 +39,7 @@ "account.follows.empty": "Momentan acest utilizator nu are niciun abonament.", "account.follows_you": "Este abonat la tine", "account.hide_reblogs": "Ascunde distribuirile de la @{name}", - "account.joined": "S-a înscris în {date}", + "account.joined_short": "Joined", "account.languages": "Change subscribed languages", "account.link_verified_on": "Proprietatea acestui link a fost verificată pe {date}", "account.locked_info": "Acest profil este privat. Această persoană aprobă manual conturile care se abonează la ea.", @@ -63,12 +79,24 @@ "audio.hide": "Hide audio", "autosuggest_hashtag.per_week": "{count} pe săptămână", "boost_modal.combo": "Poți apăsa {combo} pentru a sări peste asta data viitoare", - "bundle_column_error.body": "A apărut o eroare la încărcarea acestui element.", + "bundle_column_error.copy_stacktrace": "Copy error report", + "bundle_column_error.error.body": "The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.", + "bundle_column_error.error.title": "Oh, no!", + "bundle_column_error.network.body": "There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.", + "bundle_column_error.network.title": "Network error", "bundle_column_error.retry": "Încearcă din nou", - "bundle_column_error.title": "Eroare de rețea", + "bundle_column_error.return": "Go back home", + "bundle_column_error.routing.body": "The requested page could not be found. Are you sure the URL in the address bar is correct?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Închide", "bundle_modal_error.message": "A apărut o eroare la încărcarea acestui element.", "bundle_modal_error.retry": "Încearcă din nou", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "About", "column.blocks": "Utilizatori blocați", "column.bookmarks": "Marcaje", "column.community": "Cronologie locală", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "Blochează și raportează", "confirmations.block.confirm": "Blochează", "confirmations.block.message": "Ești sigur că vrei să blochezi pe {name}?", + "confirmations.cancel_follow_request.confirm": "Withdraw request", + "confirmations.cancel_follow_request.message": "Are you sure you want to withdraw your request to follow {name}?", "confirmations.delete.confirm": "Elimină", "confirmations.delete.message": "Ești sigur că vrei să elimini această postare?", "confirmations.delete_list.confirm": "Elimină", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Marchează ca citit", "conversation.open": "Vizualizează conversația", "conversation.with": "Cu {names}", + "copypaste.copied": "Copied", + "copypaste.copy": "Copy", "directory.federated": "Din fediversul cunoscut", "directory.local": "Doar din {domain}", "directory.new_arrivals": "Înscriși recent", "directory.recently_active": "Activi recent", + "dismissable_banner.community_timeline": "These are the most recent public posts from people whose accounts are hosted by {domain}.", + "dismissable_banner.dismiss": "Dismiss", + "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", + "dismissable_banner.explore_statuses": "These posts from this and other servers in the decentralized network are gaining traction on this server right now.", + "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", + "dismissable_banner.public_timeline": "These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.", "embed.instructions": "Integrează această postare în site-ul tău copiind codul de mai jos.", "embed.preview": "Iată cum va arăta:", "emoji_button.activity": "Activități", @@ -221,14 +259,14 @@ "follow_request.reject": "Respinge", "follow_requests.unlocked_explanation": "Chiar dacă contul tău nu este blocat, personalul {domain} a considerat că ai putea prefera să consulți manual cererile de abonare de la aceste conturi.", "generic.saved": "Salvat", - "getting_started.developers": "Dezvoltatori", - "getting_started.directory": "Catalog de profiluri", + "getting_started.directory": "Directory", "getting_started.documentation": "Documentație", + "getting_started.free_software_notice": "Mastodon is free, open source software. You can view the source code, contribute or report issues at {repository}.", "getting_started.heading": "Primii pași", "getting_started.invite": "Invită persoane", - "getting_started.open_source_notice": "Mastodon este un software cu sursă deschisă (open source). Poți contribui la dezvoltarea lui sau raporta probleme pe GitHub la {github}.", "getting_started.privacy_policy": "Privacy Policy", "getting_started.security": "Setări cont", + "getting_started.what_is_mastodon": "About Mastodon", "hashtag.column_header.tag_mode.all": "și {additional}", "hashtag.column_header.tag_mode.any": "sau {additional}", "hashtag.column_header.tag_mode.none": "fără {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Afișează răspunsurile", "home.hide_announcements": "Ascunde anunțurile", "home.show_announcements": "Afișează anunțurile", + "interaction_modal.description.favourite": "With an account on Mastodon, you can favourite this post to let the author know you appreciate it and save it for later.", + "interaction_modal.description.follow": "With an account on Mastodon, you can follow {name} to receive their posts in your home feed.", + "interaction_modal.description.reblog": "With an account on Mastodon, you can boost this post to share it with your own followers.", + "interaction_modal.description.reply": "With an account on Mastodon, you can respond to this post.", + "interaction_modal.on_another_server": "On a different server", + "interaction_modal.on_this_server": "On this server", + "interaction_modal.other_server_instructions": "Simply copy and paste this URL into the search bar of your favourite app or the web interface where you are signed in.", + "interaction_modal.preamble": "Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one.", + "interaction_modal.title.favourite": "Favourite {name}'s post", + "interaction_modal.title.follow": "Follow {name}", + "interaction_modal.title.reblog": "Boost {name}'s post", + "interaction_modal.title.reply": "Reply to {name}'s post", "intervals.full.days": "{number, plural,one {# zi} other {# zile}}", "intervals.full.hours": "{number, plural, one {# oră} other {# ore}}", "intervals.full.minutes": "{number, plural, one {# minut} other {# minute}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Durata", "mute_modal.hide_notifications": "Ascunde notificările de la acest utilizator?", "mute_modal.indefinite": "Nedeterminat", - "navigation_bar.apps": "Aplicații mobile", + "navigation_bar.about": "About", + "navigation_bar.apps": "Get the app", "navigation_bar.blocks": "Utilizatori blocați", "navigation_bar.bookmarks": "Marcaje", "navigation_bar.community_timeline": "Cronologie locală", @@ -324,7 +375,7 @@ "navigation_bar.filters": "Cuvinte ignorate", "navigation_bar.follow_requests": "Cereri de abonare", "navigation_bar.follows_and_followers": "Abonamente și abonați", - "navigation_bar.info": "Despre această instanță", + "navigation_bar.info": "About", "navigation_bar.keyboard_shortcuts": "Taste rapide", "navigation_bar.lists": "Liste", "navigation_bar.logout": "Deconectare", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Postări fixate", "navigation_bar.preferences": "Preferințe", "navigation_bar.public_timeline": "Cronologie globală", + "navigation_bar.search": "Search", "navigation_bar.security": "Securitate", + "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", "notification.admin.report": "{name} reported {target}", "notification.admin.sign_up": "{name} signed up", "notification.favourite": "{name} a adăugat postarea ta la favorite", @@ -401,6 +454,8 @@ "privacy.public.short": "Public", "privacy.unlisted.long": "Visible for all, but opted-out of discovery features", "privacy.unlisted.short": "Nelistat", + "privacy_policy.last_updated": "Last updated {date}", + "privacy_policy.title": "Privacy Policy", "refresh": "Reîncarcă", "regeneration_indicator.label": "Se încarcă…", "regeneration_indicator.sublabel": "Cronologia ta principală este în curs de pregătire!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "Căutarea de postări după conținutul lor nu este activată pe acest server.", "search_results.title": "Search for {q}", "search_results.total": "{count, number} {count, plural, one {rezultat} other {rezultate}}", + "server_banner.about_active_users": "People using this server during the last 30 days (Monthly Active Users)", + "server_banner.active_users": "active users", + "server_banner.administered_by": "Administered by:", + "server_banner.introduction": "{domain} is part of the decentralized social network powered by {mastodon}.", + "server_banner.learn_more": "Learn more", + "server_banner.server_stats": "Server stats:", "sign_in_banner.create_account": "Create account", "sign_in_banner.sign_in": "Sign in", "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "Nimeni nu a impulsionat această postare până acum. Când cineva o va face, va apărea aici.", "status.redraft": "Șterge și adaugă la ciorne", "status.remove_bookmark": "Îndepărtează marcajul", + "status.replied_to": "Replied to {name}", "status.reply": "Răspunde", "status.replyAll": "Răspunde la discuție", "status.report": "Raportează pe @{name}", @@ -523,9 +585,8 @@ "status.show_more": "Arată mai mult", "status.show_more_all": "Arată mai mult pentru toți", "status.show_original": "Show original", - "status.show_thread": "Arată discuția", "status.translate": "Translate", - "status.translated_from": "Translated from {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Indisponibil", "status.unmute_conversation": "Repornește conversația", "status.unpin": "Eliberează din profil", @@ -538,7 +599,6 @@ "tabs_bar.home": "Acasă", "tabs_bar.local_timeline": "Local", "tabs_bar.notifications": "Notificări", - "tabs_bar.search": "Căutare", "time_remaining.days": "{number, plural, one {# zi} other {# zile}} rămase", "time_remaining.hours": "{number, plural, one {# oră} other {# ore}} rămase", "time_remaining.minutes": "{number, plural, one {# minut} other {# minute}} rămase", diff --git a/app/javascript/mastodon/locales/ru.json b/app/javascript/mastodon/locales/ru.json index 94bcc854a..2ed3d7b45 100644 --- a/app/javascript/mastodon/locales/ru.json +++ b/app/javascript/mastodon/locales/ru.json @@ -1,4 +1,17 @@ { + "about.blocks": "Модерируемые серверы", + "about.contact": "Контакты:", + "about.domain_blocks.comment": "Причина", + "about.domain_blocks.domain": "Домен", + "about.domain_blocks.preamble": "Mastodon обычно позволяет просматривать содержимое и взаимодействовать с другими пользователями любых серверов в Федиверсе. Вот исключения, сделанные конкретно для этого сервера.", + "about.domain_blocks.severity": "Severity", + "about.domain_blocks.silenced.explanation": "You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.", + "about.domain_blocks.silenced.title": "Limited", + "about.domain_blocks.suspended.explanation": "No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.", + "about.domain_blocks.suspended.title": "Suspended", + "about.not_available": "This information has not been made available on this server.", + "about.powered_by": "Децентрализованные социальные сети на базе {mastodon}", + "about.rules": "Правила сервера", "account.account_note_header": "Заметка", "account.add_or_remove_from_list": "Управление списками", "account.badges.bot": "Бот", @@ -7,13 +20,16 @@ "account.block_domain": "Заблокировать {domain}", "account.blocked": "Заблокирован(а)", "account.browse_more_on_origin_server": "Посмотреть в оригинальном профиле", - "account.cancel_follow_request": "Отменить подписку", + "account.cancel_follow_request": "Withdraw follow request", "account.direct": "Написать @{name}", "account.disable_notifications": "Не уведомлять о постах от @{name}", "account.domain_blocked": "Домен заблокирован", "account.edit_profile": "Редактировать профиль", "account.enable_notifications": "Уведомлять о постах от @{name}", "account.endorse": "Рекомендовать в профиле", + "account.featured_tags.last_status_at": "Last post on {date}", + "account.featured_tags.last_status_never": "No posts", + "account.featured_tags.title": "{name}'s featured hashtags", "account.follow": "Подписаться", "account.followers": "Подписчики", "account.followers.empty": "На этого пользователя пока никто не подписан.", @@ -23,7 +39,7 @@ "account.follows.empty": "Этот пользователь пока ни на кого не подписался.", "account.follows_you": "Подписан(а) на вас", "account.hide_reblogs": "Скрыть продвижения от @{name}", - "account.joined": "Зарегистрирован(а) с {date}", + "account.joined_short": "Joined", "account.languages": "Изменить языки подписки", "account.link_verified_on": "Владение этой ссылкой было проверено {date}", "account.locked_info": "Это закрытый аккаунт. Его владелец вручную одобряет подписчиков.", @@ -63,12 +79,24 @@ "audio.hide": "Скрыть аудио", "autosuggest_hashtag.per_week": "{count} / неделю", "boost_modal.combo": "{combo}, чтобы пропустить это в следующий раз", - "bundle_column_error.body": "Что-то пошло не так при загрузке этого компонента.", + "bundle_column_error.copy_stacktrace": "Скопировать отчет об ошибке", + "bundle_column_error.error.body": "Запрошенная страница не может быть отображена. Это может быть вызвано ошибкой в нашем коде или проблемой совместимости браузера.", + "bundle_column_error.error.title": "О нет!", + "bundle_column_error.network.body": "There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.", + "bundle_column_error.network.title": "Ошибка сети", "bundle_column_error.retry": "Попробовать снова", - "bundle_column_error.title": "Ошибка сети", + "bundle_column_error.return": "Вернуться на главную", + "bundle_column_error.routing.body": "Запрошенная страница не найдена. Вы уверены, что URL в адресной строке правильный?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Закрыть", "bundle_modal_error.message": "Что-то пошло не так при загрузке этого компонента.", "bundle_modal_error.retry": "Попробовать снова", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "About", "column.blocks": "Заблокированные пользователи", "column.bookmarks": "Закладки", "column.community": "Локальная лента", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "Заблокировать и пожаловаться", "confirmations.block.confirm": "Заблокировать", "confirmations.block.message": "Вы уверены, что хотите заблокировать {name}?", + "confirmations.cancel_follow_request.confirm": "Withdraw request", + "confirmations.cancel_follow_request.message": "Are you sure you want to withdraw your request to follow {name}?", "confirmations.delete.confirm": "Удалить", "confirmations.delete.message": "Вы уверены, что хотите удалить этот пост?", "confirmations.delete_list.confirm": "Удалить", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Отметить как прочитанное", "conversation.open": "Просмотр беседы", "conversation.with": "С {names}", + "copypaste.copied": "Скопировано", + "copypaste.copy": "Скопировать", "directory.federated": "Со всей федерации", "directory.local": "Только с {domain}", "directory.new_arrivals": "Новички", "directory.recently_active": "Недавно активные", + "dismissable_banner.community_timeline": "Это самые последние публичные сообщения от людей, чьи учетные записи размещены в {domain}.", + "dismissable_banner.dismiss": "Dismiss", + "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", + "dismissable_banner.explore_statuses": "These posts from this and other servers in the decentralized network are gaining traction on this server right now.", + "dismissable_banner.explore_tags": "Эти хэштеги привлекают людей на этом и других серверах децентрализованной сети прямо сейчас.", + "dismissable_banner.public_timeline": "These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.", "embed.instructions": "Встройте этот пост на свой сайт, скопировав следующий код:", "embed.preview": "Так это будет выглядеть:", "emoji_button.activity": "Занятия", @@ -221,14 +259,14 @@ "follow_request.reject": "Отказать", "follow_requests.unlocked_explanation": "Этот запрос отправлен с учётной записи, для которой администрация {domain} включила ручную проверку подписок.", "generic.saved": "Сохранено", - "getting_started.developers": "Разработчикам", - "getting_started.directory": "Каталог профилей", + "getting_started.directory": "Каталог", "getting_started.documentation": "Документация", + "getting_started.free_software_notice": "Mastodon — это бесплатное программное обеспечение с открытым исходным кодом. Вы можете посмотреть исходный код, внести свой вклад или сообщить о проблемах в {repository}.", "getting_started.heading": "Начать", "getting_started.invite": "Пригласить людей", - "getting_started.open_source_notice": "Mastodon — сервис с открытым исходным кодом. Вы можете внести вклад или сообщить о проблемах на GitHub: {github}.", "getting_started.privacy_policy": "Политика конфиденциальности", "getting_started.security": "Настройки учётной записи", + "getting_started.what_is_mastodon": "О Mastodon", "hashtag.column_header.tag_mode.all": "и {additional}", "hashtag.column_header.tag_mode.any": "или {additional}", "hashtag.column_header.tag_mode.none": "без {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Показывать ответы", "home.hide_announcements": "Скрыть объявления", "home.show_announcements": "Показать объявления", + "interaction_modal.description.favourite": "With an account on Mastodon, you can favourite this post to let the author know you appreciate it and save it for later.", + "interaction_modal.description.follow": "With an account on Mastodon, you can follow {name} to receive their posts in your home feed.", + "interaction_modal.description.reblog": "With an account on Mastodon, you can boost this post to share it with your own followers.", + "interaction_modal.description.reply": "With an account on Mastodon, you can respond to this post.", + "interaction_modal.on_another_server": "На другом сервере", + "interaction_modal.on_this_server": "На этом сервере", + "interaction_modal.other_server_instructions": "Просто скопируйте и вставьте этот URL в строку поиска вашего любимого приложения или веб-интерфейса там, где вы вошли.", + "interaction_modal.preamble": "Поскольку Mastodon децентрализован, вы можете использовать существующую учётную запись, размещенную на другом сервере Mastodon или совместимой платформе, если у вас нет учётной записи на этом сервере.", + "interaction_modal.title.favourite": "Favourite {name}'s post", + "interaction_modal.title.follow": "Подписаться на {name}", + "interaction_modal.title.reblog": "Boost {name}'s post", + "interaction_modal.title.reply": "Reply to {name}'s post", "intervals.full.days": "{number, plural, one {# день} few {# дня} other {# дней}}", "intervals.full.hours": "{number, plural, one {# час} few {# часа} other {# часов}}", "intervals.full.minutes": "{number, plural, one {# минута} few {# минуты} other {# минут}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Продолжительность", "mute_modal.hide_notifications": "Скрыть уведомления от этого пользователя?", "mute_modal.indefinite": "Не определена", - "navigation_bar.apps": "Мобильные приложения", + "navigation_bar.about": "About", + "navigation_bar.apps": "Скачать приложение", "navigation_bar.blocks": "Список блокировки", "navigation_bar.bookmarks": "Закладки", "navigation_bar.community_timeline": "Локальная лента", @@ -324,7 +375,7 @@ "navigation_bar.filters": "Игнорируемые слова", "navigation_bar.follow_requests": "Запросы на подписку", "navigation_bar.follows_and_followers": "Подписки и подписчики", - "navigation_bar.info": "Об узле", + "navigation_bar.info": "About", "navigation_bar.keyboard_shortcuts": "Сочетания клавиш", "navigation_bar.lists": "Списки", "navigation_bar.logout": "Выйти", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Закреплённые посты", "navigation_bar.preferences": "Настройки", "navigation_bar.public_timeline": "Глобальная лента", + "navigation_bar.search": "Search", "navigation_bar.security": "Безопасность", + "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", "notification.admin.report": "{name} сообщил о {target}", "notification.admin.sign_up": "{name} зарегистрирован", "notification.favourite": "{name} добавил(а) ваш пост в избранное", @@ -401,6 +454,8 @@ "privacy.public.short": "Публичный", "privacy.unlisted.long": "Виден всем, но не через функции обзора", "privacy.unlisted.short": "Скрытый", + "privacy_policy.last_updated": "Последнее обновление {date}", + "privacy_policy.title": "Политика конфиденциальности", "refresh": "Обновить", "regeneration_indicator.label": "Загрузка…", "regeneration_indicator.sublabel": "Один момент, мы подготавливаем вашу ленту!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "Поиск постов по их содержанию не поддерживается данным сервером Mastodon.", "search_results.title": "Поиск {q}", "search_results.total": "{count, number} {count, plural, one {результат} few {результата} many {результатов} other {результатов}}", + "server_banner.about_active_users": "People using this server during the last 30 days (Monthly Active Users)", + "server_banner.active_users": "активные пользователи", + "server_banner.administered_by": "Управляется:", + "server_banner.introduction": "{domain} является частью децентрализованной социальной сети, основанной на {mastodon}.", + "server_banner.learn_more": "Узнать больше", + "server_banner.server_stats": "Статистика сервера:", "sign_in_banner.create_account": "Создать учётную запись", "sign_in_banner.sign_in": "Войти", "sign_in_banner.text": "Войдите, чтобы следить за профилями, хэштегами или избранным, делиться сообщениями и отвечать на них или взаимодействовать с вашей учётной записью на другом сервере.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "Никто ещё не продвинул этот пост. Как только кто-то это сделает, они появятся здесь.", "status.redraft": "Удалить и исправить", "status.remove_bookmark": "Убрать из закладок", + "status.replied_to": "Replied to {name}", "status.reply": "Ответить", "status.replyAll": "Ответить всем", "status.report": "Пожаловаться", @@ -523,9 +585,8 @@ "status.show_more": "Развернуть", "status.show_more_all": "Развернуть все спойлеры в ветке", "status.show_original": "Показать оригинал", - "status.show_thread": "Показать обсуждение", "status.translate": "Перевод", - "status.translated_from": "Переведено с {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Невозможно отобразить файл", "status.unmute_conversation": "Не игнорировать обсуждение", "status.unpin": "Открепить от профиля", @@ -538,7 +599,6 @@ "tabs_bar.home": "Главная", "tabs_bar.local_timeline": "Локальная", "tabs_bar.notifications": "Уведомления", - "tabs_bar.search": "Поиск", "time_remaining.days": "{number, plural, one {остался # день} few {осталось # дня} many {осталось # дней} other {осталось # дней}}", "time_remaining.hours": "{number, plural, one {остался # час} few {осталось # часа} many {осталось # часов} other {осталось # часов}}", "time_remaining.minutes": "{number, plural, one {осталась # минута} few {осталось # минуты} many {осталось # минут} other {осталось # минут}}", diff --git a/app/javascript/mastodon/locales/sa.json b/app/javascript/mastodon/locales/sa.json index 39dab7c97..691011e7e 100644 --- a/app/javascript/mastodon/locales/sa.json +++ b/app/javascript/mastodon/locales/sa.json @@ -1,4 +1,17 @@ { + "about.blocks": "Moderated servers", + "about.contact": "Contact:", + "about.domain_blocks.comment": "Reason", + "about.domain_blocks.domain": "Domain", + "about.domain_blocks.preamble": "Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.", + "about.domain_blocks.severity": "Severity", + "about.domain_blocks.silenced.explanation": "You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.", + "about.domain_blocks.silenced.title": "Limited", + "about.domain_blocks.suspended.explanation": "No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.", + "about.domain_blocks.suspended.title": "Suspended", + "about.not_available": "This information has not been made available on this server.", + "about.powered_by": "Decentralized social media powered by {mastodon}", + "about.rules": "Server rules", "account.account_note_header": "टीका", "account.add_or_remove_from_list": "युज्यतां / नश्यतां सूच्याः", "account.badges.bot": "यन्त्रम्", @@ -7,13 +20,16 @@ "account.block_domain": "अवरुध्यतां प्रदेशः {domain}", "account.blocked": "अवरुद्धम्", "account.browse_more_on_origin_server": "अधिकं मूलव्यक्तिगतविवरणे दृश्यताम्", - "account.cancel_follow_request": "अनुसरणानुरोधो नश्यताम्", + "account.cancel_follow_request": "Withdraw follow request", "account.direct": "प्रत्यक्षसन्देशः @{name}", "account.disable_notifications": "Stop notifying me when @{name} posts", "account.domain_blocked": "प्रदेशो निषिद्धः", "account.edit_profile": "सम्पाद्यताम्", "account.enable_notifications": "Notify me when @{name} posts", "account.endorse": "व्यक्तिगतविवरणे वैशिष्ट्यम्", + "account.featured_tags.last_status_at": "Last post on {date}", + "account.featured_tags.last_status_never": "No posts", + "account.featured_tags.title": "{name}'s featured hashtags", "account.follow": "अनुस्रियताम्", "account.followers": "अनुसर्तारः", "account.followers.empty": "नाऽनुसर्तारो वर्तन्ते", @@ -23,7 +39,7 @@ "account.follows.empty": "न कोऽप्यनुसृतो वर्तते", "account.follows_you": "त्वामनुसरति", "account.hide_reblogs": "@{name} मित्रस्य प्रकाशनानि छिद्यन्ताम्", - "account.joined": "Joined {date}", + "account.joined_short": "Joined", "account.languages": "Change subscribed languages", "account.link_verified_on": "अन्तर्जालस्थानस्यास्य स्वामित्वं परीक्षितमासीत् {date} दिने", "account.locked_info": "एतस्या लेखायाः गुह्यता \"निषिद्ध\"इति वर्तते । स्वामी स्वयञ्चिनोति कोऽनुसर्ता भवितुमर्हतीति ।", @@ -63,12 +79,24 @@ "audio.hide": "Hide audio", "autosuggest_hashtag.per_week": "{count} प्रतिसप्ताहे", "boost_modal.combo": "{combo} अत्र स्प्रष्टुं शक्यते, त्यक्तुमेतमन्यस्मिन् समये", - "bundle_column_error.body": "विषयस्याऽऽरोपणे कश्चिद्दोषो जातः", + "bundle_column_error.copy_stacktrace": "Copy error report", + "bundle_column_error.error.body": "The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.", + "bundle_column_error.error.title": "Oh, no!", + "bundle_column_error.network.body": "There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.", + "bundle_column_error.network.title": "Network error", "bundle_column_error.retry": "पुनः यतताम्", - "bundle_column_error.title": "जाले दोषः", + "bundle_column_error.return": "Go back home", + "bundle_column_error.routing.body": "The requested page could not be found. Are you sure the URL in the address bar is correct?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "पिधीयताम्", "bundle_modal_error.message": "आरोपणे कश्चन दोषो जातः", "bundle_modal_error.retry": "पुनः यतताम्", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "About", "column.blocks": "निषिद्धभोक्तारः", "column.bookmarks": "पुटचिह्नानि", "column.community": "स्थानीयसमयतालिका", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "अवरुध्य आविद्यताम्", "confirmations.block.confirm": "निषेधः", "confirmations.block.message": "निश्चयेनाऽवरोधो विधेयः {name}?", + "confirmations.cancel_follow_request.confirm": "Withdraw request", + "confirmations.cancel_follow_request.message": "Are you sure you want to withdraw your request to follow {name}?", "confirmations.delete.confirm": "नश्यताम्", "confirmations.delete.message": "निश्चयेन दौत्यमिदं नश्यताम्?", "confirmations.delete_list.confirm": "नश्यताम्", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "पठितमित्यङ्क्यताम्", "conversation.open": "वार्तालापो दृश्यताम्", "conversation.with": "{names} जनैः साकम्", + "copypaste.copied": "Copied", + "copypaste.copy": "Copy", "directory.federated": "सुपरिचितं Fediverse इति स्थानात्", "directory.local": "{domain} प्रदेशात्केवलम्", "directory.new_arrivals": "नवामगमाः", "directory.recently_active": "नातिपूर्वं सक्रियः", + "dismissable_banner.community_timeline": "These are the most recent public posts from people whose accounts are hosted by {domain}.", + "dismissable_banner.dismiss": "Dismiss", + "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", + "dismissable_banner.explore_statuses": "These posts from this and other servers in the decentralized network are gaining traction on this server right now.", + "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", + "dismissable_banner.public_timeline": "These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.", "embed.instructions": "दौत्यमेतत् स्वीयजालस्थाने स्थापयितुमधो लिखितो विध्यादेशो युज्यताम्", "embed.preview": "अत्रैवं दृश्यते तत्:", "emoji_button.activity": "आचरणम्", @@ -221,14 +259,14 @@ "follow_request.reject": "Reject", "follow_requests.unlocked_explanation": "Even though your account is not locked, the {domain} staff thought you might want to review follow requests from these accounts manually.", "generic.saved": "Saved", - "getting_started.developers": "Developers", - "getting_started.directory": "Profile directory", + "getting_started.directory": "Directory", "getting_started.documentation": "Documentation", + "getting_started.free_software_notice": "Mastodon is free, open source software. You can view the source code, contribute or report issues at {repository}.", "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.privacy_policy": "Privacy Policy", "getting_started.security": "Security", + "getting_started.what_is_mastodon": "About Mastodon", "hashtag.column_header.tag_mode.all": "and {additional}", "hashtag.column_header.tag_mode.any": "or {additional}", "hashtag.column_header.tag_mode.none": "without {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Show replies", "home.hide_announcements": "Hide announcements", "home.show_announcements": "Show announcements", + "interaction_modal.description.favourite": "With an account on Mastodon, you can favourite this post to let the author know you appreciate it and save it for later.", + "interaction_modal.description.follow": "With an account on Mastodon, you can follow {name} to receive their posts in your home feed.", + "interaction_modal.description.reblog": "With an account on Mastodon, you can boost this post to share it with your own followers.", + "interaction_modal.description.reply": "With an account on Mastodon, you can respond to this post.", + "interaction_modal.on_another_server": "On a different server", + "interaction_modal.on_this_server": "On this server", + "interaction_modal.other_server_instructions": "Simply copy and paste this URL into the search bar of your favourite app or the web interface where you are signed in.", + "interaction_modal.preamble": "Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one.", + "interaction_modal.title.favourite": "Favourite {name}'s post", + "interaction_modal.title.follow": "Follow {name}", + "interaction_modal.title.reblog": "Boost {name}'s post", + "interaction_modal.title.reply": "Reply to {name}'s post", "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}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Duration", "mute_modal.hide_notifications": "Hide notifications from this user?", "mute_modal.indefinite": "Indefinite", - "navigation_bar.apps": "Mobile apps", + "navigation_bar.about": "About", + "navigation_bar.apps": "Get the app", "navigation_bar.blocks": "Blocked users", "navigation_bar.bookmarks": "Bookmarks", "navigation_bar.community_timeline": "Local timeline", @@ -324,7 +375,7 @@ "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.info": "About", "navigation_bar.keyboard_shortcuts": "Hotkeys", "navigation_bar.lists": "Lists", "navigation_bar.logout": "Logout", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Pinned toots", "navigation_bar.preferences": "Preferences", "navigation_bar.public_timeline": "Federated timeline", + "navigation_bar.search": "Search", "navigation_bar.security": "Security", + "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", "notification.admin.report": "{name} reported {target}", "notification.admin.sign_up": "{name} signed up", "notification.favourite": "{name} favourited your status", @@ -401,6 +454,8 @@ "privacy.public.short": "Public", "privacy.unlisted.long": "Visible for all, but opted-out of discovery features", "privacy.unlisted.short": "Unlisted", + "privacy_policy.last_updated": "Last updated {date}", + "privacy_policy.title": "Privacy Policy", "refresh": "Refresh", "regeneration_indicator.label": "Loading…", "regeneration_indicator.sublabel": "Your home feed is being prepared!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.title": "Search for {q}", "search_results.total": "{count, number} {count, plural, one {result} other {results}}", + "server_banner.about_active_users": "People using this server during the last 30 days (Monthly Active Users)", + "server_banner.active_users": "active users", + "server_banner.administered_by": "Administered by:", + "server_banner.introduction": "{domain} is part of the decentralized social network powered by {mastodon}.", + "server_banner.learn_more": "Learn more", + "server_banner.server_stats": "Server stats:", "sign_in_banner.create_account": "Create account", "sign_in_banner.sign_in": "Sign in", "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "No one has boosted this toot yet. When someone does, they will show up here.", "status.redraft": "Delete & re-draft", "status.remove_bookmark": "Remove bookmark", + "status.replied_to": "Replied to {name}", "status.reply": "Reply", "status.replyAll": "Reply to thread", "status.report": "Report @{name}", @@ -523,9 +585,8 @@ "status.show_more": "Show more", "status.show_more_all": "Show more for all", "status.show_original": "Show original", - "status.show_thread": "Show thread", "status.translate": "Translate", - "status.translated_from": "Translated from {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Not available", "status.unmute_conversation": "Unmute conversation", "status.unpin": "Unpin from profile", @@ -538,7 +599,6 @@ "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", diff --git a/app/javascript/mastodon/locales/sc.json b/app/javascript/mastodon/locales/sc.json index 50f6a0b80..393d7144c 100644 --- a/app/javascript/mastodon/locales/sc.json +++ b/app/javascript/mastodon/locales/sc.json @@ -1,4 +1,17 @@ { + "about.blocks": "Moderated servers", + "about.contact": "Contact:", + "about.domain_blocks.comment": "Reason", + "about.domain_blocks.domain": "Domain", + "about.domain_blocks.preamble": "Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.", + "about.domain_blocks.severity": "Severity", + "about.domain_blocks.silenced.explanation": "You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.", + "about.domain_blocks.silenced.title": "Limited", + "about.domain_blocks.suspended.explanation": "No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.", + "about.domain_blocks.suspended.title": "Suspended", + "about.not_available": "This information has not been made available on this server.", + "about.powered_by": "Decentralized social media powered by {mastodon}", + "about.rules": "Server rules", "account.account_note_header": "Nota", "account.add_or_remove_from_list": "Agiunghe o boga dae is listas", "account.badges.bot": "Robot", @@ -7,13 +20,16 @@ "account.block_domain": "Bloca su domìniu {domain}", "account.blocked": "Blocadu", "account.browse_more_on_origin_server": "Esplora de prus in su profilu originale", - "account.cancel_follow_request": "Annulla rechesta de sighidura", + "account.cancel_follow_request": "Withdraw follow request", "account.direct": "Messàgiu deretu a @{name}", "account.disable_notifications": "Non mi notìfiches prus cando @{name} pùblichet messàgios", "account.domain_blocked": "Domìniu blocadu", "account.edit_profile": "Modìfica profilu", "account.enable_notifications": "Notìfica·mi cando @{name} pùblicat messàgios", "account.endorse": "Cussìgia in su profilu tuo", + "account.featured_tags.last_status_at": "Last post on {date}", + "account.featured_tags.last_status_never": "No posts", + "account.featured_tags.title": "{name}'s featured hashtags", "account.follow": "Sighi", "account.followers": "Sighiduras", "account.followers.empty": "Nemos sighit ancora custa persone.", @@ -23,7 +39,7 @@ "account.follows.empty": "Custa persone non sighit ancora a nemos.", "account.follows_you": "Ti sighit", "account.hide_reblogs": "Cua is cumpartziduras de @{name}", - "account.joined": "At aderidu su {date}", + "account.joined_short": "Joined", "account.languages": "Change subscribed languages", "account.link_verified_on": "Sa propiedade de custu ligòngiu est istada controllada su {date}", "account.locked_info": "S'istadu de riservadesa de custu contu est istadu cunfiguradu comente blocadu. Sa persone chi tenet sa propiedade revisionat a manu chie dda podet sighire.", @@ -63,12 +79,24 @@ "audio.hide": "Hide audio", "autosuggest_hashtag.per_week": "{count} a sa chida", "boost_modal.combo": "Podes incarcare {combo} pro brincare custu sa borta chi benit", - "bundle_column_error.body": "Faddina in su carrigamentu de custu cumponente.", + "bundle_column_error.copy_stacktrace": "Copy error report", + "bundle_column_error.error.body": "The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.", + "bundle_column_error.error.title": "Oh, no!", + "bundle_column_error.network.body": "There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.", + "bundle_column_error.network.title": "Network error", "bundle_column_error.retry": "Torra·bi a proare", - "bundle_column_error.title": "Faddina de connessione", + "bundle_column_error.return": "Go back home", + "bundle_column_error.routing.body": "The requested page could not be found. Are you sure the URL in the address bar is correct?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Serra", "bundle_modal_error.message": "Faddina in su carrigamentu de custu cumponente.", "bundle_modal_error.retry": "Torra·bi a proare", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "About", "column.blocks": "Persones blocadas", "column.bookmarks": "Sinnalibros", "column.community": "Lìnia de tempus locale", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "Bloca e signala", "confirmations.block.confirm": "Bloca", "confirmations.block.message": "Seguru chi boles blocare {name}?", + "confirmations.cancel_follow_request.confirm": "Withdraw request", + "confirmations.cancel_follow_request.message": "Are you sure you want to withdraw your request to follow {name}?", "confirmations.delete.confirm": "Cantzella", "confirmations.delete.message": "Seguru chi boles cantzellare custa publicatzione?", "confirmations.delete_list.confirm": "Cantzella", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Signala comente lèghidu", "conversation.open": "Ammustra arresonada", "conversation.with": "Cun {names}", + "copypaste.copied": "Copied", + "copypaste.copy": "Copy", "directory.federated": "Dae unu fediversu connotu", "directory.local": "Isceti dae {domain}", "directory.new_arrivals": "Arribos noos", "directory.recently_active": "Cun atividade dae pagu", + "dismissable_banner.community_timeline": "These are the most recent public posts from people whose accounts are hosted by {domain}.", + "dismissable_banner.dismiss": "Dismiss", + "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", + "dismissable_banner.explore_statuses": "These posts from this and other servers in the decentralized network are gaining traction on this server right now.", + "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", + "dismissable_banner.public_timeline": "These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.", "embed.instructions": "Inserta custa publicatzione in su situ web tuo copiende su còdighe de suta.", "embed.preview": "At a aparèssere aici:", "emoji_button.activity": "Atividade", @@ -221,14 +259,14 @@ "follow_request.reject": "Refuda", "follow_requests.unlocked_explanation": "Fintzas si su contu tuo no est blocadu, su personale de {domain} at pensadu chi forsis bolias revisionare a manu is rechestas de custos contos.", "generic.saved": "Sarvadu", - "getting_started.developers": "Iscuadra de isvilupu", - "getting_started.directory": "Diretòriu de profilos", + "getting_started.directory": "Directory", "getting_started.documentation": "Documentatzione", + "getting_started.free_software_notice": "Mastodon is free, open source software. You can view the source code, contribute or report issues at {repository}.", "getting_started.heading": "Comente cumintzare", "getting_started.invite": "Invita gente", - "getting_started.open_source_notice": "Mastodon est de còdighe abertu. Bi podes contribuire o sinnalare faddinas in {github}.", "getting_started.privacy_policy": "Privacy Policy", "getting_started.security": "Cunfiguratziones de su contu", + "getting_started.what_is_mastodon": "About Mastodon", "hashtag.column_header.tag_mode.all": "e {additional}", "hashtag.column_header.tag_mode.any": "o {additional}", "hashtag.column_header.tag_mode.none": "sena {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Ammustra rispostas", "home.hide_announcements": "Cua annùntzios", "home.show_announcements": "Ammustra annùntzios", + "interaction_modal.description.favourite": "With an account on Mastodon, you can favourite this post to let the author know you appreciate it and save it for later.", + "interaction_modal.description.follow": "With an account on Mastodon, you can follow {name} to receive their posts in your home feed.", + "interaction_modal.description.reblog": "With an account on Mastodon, you can boost this post to share it with your own followers.", + "interaction_modal.description.reply": "With an account on Mastodon, you can respond to this post.", + "interaction_modal.on_another_server": "On a different server", + "interaction_modal.on_this_server": "On this server", + "interaction_modal.other_server_instructions": "Simply copy and paste this URL into the search bar of your favourite app or the web interface where you are signed in.", + "interaction_modal.preamble": "Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one.", + "interaction_modal.title.favourite": "Favourite {name}'s post", + "interaction_modal.title.follow": "Follow {name}", + "interaction_modal.title.reblog": "Boost {name}'s post", + "interaction_modal.title.reply": "Reply to {name}'s post", "intervals.full.days": "{number, plural, one {# die} other {# dies}}", "intervals.full.hours": "{number, plural, one {# ora} other {# oras}}", "intervals.full.minutes": "{number, plural, one {# minutu} other {# minutos}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Durada", "mute_modal.hide_notifications": "Boles cuare is notìficas de custa persone?", "mute_modal.indefinite": "Indefinida", - "navigation_bar.apps": "Aplicatziones mòbiles", + "navigation_bar.about": "About", + "navigation_bar.apps": "Get the app", "navigation_bar.blocks": "Persones blocadas", "navigation_bar.bookmarks": "Sinnalibros", "navigation_bar.community_timeline": "Lìnia de tempus locale", @@ -324,7 +375,7 @@ "navigation_bar.filters": "Faeddos a sa muda", "navigation_bar.follow_requests": "Rechestas de sighidura", "navigation_bar.follows_and_followers": "Gente chi sighis e sighiduras", - "navigation_bar.info": "Informatziones de su serbidore", + "navigation_bar.info": "About", "navigation_bar.keyboard_shortcuts": "Teclas de atzessu diretu", "navigation_bar.lists": "Listas", "navigation_bar.logout": "Essi", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Publicatziones apicadas", "navigation_bar.preferences": "Preferèntzias", "navigation_bar.public_timeline": "Lìnia de tempus federada", + "navigation_bar.search": "Search", "navigation_bar.security": "Seguresa", + "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", "notification.admin.report": "{name} reported {target}", "notification.admin.sign_up": "{name} signed up", "notification.favourite": "{name} at marcadu sa publicatzione tua comente a preferida", @@ -401,6 +454,8 @@ "privacy.public.short": "Pùblicu", "privacy.unlisted.long": "Visible for all, but opted-out of discovery features", "privacy.unlisted.short": "Esclùidu de sa lista", + "privacy_policy.last_updated": "Last updated {date}", + "privacy_policy.title": "Privacy Policy", "refresh": "Atualiza", "regeneration_indicator.label": "Carrighende…", "regeneration_indicator.sublabel": "Preparende sa lìnia de tempus printzipale tua.", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "Sa chirca de publicatziones pro su cuntenutu issoro no est abilitada in custu serbidore de Mastodon.", "search_results.title": "Search for {q}", "search_results.total": "{count, number} {count, plural, one {resurtadu} other {resurtados}}", + "server_banner.about_active_users": "People using this server during the last 30 days (Monthly Active Users)", + "server_banner.active_users": "active users", + "server_banner.administered_by": "Administered by:", + "server_banner.introduction": "{domain} is part of the decentralized social network powered by {mastodon}.", + "server_banner.learn_more": "Learn more", + "server_banner.server_stats": "Server stats:", "sign_in_banner.create_account": "Create account", "sign_in_banner.sign_in": "Sign in", "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "Nemos at ancora cumpartzidu custa publicatzione. Cando calicunu dd'at a fàghere, at a èssere ammustrada inoghe.", "status.redraft": "Cantzella e torra a iscrìere", "status.remove_bookmark": "Boga su sinnalibru", + "status.replied_to": "Replied to {name}", "status.reply": "Risponde", "status.replyAll": "Risponde a su tema", "status.report": "Sinnala @{name}", @@ -523,9 +585,8 @@ "status.show_more": "Ammustra·nde prus", "status.show_more_all": "Ammustra·nde prus pro totus", "status.show_original": "Show original", - "status.show_thread": "Ammustra su tema", "status.translate": "Translate", - "status.translated_from": "Translated from {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "No est a disponimentu", "status.unmute_conversation": "Torra a ativare s'arresonada", "status.unpin": "Boga dae pitzu de su profilu", @@ -538,7 +599,6 @@ "tabs_bar.home": "Printzipale", "tabs_bar.local_timeline": "Locale", "tabs_bar.notifications": "Notìficas", - "tabs_bar.search": "Chirca", "time_remaining.days": "{number, plural, one {abarrat # die} other {abarrant # dies}}", "time_remaining.hours": "{number, plural, one {abarrat # ora} other {abarrant # oras}}", "time_remaining.minutes": "{number, plural, one {abarrat # minutu} other {abarrant # minutos}}", diff --git a/app/javascript/mastodon/locales/si.json b/app/javascript/mastodon/locales/si.json index 3503dda8d..56ee9c17a 100644 --- a/app/javascript/mastodon/locales/si.json +++ b/app/javascript/mastodon/locales/si.json @@ -1,4 +1,17 @@ { + "about.blocks": "Moderated servers", + "about.contact": "Contact:", + "about.domain_blocks.comment": "Reason", + "about.domain_blocks.domain": "Domain", + "about.domain_blocks.preamble": "Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.", + "about.domain_blocks.severity": "Severity", + "about.domain_blocks.silenced.explanation": "You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.", + "about.domain_blocks.silenced.title": "Limited", + "about.domain_blocks.suspended.explanation": "No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.", + "about.domain_blocks.suspended.title": "Suspended", + "about.not_available": "This information has not been made available on this server.", + "about.powered_by": "Decentralized social media powered by {mastodon}", + "about.rules": "Server rules", "account.account_note_header": "සටහන", "account.add_or_remove_from_list": "ලැයිස්තු වලින් එකතු හෝ ඉවත් කරන්න", "account.badges.bot": "ස්වයං ක්රමලේඛය", @@ -7,23 +20,26 @@ "account.block_domain": "{domain} වසම අවහිර කරන්න", "account.blocked": "අවහිර කර ඇත", "account.browse_more_on_origin_server": "මුල් පැතිකඩෙහි තවත් පිරික්සන්න", - "account.cancel_follow_request": "ඉල්ලීම අනුගමනය කිරීම අවලංගු කරන්න", + "account.cancel_follow_request": "Withdraw follow request", "account.direct": "@{name} සෘජු පණිවිඩය", - "account.disable_notifications": "@{name} පළ කරන විට මට දැනුම් දීම නවත්වන්න", + "account.disable_notifications": "@{name} පළ කරන විට මට දැනුම් නොදෙන්න", "account.domain_blocked": "වසම අවහිර කර ඇත", "account.edit_profile": "පැතිකඩ සංස්කරණය", "account.enable_notifications": "@{name} පළ කරන විට මට දැනුම් දෙන්න", "account.endorse": "පැතිකඩෙහි විශේෂාංගය", + "account.featured_tags.last_status_at": "Last post on {date}", + "account.featured_tags.last_status_never": "No posts", + "account.featured_tags.title": "{name}'s featured hashtags", "account.follow": "අනුගමනය", "account.followers": "අනුගාමිකයින්", - "account.followers.empty": "කිසිවෙකු තවමත් මෙම පරිශීලකයා අනුගමනය නොකරයි.", + "account.followers.empty": "කිසිවෙක් අනුගමනය කර නැත.", "account.followers_counter": "{count, plural, one {{counter} අනුගාමිකයෙක්} other {{counter} අනුගාමිකයින්}}", "account.following": "අනුගමනය", - "account.following_counter": "{count, plural, one {{counter} අනුගමනය කරන්න} other {{counter} අනුගමනය කරන්න}}", - "account.follows.empty": "මෙම පරිශීලකයා තවමත් කිසිවෙකු අනුගමනය නොකරයි.", + "account.following_counter": "{count, plural, one {අනුගාමිකයින් {counter}} other {අනුගාමිකයින් {counter}}}", + "account.follows.empty": "තවමත් කිසිවෙක් අනුගමනය නොකරයි.", "account.follows_you": "ඔබව අනුගමනය කරයි", "account.hide_reblogs": "@{name}සිට බූස්ට් සඟවන්න", - "account.joined": "{date} එක් වී ඇත", + "account.joined_short": "Joined", "account.languages": "Change subscribed languages", "account.link_verified_on": "මෙම සබැඳියේ අයිතිය {date} දී පරීක්ෂා කෙරිණි", "account.locked_info": "මෙම ගිණුමේ රහස්යතා තත්ත්වය අගුලු දමා ඇත. හිමිකරු ඔවුන් අනුගමනය කළ හැක්කේ කාටදැයි හස්තීයව සමාලෝචනය කරයි.", @@ -53,7 +69,7 @@ "admin.dashboard.monthly_retention": "ලියාපදිංචි වීමෙන් පසු මාසය අනුව පරිශීලක රඳවා ගැනීමේ අනුපාතය", "admin.dashboard.retention.average": "සාමාන්යය", "admin.dashboard.retention.cohort": "ලියාපදිංචි වීමේ මාසය", - "admin.dashboard.retention.cohort_size": "නව පරිශීලකයින්", + "admin.dashboard.retention.cohort_size": "නව පරිශ්රීලකයින්", "alert.rate_limited.message": "{retry_time, time, medium} කට පසුව උත්සාහ කරන්න.", "alert.rate_limited.title": "මිල සීමා සහිතයි", "alert.unexpected.message": "අනපේක්ෂිත දෝෂයක් ඇතිවුනා.", @@ -63,20 +79,32 @@ "audio.hide": "හඬපටය සඟවන්න", "autosuggest_hashtag.per_week": "සතියකට {count}", "boost_modal.combo": "ඊළඟ වතාවේ මෙය මඟ හැරීමට ඔබට {combo} එබිය හැක", - "bundle_column_error.body": "මෙම සංරචකය පූරණය කිරීමේදී යම් දෙයක් වැරදී ඇත.", + "bundle_column_error.copy_stacktrace": "Copy error report", + "bundle_column_error.error.body": "The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.", + "bundle_column_error.error.title": "Oh, no!", + "bundle_column_error.network.body": "There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.", + "bundle_column_error.network.title": "Network error", "bundle_column_error.retry": "නැවත උත්සාහ කරන්න", - "bundle_column_error.title": "ජාලයේ දෝෂයකි", + "bundle_column_error.return": "Go back home", + "bundle_column_error.routing.body": "The requested page could not be found. Are you sure the URL in the address bar is correct?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "වසන්න", "bundle_modal_error.message": "මෙම සංරචකය පූරණය කිරීමේදී යම් දෙයක් වැරදී ඇත.", "bundle_modal_error.retry": "නැවත උත්සාහ කරන්න", - "column.blocks": "අවහිර කළ පරිශීලකයින්", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "පිලිබඳව", + "column.blocks": "අවහිර කළ අය", "column.bookmarks": "පොත් යොමු", "column.community": "දේශීය කාලරේඛාව", "column.direct": "සෘජු පණිවිඩ", "column.directory": "පැතිකඩ පිරික්සන්න", "column.domain_blocks": "අවහිර කළ වසම්", "column.favourites": "ප්රියතමයන්", - "column.follow_requests": "ඉල්ලීම් අනුගමනය කරන්න", + "column.follow_requests": "අනුගමන ඉල්ලීම්", "column.home": "මුල් පිටුව", "column.lists": "ලේඛන", "column.mutes": "නිහඬ කළ අය", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "අවහිර කර වාර්තා කරන්න", "confirmations.block.confirm": "අවහිර", "confirmations.block.message": "ඔබට {name} අවහිර කිරීමට වුවමනා ද?", + "confirmations.cancel_follow_request.confirm": "Withdraw request", + "confirmations.cancel_follow_request.message": "Are you sure you want to withdraw your request to follow {name}?", "confirmations.delete.confirm": "මකන්න", "confirmations.delete.message": "ඔබට මෙම තත්ත්වය මැකීමට අවශ්ය බව විශ්වාසද?", "confirmations.delete_list.confirm": "මකන්න", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "කියවූ බව යොදන්න", "conversation.open": "සංවාදය බලන්න", "conversation.with": "{names} සමඟ", + "copypaste.copied": "පිටපත් විය", + "copypaste.copy": "පිටපතක්", "directory.federated": "දන්නා fediverse වලින්", "directory.local": "{domain} වෙතින් පමණි", "directory.new_arrivals": "නව පැමිණීම්", "directory.recently_active": "මෑත දී සක්රියයි", + "dismissable_banner.community_timeline": "These are the most recent public posts from people whose accounts are hosted by {domain}.", + "dismissable_banner.dismiss": "Dismiss", + "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", + "dismissable_banner.explore_statuses": "These posts from this and other servers in the decentralized network are gaining traction on this server right now.", + "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", + "dismissable_banner.public_timeline": "These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.", "embed.instructions": "පහත කේතය පිටපත් කිරීමෙන් මෙම තත්ත්වය ඔබේ වෙබ් අඩවියට ඇතුළත් කරන්න.", "embed.preview": "එය පෙනෙන්නේ කෙසේද යන්න මෙන්න:", "emoji_button.activity": "ක්රියාකාරකම", @@ -221,14 +259,14 @@ "follow_request.reject": "ප්රතික්ෂේප", "follow_requests.unlocked_explanation": "ඔබගේ ගිණුම අගුලු දමා නොතිබුණද, {domain} කාර්ය මණ්ඩලය සිතුවේ ඔබට මෙම ගිණුම් වලින් ලැබෙන ඉල්ලීම් හස්තීයව සමාලෝචනය කිරීමට අවශ්ය විය හැකි බවයි.", "generic.saved": "සුරැකිණි", - "getting_started.developers": "සංවර්ධකයින්", - "getting_started.directory": "පැතිකඩ නාමාවලිය", + "getting_started.directory": "නාමාවලිය", "getting_started.documentation": "ප්රලේඛනය", + "getting_started.free_software_notice": "Mastodon is free, open source software. You can view the source code, contribute or report issues at {repository}.", "getting_started.heading": "පටන් ගන්න", "getting_started.invite": "මිනිසුන්ට ආරාධනය", - "getting_started.open_source_notice": "Mastodon යනු විවෘත කේත මෘදුකාංගයකි. ඔබට GitHub හි {github}ට දායක වීමට හෝ ගැටළු වාර්තා කිරීමට හැකිය.", - "getting_started.privacy_policy": "Privacy Policy", + "getting_started.privacy_policy": "රහස්යතා ප්රතිපත්තිය", "getting_started.security": "ගිණුමේ සැකසුම්", + "getting_started.what_is_mastodon": "මාස්ටඩන් ගැන", "hashtag.column_header.tag_mode.all": "සහ {additional}", "hashtag.column_header.tag_mode.any": "හෝ {additional}", "hashtag.column_header.tag_mode.none": "{additional}නොමැතිව", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "පිළිතුරු පෙන්වන්න", "home.hide_announcements": "නිවේදන සඟවන්න", "home.show_announcements": "නිවේදන පෙන්වන්න", + "interaction_modal.description.favourite": "With an account on Mastodon, you can favourite this post to let the author know you appreciate it and save it for later.", + "interaction_modal.description.follow": "With an account on Mastodon, you can follow {name} to receive their posts in your home feed.", + "interaction_modal.description.reblog": "With an account on Mastodon, you can boost this post to share it with your own followers.", + "interaction_modal.description.reply": "With an account on Mastodon, you can respond to this post.", + "interaction_modal.on_another_server": "On a different server", + "interaction_modal.on_this_server": "On this server", + "interaction_modal.other_server_instructions": "Simply copy and paste this URL into the search bar of your favourite app or the web interface where you are signed in.", + "interaction_modal.preamble": "Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one.", + "interaction_modal.title.favourite": "Favourite {name}'s post", + "interaction_modal.title.follow": "Follow {name}", + "interaction_modal.title.reblog": "Boost {name}'s post", + "interaction_modal.title.reply": "Reply to {name}'s post", "intervals.full.days": "{number, plural, one {# දින} other {# දින}}", "intervals.full.hours": "{number, plural, one {# පැය} other {# පැය}}", "intervals.full.minutes": "{number, plural, one {විනාඩි #} other {# මිනිත්තු}}", @@ -256,7 +306,7 @@ "keyboard_shortcuts.description": "සවිස්තරය", "keyboard_shortcuts.direct": "සෘජු පණිවිඩ තීරුව විවෘත කිරීමට", "keyboard_shortcuts.down": "ලැයිස්තුවේ පහළට ගමන් කිරීමට", - "keyboard_shortcuts.enter": "තත්ත්වය විවෘත කිරීමට", + "keyboard_shortcuts.enter": "ලිපිය අරින්න", "keyboard_shortcuts.favourite": "කැමති කිරීමට", "keyboard_shortcuts.favourites": "ප්රියතම ලැයිස්තුව විවෘත කිරීමට", "keyboard_shortcuts.federated": "ෆෙඩරේටඩ් කාලරාමුව විවෘත කිරීමට", @@ -270,7 +320,7 @@ "keyboard_shortcuts.my_profile": "ඔබගේ පැතිකඩ අරින්න", "keyboard_shortcuts.notifications": "දැනුම්දීම් තීරුව විවෘත කිරීමට", "keyboard_shortcuts.open_media": "මාධ්ය අරින්න", - "keyboard_shortcuts.pinned": "පින් කළ මෙවලම් ලැයිස්තුව විවෘත කිරීමට", + "keyboard_shortcuts.pinned": "ඇමිණූ ලිපි ලේඛනය අරින්න", "keyboard_shortcuts.profile": "කතෘගේ පැතිකඩ අරින්න", "keyboard_shortcuts.reply": "පිළිතුරු දීමට", "keyboard_shortcuts.requests": "පහත ඉල්ලීම් ලැයිස්තුව විවෘත කිරීමට", @@ -310,7 +360,8 @@ "mute_modal.duration": "පරාසය", "mute_modal.hide_notifications": "මෙම පරිශීලකයාගෙන් දැනුම්දීම් සඟවන්නද?", "mute_modal.indefinite": "අවිනිශ්චිත", - "navigation_bar.apps": "ජංගම යෙදුම්", + "navigation_bar.about": "About", + "navigation_bar.apps": "Get the app", "navigation_bar.blocks": "අවහිර කළ අය", "navigation_bar.bookmarks": "පොත්යොමු", "navigation_bar.community_timeline": "දේශීය කාලරේඛාව", @@ -324,7 +375,7 @@ "navigation_bar.filters": "නිහඬ කළ වචන", "navigation_bar.follow_requests": "අනුගමන ඉල්ලීම්", "navigation_bar.follows_and_followers": "අනුගමනය හා අනුගාමිකයින්", - "navigation_bar.info": "මෙම සේවාදායකය ගැන", + "navigation_bar.info": "About", "navigation_bar.keyboard_shortcuts": "උණු යතුරු", "navigation_bar.lists": "ලේඛන", "navigation_bar.logout": "නික්මෙන්න", @@ -333,7 +384,9 @@ "navigation_bar.pins": "ඇමිණූ ලිපි", "navigation_bar.preferences": "අභිප්රේත", "navigation_bar.public_timeline": "ෆෙඩරේටඩ් කාලරේඛාව", + "navigation_bar.search": "Search", "navigation_bar.security": "ආරක්ෂාව", + "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", "notification.admin.report": "{name} වාර්තා {target}", "notification.admin.sign_up": "{name} අත්සන් කර ඇත", "notification.favourite": "{name} ඔබගේ තත්වයට කැමති විය", @@ -401,6 +454,8 @@ "privacy.public.short": "ප්රසිද්ධ", "privacy.unlisted.long": "සැමට දෘශ්යමාන, නමුත් සොයාගැනීමේ විශේෂාංග වලින් ඉවත් විය", "privacy.unlisted.short": "ලැයිස්තුගත නොකළ", + "privacy_policy.last_updated": "Last updated {date}", + "privacy_policy.title": "Privacy Policy", "refresh": "නැවුම් කරන්න", "regeneration_indicator.label": "පූරණය වෙමින්…", "regeneration_indicator.sublabel": "ඔබේ නිවසේ පෝෂණය සූදානම් වෙමින් පවතී!", @@ -453,7 +508,7 @@ "report.thanks.title_actionable": "වාර්තා කිරීමට ස්තූතියි, අපි මේ ගැන සොයා බලමු.", "report.unfollow": "@{name}අනුගමනය නොකරන්න", "report.unfollow_explanation": "ඔබ මෙම ගිණුම අනුගමනය කරයි. ඔබේ නිවසේ සංග්රහයේ ඔවුන්ගේ පළ කිරීම් තවදුරටත් නොදැකීමට, ඒවා අනුගමනය නොකරන්න.", - "report_notification.attached_statuses": "{count, plural, one {{count} තැපැල්} other {{count} තනතුරු}} අමුණා ඇත", + "report_notification.attached_statuses": "{count, plural, one {ලිපි {count}} other {ලිපි {count} ක්}} අමුණා ඇත", "report_notification.categories.other": "වෙනත්", "report_notification.categories.spam": "ආයාචිත", "report_notification.categories.violation": "නීතිය කඩ කිරීම", @@ -462,7 +517,7 @@ "search_popout.search_format": "උසස් සෙවුම් ආකෘතිය", "search_popout.tips.full_text": "සරල පෙළ ඔබ ලියා ඇති, ප්රිය කළ, වැඩි කළ හෝ සඳහන් කර ඇති තත්ත්වයන් මෙන්ම ගැළපෙන පරිශීලක නාම, සංදර්ශක නම් සහ හැෂ් ටැග් ලබා දෙයි.", "search_popout.tips.hashtag": "හෑෂ් ටැගය", - "search_popout.tips.status": "තත්ත්වය", + "search_popout.tips.status": "ලිපිය", "search_popout.tips.text": "සරල පෙළ ගැළපෙන සංදර්ශක නම්, පරිශීලක නාම සහ හැෂ් ටැග් ලබා දෙයි", "search_popout.tips.user": "පරිශීලක", "search_results.accounts": "මිනිසුන්", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "මෙම Mastodon සේවාදායකයේ ඒවායේ අන්තර්ගතය අනුව මෙවලම් සෙවීම සබල නොවේ.", "search_results.title": "Search for {q}", "search_results.total": "{count, number} {count, plural, one {ප්රතිඵලය} other {ප්රතිපල}}", + "server_banner.about_active_users": "People using this server during the last 30 days (Monthly Active Users)", + "server_banner.active_users": "active users", + "server_banner.administered_by": "Administered by:", + "server_banner.introduction": "{domain} is part of the decentralized social network powered by {mastodon}.", + "server_banner.learn_more": "Learn more", + "server_banner.server_stats": "Server stats:", "sign_in_banner.create_account": "Create account", "sign_in_banner.sign_in": "Sign in", "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "තාම කවුරුත් මේ toot එක boost කරලා නැහැ. යමෙකු එසේ කළ විට, ඔවුන් මෙහි පෙන්වනු ඇත.", "status.redraft": "මකන්න සහ නැවත කෙටුම්පත", "status.remove_bookmark": "පොත්යොමුව ඉවතලන්න", + "status.replied_to": "Replied to {name}", "status.reply": "පිළිතුරු", "status.replyAll": "ත්රෙඩ් එකට පිළිතුරු දෙන්න", "status.report": "@{name} වාර්තාව", @@ -523,9 +585,8 @@ "status.show_more": "තවත් පෙන්වන්න", "status.show_more_all": "සියල්ල වැඩියෙන් පෙන්වන්න", "status.show_original": "Show original", - "status.show_thread": "නූල් පෙන්වන්න", "status.translate": "Translate", - "status.translated_from": "Translated from {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "නොතිබේ", "status.unmute_conversation": "සංවාදය නොනිහඬ", "status.unpin": "පැතිකඩෙන් ගළවන්න", @@ -538,7 +599,6 @@ "tabs_bar.home": "මුල් පිටුව", "tabs_bar.local_timeline": "ස්ථානීය", "tabs_bar.notifications": "දැනුම්දීම්", - "tabs_bar.search": "සොයන්න", "time_remaining.days": "{number, plural, one {# දින} other {# දින}} අත්හැරියා", "time_remaining.hours": "{number, plural, one {# පැය} other {# පැය}} අත්හැරියා", "time_remaining.minutes": "{number, plural, one {විනාඩි #} other {# මිනිත්තු}} අත්හැරියා", @@ -552,7 +612,7 @@ "trends.trending_now": "දැන් ප්රවණතාවය", "ui.beforeunload": "ඔබ මාස්ටඩන් හැර ගියහොත් කටුපිටපත අහිමි වේ.", "units.short.billion": "{count}බී", - "units.short.million": "{count}එම්", + "units.short.million": "ද.ල. {count}", "units.short.thousand": "{count}කි", "upload_area.title": "උඩුගතයට ඇද දමන්න", "upload_button.label": "රූප, දෘශ්යක හෝ හඬපට යොදන්න", diff --git a/app/javascript/mastodon/locales/sk.json b/app/javascript/mastodon/locales/sk.json index fef39cc22..1a9692954 100644 --- a/app/javascript/mastodon/locales/sk.json +++ b/app/javascript/mastodon/locales/sk.json @@ -1,4 +1,17 @@ { + "about.blocks": "Moderated servers", + "about.contact": "Contact:", + "about.domain_blocks.comment": "Reason", + "about.domain_blocks.domain": "Domain", + "about.domain_blocks.preamble": "Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.", + "about.domain_blocks.severity": "Severity", + "about.domain_blocks.silenced.explanation": "You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.", + "about.domain_blocks.silenced.title": "Limited", + "about.domain_blocks.suspended.explanation": "No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.", + "about.domain_blocks.suspended.title": "Suspended", + "about.not_available": "This information has not been made available on this server.", + "about.powered_by": "Decentralized social media powered by {mastodon}", + "about.rules": "Server rules", "account.account_note_header": "Poznámka", "account.add_or_remove_from_list": "Pridaj do, alebo odober zo zoznamov", "account.badges.bot": "Bot", @@ -7,13 +20,16 @@ "account.block_domain": "Ukry všetko z {domain}", "account.blocked": "Blokovaný/á", "account.browse_more_on_origin_server": "Prehľadávaj viac na pôvodnom profile", - "account.cancel_follow_request": "Zruš žiadosť o sledovanie", + "account.cancel_follow_request": "Withdraw follow request", "account.direct": "Priama správa pre @{name}", "account.disable_notifications": "Prestaň oznamovať, keď má príspevky @{name}", "account.domain_blocked": "Doména ukrytá", "account.edit_profile": "Uprav profil", "account.enable_notifications": "Oboznamuj ma, keď má @{name} príspevky", "account.endorse": "Zobrazuj na profile", + "account.featured_tags.last_status_at": "Last post on {date}", + "account.featured_tags.last_status_never": "No posts", + "account.featured_tags.title": "{name}'s featured hashtags", "account.follow": "Nasleduj", "account.followers": "Sledujúci", "account.followers.empty": "Tohto používateľa ešte nikto nenásleduje.", @@ -23,7 +39,7 @@ "account.follows.empty": "Tento používateľ ešte nikoho nenasleduje.", "account.follows_you": "Nasleduje ťa", "account.hide_reblogs": "Skry vyzdvihnutia od @{name}", - "account.joined": "Pridal/a sa v {date}", + "account.joined_short": "Joined", "account.languages": "Change subscribed languages", "account.link_verified_on": "Vlastníctvo tohto odkazu bolo skontrolované {date}", "account.locked_info": "Stav súkromia pre tento účet je nastavený na zamknutý. Jeho vlastník sám prehodnocuje, kto ho môže sledovať.", @@ -63,12 +79,24 @@ "audio.hide": "Skry zvuk", "autosuggest_hashtag.per_week": "{count} týždenne", "boost_modal.combo": "Nabudúce môžeš kliknúť {combo} pre preskočenie", - "bundle_column_error.body": "Pri načítaní tohto prvku nastala nejaká chyba.", + "bundle_column_error.copy_stacktrace": "Copy error report", + "bundle_column_error.error.body": "The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.", + "bundle_column_error.error.title": "Oh, no!", + "bundle_column_error.network.body": "There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.", + "bundle_column_error.network.title": "Network error", "bundle_column_error.retry": "Skús to znova", - "bundle_column_error.title": "Chyba siete", + "bundle_column_error.return": "Go back home", + "bundle_column_error.routing.body": "The requested page could not be found. Are you sure the URL in the address bar is correct?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Zatvor", "bundle_modal_error.message": "Nastala chyba pri načítaní tohto komponentu.", "bundle_modal_error.retry": "Skúsiť znova", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "About", "column.blocks": "Blokovaní užívatelia", "column.bookmarks": "Záložky", "column.community": "Miestna časová os", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "Zablokuj a nahlás", "confirmations.block.confirm": "Blokuj", "confirmations.block.message": "Si si istý/á, že chceš blokovať {name}?", + "confirmations.cancel_follow_request.confirm": "Withdraw request", + "confirmations.cancel_follow_request.message": "Are you sure you want to withdraw your request to follow {name}?", "confirmations.delete.confirm": "Vymaž", "confirmations.delete.message": "Si si istý/á, že chceš vymazať túto správu?", "confirmations.delete_list.confirm": "Vymaž", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Označ za prečítané", "conversation.open": "Ukáž konverzáciu", "conversation.with": "S {names}", + "copypaste.copied": "Copied", + "copypaste.copy": "Copy", "directory.federated": "Zo známého fedivesmíru", "directory.local": "Iba z {domain}", "directory.new_arrivals": "Nové príchody", "directory.recently_active": "Nedávno aktívne", + "dismissable_banner.community_timeline": "These are the most recent public posts from people whose accounts are hosted by {domain}.", + "dismissable_banner.dismiss": "Dismiss", + "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", + "dismissable_banner.explore_statuses": "These posts from this and other servers in the decentralized network are gaining traction on this server right now.", + "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", + "dismissable_banner.public_timeline": "These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.", "embed.instructions": "Umiestni kód uvedený nižšie pre pridanie tohto statusu na tvoju web stránku.", "embed.preview": "Tu je ako to bude vyzerať:", "emoji_button.activity": "Aktivita", @@ -221,14 +259,14 @@ "follow_request.reject": "Odmietni", "follow_requests.unlocked_explanation": "Síce Váš učet nie je uzamknutý, ale {domain} tím si myslel že môžete chcieť skontrolovať žiadosti o sledovanie z týchto účtov manuálne.", "generic.saved": "Uložené", - "getting_started.developers": "Vývojári", - "getting_started.directory": "Zoznam profilov", + "getting_started.directory": "Directory", "getting_started.documentation": "Dokumentácia", + "getting_started.free_software_notice": "Mastodon is free, open source software. You can view the source code, contribute or report issues at {repository}.", "getting_started.heading": "Začni tu", "getting_started.invite": "Pozvi ľudí", - "getting_started.open_source_notice": "Mastodon je softvér s otvoreným kódom. Nahlásiť chyby, alebo prispievať môžeš na GitHube v {github}.", "getting_started.privacy_policy": "Privacy Policy", "getting_started.security": "Zabezpečenie", + "getting_started.what_is_mastodon": "About Mastodon", "hashtag.column_header.tag_mode.all": "a {additional}", "hashtag.column_header.tag_mode.any": "alebo {additional}", "hashtag.column_header.tag_mode.none": "bez {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Ukáž odpovede", "home.hide_announcements": "Skry oboznámenia", "home.show_announcements": "Ukáž oboznámenia", + "interaction_modal.description.favourite": "With an account on Mastodon, you can favourite this post to let the author know you appreciate it and save it for later.", + "interaction_modal.description.follow": "With an account on Mastodon, you can follow {name} to receive their posts in your home feed.", + "interaction_modal.description.reblog": "With an account on Mastodon, you can boost this post to share it with your own followers.", + "interaction_modal.description.reply": "With an account on Mastodon, you can respond to this post.", + "interaction_modal.on_another_server": "On a different server", + "interaction_modal.on_this_server": "On this server", + "interaction_modal.other_server_instructions": "Simply copy and paste this URL into the search bar of your favourite app or the web interface where you are signed in.", + "interaction_modal.preamble": "Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one.", + "interaction_modal.title.favourite": "Favourite {name}'s post", + "interaction_modal.title.follow": "Follow {name}", + "interaction_modal.title.reblog": "Boost {name}'s post", + "interaction_modal.title.reply": "Reply to {name}'s post", "intervals.full.days": "{number, plural, one {# deň} few {# dní} many {# dní} other {# dní}}", "intervals.full.hours": "{number, plural, one {# hodina} few {# hodín} many {# hodín} other {# hodín}}", "intervals.full.minutes": "{number, plural, one {# minúta} few {# minút} many {# minút} other {# minút}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Trvanie", "mute_modal.hide_notifications": "Skry oznámenia od tohto používateľa?", "mute_modal.indefinite": "Bez obmedzenia", - "navigation_bar.apps": "Aplikácie", + "navigation_bar.about": "About", + "navigation_bar.apps": "Get the app", "navigation_bar.blocks": "Blokovaní užívatelia", "navigation_bar.bookmarks": "Záložky", "navigation_bar.community_timeline": "Miestna časová os", @@ -324,7 +375,7 @@ "navigation_bar.filters": "Filtrované slová", "navigation_bar.follow_requests": "Žiadosti o sledovanie", "navigation_bar.follows_and_followers": "Sledovania a následovatelia", - "navigation_bar.info": "O tomto serveri", + "navigation_bar.info": "About", "navigation_bar.keyboard_shortcuts": "Klávesové skratky", "navigation_bar.lists": "Zoznamy", "navigation_bar.logout": "Odhlás sa", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Pripnuté príspevky", "navigation_bar.preferences": "Nastavenia", "navigation_bar.public_timeline": "Federovaná časová os", + "navigation_bar.search": "Search", "navigation_bar.security": "Zabezbečenie", + "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", "notification.admin.report": "{name} nahlásil/a {target}", "notification.admin.sign_up": "{name} sa zaregistroval/a", "notification.favourite": "{name} si obľúbil/a tvoj príspevok", @@ -401,6 +454,8 @@ "privacy.public.short": "Verejné", "privacy.unlisted.long": "Visible for all, but opted-out of discovery features", "privacy.unlisted.short": "Verejne, ale nezobraziť v osi", + "privacy_policy.last_updated": "Last updated {date}", + "privacy_policy.title": "Privacy Policy", "refresh": "Obnoviť", "regeneration_indicator.label": "Načítava sa…", "regeneration_indicator.sublabel": "Tvoja domovská nástenka sa pripravuje!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "Vyhľadávanie v obsahu príspevkov nieje na tomto Mastodon serveri povolené.", "search_results.title": "Search for {q}", "search_results.total": "{count, number} {count, plural, one {výsledok} many {výsledkov} other {výsledky}}", + "server_banner.about_active_users": "People using this server during the last 30 days (Monthly Active Users)", + "server_banner.active_users": "active users", + "server_banner.administered_by": "Administered by:", + "server_banner.introduction": "{domain} is part of the decentralized social network powered by {mastodon}.", + "server_banner.learn_more": "Learn more", + "server_banner.server_stats": "Server stats:", "sign_in_banner.create_account": "Create account", "sign_in_banner.sign_in": "Sign in", "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "Nikto ešte nevyzdvihol tento príspevok. Keď tak niekto urobí, bude to zobrazené práve tu.", "status.redraft": "Vymaž a prepíš", "status.remove_bookmark": "Odstráň záložku", + "status.replied_to": "Replied to {name}", "status.reply": "Odpovedať", "status.replyAll": "Odpovedz na diskusiu", "status.report": "Nahlás @{name}", @@ -523,9 +585,8 @@ "status.show_more": "Ukáž viac", "status.show_more_all": "Všetkým ukáž viac", "status.show_original": "Show original", - "status.show_thread": "Ukáž diskusné vlákno", "status.translate": "Translate", - "status.translated_from": "Translated from {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Nedostupný/é", "status.unmute_conversation": "Prestaň si nevšímať konverzáciu", "status.unpin": "Odopni z profilu", @@ -538,7 +599,6 @@ "tabs_bar.home": "Domov", "tabs_bar.local_timeline": "Miestna", "tabs_bar.notifications": "Oboznámenia", - "tabs_bar.search": "Hľadaj", "time_remaining.days": "Ostáva {number, plural, one {# deň} few {# dní} many {# dní} other {# dní}}", "time_remaining.hours": "Ostáva {number, plural, one {# hodina} few {# hodín} many {# hodín} other {# hodiny}}", "time_remaining.minutes": "Ostáva {number, plural, one {# minúta} few {# minút} many {# minút} other {# minúty}}", diff --git a/app/javascript/mastodon/locales/sl.json b/app/javascript/mastodon/locales/sl.json index 8eefb02db..2b8ed7626 100644 --- a/app/javascript/mastodon/locales/sl.json +++ b/app/javascript/mastodon/locales/sl.json @@ -1,4 +1,17 @@ { + "about.blocks": "Moderirani strežniki", + "about.contact": "Stik:", + "about.domain_blocks.comment": "Razlog", + "about.domain_blocks.domain": "Domena", + "about.domain_blocks.preamble": "Mastodon vam splošno omogoča ogled vsebin in interakcijo z uporabniki iz vseh drugih strežnikov v fediverzumu. To so izjeme, opravljene na tem strežniku.", + "about.domain_blocks.severity": "Resnost", + "about.domain_blocks.silenced.explanation": "V splošnem ne boste videli profilov in vsebin s tega strežnika, če jih eksplicino ne poiščete ali nanje naročite s sledenjem.", + "about.domain_blocks.silenced.title": "Omejeno", + "about.domain_blocks.suspended.explanation": "Nobeni podatki s tega strežnika ne bodo obdelani, shranjeni ali izmenjani, zaradi česar je nemogoča kakršna koli interakcija ali komunikacija z uporabniki s tega strežnika.", + "about.domain_blocks.suspended.title": "Suspendiran", + "about.not_available": "Ti podatki še niso na voljo na tem strežniku.", + "about.powered_by": "Decentraliziran družabni medij, ki ga poganja {mastodon}", + "about.rules": "Pravila strežnika", "account.account_note_header": "Opombe", "account.add_or_remove_from_list": "Dodaj ali odstrani s seznamov", "account.badges.bot": "Robot", @@ -7,13 +20,16 @@ "account.block_domain": "Blokiraj domeno {domain}", "account.blocked": "Blokirano", "account.browse_more_on_origin_server": "Brskaj več po izvirnem profilu", - "account.cancel_follow_request": "Prekliči prošnjo za sledenje", + "account.cancel_follow_request": "Umakni zahtevo za sledenje", "account.direct": "Neposredno sporočilo @{name}", "account.disable_notifications": "Ne obveščaj me več, ko ima @{name} novo objavo", "account.domain_blocked": "Blokirana domena", "account.edit_profile": "Uredi profil", "account.enable_notifications": "Obvesti me, ko ima @{name} novo objavo", "account.endorse": "Izpostavi v profilu", + "account.featured_tags.last_status_at": "Zadnja objava {date}", + "account.featured_tags.last_status_never": "Ni objav", + "account.featured_tags.title": "Izpostavljeni ključniki {name}", "account.follow": "Sledi", "account.followers": "Sledilci", "account.followers.empty": "Nihče ne sledi temu uporabniku.", @@ -23,7 +39,7 @@ "account.follows.empty": "Ta uporabnik še ne sledi nikomur.", "account.follows_you": "Vam sledi", "account.hide_reblogs": "Skrij izpostavitve od @{name}", - "account.joined": "Pridružen/a {date}", + "account.joined_short": "Joined", "account.languages": "Spremeni naročene jezike", "account.link_verified_on": "Lastništvo te povezave je bilo preverjeno {date}", "account.locked_info": "Stanje zasebnosti računa je nastavljeno na zaklenjeno. Lastnik ročno pregleda, kdo ga lahko spremlja.", @@ -63,12 +79,24 @@ "audio.hide": "Skrij zvok", "autosuggest_hashtag.per_week": "{count} na teden", "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.copy_stacktrace": "Kopiraj poročilo o napaki", + "bundle_column_error.error.body": "Zahtevane strani ni mogoče upodobiti. Vzrok težave je morda hrošč v naši kodi ali pa nezdružljivost z brskalnikom.", + "bundle_column_error.error.title": "Oh, ne!", + "bundle_column_error.network.body": "Pri poskusu nalaganja te strani je prišlo do napake. Vzrok je lahko začasna težava z vašo internetno povezavo ali s tem strežnikom.", + "bundle_column_error.network.title": "Napaka omrežja", "bundle_column_error.retry": "Poskusi ponovno", - "bundle_column_error.title": "Napaka omrežja", + "bundle_column_error.return": "Nazaj domov", + "bundle_column_error.routing.body": "Zahtevane strani ni mogoče najti. Ali ste prepričani, da je naslov URL v naslovni vrstici pravilen?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Zapri", "bundle_modal_error.message": "Med nalaganjem te komponente je prišlo do napake.", "bundle_modal_error.retry": "Poskusi ponovno", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "O programu", "column.blocks": "Blokirani uporabniki", "column.bookmarks": "Zaznamki", "column.community": "Lokalna časovnica", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "Blokiraj in Prijavi", "confirmations.block.confirm": "Blokiraj", "confirmations.block.message": "Ali ste prepričani, da želite blokirati {name}?", + "confirmations.cancel_follow_request.confirm": "Umakni zahtevo", + "confirmations.cancel_follow_request.message": "Ali ste prepričani, da želite umakniti svojo zahtevo, da bi sledili {name}?", "confirmations.delete.confirm": "Izbriši", "confirmations.delete.message": "Ali ste prepričani, da želite izbrisati to objavo?", "confirmations.delete_list.confirm": "Izbriši", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Označi kot prebrano", "conversation.open": "Prikaži pogovor", "conversation.with": "Z {names}", + "copypaste.copied": "Kopirano", + "copypaste.copy": "Kopiraj", "directory.federated": "Iz znanega fediverzuma", "directory.local": "Samo iz {domain}", "directory.new_arrivals": "Novi prišleki", "directory.recently_active": "Nedavno aktiven/a", + "dismissable_banner.community_timeline": "To so najnovejše javne objave oseb, katerih računi gostujejo na {domain}.", + "dismissable_banner.dismiss": "Opusti", + "dismissable_banner.explore_links": "O teh novicah ravno zdaj veliko govorijo osebe na tem in drugih strežnikih decentraliziranega omrežja.", + "dismissable_banner.explore_statuses": "Te objave s tega in drugih strežnikov v decentraliziranem omrežju pridobivajo ravno zdaj veliko pozornosti na tem strežniku.", + "dismissable_banner.explore_tags": "Ravno zdaj dobivajo ti ključniki veliko pozoronosti med osebami na tem in drugih strežnikih decentraliziranega omrežja.", + "dismissable_banner.public_timeline": "To so zadnje javne objave oseb na tem in drugih strežnikih decentraliziranega omrežja, za katera ve ta strežnik.", "embed.instructions": "Vstavi ta status na svojo spletno stran tako, da kopirate spodnjo kodo.", "embed.preview": "Tako bo izgledalo:", "emoji_button.activity": "Dejavnost", @@ -221,14 +259,14 @@ "follow_request.reject": "Zavrni", "follow_requests.unlocked_explanation": "Čeprav vaš račun ni zaklenjen, zaposleni pri {domain} menijo, da bi morda želeli pregledati zahteve za sledenje teh računov ročno.", "generic.saved": "Shranjeno", - "getting_started.developers": "Razvijalci", - "getting_started.directory": "Imenik profilov", + "getting_started.directory": "Adresár", "getting_started.documentation": "Dokumentacija", + "getting_started.free_software_notice": "Mastodon je brezplačno, odprtokodno programje. V {repository} si lahko ogledate izvorno kodo, prispevate svojo kodo in poročate o težavah.", "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.privacy_policy": "Pravilnik o zasebnosti", "getting_started.security": "Varnost", + "getting_started.what_is_mastodon": "O programu Mastodon", "hashtag.column_header.tag_mode.all": "in {additional}", "hashtag.column_header.tag_mode.any": "ali {additional}", "hashtag.column_header.tag_mode.none": "brez {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Pokaži odgovore", "home.hide_announcements": "Skrij objave", "home.show_announcements": "Prikaži objave", + "interaction_modal.description.favourite": "Z računom na Mastodonu lahko to objavo postavite med priljubljene in tako avtorju nakažete, da jo cenite, in jo shranite za kasneje.", + "interaction_modal.description.follow": "Z računom na Mastodonu lahko sledite {name}, da prejemate njihove objave v svoj domači vir.", + "interaction_modal.description.reblog": "Z računom na Mastodonu lahko izpostavite to objavo, tako da jo delite s svojimi sledilci.", + "interaction_modal.description.reply": "Z računom na Masodonu lahko odgovorite na to objavo.", + "interaction_modal.on_another_server": "Na drugem strežniku", + "interaction_modal.on_this_server": "Na tem strežniku", + "interaction_modal.other_server_instructions": "Enostavno kopirajte in prilepite ta URL v iskalno vrstico svoje priljubljene aplikacije ali spletni vmesnik, kjer ste prijavljeni.", + "interaction_modal.preamble": "Ker je Mastodon decentraliziran, lahko uporabite svoj obstoječi račun, ki gostuje na drugem strežniku Mastodon ali združljivi platformi, če nimate računa na tej.", + "interaction_modal.title.favourite": "Daj objavo {name} med priljubljene", + "interaction_modal.title.follow": "Sledi {name}", + "interaction_modal.title.reblog": "Izpostavi objavo {name}", + "interaction_modal.title.reply": "Odgovori na objavo {name}", "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}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Trajanje", "mute_modal.hide_notifications": "Skrij obvestila tega uporabnika?", "mute_modal.indefinite": "Nedoločeno", - "navigation_bar.apps": "Mobilne aplikacije", + "navigation_bar.about": "O programu", + "navigation_bar.apps": "Prenesite aplikacijo", "navigation_bar.blocks": "Blokirani uporabniki", "navigation_bar.bookmarks": "Zaznamki", "navigation_bar.community_timeline": "Lokalna časovnica", @@ -324,7 +375,7 @@ "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.info": "O programu", "navigation_bar.keyboard_shortcuts": "Hitre tipke", "navigation_bar.lists": "Seznami", "navigation_bar.logout": "Odjava", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Pripete objave", "navigation_bar.preferences": "Nastavitve", "navigation_bar.public_timeline": "Združena časovnica", + "navigation_bar.search": "Search", "navigation_bar.security": "Varnost", + "not_signed_in_indicator.not_signed_in": "Za dostop do tega vira se morate prijaviti.", "notification.admin.report": "{name} je prijavil/a {target}", "notification.admin.sign_up": "{name} se je vpisal/a", "notification.favourite": "{name} je vzljubil/a vaš status", @@ -401,6 +454,8 @@ "privacy.public.short": "Javno", "privacy.unlisted.long": "Vidno za vse, vendar izključeno iz funkcionalnosti odkrivanja", "privacy.unlisted.short": "Ni prikazano", + "privacy_policy.last_updated": "Zadnja posodobitev {date}", + "privacy_policy.title": "Pravilnik o zasebnosti", "refresh": "Osveži", "regeneration_indicator.label": "Nalaganje…", "regeneration_indicator.sublabel": "Vaš domači vir se pripravlja!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "Iskanje objav po njihovi vsebini ni omogočeno na tem strežniku Mastodon.", "search_results.title": "Išči {q}", "search_results.total": "{count, number} {count, plural, one {rezultat} other {rezultatov}}", + "server_banner.about_active_users": "Osebe, ki so uporabljale ta strežnik zadnjih 30 dni (dejavni uporabniki meseca)", + "server_banner.active_users": "dejavnih uporabnikov", + "server_banner.administered_by": "Upravlja:", + "server_banner.introduction": "{domain} je del decentraliziranega družbenega omrežja, ki ga poganja {mastodon}.", + "server_banner.learn_more": "Več o tem", + "server_banner.server_stats": "Statistika strežnika:", "sign_in_banner.create_account": "Ustvari račun", "sign_in_banner.sign_in": "Prijava", "sign_in_banner.text": "Prijavite se, da sledite profilom ali ključnikom, dodajate med priljubljene, delite z drugimi ter odgovarjate na objave, pa tudi ostajate v interakciji iz svojega računa na drugem strežniku.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "Nihče še ni izpostavil te objave. Ko se bo to zgodilo, se bodo pojavile tukaj.", "status.redraft": "Izbriši in preoblikuj", "status.remove_bookmark": "Odstrani zaznamek", + "status.replied_to": "Replied to {name}", "status.reply": "Odgovori", "status.replyAll": "Odgovori na objavo", "status.report": "Prijavi @{name}", @@ -523,9 +585,8 @@ "status.show_more": "Prikaži več", "status.show_more_all": "Prikaži več za vse", "status.show_original": "Pokaži izvirnik", - "status.show_thread": "Prikaži objavo", "status.translate": "Prevedi", - "status.translated_from": "Prevedeno iz jezika: {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Ni na voljo", "status.unmute_conversation": "Odtišaj pogovor", "status.unpin": "Odpni iz profila", @@ -538,7 +599,6 @@ "tabs_bar.home": "Domov", "tabs_bar.local_timeline": "Krajevno", "tabs_bar.notifications": "Obvestila", - "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", diff --git a/app/javascript/mastodon/locales/sq.json b/app/javascript/mastodon/locales/sq.json index 727e9ea16..3239d7cf4 100644 --- a/app/javascript/mastodon/locales/sq.json +++ b/app/javascript/mastodon/locales/sq.json @@ -1,4 +1,17 @@ { + "about.blocks": "Shërbyes të moderuar", + "about.contact": "Kontakt:", + "about.domain_blocks.comment": "Arsye", + "about.domain_blocks.domain": "Përkatësi", + "about.domain_blocks.preamble": "Mastodon-i ju lë përgjithësisht të shihni lëndë prej përdoruesish dhe të ndërveproni me ta nga cilido shërbyes tjetër qofshin në fedivers. Ka përjashtime që janë bërë në këtë shërbyes të dhënë.", + "about.domain_blocks.severity": "Rëndësi", + "about.domain_blocks.silenced.explanation": "Përgjithësisht s’do të shihni profile dhe lëndë nga ky shërbyes, veç në i kërkofshi shprehimisht apo zgjidhni të bëhet kjo, duke i ndjekur.", + "about.domain_blocks.silenced.title": "E kufizuar", + "about.domain_blocks.suspended.explanation": "S’do të përpunohen, depozitohen apo shkëmbehen të dhëna të këtij shërbyesi, duke e bërë të pamundur çfarëdo ndërveprimi apo komunikimi me përdorues nga ky shërbyes.", + "about.domain_blocks.suspended.title": "E pezulluar", + "about.not_available": "Ky informacion nuk jepet në këtë shërbyes.", + "about.powered_by": "Media shoqërore e decentralizuar, bazuar në {mastodon}", + "about.rules": "Rregulla shërbyesi", "account.account_note_header": "Shënim", "account.add_or_remove_from_list": "Shtoni ose Hiqni prej listash", "account.badges.bot": "Robot", @@ -7,13 +20,16 @@ "account.block_domain": "Blloko përkatësinë {domain}", "account.blocked": "E bllokuar", "account.browse_more_on_origin_server": "Shfletoni më tepër rreth profilit origjinal", - "account.cancel_follow_request": "Anulo kërkesë ndjekjeje", + "account.cancel_follow_request": "Withdraw follow request", "account.direct": "Mesazh i drejtpërdrejtë për @{name}", "account.disable_notifications": "Resht së njoftuari mua, kur poston @{name}", "account.domain_blocked": "Përkatësia u bllokua", "account.edit_profile": "Përpunoni profilin", "account.enable_notifications": "Njoftomë, kur poston @{name}", "account.endorse": "Pasqyrojeni në profil", + "account.featured_tags.last_status_at": "Last post on {date}", + "account.featured_tags.last_status_never": "No posts", + "account.featured_tags.title": "{name}'s featured hashtags", "account.follow": "Ndiqeni", "account.followers": "Ndjekës", "account.followers.empty": "Këtë përdorues ende s’e ndjek kush.", @@ -23,7 +39,7 @@ "account.follows.empty": "Ky përdorues ende s’ndjek kënd.", "account.follows_you": "Ju ndjek", "account.hide_reblogs": "Fshih përforcime nga @{name}", - "account.joined": "U bë pjesë më {date}", + "account.joined_short": "Joined", "account.languages": "Ndryshoni gjuhë pajtimesh", "account.link_verified_on": "Pronësia e kësaj lidhjeje qe kontrolluar më {date}", "account.locked_info": "Gjendja e privatësisë së kësaj llogarie është caktuar si e kyçur. I zoti merr dorazi në shqyrtim cilët mund ta ndjekin.", @@ -63,12 +79,24 @@ "audio.hide": "Fshihe audion", "autosuggest_hashtag.per_week": "{count} për javë", "boost_modal.combo": "Që kjo të anashkalohet herës tjetër, mund të shtypni {combo}", - "bundle_column_error.body": "Diç shkoi ters teksa ngarkohej ky përbërës.", + "bundle_column_error.copy_stacktrace": "Copy error report", + "bundle_column_error.error.body": "The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.", + "bundle_column_error.error.title": "Oh, no!", + "bundle_column_error.network.body": "There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.", + "bundle_column_error.network.title": "Network error", "bundle_column_error.retry": "Riprovoni", - "bundle_column_error.title": "Gabim rrjeti", + "bundle_column_error.return": "Go back home", + "bundle_column_error.routing.body": "The requested page could not be found. Are you sure the URL in the address bar is correct?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Mbylle", "bundle_modal_error.message": "Diç shkoi ters teksa ngarkohej ky përbërës.", "bundle_modal_error.retry": "Riprovoni", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "Mbi", "column.blocks": "Përdorues të bllokuar", "column.bookmarks": "Faqerojtës", "column.community": "Rrjedhë kohore vendore", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "Bllokojeni & Raportojeni", "confirmations.block.confirm": "Bllokoje", "confirmations.block.message": "Jeni i sigurt se doni të bllokohet {name}?", + "confirmations.cancel_follow_request.confirm": "Withdraw request", + "confirmations.cancel_follow_request.message": "Are you sure you want to withdraw your request to follow {name}?", "confirmations.delete.confirm": "Fshije", "confirmations.delete.message": "Jeni i sigurt se doni të fshihet kjo gjendje?", "confirmations.delete_list.confirm": "Fshije", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Vëri shenjë si të lexuar", "conversation.open": "Shfaq bisedën", "conversation.with": "Me {names}", + "copypaste.copied": "U kopjua", + "copypaste.copy": "Kopjoje", "directory.federated": "Nga fedivers i njohur", "directory.local": "Vetëm nga {domain}", "directory.new_arrivals": "Të ardhur rishtas", "directory.recently_active": "Aktivë së fundi", + "dismissable_banner.community_timeline": "Këto janë postime më të freskëta publike nga persona llogaritë e të cilëve strehohen nga {domain}.", + "dismissable_banner.dismiss": "Hidhe tej", + "dismissable_banner.explore_links": "Këto histori të reja po tirren nga persona në këtë shërbyes dhe të tjerë të tillë të rrjetit të decentralizuar mu tani.", + "dismissable_banner.explore_statuses": "Këto postime nga ky shërbyes dhe të tjerë në rrjetin e decentralizuar po tërheqin vëmendjen tani.", + "dismissable_banner.explore_tags": "Këta hashtag-ë po tërheqin vëmendjen mes personave në këtë shërbyes dhe të tjerë të tillë të rrjetit të decentralizuar mu tani.", + "dismissable_banner.public_timeline": "Këto janë postimet publike më të freskëta nga persona në këtë shërbyes dhe të tjerë të rrejtit të decentralizuar për të cilët ky shërbyes ka dijeni.", "embed.instructions": "Trupëzojeni këtë gjendje në sajtin tuaj duke kopjuar kodin më poshtë.", "embed.preview": "Ja si do të duket:", "emoji_button.activity": "Veprimtari", @@ -221,14 +259,14 @@ "follow_request.reject": "Hidhe tej", "follow_requests.unlocked_explanation": "Edhe pse llogaria juaj s’është e kyçur, ekipi i {domain} mendoi se mund të donit të shqyrtonit dorazi kërkesa ndjekjeje prej këtyre llogarive.", "generic.saved": "U ruajt", - "getting_started.developers": "Zhvillues", - "getting_started.directory": "Drejtori profilesh", + "getting_started.directory": "Drejtori", "getting_started.documentation": "Dokumentim", + "getting_started.free_software_notice": "Mastodon-i është software i lirë dhe me burim të hapët. Te {repository} mund t’i shihni kodin burim, të jepni ndihmesë ose të njoftoni çështje.", "getting_started.heading": "Si t’ia fillohet", "getting_started.invite": "Ftoni njerëz", - "getting_started.open_source_notice": "Mastodon-i është software me burim të hapur. Mund të jepni ndihmesë ose të njoftoni probleme në GitHub, te {github}.", "getting_started.privacy_policy": "Rregulla Privatësie", "getting_started.security": "Rregullime llogarie", + "getting_started.what_is_mastodon": "Mbi Mastodon-in", "hashtag.column_header.tag_mode.all": "dhe {additional}", "hashtag.column_header.tag_mode.any": "ose {additional}", "hashtag.column_header.tag_mode.none": "pa {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Shfaq përgjigje", "home.hide_announcements": "Fshihi lajmërimet", "home.show_announcements": "Shfaqi lajmërimet", + "interaction_modal.description.favourite": "Me një llogari në Mastodon, mund ta pëlqeni këtë postim, për t’i bërë të ditur autorit se e çmoni dhe e ruani për më vonë.", + "interaction_modal.description.follow": "Me një llogari në Mastodon, mund ta ndiqni {name} për të marrë postimet e tyre në prurjen tuaj të kreut.", + "interaction_modal.description.reblog": "Me një llogari në Mastodon, mund ta përforconi këtë postim për ta ndarë me ndjekësit tuaj.", + "interaction_modal.description.reply": "Me një llogari në Mastodon, mund t’i përgjigjeni këtij postimi.", + "interaction_modal.on_another_server": "Në një tjetër shërbyes", + "interaction_modal.on_this_server": "Në këtë shërbyes", + "interaction_modal.other_server_instructions": "Thjesht kopjojeni dhe ngjiteni këtë URL te shtylla e kërkimeve të aplikacionit tuaj apo ndërfaqes tuaj web të parapëlqyer, kur të jeni i futur në llogari.", + "interaction_modal.preamble": "Ngaqë Mastodon-i është i decentralizuar, mund të përdorni llogarinë tuaj ekzistuese të sterhuar nga një tjetër shërbyes Mastodon, ose platformë e përputhshme, nëse s’keni një llogari në këtë shërbyes.", + "interaction_modal.title.favourite": "Parapëlqejeni postimin e {name}", + "interaction_modal.title.follow": "Ndiq {name}", + "interaction_modal.title.reblog": "Përforconi postimin e {name}", + "interaction_modal.title.reply": "Përgjigjuni postimit të {name}", "intervals.full.days": "{number, plural, one {# ditë} other {# ditë}}", "intervals.full.hours": "{number, plural, one {# orë} other {# orë}}", "intervals.full.minutes": "{number, plural, one {# minutë} other {# minuta}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Kohëzgjatje", "mute_modal.hide_notifications": "Të kalohen të fshehura njoftimet prej këtij përdoruesi?", "mute_modal.indefinite": "E pacaktuar", - "navigation_bar.apps": "Aplikacione për celular", + "navigation_bar.about": "Mbi", + "navigation_bar.apps": "Merreni aplikacionin", "navigation_bar.blocks": "Përdorues të bllokuar", "navigation_bar.bookmarks": "Faqerojtës", "navigation_bar.community_timeline": "Rrjedhë kohore vendore", @@ -324,7 +375,7 @@ "navigation_bar.filters": "Fjalë të heshtuara", "navigation_bar.follow_requests": "Kërkesa për ndjekje", "navigation_bar.follows_and_followers": "Ndjekje dhe ndjekës", - "navigation_bar.info": "Mbi këtë shërbyes", + "navigation_bar.info": "Mbi", "navigation_bar.keyboard_shortcuts": "Taste përkatës", "navigation_bar.lists": "Lista", "navigation_bar.logout": "Dalje", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Mesazhe të fiksuar", "navigation_bar.preferences": "Parapëlqime", "navigation_bar.public_timeline": "Rrjedhë kohore të federuarish", + "navigation_bar.search": "Search", "navigation_bar.security": "Siguri", + "not_signed_in_indicator.not_signed_in": "Që të përdorni këtë burim, lypset të bëni hyrjen.", "notification.admin.report": "{name} raportoi {target}", "notification.admin.sign_up": "{name} u regjistrua", "notification.favourite": "{name} pëlqeu mesazhin tuaj", @@ -401,6 +454,8 @@ "privacy.public.short": "Publik", "privacy.unlisted.long": "I dukshëm për të tërë, por lënë jashtë nga veçoritë e zbulimit", "privacy.unlisted.short": "Jo në lista", + "privacy_policy.last_updated": "Përditësuar së fundi më {date}", + "privacy_policy.title": "Rregulla Privatësie", "refresh": "Rifreskoje", "regeneration_indicator.label": "Po ngarkohet…", "regeneration_indicator.sublabel": "Prurja juaj vetjake po përgatitet!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "Kërkimi i mesazheve sipas lëndës së tyre s’është i aktivizuar në këtë shërbyes Mastodon.", "search_results.title": "Kërkoni për {q}", "search_results.total": "{count, number} {count, plural, one {përfundim} other {përfundime}}", + "server_banner.about_active_users": "Persona që përdorin këtë shërbyes gjatë 30 ditëve të fundit (Përdorues Mujorë Aktivë)", + "server_banner.active_users": "përdorues aktivë", + "server_banner.administered_by": "Administruar nga:", + "server_banner.introduction": "{domain} është pjesë e rrjetit shoqëror të decentralizuar të ngritur mbi {mastodon}.", + "server_banner.learn_more": "Mësoni më tepër", + "server_banner.server_stats": "Statistika shërbyesi:", "sign_in_banner.create_account": "Krijoni llogari", "sign_in_banner.sign_in": "Hyni", "sign_in_banner.text": "Që të ndiqni profile ose hashtag-ë, të pëlqeni, të ndani me të tjerë dhe të përgjigjeni në postime, apo të ndërveproni me llogarinë tuaj nga një shërbyes tjetër, bëni hyrjen.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "Këtë mesazh s’e ka përforcuar njeri deri tani. Kur ta bëjë dikush, kjo do të duket këtu.", "status.redraft": "Fshijeni & rihartojeni", "status.remove_bookmark": "Hiqe faqerojtësin", + "status.replied_to": "Replied to {name}", "status.reply": "Përgjigjuni", "status.replyAll": "Përgjigjuni rrjedhës", "status.report": "Raportojeni @{name}", @@ -523,9 +585,8 @@ "status.show_more": "Shfaq më tepër", "status.show_more_all": "Shfaq më tepër për të tërë", "status.show_original": "Shfaq origjinalin", - "status.show_thread": "Shfaq rrjedhën", "status.translate": "Përktheje", - "status.translated_from": "Përkthyer nga {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Jo e passhme", "status.unmute_conversation": "Ktheji zërin bisedës", "status.unpin": "Shfiksoje nga profili", @@ -538,7 +599,6 @@ "tabs_bar.home": "Kreu", "tabs_bar.local_timeline": "Vendore", "tabs_bar.notifications": "Njoftime", - "tabs_bar.search": "Kërkim", "time_remaining.days": "Edhe {number, plural, one {# ditë} other {# ditë}}", "time_remaining.hours": "Edhe {number, plural, one {# orë} other {# orë}}", "time_remaining.minutes": "Edhe {number, plural, one {# minutë} other {# minuta}}", diff --git a/app/javascript/mastodon/locales/sr-Latn.json b/app/javascript/mastodon/locales/sr-Latn.json index 63d09b7a9..843fbcb11 100644 --- a/app/javascript/mastodon/locales/sr-Latn.json +++ b/app/javascript/mastodon/locales/sr-Latn.json @@ -1,4 +1,17 @@ { + "about.blocks": "Moderated servers", + "about.contact": "Contact:", + "about.domain_blocks.comment": "Reason", + "about.domain_blocks.domain": "Domain", + "about.domain_blocks.preamble": "Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.", + "about.domain_blocks.severity": "Severity", + "about.domain_blocks.silenced.explanation": "You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.", + "about.domain_blocks.silenced.title": "Limited", + "about.domain_blocks.suspended.explanation": "No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.", + "about.domain_blocks.suspended.title": "Suspended", + "about.not_available": "This information has not been made available on this server.", + "about.powered_by": "Decentralized social media powered by {mastodon}", + "about.rules": "Server rules", "account.account_note_header": "Note", "account.add_or_remove_from_list": "Add or Remove from lists", "account.badges.bot": "Bot", @@ -7,13 +20,16 @@ "account.block_domain": "Sakrij sve sa domena {domain}", "account.blocked": "Blocked", "account.browse_more_on_origin_server": "Browse more on the original profile", - "account.cancel_follow_request": "Cancel follow request", + "account.cancel_follow_request": "Withdraw follow request", "account.direct": "Direct Message @{name}", "account.disable_notifications": "Stop notifying me when @{name} posts", "account.domain_blocked": "Domain hidden", "account.edit_profile": "Izmeni profil", "account.enable_notifications": "Notify me when @{name} posts", "account.endorse": "Feature on profile", + "account.featured_tags.last_status_at": "Last post on {date}", + "account.featured_tags.last_status_never": "No posts", + "account.featured_tags.title": "{name}'s featured hashtags", "account.follow": "Zaprati", "account.followers": "Pratioca", "account.followers.empty": "No one follows this user yet.", @@ -23,7 +39,7 @@ "account.follows.empty": "This user doesn't follow anyone yet.", "account.follows_you": "Prati Vas", "account.hide_reblogs": "Sakrij podrške koje daje korisnika @{name}", - "account.joined": "Joined {date}", + "account.joined_short": "Joined", "account.languages": "Change subscribed languages", "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.", @@ -63,12 +79,24 @@ "audio.hide": "Hide audio", "autosuggest_hashtag.per_week": "{count} per week", "boost_modal.combo": "Možete pritisnuti {combo} da preskočite ovo sledeći put", - "bundle_column_error.body": "Nešto je pošlo po zlu prilikom učitavanja ove komponente.", + "bundle_column_error.copy_stacktrace": "Copy error report", + "bundle_column_error.error.body": "The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.", + "bundle_column_error.error.title": "Oh, no!", + "bundle_column_error.network.body": "There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.", + "bundle_column_error.network.title": "Network error", "bundle_column_error.retry": "Pokušajte ponovo", - "bundle_column_error.title": "Mrežna greška", + "bundle_column_error.return": "Go back home", + "bundle_column_error.routing.body": "The requested page could not be found. Are you sure the URL in the address bar is correct?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Zatvori", "bundle_modal_error.message": "Nešto nije bilo u redu pri učitavanju ove komponente.", "bundle_modal_error.retry": "Pokušajte ponovo", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "About", "column.blocks": "Blokirani korisnici", "column.bookmarks": "Bookmarks", "column.community": "Lokalna lajna", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "Block & Report", "confirmations.block.confirm": "Blokiraj", "confirmations.block.message": "Da li ste sigurni da želite da blokirate korisnika {name}?", + "confirmations.cancel_follow_request.confirm": "Withdraw request", + "confirmations.cancel_follow_request.message": "Are you sure you want to withdraw your request to follow {name}?", "confirmations.delete.confirm": "Obriši", "confirmations.delete.message": "Da li ste sigurni da želite obrišete ovaj status?", "confirmations.delete_list.confirm": "Obriši", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Mark as read", "conversation.open": "View conversation", "conversation.with": "With {names}", + "copypaste.copied": "Copied", + "copypaste.copy": "Copy", "directory.federated": "From known fediverse", "directory.local": "From {domain} only", "directory.new_arrivals": "New arrivals", "directory.recently_active": "Recently active", + "dismissable_banner.community_timeline": "These are the most recent public posts from people whose accounts are hosted by {domain}.", + "dismissable_banner.dismiss": "Dismiss", + "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", + "dismissable_banner.explore_statuses": "These posts from this and other servers in the decentralized network are gaining traction on this server right now.", + "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", + "dismissable_banner.public_timeline": "These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.", "embed.instructions": "Ugradi ovaj status na Vaš veb sajt kopiranjem koda ispod.", "embed.preview": "Ovako će da izgleda:", "emoji_button.activity": "Aktivnost", @@ -221,14 +259,14 @@ "follow_request.reject": "Odbij", "follow_requests.unlocked_explanation": "Even though your account is not locked, the {domain} staff thought you might want to review follow requests from these accounts manually.", "generic.saved": "Saved", - "getting_started.developers": "Developers", - "getting_started.directory": "Profile directory", + "getting_started.directory": "Directory", "getting_started.documentation": "Documentation", + "getting_started.free_software_notice": "Mastodon is free, open source software. You can view the source code, contribute or report issues at {repository}.", "getting_started.heading": "Da počnete", "getting_started.invite": "Invite people", - "getting_started.open_source_notice": "Mastodont je softver otvorenog koda. Možete mu doprineti ili prijaviti probleme preko GitHub-a na {github}.", "getting_started.privacy_policy": "Privacy Policy", "getting_started.security": "Security", + "getting_started.what_is_mastodon": "About Mastodon", "hashtag.column_header.tag_mode.all": "and {additional}", "hashtag.column_header.tag_mode.any": "or {additional}", "hashtag.column_header.tag_mode.none": "without {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Prikaži odgovore", "home.hide_announcements": "Hide announcements", "home.show_announcements": "Show announcements", + "interaction_modal.description.favourite": "With an account on Mastodon, you can favourite this post to let the author know you appreciate it and save it for later.", + "interaction_modal.description.follow": "With an account on Mastodon, you can follow {name} to receive their posts in your home feed.", + "interaction_modal.description.reblog": "With an account on Mastodon, you can boost this post to share it with your own followers.", + "interaction_modal.description.reply": "With an account on Mastodon, you can respond to this post.", + "interaction_modal.on_another_server": "On a different server", + "interaction_modal.on_this_server": "On this server", + "interaction_modal.other_server_instructions": "Simply copy and paste this URL into the search bar of your favourite app or the web interface where you are signed in.", + "interaction_modal.preamble": "Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one.", + "interaction_modal.title.favourite": "Favourite {name}'s post", + "interaction_modal.title.follow": "Follow {name}", + "interaction_modal.title.reblog": "Boost {name}'s post", + "interaction_modal.title.reply": "Reply to {name}'s post", "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}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Duration", "mute_modal.hide_notifications": "Sakrij obaveštenja od ovog korisnika?", "mute_modal.indefinite": "Indefinite", - "navigation_bar.apps": "Mobile apps", + "navigation_bar.about": "About", + "navigation_bar.apps": "Get the app", "navigation_bar.blocks": "Blokirani korisnici", "navigation_bar.bookmarks": "Bookmarks", "navigation_bar.community_timeline": "Lokalna lajna", @@ -324,7 +375,7 @@ "navigation_bar.filters": "Muted words", "navigation_bar.follow_requests": "Zahtevi za praćenje", "navigation_bar.follows_and_followers": "Follows and followers", - "navigation_bar.info": "O ovoj instanci", + "navigation_bar.info": "About", "navigation_bar.keyboard_shortcuts": "Prečice na tastaturi", "navigation_bar.lists": "Liste", "navigation_bar.logout": "Odjava", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Prikačeni tutovi", "navigation_bar.preferences": "Podešavanja", "navigation_bar.public_timeline": "Federisana lajna", + "navigation_bar.search": "Search", "navigation_bar.security": "Security", + "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", "notification.admin.report": "{name} reported {target}", "notification.admin.sign_up": "{name} signed up", "notification.favourite": "{name} je stavio Vaš status kao omiljeni", @@ -401,6 +454,8 @@ "privacy.public.short": "Javno", "privacy.unlisted.long": "Visible for all, but opted-out of discovery features", "privacy.unlisted.short": "Neizlistano", + "privacy_policy.last_updated": "Last updated {date}", + "privacy_policy.title": "Privacy Policy", "refresh": "Refresh", "regeneration_indicator.label": "Loading…", "regeneration_indicator.sublabel": "Your home feed is being prepared!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.title": "Search for {q}", "search_results.total": "{count, number} {count, plural, one {rezultat} few {rezultata} other {rezultata}}", + "server_banner.about_active_users": "People using this server during the last 30 days (Monthly Active Users)", + "server_banner.active_users": "active users", + "server_banner.administered_by": "Administered by:", + "server_banner.introduction": "{domain} is part of the decentralized social network powered by {mastodon}.", + "server_banner.learn_more": "Learn more", + "server_banner.server_stats": "Server stats:", "sign_in_banner.create_account": "Create account", "sign_in_banner.sign_in": "Sign in", "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "No one has boosted this toot yet. When someone does, they will show up here.", "status.redraft": "Delete & re-draft", "status.remove_bookmark": "Remove bookmark", + "status.replied_to": "Replied to {name}", "status.reply": "Odgovori", "status.replyAll": "Odgovori na diskusiju", "status.report": "Prijavi korisnika @{name}", @@ -523,9 +585,8 @@ "status.show_more": "Prikaži više", "status.show_more_all": "Show more for all", "status.show_original": "Show original", - "status.show_thread": "Show thread", "status.translate": "Translate", - "status.translated_from": "Translated from {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Not available", "status.unmute_conversation": "Uključi prepisku", "status.unpin": "Otkači sa profila", @@ -538,7 +599,6 @@ "tabs_bar.home": "Početna", "tabs_bar.local_timeline": "Lokalno", "tabs_bar.notifications": "Obaveštenja", - "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", diff --git a/app/javascript/mastodon/locales/sr.json b/app/javascript/mastodon/locales/sr.json index 52c994ee9..4c775626a 100644 --- a/app/javascript/mastodon/locales/sr.json +++ b/app/javascript/mastodon/locales/sr.json @@ -1,4 +1,17 @@ { + "about.blocks": "Moderated servers", + "about.contact": "Contact:", + "about.domain_blocks.comment": "Reason", + "about.domain_blocks.domain": "Domain", + "about.domain_blocks.preamble": "Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.", + "about.domain_blocks.severity": "Severity", + "about.domain_blocks.silenced.explanation": "You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.", + "about.domain_blocks.silenced.title": "Limited", + "about.domain_blocks.suspended.explanation": "No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.", + "about.domain_blocks.suspended.title": "Suspended", + "about.not_available": "This information has not been made available on this server.", + "about.powered_by": "Decentralized social media powered by {mastodon}", + "about.rules": "Server rules", "account.account_note_header": "Напомена", "account.add_or_remove_from_list": "Додај или Одстрани са листа", "account.badges.bot": "Бот", @@ -7,13 +20,16 @@ "account.block_domain": "Сакриј све са домена {domain}", "account.blocked": "Блокиран", "account.browse_more_on_origin_server": "Погледајте још на оригиналном налогу", - "account.cancel_follow_request": "Поништи захтеве за праћење", + "account.cancel_follow_request": "Withdraw follow request", "account.direct": "Директна порука @{name}", "account.disable_notifications": "Прекини обавештавање за објаве корисника @{name}", "account.domain_blocked": "Домен сакривен", "account.edit_profile": "Уреди налог", "account.enable_notifications": "Обавести ме када @{name} објави", "account.endorse": "Истакнуто на налогу", + "account.featured_tags.last_status_at": "Last post on {date}", + "account.featured_tags.last_status_never": "No posts", + "account.featured_tags.title": "{name}'s featured hashtags", "account.follow": "Запрати", "account.followers": "Пратиоци", "account.followers.empty": "Тренутно нико не прати овог корисника.", @@ -23,7 +39,7 @@ "account.follows.empty": "Корисник тренутно не прати никога.", "account.follows_you": "Прати Вас", "account.hide_reblogs": "Сакриј подршке које даје корисника @{name}", - "account.joined": "Придружио/ла се {date}", + "account.joined_short": "Joined", "account.languages": "Change subscribed languages", "account.link_verified_on": "Власништво над овом везом је проверено {date}", "account.locked_info": "Статус приватности овог налога је подешен на закључано. Власник ручно прегледа ко га може пратити.", @@ -63,12 +79,24 @@ "audio.hide": "Hide audio", "autosuggest_hashtag.per_week": "{count} недељно", "boost_modal.combo": "Можете притиснути {combo} да прескочите ово следећи пут", - "bundle_column_error.body": "Нешто је пошло по злу приликом учитавања ове компоненте.", + "bundle_column_error.copy_stacktrace": "Copy error report", + "bundle_column_error.error.body": "The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.", + "bundle_column_error.error.title": "Oh, no!", + "bundle_column_error.network.body": "There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.", + "bundle_column_error.network.title": "Network error", "bundle_column_error.retry": "Покушајте поново", - "bundle_column_error.title": "Мрежна грешка", + "bundle_column_error.return": "Go back home", + "bundle_column_error.routing.body": "The requested page could not be found. Are you sure the URL in the address bar is correct?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Затвори", "bundle_modal_error.message": "Нешто није било у реду при учитавању ове компоненте.", "bundle_modal_error.retry": "Покушајте поново", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "About", "column.blocks": "Блокирани корисници", "column.bookmarks": "Обележивачи", "column.community": "Локална временска линија", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "Блокирај и Пријави", "confirmations.block.confirm": "Блокирај", "confirmations.block.message": "Да ли сте сигурни да желите да блокирате корисника {name}?", + "confirmations.cancel_follow_request.confirm": "Withdraw request", + "confirmations.cancel_follow_request.message": "Are you sure you want to withdraw your request to follow {name}?", "confirmations.delete.confirm": "Обриши", "confirmations.delete.message": "Да ли сте сигурни да желите обришете овај статус?", "confirmations.delete_list.confirm": "Обриши", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Означи као прочитано", "conversation.open": "Прикажи преписку", "conversation.with": "Са {names}", + "copypaste.copied": "Copied", + "copypaste.copy": "Copy", "directory.federated": "Са знаних здружених инстанци", "directory.local": "Само са {domain}", "directory.new_arrivals": "Новопридошли", "directory.recently_active": "Недавно активни", + "dismissable_banner.community_timeline": "These are the most recent public posts from people whose accounts are hosted by {domain}.", + "dismissable_banner.dismiss": "Dismiss", + "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", + "dismissable_banner.explore_statuses": "These posts from this and other servers in the decentralized network are gaining traction on this server right now.", + "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", + "dismissable_banner.public_timeline": "These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.", "embed.instructions": "Угради овај статус на Ваш веб сајт копирањем кода испод.", "embed.preview": "Овако ће да изгледа:", "emoji_button.activity": "Активност", @@ -221,14 +259,14 @@ "follow_request.reject": "Одбиј", "follow_requests.unlocked_explanation": "Иако ваш налог није закључан, особље {domain} је помислило да бисте можда желели ручно да прегледате захтеве за праћење са ових налога.", "generic.saved": "Сачувано", - "getting_started.developers": "Програмери", - "getting_started.directory": "Директоријум налога", + "getting_started.directory": "Directory", "getting_started.documentation": "Документација", + "getting_started.free_software_notice": "Mastodon is free, open source software. You can view the source code, contribute or report issues at {repository}.", "getting_started.heading": "Да почнете", "getting_started.invite": "Позовите људе", - "getting_started.open_source_notice": "Мастoдон је софтвер отвореног кода. Можете му допринети или пријавити проблеме преко ГитХаба на {github}.", "getting_started.privacy_policy": "Privacy Policy", "getting_started.security": "Безбедност", + "getting_started.what_is_mastodon": "About Mastodon", "hashtag.column_header.tag_mode.all": "и {additional}", "hashtag.column_header.tag_mode.any": "или {additional}", "hashtag.column_header.tag_mode.none": "без {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Прикажи одговоре", "home.hide_announcements": "Сакриј најаве", "home.show_announcements": "Пријажи најаве", + "interaction_modal.description.favourite": "With an account on Mastodon, you can favourite this post to let the author know you appreciate it and save it for later.", + "interaction_modal.description.follow": "With an account on Mastodon, you can follow {name} to receive their posts in your home feed.", + "interaction_modal.description.reblog": "With an account on Mastodon, you can boost this post to share it with your own followers.", + "interaction_modal.description.reply": "With an account on Mastodon, you can respond to this post.", + "interaction_modal.on_another_server": "On a different server", + "interaction_modal.on_this_server": "On this server", + "interaction_modal.other_server_instructions": "Simply copy and paste this URL into the search bar of your favourite app or the web interface where you are signed in.", + "interaction_modal.preamble": "Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one.", + "interaction_modal.title.favourite": "Favourite {name}'s post", + "interaction_modal.title.follow": "Follow {name}", + "interaction_modal.title.reblog": "Boost {name}'s post", + "interaction_modal.title.reply": "Reply to {name}'s post", "intervals.full.days": "{number, plural, one {# дан} other {# дана}}", "intervals.full.hours": "{number, plural, one {# сат} other {# сати}}", "intervals.full.minutes": "{number, plural, one {# минут} other {# минута}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Трајање", "mute_modal.hide_notifications": "Сакриј обавештења од овог корисника?", "mute_modal.indefinite": "Неодређен", - "navigation_bar.apps": "Мобилне апликације", + "navigation_bar.about": "About", + "navigation_bar.apps": "Get the app", "navigation_bar.blocks": "Блокирани корисници", "navigation_bar.bookmarks": "Маркери", "navigation_bar.community_timeline": "Локална временска линија", @@ -324,7 +375,7 @@ "navigation_bar.filters": "Пригушене речи", "navigation_bar.follow_requests": "Захтеви за праћење", "navigation_bar.follows_and_followers": "Праћења и пратиоци", - "navigation_bar.info": "О овој инстанци", + "navigation_bar.info": "About", "navigation_bar.keyboard_shortcuts": "Пречице на тастатури", "navigation_bar.lists": "Листе", "navigation_bar.logout": "Одјава", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Прикачене трубе", "navigation_bar.preferences": "Подешавања", "navigation_bar.public_timeline": "Здружена временска линија", + "navigation_bar.search": "Search", "navigation_bar.security": "Безбедност", + "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", "notification.admin.report": "{name} reported {target}", "notification.admin.sign_up": "{name} signed up", "notification.favourite": "{name} је ставио/ла Ваш статус као омиљени", @@ -401,6 +454,8 @@ "privacy.public.short": "Јавно", "privacy.unlisted.long": "Visible for all, but opted-out of discovery features", "privacy.unlisted.short": "Неизлистано", + "privacy_policy.last_updated": "Last updated {date}", + "privacy_policy.title": "Privacy Policy", "refresh": "Освежи", "regeneration_indicator.label": "Учитавање…", "regeneration_indicator.sublabel": "Ваша почетна страница се припрема!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.title": "Search for {q}", "search_results.total": "{count, number} {count, plural, one {резултат} few {резултата} other {резултата}}", + "server_banner.about_active_users": "People using this server during the last 30 days (Monthly Active Users)", + "server_banner.active_users": "active users", + "server_banner.administered_by": "Administered by:", + "server_banner.introduction": "{domain} is part of the decentralized social network powered by {mastodon}.", + "server_banner.learn_more": "Learn more", + "server_banner.server_stats": "Server stats:", "sign_in_banner.create_account": "Create account", "sign_in_banner.sign_in": "Sign in", "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "Још увек нико није подржао ову трубу. Када буде подржана, појавиће се овде.", "status.redraft": "Избриши и преправи", "status.remove_bookmark": "Уклони обележивач", + "status.replied_to": "Replied to {name}", "status.reply": "Одговори", "status.replyAll": "Одговори на дискусију", "status.report": "Пријави корисника @{name}", @@ -523,9 +585,8 @@ "status.show_more": "Прикажи више", "status.show_more_all": "Прикажи више за све", "status.show_original": "Show original", - "status.show_thread": "Show thread", "status.translate": "Translate", - "status.translated_from": "Translated from {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Није доступно", "status.unmute_conversation": "Укључи преписку", "status.unpin": "Откачи са налога", @@ -538,7 +599,6 @@ "tabs_bar.home": "Почетна", "tabs_bar.local_timeline": "Локално", "tabs_bar.notifications": "Обавештења", - "tabs_bar.search": "Претрага", "time_remaining.days": "Остало {number, plural, one {# дан} few {# дана} other {# дана}}", "time_remaining.hours": "Остало {number, plural, one {# сат} few {# сата} other {# сати}}", "time_remaining.minutes": "Остало {number, plural, one {# минут} few {# минута} other {# минута}}", diff --git a/app/javascript/mastodon/locales/sv.json b/app/javascript/mastodon/locales/sv.json index 66e7c6176..48c2a48ad 100644 --- a/app/javascript/mastodon/locales/sv.json +++ b/app/javascript/mastodon/locales/sv.json @@ -1,4 +1,17 @@ { + "about.blocks": "Moderated servers", + "about.contact": "Contact:", + "about.domain_blocks.comment": "Reason", + "about.domain_blocks.domain": "Domain", + "about.domain_blocks.preamble": "Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.", + "about.domain_blocks.severity": "Severity", + "about.domain_blocks.silenced.explanation": "You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.", + "about.domain_blocks.silenced.title": "Limited", + "about.domain_blocks.suspended.explanation": "No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.", + "about.domain_blocks.suspended.title": "Suspended", + "about.not_available": "This information has not been made available on this server.", + "about.powered_by": "Decentralized social media powered by {mastodon}", + "about.rules": "Server rules", "account.account_note_header": "Anteckning", "account.add_or_remove_from_list": "Lägg till i eller ta bort från listor", "account.badges.bot": "Robot", @@ -7,13 +20,16 @@ "account.block_domain": "Dölj allt från {domain}", "account.blocked": "Blockerad", "account.browse_more_on_origin_server": "Läs mer på original profilen", - "account.cancel_follow_request": "Avbryt följarförfrågan", + "account.cancel_follow_request": "Withdraw follow request", "account.direct": "Skicka ett direktmeddelande till @{name}", "account.disable_notifications": "Sluta meddela mig när @{name} tutar", "account.domain_blocked": "Domän dold", "account.edit_profile": "Redigera profil", "account.enable_notifications": "Meddela mig när @{name} tutar", "account.endorse": "Visa på profil", + "account.featured_tags.last_status_at": "Last post on {date}", + "account.featured_tags.last_status_never": "No posts", + "account.featured_tags.title": "{name}'s featured hashtags", "account.follow": "Följ", "account.followers": "Följare", "account.followers.empty": "Ingen följer denna användare än.", @@ -23,7 +39,7 @@ "account.follows.empty": "Denna användare följer inte någon än.", "account.follows_you": "Följer dig", "account.hide_reblogs": "Dölj knuffar från @{name}", - "account.joined": "Gick med {date}", + "account.joined_short": "Joined", "account.languages": "Change subscribed languages", "account.link_verified_on": "Ägarskap för detta konto kontrollerades den {date}", "account.locked_info": "Detta konto har låst integritetsstatus. Ägaren väljer manuellt vem som kan följa.", @@ -63,12 +79,24 @@ "audio.hide": "Dölj audio", "autosuggest_hashtag.per_week": "{count} per vecka", "boost_modal.combo": "Du kan trycka {combo} för att slippa detta nästa gång", - "bundle_column_error.body": "Något gick fel medan denna komponent laddades.", + "bundle_column_error.copy_stacktrace": "Copy error report", + "bundle_column_error.error.body": "The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.", + "bundle_column_error.error.title": "Oh, no!", + "bundle_column_error.network.body": "There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.", + "bundle_column_error.network.title": "Network error", "bundle_column_error.retry": "Försök igen", - "bundle_column_error.title": "Nätverksfel", + "bundle_column_error.return": "Go back home", + "bundle_column_error.routing.body": "The requested page could not be found. Are you sure the URL in the address bar is correct?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Stäng", "bundle_modal_error.message": "Något gick fel när denna komponent laddades.", "bundle_modal_error.retry": "Försök igen", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "About", "column.blocks": "Blockerade användare", "column.bookmarks": "Bokmärken", "column.community": "Lokal tidslinje", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "Blockera & rapportera", "confirmations.block.confirm": "Blockera", "confirmations.block.message": "Är du säker på att du vill blockera {name}?", + "confirmations.cancel_follow_request.confirm": "Withdraw request", + "confirmations.cancel_follow_request.message": "Are you sure you want to withdraw your request to follow {name}?", "confirmations.delete.confirm": "Radera", "confirmations.delete.message": "Är du säker på att du vill radera denna status?", "confirmations.delete_list.confirm": "Radera", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Markera som läst", "conversation.open": "Visa konversation", "conversation.with": "Med {names}", + "copypaste.copied": "Copied", + "copypaste.copy": "Copy", "directory.federated": "Från känt servernätverk", "directory.local": "Endast från {domain}", "directory.new_arrivals": "Nyanlända", "directory.recently_active": "Nyligen aktiva", + "dismissable_banner.community_timeline": "These are the most recent public posts from people whose accounts are hosted by {domain}.", + "dismissable_banner.dismiss": "Dismiss", + "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", + "dismissable_banner.explore_statuses": "These posts from this and other servers in the decentralized network are gaining traction on this server right now.", + "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", + "dismissable_banner.public_timeline": "These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.", "embed.instructions": "Lägg in denna status på din webbplats genom att kopiera koden nedan.", "embed.preview": "Så här kommer det att se ut:", "emoji_button.activity": "Aktivitet", @@ -221,14 +259,14 @@ "follow_request.reject": "Avvisa", "follow_requests.unlocked_explanation": "Även om ditt konto inte är låst tror {domain} personalen att du kanske vill granska dessa följares förfrågningar manuellt.", "generic.saved": "Sparad", - "getting_started.developers": "Utvecklare", - "getting_started.directory": "Profilkatalog", + "getting_started.directory": "Directory", "getting_started.documentation": "Dokumentation", + "getting_started.free_software_notice": "Mastodon is free, open source software. You can view the source code, contribute or report issues at {repository}.", "getting_started.heading": "Kom igång", "getting_started.invite": "Skicka inbjudningar", - "getting_started.open_source_notice": "Mastodon är programvara med öppen källkod. Du kan bidra eller rapportera problem via GitHub på {github}.", "getting_started.privacy_policy": "Privacy Policy", "getting_started.security": "Kontoinställningar", + "getting_started.what_is_mastodon": "About Mastodon", "hashtag.column_header.tag_mode.all": "och {additional}", "hashtag.column_header.tag_mode.any": "eller {additional}", "hashtag.column_header.tag_mode.none": "utan {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Visa svar", "home.hide_announcements": "Dölj notiser", "home.show_announcements": "Visa notiser", + "interaction_modal.description.favourite": "With an account on Mastodon, you can favourite this post to let the author know you appreciate it and save it for later.", + "interaction_modal.description.follow": "With an account on Mastodon, you can follow {name} to receive their posts in your home feed.", + "interaction_modal.description.reblog": "With an account on Mastodon, you can boost this post to share it with your own followers.", + "interaction_modal.description.reply": "With an account on Mastodon, you can respond to this post.", + "interaction_modal.on_another_server": "On a different server", + "interaction_modal.on_this_server": "On this server", + "interaction_modal.other_server_instructions": "Simply copy and paste this URL into the search bar of your favourite app or the web interface where you are signed in.", + "interaction_modal.preamble": "Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one.", + "interaction_modal.title.favourite": "Favourite {name}'s post", + "interaction_modal.title.follow": "Follow {name}", + "interaction_modal.title.reblog": "Boost {name}'s post", + "interaction_modal.title.reply": "Reply to {name}'s post", "intervals.full.days": "{number, plural, one {# dag} other {# dagar}}", "intervals.full.hours": "{number, plural, one {# timme} other {# timmar}}", "intervals.full.minutes": "{number, plural, one {# minut} other {# minuter}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Varaktighet", "mute_modal.hide_notifications": "Dölj aviseringar från denna användare?", "mute_modal.indefinite": "Obestämt", - "navigation_bar.apps": "Mobilappar", + "navigation_bar.about": "About", + "navigation_bar.apps": "Get the app", "navigation_bar.blocks": "Blockerade användare", "navigation_bar.bookmarks": "Bokmärken", "navigation_bar.community_timeline": "Lokal tidslinje", @@ -324,7 +375,7 @@ "navigation_bar.filters": "Tystade ord", "navigation_bar.follow_requests": "Följförfrågningar", "navigation_bar.follows_and_followers": "Följer och följare", - "navigation_bar.info": "Om denna instans", + "navigation_bar.info": "About", "navigation_bar.keyboard_shortcuts": "Kortkommandon", "navigation_bar.lists": "Listor", "navigation_bar.logout": "Logga ut", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Nålade inlägg (toots)", "navigation_bar.preferences": "Inställningar", "navigation_bar.public_timeline": "Federerad tidslinje", + "navigation_bar.search": "Search", "navigation_bar.security": "Säkerhet", + "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", "notification.admin.report": "{name} reported {target}", "notification.admin.sign_up": "{name} registrerade sig", "notification.favourite": "{name} favoriserade din status", @@ -401,6 +454,8 @@ "privacy.public.short": "Publik", "privacy.unlisted.long": "Visible for all, but opted-out of discovery features", "privacy.unlisted.short": "Olistad", + "privacy_policy.last_updated": "Last updated {date}", + "privacy_policy.title": "Privacy Policy", "refresh": "Läs om", "regeneration_indicator.label": "Laddar…", "regeneration_indicator.sublabel": "Ditt hemmaflöde förbereds!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "Att söka toots med deras innehåll är inte möjligt på denna Mastodon-server.", "search_results.title": "Search for {q}", "search_results.total": "{count, number} {count, plural, one {result} other {results}}", + "server_banner.about_active_users": "People using this server during the last 30 days (Monthly Active Users)", + "server_banner.active_users": "active users", + "server_banner.administered_by": "Administered by:", + "server_banner.introduction": "{domain} is part of the decentralized social network powered by {mastodon}.", + "server_banner.learn_more": "Learn more", + "server_banner.server_stats": "Server stats:", "sign_in_banner.create_account": "Create account", "sign_in_banner.sign_in": "Sign in", "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "Ingen har favoriserat den här tutningen än. När någon gör det kommer den att synas här.", "status.redraft": "Radera & gör om", "status.remove_bookmark": "Ta bort bokmärke", + "status.replied_to": "Replied to {name}", "status.reply": "Svara", "status.replyAll": "Svara på tråden", "status.report": "Rapportera @{name}", @@ -523,9 +585,8 @@ "status.show_more": "Visa mer", "status.show_more_all": "Visa mer för alla", "status.show_original": "Show original", - "status.show_thread": "Visa tråd", "status.translate": "Translate", - "status.translated_from": "Translated from {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Ej tillgängligt", "status.unmute_conversation": "Öppna konversation", "status.unpin": "Ångra fäst i profil", @@ -538,7 +599,6 @@ "tabs_bar.home": "Hem", "tabs_bar.local_timeline": "Lokal", "tabs_bar.notifications": "Aviseringar", - "tabs_bar.search": "Sök", "time_remaining.days": "{number, plural, one {# dag} other {# dagar}} kvar", "time_remaining.hours": "{hours, plural, one {# timme} other {# timmar}} kvar", "time_remaining.minutes": "{minutes, plural, one {1 minut} other {# minuter}} kvar", diff --git a/app/javascript/mastodon/locales/szl.json b/app/javascript/mastodon/locales/szl.json index de4e76507..cc0fa7069 100644 --- a/app/javascript/mastodon/locales/szl.json +++ b/app/javascript/mastodon/locales/szl.json @@ -1,4 +1,17 @@ { + "about.blocks": "Moderated servers", + "about.contact": "Contact:", + "about.domain_blocks.comment": "Reason", + "about.domain_blocks.domain": "Domain", + "about.domain_blocks.preamble": "Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.", + "about.domain_blocks.severity": "Severity", + "about.domain_blocks.silenced.explanation": "You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.", + "about.domain_blocks.silenced.title": "Limited", + "about.domain_blocks.suspended.explanation": "No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.", + "about.domain_blocks.suspended.title": "Suspended", + "about.not_available": "This information has not been made available on this server.", + "about.powered_by": "Decentralized social media powered by {mastodon}", + "about.rules": "Server rules", "account.account_note_header": "Note", "account.add_or_remove_from_list": "Add or Remove from lists", "account.badges.bot": "Bot", @@ -7,13 +20,16 @@ "account.block_domain": "Block domain {domain}", "account.blocked": "Blocked", "account.browse_more_on_origin_server": "Browse more on the original profile", - "account.cancel_follow_request": "Cancel follow request", + "account.cancel_follow_request": "Withdraw follow request", "account.direct": "Direct message @{name}", "account.disable_notifications": "Stop notifying me when @{name} posts", "account.domain_blocked": "Domain blocked", "account.edit_profile": "Edit profile", "account.enable_notifications": "Notify me when @{name} posts", "account.endorse": "Feature on profile", + "account.featured_tags.last_status_at": "Last post on {date}", + "account.featured_tags.last_status_never": "No posts", + "account.featured_tags.title": "{name}'s featured hashtags", "account.follow": "Follow", "account.followers": "Followers", "account.followers.empty": "No one follows this user yet.", @@ -23,7 +39,7 @@ "account.follows.empty": "This user doesn't follow anyone yet.", "account.follows_you": "Follows you", "account.hide_reblogs": "Hide boosts from @{name}", - "account.joined": "Joined {date}", + "account.joined_short": "Joined", "account.languages": "Change subscribed languages", "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.", @@ -63,12 +79,24 @@ "audio.hide": "Hide audio", "autosuggest_hashtag.per_week": "{count} per week", "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.copy_stacktrace": "Copy error report", + "bundle_column_error.error.body": "The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.", + "bundle_column_error.error.title": "Oh, no!", + "bundle_column_error.network.body": "There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.", + "bundle_column_error.network.title": "Network error", "bundle_column_error.retry": "Try again", - "bundle_column_error.title": "Network error", + "bundle_column_error.return": "Go back home", + "bundle_column_error.routing.body": "The requested page could not be found. Are you sure the URL in the address bar is correct?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Close", "bundle_modal_error.message": "Something went wrong while loading this component.", "bundle_modal_error.retry": "Try again", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "About", "column.blocks": "Blocked users", "column.bookmarks": "Bookmarks", "column.community": "Local timeline", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "Block & Report", "confirmations.block.confirm": "Block", "confirmations.block.message": "Are you sure you want to block {name}?", + "confirmations.cancel_follow_request.confirm": "Withdraw request", + "confirmations.cancel_follow_request.message": "Are you sure you want to withdraw your request to follow {name}?", "confirmations.delete.confirm": "Delete", "confirmations.delete.message": "Are you sure you want to delete this status?", "confirmations.delete_list.confirm": "Delete", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Mark as read", "conversation.open": "View conversation", "conversation.with": "With {names}", + "copypaste.copied": "Copied", + "copypaste.copy": "Copy", "directory.federated": "From known fediverse", "directory.local": "From {domain} only", "directory.new_arrivals": "New arrivals", "directory.recently_active": "Recently active", + "dismissable_banner.community_timeline": "These are the most recent public posts from people whose accounts are hosted by {domain}.", + "dismissable_banner.dismiss": "Dismiss", + "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", + "dismissable_banner.explore_statuses": "These posts from this and other servers in the decentralized network are gaining traction on this server right now.", + "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", + "dismissable_banner.public_timeline": "These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.", "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", @@ -221,14 +259,14 @@ "follow_request.reject": "Reject", "follow_requests.unlocked_explanation": "Even though your account is not locked, the {domain} staff thought you might want to review follow requests from these accounts manually.", "generic.saved": "Saved", - "getting_started.developers": "Developers", - "getting_started.directory": "Profile directory", + "getting_started.directory": "Directory", "getting_started.documentation": "Documentation", + "getting_started.free_software_notice": "Mastodon is free, open source software. You can view the source code, contribute or report issues at {repository}.", "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.privacy_policy": "Privacy Policy", "getting_started.security": "Security", + "getting_started.what_is_mastodon": "About Mastodon", "hashtag.column_header.tag_mode.all": "and {additional}", "hashtag.column_header.tag_mode.any": "or {additional}", "hashtag.column_header.tag_mode.none": "without {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Show replies", "home.hide_announcements": "Hide announcements", "home.show_announcements": "Show announcements", + "interaction_modal.description.favourite": "With an account on Mastodon, you can favourite this post to let the author know you appreciate it and save it for later.", + "interaction_modal.description.follow": "With an account on Mastodon, you can follow {name} to receive their posts in your home feed.", + "interaction_modal.description.reblog": "With an account on Mastodon, you can boost this post to share it with your own followers.", + "interaction_modal.description.reply": "With an account on Mastodon, you can respond to this post.", + "interaction_modal.on_another_server": "On a different server", + "interaction_modal.on_this_server": "On this server", + "interaction_modal.other_server_instructions": "Simply copy and paste this URL into the search bar of your favourite app or the web interface where you are signed in.", + "interaction_modal.preamble": "Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one.", + "interaction_modal.title.favourite": "Favourite {name}'s post", + "interaction_modal.title.follow": "Follow {name}", + "interaction_modal.title.reblog": "Boost {name}'s post", + "interaction_modal.title.reply": "Reply to {name}'s post", "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}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Duration", "mute_modal.hide_notifications": "Hide notifications from this user?", "mute_modal.indefinite": "Indefinite", - "navigation_bar.apps": "Mobile apps", + "navigation_bar.about": "About", + "navigation_bar.apps": "Get the app", "navigation_bar.blocks": "Blocked users", "navigation_bar.bookmarks": "Bookmarks", "navigation_bar.community_timeline": "Local timeline", @@ -324,7 +375,7 @@ "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.info": "About", "navigation_bar.keyboard_shortcuts": "Hotkeys", "navigation_bar.lists": "Lists", "navigation_bar.logout": "Logout", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Pinned toots", "navigation_bar.preferences": "Preferences", "navigation_bar.public_timeline": "Federated timeline", + "navigation_bar.search": "Search", "navigation_bar.security": "Security", + "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", "notification.admin.report": "{name} reported {target}", "notification.admin.sign_up": "{name} signed up", "notification.favourite": "{name} favourited your status", @@ -401,6 +454,8 @@ "privacy.public.short": "Public", "privacy.unlisted.long": "Visible for all, but opted-out of discovery features", "privacy.unlisted.short": "Unlisted", + "privacy_policy.last_updated": "Last updated {date}", + "privacy_policy.title": "Privacy Policy", "refresh": "Refresh", "regeneration_indicator.label": "Loading…", "regeneration_indicator.sublabel": "Your home feed is being prepared!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.title": "Search for {q}", "search_results.total": "{count, number} {count, plural, one {result} other {results}}", + "server_banner.about_active_users": "People using this server during the last 30 days (Monthly Active Users)", + "server_banner.active_users": "active users", + "server_banner.administered_by": "Administered by:", + "server_banner.introduction": "{domain} is part of the decentralized social network powered by {mastodon}.", + "server_banner.learn_more": "Learn more", + "server_banner.server_stats": "Server stats:", "sign_in_banner.create_account": "Create account", "sign_in_banner.sign_in": "Sign in", "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "No one has boosted this toot yet. When someone does, they will show up here.", "status.redraft": "Delete & re-draft", "status.remove_bookmark": "Remove bookmark", + "status.replied_to": "Replied to {name}", "status.reply": "Reply", "status.replyAll": "Reply to thread", "status.report": "Report @{name}", @@ -523,9 +585,8 @@ "status.show_more": "Show more", "status.show_more_all": "Show more for all", "status.show_original": "Show original", - "status.show_thread": "Show thread", "status.translate": "Translate", - "status.translated_from": "Translated from {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Not available", "status.unmute_conversation": "Unmute conversation", "status.unpin": "Unpin from profile", @@ -538,7 +599,6 @@ "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", diff --git a/app/javascript/mastodon/locales/ta.json b/app/javascript/mastodon/locales/ta.json index 8ef02972b..8155200bb 100644 --- a/app/javascript/mastodon/locales/ta.json +++ b/app/javascript/mastodon/locales/ta.json @@ -1,4 +1,17 @@ { + "about.blocks": "Moderated servers", + "about.contact": "Contact:", + "about.domain_blocks.comment": "Reason", + "about.domain_blocks.domain": "Domain", + "about.domain_blocks.preamble": "Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.", + "about.domain_blocks.severity": "Severity", + "about.domain_blocks.silenced.explanation": "You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.", + "about.domain_blocks.silenced.title": "Limited", + "about.domain_blocks.suspended.explanation": "No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.", + "about.domain_blocks.suspended.title": "Suspended", + "about.not_available": "This information has not been made available on this server.", + "about.powered_by": "Decentralized social media powered by {mastodon}", + "about.rules": "Server rules", "account.account_note_header": "குறிப்பு", "account.add_or_remove_from_list": "பட்டியல்களில் சேர்/நீக்கு", "account.badges.bot": "பாட்", @@ -7,13 +20,16 @@ "account.block_domain": "{domain} யில் இருந்து வரும் எல்லாவற்றையும் மறை", "account.blocked": "முடக்கப்பட்டது", "account.browse_more_on_origin_server": "மேலும் உலாவ சுயவிவரத்திற்குச் செல்க", - "account.cancel_follow_request": "பின்தொடரும் கோரிக்கையை நிராகரி", + "account.cancel_follow_request": "Withdraw follow request", "account.direct": "நேரடி செய்தி @{name}", "account.disable_notifications": "@{name} பதிவிட்டல் எனக்கு தெரியபடுத்த வேண்டாம்", "account.domain_blocked": "மறைக்கப்பட்டத் தளங்கள்", "account.edit_profile": "சுயவிவரத்தை மாற்று", "account.enable_notifications": "@{name} பதிவிட்டல் எனக்குத் தெரியப்படுத்தவும்", "account.endorse": "சுயவிவரத்தில் வெளிப்படுத்து", + "account.featured_tags.last_status_at": "Last post on {date}", + "account.featured_tags.last_status_never": "No posts", + "account.featured_tags.title": "{name}'s featured hashtags", "account.follow": "பின்தொடர்", "account.followers": "பின்தொடர்பவர்கள்", "account.followers.empty": "இதுவரை யாரும் இந்த பயனரைப் பின்தொடரவில்லை.", @@ -23,7 +39,7 @@ "account.follows.empty": "இந்த பயனர் இதுவரை யாரையும் பின்தொடரவில்லை.", "account.follows_you": "உங்களைப் பின்தொடர்கிறார்", "account.hide_reblogs": "இருந்து ஊக்கியாக மறை @{name}", - "account.joined": "சேர்ந்த நாள் {date}", + "account.joined_short": "Joined", "account.languages": "Change subscribed languages", "account.link_verified_on": "இந்த இணைப்பை உரிமையாளர் சரிபார்க்கப்பட்டது {date}", "account.locked_info": "இந்தக் கணக்கு தனியுரிமை நிலை பூட்டப்பட்டுள்ளது. அவர்களைப் பின்தொடர்பவர் யார் என்பதை உரிமையாளர் கைமுறையாக மதிப்பாய்வு செய்கிறார்.", @@ -63,12 +79,24 @@ "audio.hide": "ஆடியோவை மறை", "autosuggest_hashtag.per_week": "ஒவ்வொரு வாரம் {count}", "boost_modal.combo": "நீங்கள் இதை அடுத்தமுறை தவிர்க்க {combo} வை அழுத்தவும்", - "bundle_column_error.body": "இக்கூற்றை ஏற்றம் செய்யும்பொழுது ஏதோ தவறு ஏற்பட்டுள்ளது.", + "bundle_column_error.copy_stacktrace": "Copy error report", + "bundle_column_error.error.body": "The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.", + "bundle_column_error.error.title": "Oh, no!", + "bundle_column_error.network.body": "There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.", + "bundle_column_error.network.title": "Network error", "bundle_column_error.retry": "மீண்டும் முயற்சிக்கவும்", - "bundle_column_error.title": "பிணையப் பிழை", + "bundle_column_error.return": "Go back home", + "bundle_column_error.routing.body": "The requested page could not be found. Are you sure the URL in the address bar is correct?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "மூடுக", "bundle_modal_error.message": "இக்கூற்றை ஏற்றம் செய்யும்பொழுது ஏதோ தவறு ஏற்பட்டுள்ளது.", "bundle_modal_error.retry": "மீண்டும் முயற்சி செய்", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "About", "column.blocks": "தடுக்கப்பட்ட பயனர்கள்", "column.bookmarks": "அடையாளக்குறிகள்", "column.community": "சுய நிகழ்வு காலவரிசை", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "தடுத்துப் புகாரளி", "confirmations.block.confirm": "தடு", "confirmations.block.message": "{name}-ஐ நிச்சயமாகத் தடுக்க விரும்புகிறீர்களா?", + "confirmations.cancel_follow_request.confirm": "Withdraw request", + "confirmations.cancel_follow_request.message": "Are you sure you want to withdraw your request to follow {name}?", "confirmations.delete.confirm": "நீக்கு", "confirmations.delete.message": "இப்பதிவை நிச்சயமாக நீக்க விரும்புகிறீர்களா?", "confirmations.delete_list.confirm": "நீக்கு", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "படிக்கபட்டதாகக் குறி", "conversation.open": "உரையாடலைக் காட்டு", "conversation.with": "{names} உடன்", + "copypaste.copied": "Copied", + "copypaste.copy": "Copy", "directory.federated": "அறியப்பட்ட ஃபெடிவெர்சிலிருந்து", "directory.local": "{domain} களத்திலிருந்து மட்டும்", "directory.new_arrivals": "புதிய வரவு", "directory.recently_active": "சற்றுமுன் செயல்பாட்டில் இருந்தவர்கள்", + "dismissable_banner.community_timeline": "These are the most recent public posts from people whose accounts are hosted by {domain}.", + "dismissable_banner.dismiss": "Dismiss", + "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", + "dismissable_banner.explore_statuses": "These posts from this and other servers in the decentralized network are gaining traction on this server right now.", + "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", + "dismissable_banner.public_timeline": "These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.", "embed.instructions": "இந்தப் பதிவை உங்கள் வலைதளத்தில் பொதிக்கக் கீழே உள்ள வரிகளை காப்பி செய்யவும்.", "embed.preview": "பார்க்க இப்படி இருக்கும்:", "emoji_button.activity": "செயல்பாடு", @@ -221,14 +259,14 @@ "follow_request.reject": "நிராகரி", "follow_requests.unlocked_explanation": "உங்கள் கணக்கு பூட்டப்படவில்லை என்றாலும், இந்தக் கணக்குகளிலிருந்து உங்களைப் பின்தொடர விரும்பும் கோரிக்கைகளை நீங்கள் பரீசீலிப்பது நலம் என்று {domain} ஊழியர் எண்ணுகிறார்.", "generic.saved": "சேமிக்கப்பட்டது", - "getting_started.developers": "உருவாக்குநர்கள்", - "getting_started.directory": "பயனர்கள்", + "getting_started.directory": "Directory", "getting_started.documentation": "ஆவணங்கள்", + "getting_started.free_software_notice": "Mastodon is free, open source software. You can view the source code, contribute or report issues at {repository}.", "getting_started.heading": "முதன்மைப் பக்கம்", "getting_started.invite": "நண்பர்களை அழைக்க", - "getting_started.open_source_notice": "மாஸ்டடான் ஒரு open source மென்பொருள் ஆகும். {github} -இன் மூலம் உங்களால் இதில் பங்களிக்கவோ, சிக்கல்களைத் தெரியப்படுத்தவோ முடியும்.", "getting_started.privacy_policy": "Privacy Policy", "getting_started.security": "கணக்கு அமைப்புகள்", + "getting_started.what_is_mastodon": "About Mastodon", "hashtag.column_header.tag_mode.all": "மற்றும் {additional}", "hashtag.column_header.tag_mode.any": "அல்லது {additional}", "hashtag.column_header.tag_mode.none": "{additional} தவிர்த்து", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "மறுமொழிகளைக் காண்பி", "home.hide_announcements": "அறிவிப்புகளை மறை", "home.show_announcements": "அறிவிப்புகளைக் காட்டு", + "interaction_modal.description.favourite": "With an account on Mastodon, you can favourite this post to let the author know you appreciate it and save it for later.", + "interaction_modal.description.follow": "With an account on Mastodon, you can follow {name} to receive their posts in your home feed.", + "interaction_modal.description.reblog": "With an account on Mastodon, you can boost this post to share it with your own followers.", + "interaction_modal.description.reply": "With an account on Mastodon, you can respond to this post.", + "interaction_modal.on_another_server": "On a different server", + "interaction_modal.on_this_server": "On this server", + "interaction_modal.other_server_instructions": "Simply copy and paste this URL into the search bar of your favourite app or the web interface where you are signed in.", + "interaction_modal.preamble": "Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one.", + "interaction_modal.title.favourite": "Favourite {name}'s post", + "interaction_modal.title.follow": "Follow {name}", + "interaction_modal.title.reblog": "Boost {name}'s post", + "interaction_modal.title.reply": "Reply to {name}'s post", "intervals.full.days": "{number, plural, one {# நாள்} other {# நாட்கள்}}", "intervals.full.hours": "{number, plural, one {# மணிநேரம்} other {# மணிநேரங்கள்}}", "intervals.full.minutes": "{number, plural, one {# நிமிடம்} other {# நிமிடங்கள்}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Duration", "mute_modal.hide_notifications": "இந்த பயனரின் அறிவிப்புகளை மறைக்கவா?", "mute_modal.indefinite": "Indefinite", - "navigation_bar.apps": "மொபைல் பயன்பாடுகள்", + "navigation_bar.about": "About", + "navigation_bar.apps": "Get the app", "navigation_bar.blocks": "தடுக்கப்பட்ட பயனர்கள்", "navigation_bar.bookmarks": "அடையாளக்குறிகள்", "navigation_bar.community_timeline": "உள்ளூர் காலக்கெடு", @@ -324,7 +375,7 @@ "navigation_bar.filters": "முடக்கப்பட்ட வார்த்தைகள்", "navigation_bar.follow_requests": "கோரிக்கைகளை பின்பற்றவும்", "navigation_bar.follows_and_followers": "பின்பற்றல்கள் மற்றும் பின்பற்றுபவர்கள்", - "navigation_bar.info": "இந்த நிகழ்வு பற்றி", + "navigation_bar.info": "About", "navigation_bar.keyboard_shortcuts": "சுருக்குவிசைகள்", "navigation_bar.lists": "குதிரை வீர்ர்கள்", "navigation_bar.logout": "விடு பதிகை", @@ -333,7 +384,9 @@ "navigation_bar.pins": "பொருத்தப்பட்டன toots", "navigation_bar.preferences": "விருப்பங்கள்", "navigation_bar.public_timeline": "கூட்டாட்சி காலக்கெடு", + "navigation_bar.search": "Search", "navigation_bar.security": "பத்திரம்", + "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", "notification.admin.report": "{name} reported {target}", "notification.admin.sign_up": "{name} signed up", "notification.favourite": "{name} ஆர்வம் கொண்டவர், உங்கள் நிலை", @@ -401,6 +454,8 @@ "privacy.public.short": "பொது", "privacy.unlisted.long": "Visible for all, but opted-out of discovery features", "privacy.unlisted.short": "பட்டியலிடப்படாத", + "privacy_policy.last_updated": "Last updated {date}", + "privacy_policy.title": "Privacy Policy", "refresh": "புதுப்பி", "regeneration_indicator.label": "சுமையேற்றம்…", "regeneration_indicator.sublabel": "உங்கள் வீட்டு ஊட்டம் தயார் செய்யப்படுகிறது!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "டூட்டுகளின் வார்த்தைகளைக்கொண்டு தேடுவது இந்த மச்டோடன் வழங்கியில் இயல்விக்கப்படவில்லை.", "search_results.title": "Search for {q}", "search_results.total": "{count, number} {count, plural, one {result} மற்ற {results}}", + "server_banner.about_active_users": "People using this server during the last 30 days (Monthly Active Users)", + "server_banner.active_users": "active users", + "server_banner.administered_by": "Administered by:", + "server_banner.introduction": "{domain} is part of the decentralized social network powered by {mastodon}.", + "server_banner.learn_more": "Learn more", + "server_banner.server_stats": "Server stats:", "sign_in_banner.create_account": "Create account", "sign_in_banner.sign_in": "Sign in", "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "இதுவரை யாரும் இந்த மோதலை அதிகரிக்கவில்லை. யாராவது செய்தால், அவர்கள் இங்கே காண்பார்கள்.", "status.redraft": "நீக்கு மற்றும் மீண்டும் வரைவு", "status.remove_bookmark": "அடையாளம் நீக்கு", + "status.replied_to": "Replied to {name}", "status.reply": "பதில்", "status.replyAll": "நூலுக்கு பதிலளிக்கவும்", "status.report": "@{name} மீது புகாரளி", @@ -523,9 +585,8 @@ "status.show_more": "மேலும் காட்ட", "status.show_more_all": "அனைவருக்கும் மேலும் காட்டு", "status.show_original": "Show original", - "status.show_thread": "நூல் காட்டு", "status.translate": "Translate", - "status.translated_from": "Translated from {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "கிடைக்கவில்லை", "status.unmute_conversation": "ஊமையாக உரையாடல் இல்லை", "status.unpin": "சுயவிவரத்திலிருந்து நீக்கவும்", @@ -538,7 +599,6 @@ "tabs_bar.home": "முகப்பு", "tabs_bar.local_timeline": "உள்ளூர்", "tabs_bar.notifications": "அறிவிப்புகள்", - "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", diff --git a/app/javascript/mastodon/locales/tai.json b/app/javascript/mastodon/locales/tai.json index 257f5df24..99d998ef6 100644 --- a/app/javascript/mastodon/locales/tai.json +++ b/app/javascript/mastodon/locales/tai.json @@ -1,4 +1,17 @@ { + "about.blocks": "Moderated servers", + "about.contact": "Contact:", + "about.domain_blocks.comment": "Reason", + "about.domain_blocks.domain": "Domain", + "about.domain_blocks.preamble": "Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.", + "about.domain_blocks.severity": "Severity", + "about.domain_blocks.silenced.explanation": "You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.", + "about.domain_blocks.silenced.title": "Limited", + "about.domain_blocks.suspended.explanation": "No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.", + "about.domain_blocks.suspended.title": "Suspended", + "about.not_available": "This information has not been made available on this server.", + "about.powered_by": "Decentralized social media powered by {mastodon}", + "about.rules": "Server rules", "account.account_note_header": "Note", "account.add_or_remove_from_list": "Add or Remove from lists", "account.badges.bot": "Bot", @@ -7,13 +20,16 @@ "account.block_domain": "Block domain {domain}", "account.blocked": "Blocked", "account.browse_more_on_origin_server": "Browse more on the original profile", - "account.cancel_follow_request": "Cancel follow request", + "account.cancel_follow_request": "Withdraw follow request", "account.direct": "Direct message @{name}", "account.disable_notifications": "Stop notifying me when @{name} posts", "account.domain_blocked": "Domain blocked", "account.edit_profile": "Edit profile", "account.enable_notifications": "Notify me when @{name} posts", "account.endorse": "Feature on profile", + "account.featured_tags.last_status_at": "Last post on {date}", + "account.featured_tags.last_status_never": "No posts", + "account.featured_tags.title": "{name}'s featured hashtags", "account.follow": "Follow", "account.followers": "Followers", "account.followers.empty": "No one follows this user yet.", @@ -23,7 +39,7 @@ "account.follows.empty": "This user doesn't follow anyone yet.", "account.follows_you": "Follows you", "account.hide_reblogs": "Hide boosts from @{name}", - "account.joined": "Joined {date}", + "account.joined_short": "Joined", "account.languages": "Change subscribed languages", "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.", @@ -63,12 +79,24 @@ "audio.hide": "Hide audio", "autosuggest_hashtag.per_week": "{count} per week", "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.copy_stacktrace": "Copy error report", + "bundle_column_error.error.body": "The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.", + "bundle_column_error.error.title": "Oh, no!", + "bundle_column_error.network.body": "There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.", + "bundle_column_error.network.title": "Network error", "bundle_column_error.retry": "Try again", - "bundle_column_error.title": "Network error", + "bundle_column_error.return": "Go back home", + "bundle_column_error.routing.body": "The requested page could not be found. Are you sure the URL in the address bar is correct?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Close", "bundle_modal_error.message": "Something went wrong while loading this component.", "bundle_modal_error.retry": "Try again", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "About", "column.blocks": "Blocked users", "column.bookmarks": "Bookmarks", "column.community": "Local timeline", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "Block & Report", "confirmations.block.confirm": "Block", "confirmations.block.message": "Are you sure you want to block {name}?", + "confirmations.cancel_follow_request.confirm": "Withdraw request", + "confirmations.cancel_follow_request.message": "Are you sure you want to withdraw your request to follow {name}?", "confirmations.delete.confirm": "Delete", "confirmations.delete.message": "Are you sure you want to delete this status?", "confirmations.delete_list.confirm": "Delete", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Mark as read", "conversation.open": "View conversation", "conversation.with": "With {names}", + "copypaste.copied": "Copied", + "copypaste.copy": "Copy", "directory.federated": "From known fediverse", "directory.local": "From {domain} only", "directory.new_arrivals": "New arrivals", "directory.recently_active": "Recently active", + "dismissable_banner.community_timeline": "These are the most recent public posts from people whose accounts are hosted by {domain}.", + "dismissable_banner.dismiss": "Dismiss", + "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", + "dismissable_banner.explore_statuses": "These posts from this and other servers in the decentralized network are gaining traction on this server right now.", + "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", + "dismissable_banner.public_timeline": "These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.", "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", @@ -221,14 +259,14 @@ "follow_request.reject": "Reject", "follow_requests.unlocked_explanation": "Even though your account is not locked, the {domain} staff thought you might want to review follow requests from these accounts manually.", "generic.saved": "Saved", - "getting_started.developers": "Developers", - "getting_started.directory": "Profile directory", + "getting_started.directory": "Directory", "getting_started.documentation": "Documentation", + "getting_started.free_software_notice": "Mastodon is free, open source software. You can view the source code, contribute or report issues at {repository}.", "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.privacy_policy": "Privacy Policy", "getting_started.security": "Security", + "getting_started.what_is_mastodon": "About Mastodon", "hashtag.column_header.tag_mode.all": "and {additional}", "hashtag.column_header.tag_mode.any": "or {additional}", "hashtag.column_header.tag_mode.none": "without {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Show replies", "home.hide_announcements": "Hide announcements", "home.show_announcements": "Show announcements", + "interaction_modal.description.favourite": "With an account on Mastodon, you can favourite this post to let the author know you appreciate it and save it for later.", + "interaction_modal.description.follow": "With an account on Mastodon, you can follow {name} to receive their posts in your home feed.", + "interaction_modal.description.reblog": "With an account on Mastodon, you can boost this post to share it with your own followers.", + "interaction_modal.description.reply": "With an account on Mastodon, you can respond to this post.", + "interaction_modal.on_another_server": "On a different server", + "interaction_modal.on_this_server": "On this server", + "interaction_modal.other_server_instructions": "Simply copy and paste this URL into the search bar of your favourite app or the web interface where you are signed in.", + "interaction_modal.preamble": "Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one.", + "interaction_modal.title.favourite": "Favourite {name}'s post", + "interaction_modal.title.follow": "Follow {name}", + "interaction_modal.title.reblog": "Boost {name}'s post", + "interaction_modal.title.reply": "Reply to {name}'s post", "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}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Duration", "mute_modal.hide_notifications": "Hide notifications from this user?", "mute_modal.indefinite": "Indefinite", - "navigation_bar.apps": "Mobile apps", + "navigation_bar.about": "About", + "navigation_bar.apps": "Get the app", "navigation_bar.blocks": "Blocked users", "navigation_bar.bookmarks": "Bookmarks", "navigation_bar.community_timeline": "Local timeline", @@ -324,7 +375,7 @@ "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.info": "About", "navigation_bar.keyboard_shortcuts": "Hotkeys", "navigation_bar.lists": "Lists", "navigation_bar.logout": "Logout", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Pinned toots", "navigation_bar.preferences": "Preferences", "navigation_bar.public_timeline": "Federated timeline", + "navigation_bar.search": "Search", "navigation_bar.security": "Security", + "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", "notification.admin.report": "{name} reported {target}", "notification.admin.sign_up": "{name} signed up", "notification.favourite": "{name} favourited your status", @@ -401,6 +454,8 @@ "privacy.public.short": "Public", "privacy.unlisted.long": "Visible for all, but opted-out of discovery features", "privacy.unlisted.short": "Unlisted", + "privacy_policy.last_updated": "Last updated {date}", + "privacy_policy.title": "Privacy Policy", "refresh": "Refresh", "regeneration_indicator.label": "Loading…", "regeneration_indicator.sublabel": "Your home feed is being prepared!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.title": "Search for {q}", "search_results.total": "{count, number} {count, plural, one {result} other {results}}", + "server_banner.about_active_users": "People using this server during the last 30 days (Monthly Active Users)", + "server_banner.active_users": "active users", + "server_banner.administered_by": "Administered by:", + "server_banner.introduction": "{domain} is part of the decentralized social network powered by {mastodon}.", + "server_banner.learn_more": "Learn more", + "server_banner.server_stats": "Server stats:", "sign_in_banner.create_account": "Create account", "sign_in_banner.sign_in": "Sign in", "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "No one has boosted this toot yet. When someone does, they will show up here.", "status.redraft": "Delete & re-draft", "status.remove_bookmark": "Remove bookmark", + "status.replied_to": "Replied to {name}", "status.reply": "Reply", "status.replyAll": "Reply to thread", "status.report": "Report @{name}", @@ -523,9 +585,8 @@ "status.show_more": "Show more", "status.show_more_all": "Show more for all", "status.show_original": "Show original", - "status.show_thread": "Show thread", "status.translate": "Translate", - "status.translated_from": "Translated from {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Not available", "status.unmute_conversation": "Unmute conversation", "status.unpin": "Unpin from profile", @@ -538,7 +599,6 @@ "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", diff --git a/app/javascript/mastodon/locales/te.json b/app/javascript/mastodon/locales/te.json index 7f8bdc7d2..1815d4e3e 100644 --- a/app/javascript/mastodon/locales/te.json +++ b/app/javascript/mastodon/locales/te.json @@ -1,4 +1,17 @@ { + "about.blocks": "Moderated servers", + "about.contact": "Contact:", + "about.domain_blocks.comment": "Reason", + "about.domain_blocks.domain": "Domain", + "about.domain_blocks.preamble": "Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.", + "about.domain_blocks.severity": "Severity", + "about.domain_blocks.silenced.explanation": "You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.", + "about.domain_blocks.silenced.title": "Limited", + "about.domain_blocks.suspended.explanation": "No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.", + "about.domain_blocks.suspended.title": "Suspended", + "about.not_available": "This information has not been made available on this server.", + "about.powered_by": "Decentralized social media powered by {mastodon}", + "about.rules": "Server rules", "account.account_note_header": "Note", "account.add_or_remove_from_list": "జాబితాల నుండి చేర్చు లేదా తీసివేయి", "account.badges.bot": "బాట్", @@ -7,13 +20,16 @@ "account.block_domain": "{domain} నుంచి అన్నీ దాచిపెట్టు", "account.blocked": "బ్లాక్ అయినవి", "account.browse_more_on_origin_server": "Browse more on the original profile", - "account.cancel_follow_request": "Cancel follow request", + "account.cancel_follow_request": "Withdraw follow request", "account.direct": "@{name}కు నేరుగా సందేశం పంపు", "account.disable_notifications": "Stop notifying me when @{name} posts", "account.domain_blocked": "డొమైన్ దాచిపెట్టబడినది", "account.edit_profile": "ప్రొఫైల్ని సవరించండి", "account.enable_notifications": "Notify me when @{name} posts", "account.endorse": "ప్రొఫైల్లో చూపించు", + "account.featured_tags.last_status_at": "Last post on {date}", + "account.featured_tags.last_status_never": "No posts", + "account.featured_tags.title": "{name}'s featured hashtags", "account.follow": "అనుసరించు", "account.followers": "అనుచరులు", "account.followers.empty": "ఈ వినియోగదారుడిని ఇంకా ఎవరూ అనుసరించడంలేదు.", @@ -23,7 +39,7 @@ "account.follows.empty": "ఈ వినియోగదారి ఇంకా ఎవరినీ అనుసరించడంలేదు.", "account.follows_you": "మిమ్మల్ని అనుసరిస్తున్నారు", "account.hide_reblogs": "@{name} నుంచి బూస్ట్ లను దాచిపెట్టు", - "account.joined": "Joined {date}", + "account.joined_short": "Joined", "account.languages": "Change subscribed languages", "account.link_verified_on": "ఈ లంకె యొక్క యాజమాన్యం {date}న పరీక్షించబడింది", "account.locked_info": "ఈ ఖాతా యొక్క గోప్యత స్థితి లాక్ చేయబడి వుంది. ఈ ఖాతాను ఎవరు అనుసరించవచ్చో యజమానే నిర్ణయం తీసుకుంటారు.", @@ -63,12 +79,24 @@ "audio.hide": "Hide audio", "autosuggest_hashtag.per_week": "{count} per week", "boost_modal.combo": "మీరు తదుపరిసారి దీనిని దాటవేయడానికి {combo} నొక్కవచ్చు", - "bundle_column_error.body": "ఈ భాగం లోడ్ అవుతున్నప్పుడు ఏదో తప్పు జరిగింది.", + "bundle_column_error.copy_stacktrace": "Copy error report", + "bundle_column_error.error.body": "The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.", + "bundle_column_error.error.title": "Oh, no!", + "bundle_column_error.network.body": "There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.", + "bundle_column_error.network.title": "Network error", "bundle_column_error.retry": "మళ్ళీ ప్రయత్నించండి", - "bundle_column_error.title": "నెట్వర్క్ లోపం", + "bundle_column_error.return": "Go back home", + "bundle_column_error.routing.body": "The requested page could not be found. Are you sure the URL in the address bar is correct?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "మూసివేయు", "bundle_modal_error.message": "ఈ భాగం లోడ్ అవుతున్నప్పుడు ఏదో తప్పు జరిగింది.", "bundle_modal_error.retry": "మళ్ళీ ప్రయత్నించండి", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "About", "column.blocks": "బ్లాక్ చేయబడిన వినియోగదారులు", "column.bookmarks": "Bookmarks", "column.community": "స్థానిక కాలక్రమం", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "Block & Report", "confirmations.block.confirm": "బ్లాక్ చేయి", "confirmations.block.message": "మీరు ఖచ్చితంగా {name}ని బ్లాక్ చేయాలనుకుంటున్నారా?", + "confirmations.cancel_follow_request.confirm": "Withdraw request", + "confirmations.cancel_follow_request.message": "Are you sure you want to withdraw your request to follow {name}?", "confirmations.delete.confirm": "తొలగించు", "confirmations.delete.message": "మీరు ఖచ్చితంగా ఈ స్టేటస్ ని తొలగించాలనుకుంటున్నారా?", "confirmations.delete_list.confirm": "తొలగించు", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Mark as read", "conversation.open": "View conversation", "conversation.with": "With {names}", + "copypaste.copied": "Copied", + "copypaste.copy": "Copy", "directory.federated": "From known fediverse", "directory.local": "From {domain} only", "directory.new_arrivals": "New arrivals", "directory.recently_active": "Recently active", + "dismissable_banner.community_timeline": "These are the most recent public posts from people whose accounts are hosted by {domain}.", + "dismissable_banner.dismiss": "Dismiss", + "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", + "dismissable_banner.explore_statuses": "These posts from this and other servers in the decentralized network are gaining traction on this server right now.", + "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", + "dismissable_banner.public_timeline": "These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.", "embed.instructions": "దిగువ కోడ్ను కాపీ చేయడం ద్వారా మీ వెబ్సైట్లో ఈ స్టేటస్ ని పొందుపరచండి.", "embed.preview": "అది ఈ క్రింది విధంగా కనిపిస్తుంది:", "emoji_button.activity": "కార్యకలాపాలు", @@ -221,14 +259,14 @@ "follow_request.reject": "తిరస్కరించు", "follow_requests.unlocked_explanation": "Even though your account is not locked, the {domain} staff thought you might want to review follow requests from these accounts manually.", "generic.saved": "Saved", - "getting_started.developers": "డెవలపర్లు", - "getting_started.directory": "ప్రొఫైల్ డైరెక్టరీ", + "getting_started.directory": "Directory", "getting_started.documentation": "డాక్యుమెంటేషన్", + "getting_started.free_software_notice": "Mastodon is free, open source software. You can view the source code, contribute or report issues at {repository}.", "getting_started.heading": "మొదలుపెడదాం", "getting_started.invite": "వ్యక్తులను ఆహ్వానించండి", - "getting_started.open_source_notice": "మాస్టొడొన్ ఓపెన్ సోర్స్ సాఫ్ట్వేర్. మీరు {github} వద్ద GitHub పై సమస్యలను నివేదించవచ్చు లేదా తోడ్పడచ్చు.", "getting_started.privacy_policy": "Privacy Policy", "getting_started.security": "భద్రత", + "getting_started.what_is_mastodon": "About Mastodon", "hashtag.column_header.tag_mode.all": "మరియు {additional}", "hashtag.column_header.tag_mode.any": "లేదా {additional}", "hashtag.column_header.tag_mode.none": "{additional} లేకుండా", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "ప్రత్యుత్తరాలను చూపించు", "home.hide_announcements": "Hide announcements", "home.show_announcements": "Show announcements", + "interaction_modal.description.favourite": "With an account on Mastodon, you can favourite this post to let the author know you appreciate it and save it for later.", + "interaction_modal.description.follow": "With an account on Mastodon, you can follow {name} to receive their posts in your home feed.", + "interaction_modal.description.reblog": "With an account on Mastodon, you can boost this post to share it with your own followers.", + "interaction_modal.description.reply": "With an account on Mastodon, you can respond to this post.", + "interaction_modal.on_another_server": "On a different server", + "interaction_modal.on_this_server": "On this server", + "interaction_modal.other_server_instructions": "Simply copy and paste this URL into the search bar of your favourite app or the web interface where you are signed in.", + "interaction_modal.preamble": "Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one.", + "interaction_modal.title.favourite": "Favourite {name}'s post", + "interaction_modal.title.follow": "Follow {name}", + "interaction_modal.title.reblog": "Boost {name}'s post", + "interaction_modal.title.reply": "Reply to {name}'s post", "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}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Duration", "mute_modal.hide_notifications": "ఈ వినియోగదారు నుండి నోటిఫికేషన్లను దాచాలా?", "mute_modal.indefinite": "Indefinite", - "navigation_bar.apps": "మొబైల్ ఆప్ లు", + "navigation_bar.about": "About", + "navigation_bar.apps": "Get the app", "navigation_bar.blocks": "బ్లాక్ చేయబడిన వినియోగదారులు", "navigation_bar.bookmarks": "Bookmarks", "navigation_bar.community_timeline": "స్థానిక కాలక్రమం", @@ -324,7 +375,7 @@ "navigation_bar.filters": "మ్యూట్ చేయబడిన పదాలు", "navigation_bar.follow_requests": "అనుసరించడానికి అభ్యర్ధనలు", "navigation_bar.follows_and_followers": "Follows and followers", - "navigation_bar.info": "ఈ సేవిక గురించి", + "navigation_bar.info": "About", "navigation_bar.keyboard_shortcuts": "హాట్ కీలు", "navigation_bar.lists": "జాబితాలు", "navigation_bar.logout": "లాగ్ అవుట్ చేయండి", @@ -333,7 +384,9 @@ "navigation_bar.pins": "అతికించిన టూట్లు", "navigation_bar.preferences": "ప్రాధాన్యతలు", "navigation_bar.public_timeline": "సమాఖ్య కాలక్రమం", + "navigation_bar.search": "Search", "navigation_bar.security": "భద్రత", + "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", "notification.admin.report": "{name} reported {target}", "notification.admin.sign_up": "{name} signed up", "notification.favourite": "{name} మీ స్టేటస్ ను ఇష్టపడ్డారు", @@ -401,6 +454,8 @@ "privacy.public.short": "ప్రజా", "privacy.unlisted.long": "Visible for all, but opted-out of discovery features", "privacy.unlisted.short": "జాబితా చేయబడనిది", + "privacy_policy.last_updated": "Last updated {date}", + "privacy_policy.title": "Privacy Policy", "refresh": "Refresh", "regeneration_indicator.label": "లోడ్ అవుతోంది…", "regeneration_indicator.sublabel": "మీ హోమ్ ఫీడ్ సిద్ధమవుతోంది!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.title": "Search for {q}", "search_results.total": "{count, number} {count, plural, one {result} other {results}}", + "server_banner.about_active_users": "People using this server during the last 30 days (Monthly Active Users)", + "server_banner.active_users": "active users", + "server_banner.administered_by": "Administered by:", + "server_banner.introduction": "{domain} is part of the decentralized social network powered by {mastodon}.", + "server_banner.learn_more": "Learn more", + "server_banner.server_stats": "Server stats:", "sign_in_banner.create_account": "Create account", "sign_in_banner.sign_in": "Sign in", "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "ఈ టూట్ను ఇంకా ఎవరూ బూస్ట్ చేయలేదు. ఎవరైనా చేసినప్పుడు, అవి ఇక్కడ కనబడతాయి.", "status.redraft": "తొలగించు & తిరగరాయు", "status.remove_bookmark": "Remove bookmark", + "status.replied_to": "Replied to {name}", "status.reply": "ప్రత్యుత్తరం", "status.replyAll": "సంభాషణకు ప్రత్యుత్తరం ఇవ్వండి", "status.report": "@{name}పై ఫిర్యాదుచేయు", @@ -523,9 +585,8 @@ "status.show_more": "ఇంకా చూపించు", "status.show_more_all": "అన్నిటికీ ఇంకా చూపించు", "status.show_original": "Show original", - "status.show_thread": "గొలుసును చూపించు", "status.translate": "Translate", - "status.translated_from": "Translated from {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Not available", "status.unmute_conversation": "సంభాషణను అన్మ్యూట్ చేయి", "status.unpin": "ప్రొఫైల్ నుండి పీకివేయు", @@ -538,7 +599,6 @@ "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", diff --git a/app/javascript/mastodon/locales/th.json b/app/javascript/mastodon/locales/th.json index 97178dc69..66f58d6ed 100644 --- a/app/javascript/mastodon/locales/th.json +++ b/app/javascript/mastodon/locales/th.json @@ -1,4 +1,17 @@ { + "about.blocks": "เซิร์ฟเวอร์ที่มีการควบคุม", + "about.contact": "ติดต่อ:", + "about.domain_blocks.comment": "เหตุผล", + "about.domain_blocks.domain": "โดเมน", + "about.domain_blocks.preamble": "โดยทั่วไป Mastodon อนุญาตให้คุณดูเนื้อหาจากและโต้ตอบกับผู้ใช้จากเซิร์ฟเวอร์อื่นใดในจักรวาลสหพันธ์ นี่คือข้อยกเว้นที่ทำขึ้นในเซิร์ฟเวอร์นี้โดยเฉพาะ", + "about.domain_blocks.severity": "ความรุนแรง", + "about.domain_blocks.silenced.explanation": "You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.", + "about.domain_blocks.silenced.title": "จำกัดอยู่", + "about.domain_blocks.suspended.explanation": "จะไม่ประมวลผล จัดเก็บ หรือแลกเปลี่ยนข้อมูลจากเซิร์ฟเวอร์นี้ ทำให้การโต้ตอบหรือการสื่อสารใด ๆ กับผู้ใช้จากเซิร์ฟเวอร์นี้เป็นไปไม่ได้", + "about.domain_blocks.suspended.title": "ระงับอยู่", + "about.not_available": "This information has not been made available on this server.", + "about.powered_by": "สื่อสังคมแบบกระจายศูนย์ที่ขับเคลื่อนโดย {mastodon}", + "about.rules": "กฎของเซิร์ฟเวอร์", "account.account_note_header": "หมายเหตุ", "account.add_or_remove_from_list": "เพิ่มหรือเอาออกจากรายการ", "account.badges.bot": "บอต", @@ -7,13 +20,16 @@ "account.block_domain": "ปิดกั้นโดเมน {domain}", "account.blocked": "ปิดกั้นอยู่", "account.browse_more_on_origin_server": "เรียกดูเพิ่มเติมในโปรไฟล์ดั้งเดิม", - "account.cancel_follow_request": "ยกเลิกคำขอติดตาม", + "account.cancel_follow_request": "ถอนคำขอติดตาม", "account.direct": "ส่งข้อความโดยตรงถึง @{name}", "account.disable_notifications": "หยุดแจ้งเตือนฉันเมื่อ @{name} โพสต์", "account.domain_blocked": "ปิดกั้นโดเมนอยู่", "account.edit_profile": "แก้ไขโปรไฟล์", "account.enable_notifications": "แจ้งเตือนฉันเมื่อ @{name} โพสต์", "account.endorse": "แนะนำในโปรไฟล์", + "account.featured_tags.last_status_at": "โพสต์ล่าสุดเมื่อ {date}", + "account.featured_tags.last_status_never": "ไม่มีโพสต์", + "account.featured_tags.title": "แฮชแท็กที่แนะนำของ {name}", "account.follow": "ติดตาม", "account.followers": "ผู้ติดตาม", "account.followers.empty": "ยังไม่มีใครติดตามผู้ใช้นี้", @@ -23,7 +39,7 @@ "account.follows.empty": "ผู้ใช้นี้ยังไม่ได้ติดตามใคร", "account.follows_you": "ติดตามคุณ", "account.hide_reblogs": "ซ่อนการดันจาก @{name}", - "account.joined": "เข้าร่วมเมื่อ {date}", + "account.joined_short": "Joined", "account.languages": "เปลี่ยนภาษาที่บอกรับ", "account.link_verified_on": "ตรวจสอบความเป็นเจ้าของของลิงก์นี้เมื่อ {date}", "account.locked_info": "มีการตั้งสถานะความเป็นส่วนตัวของบัญชีนี้เป็นล็อคอยู่ เจ้าของตรวจทานผู้ที่สามารถติดตามเขาด้วยตนเอง", @@ -49,8 +65,8 @@ "account.unmute_notifications": "เลิกซ่อนการแจ้งเตือนจาก @{name}", "account.unmute_short": "เลิกซ่อน", "account_note.placeholder": "คลิกเพื่อเพิ่มหมายเหตุ", - "admin.dashboard.daily_retention": "อัตราการรักษาผู้ใช้ตามวันหลังจากลงทะเบียน", - "admin.dashboard.monthly_retention": "อัตราการรักษาผู้ใช้ตามเดือนหลังจากลงทะเบียน", + "admin.dashboard.daily_retention": "อัตราการเก็บรักษาผู้ใช้ตามวันหลังจากลงทะเบียน", + "admin.dashboard.monthly_retention": "อัตราการเก็บรักษาผู้ใช้ตามเดือนหลังจากลงทะเบียน", "admin.dashboard.retention.average": "ค่าเฉลี่ย", "admin.dashboard.retention.cohort": "เดือนที่ลงทะเบียน", "admin.dashboard.retention.cohort_size": "ผู้ใช้ใหม่", @@ -63,12 +79,24 @@ "audio.hide": "ซ่อนเสียง", "autosuggest_hashtag.per_week": "{count} ต่อสัปดาห์", "boost_modal.combo": "คุณสามารถกด {combo} เพื่อข้ามสิ่งนี้ในครั้งถัดไป", - "bundle_column_error.body": "มีบางอย่างผิดพลาดขณะโหลดส่วนประกอบนี้", + "bundle_column_error.copy_stacktrace": "คัดลอกรายงานข้อผิดพลาด", + "bundle_column_error.error.body": "The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.", + "bundle_column_error.error.title": "Oh, no!", + "bundle_column_error.network.body": "There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.", + "bundle_column_error.network.title": "ข้อผิดพลาดเครือข่าย", "bundle_column_error.retry": "ลองอีกครั้ง", - "bundle_column_error.title": "ข้อผิดพลาดเครือข่าย", + "bundle_column_error.return": "กลับไปที่หน้าแรก", + "bundle_column_error.routing.body": "The requested page could not be found. Are you sure the URL in the address bar is correct?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "ปิด", "bundle_modal_error.message": "มีบางอย่างผิดพลาดขณะโหลดส่วนประกอบนี้", "bundle_modal_error.retry": "ลองอีกครั้ง", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "เกี่ยวกับ", "column.blocks": "ผู้ใช้ที่ปิดกั้นอยู่", "column.bookmarks": "ที่คั่นหน้า", "column.community": "เส้นเวลาในเซิร์ฟเวอร์", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "ปิดกั้นแล้วรายงาน", "confirmations.block.confirm": "ปิดกั้น", "confirmations.block.message": "คุณแน่ใจหรือไม่ว่าต้องการปิดกั้น {name}?", + "confirmations.cancel_follow_request.confirm": "ถอนคำขอ", + "confirmations.cancel_follow_request.message": "คุณแน่ใจหรือไม่ว่าต้องการถอนคำขอเพื่อติดตาม {name} ของคุณ?", "confirmations.delete.confirm": "ลบ", "confirmations.delete.message": "คุณแน่ใจหรือไม่ว่าต้องการลบโพสต์นี้?", "confirmations.delete_list.confirm": "ลบ", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "ทำเครื่องหมายว่าอ่านแล้ว", "conversation.open": "ดูการสนทนา", "conversation.with": "กับ {names}", + "copypaste.copied": "คัดลอกแล้ว", + "copypaste.copy": "คัดลอก", "directory.federated": "จากจักรวาลสหพันธ์ที่รู้จัก", "directory.local": "จาก {domain} เท่านั้น", "directory.new_arrivals": "มาใหม่", "directory.recently_active": "ใช้งานล่าสุด", + "dismissable_banner.community_timeline": "These are the most recent public posts from people whose accounts are hosted by {domain}.", + "dismissable_banner.dismiss": "ปิด", + "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", + "dismissable_banner.explore_statuses": "These posts from this and other servers in the decentralized network are gaining traction on this server right now.", + "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", + "dismissable_banner.public_timeline": "These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.", "embed.instructions": "ฝังโพสต์นี้ในเว็บไซต์ของคุณโดยคัดลอกโค้ดด้านล่าง", "embed.preview": "นี่คือลักษณะที่จะปรากฏ:", "emoji_button.activity": "กิจกรรม", @@ -221,14 +259,14 @@ "follow_request.reject": "ปฏิเสธ", "follow_requests.unlocked_explanation": "แม้ว่าไม่มีการล็อคบัญชีของคุณ พนักงานของ {domain} คิดว่าคุณอาจต้องการตรวจทานคำขอติดตามจากบัญชีเหล่านี้ด้วยตนเอง", "generic.saved": "บันทึกแล้ว", - "getting_started.developers": "นักพัฒนา", - "getting_started.directory": "ไดเรกทอรีโปรไฟล์", + "getting_started.directory": "ไดเรกทอรี", "getting_started.documentation": "เอกสารประกอบ", + "getting_started.free_software_notice": "Mastodon เป็นซอฟต์แวร์เสรีและโอเพนซอร์ส คุณสามารถดูโค้ดต้นฉบับ มีส่วนร่วม หรือรายงานปัญหาได้ที่ {repository}", "getting_started.heading": "เริ่มต้นใช้งาน", "getting_started.invite": "เชิญผู้คน", - "getting_started.open_source_notice": "Mastodon เป็นซอฟต์แวร์โอเพนซอร์ส คุณสามารถมีส่วนร่วมหรือรายงานปัญหาได้ใน GitHub ที่ {github}", "getting_started.privacy_policy": "นโยบายความเป็นส่วนตัว", "getting_started.security": "การตั้งค่าบัญชี", + "getting_started.what_is_mastodon": "เกี่ยวกับ Mastodon", "hashtag.column_header.tag_mode.all": "และ {additional}", "hashtag.column_header.tag_mode.any": "หรือ {additional}", "hashtag.column_header.tag_mode.none": "โดยไม่มี {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "แสดงการตอบกลับ", "home.hide_announcements": "ซ่อนประกาศ", "home.show_announcements": "แสดงประกาศ", + "interaction_modal.description.favourite": "With an account on Mastodon, you can favourite this post to let the author know you appreciate it and save it for later.", + "interaction_modal.description.follow": "With an account on Mastodon, you can follow {name} to receive their posts in your home feed.", + "interaction_modal.description.reblog": "With an account on Mastodon, you can boost this post to share it with your own followers.", + "interaction_modal.description.reply": "With an account on Mastodon, you can respond to this post.", + "interaction_modal.on_another_server": "ในเซิร์ฟเวอร์อื่น", + "interaction_modal.on_this_server": "ในเซิร์ฟเวอร์นี้", + "interaction_modal.other_server_instructions": "Simply copy and paste this URL into the search bar of your favourite app or the web interface where you are signed in.", + "interaction_modal.preamble": "Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one.", + "interaction_modal.title.favourite": "ชื่นชอบโพสต์ของ {name}", + "interaction_modal.title.follow": "ติดตาม {name}", + "interaction_modal.title.reblog": "ดันโพสต์ของ {name}", + "interaction_modal.title.reply": "ตอบกลับโพสต์ของ {name}", "intervals.full.days": "{number, plural, other {# วัน}}", "intervals.full.hours": "{number, plural, other {# ชั่วโมง}}", "intervals.full.minutes": "{number, plural, other {# นาที}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "ระยะเวลา", "mute_modal.hide_notifications": "ซ่อนการแจ้งเตือนจากผู้ใช้นี้?", "mute_modal.indefinite": "ไม่มีกำหนด", - "navigation_bar.apps": "แอปมือถือ", + "navigation_bar.about": "เกี่ยวกับ", + "navigation_bar.apps": "รับแอป", "navigation_bar.blocks": "ผู้ใช้ที่ปิดกั้นอยู่", "navigation_bar.bookmarks": "ที่คั่นหน้า", "navigation_bar.community_timeline": "เส้นเวลาในเซิร์ฟเวอร์", @@ -324,7 +375,7 @@ "navigation_bar.filters": "คำที่ซ่อนอยู่", "navigation_bar.follow_requests": "คำขอติดตาม", "navigation_bar.follows_and_followers": "การติดตามและผู้ติดตาม", - "navigation_bar.info": "เกี่ยวกับเซิร์ฟเวอร์นี้", + "navigation_bar.info": "เกี่ยวกับ", "navigation_bar.keyboard_shortcuts": "ปุ่มลัด", "navigation_bar.lists": "รายการ", "navigation_bar.logout": "ออกจากระบบ", @@ -333,7 +384,9 @@ "navigation_bar.pins": "โพสต์ที่ปักหมุด", "navigation_bar.preferences": "การกำหนดลักษณะ", "navigation_bar.public_timeline": "เส้นเวลาที่ติดต่อกับภายนอก", + "navigation_bar.search": "Search", "navigation_bar.security": "ความปลอดภัย", + "not_signed_in_indicator.not_signed_in": "คุณจำเป็นต้องลงชื่อเข้าเพื่อเข้าถึงทรัพยากรนี้", "notification.admin.report": "{name} ได้รายงาน {target}", "notification.admin.sign_up": "{name} ได้ลงทะเบียน", "notification.favourite": "{name} ได้ชื่นชอบโพสต์ของคุณ", @@ -401,6 +454,8 @@ "privacy.public.short": "สาธารณะ", "privacy.unlisted.long": "ปรากฏแก่ทั้งหมด แต่เลือกไม่รับคุณลักษณะการค้นพบ", "privacy.unlisted.short": "ไม่อยู่ในรายการ", + "privacy_policy.last_updated": "อัปเดตล่าสุดเมื่อ {date}", + "privacy_policy.title": "นโยบายความเป็นส่วนตัว", "refresh": "รีเฟรช", "regeneration_indicator.label": "กำลังโหลด…", "regeneration_indicator.sublabel": "กำลังเตรียมฟีดหน้าแรกของคุณ!", @@ -473,9 +528,15 @@ "search_results.statuses_fts_disabled": "ไม่มีการเปิดใช้งานการค้นหาโพสต์โดยเนื้อหาของโพสต์ในเซิร์ฟเวอร์ Mastodon นี้", "search_results.title": "ค้นหาสำหรับ {q}", "search_results.total": "{count, number} {count, plural, other {ผลลัพธ์}}", + "server_banner.about_active_users": "People using this server during the last 30 days (Monthly Active Users)", + "server_banner.active_users": "ผู้ใช้ที่ใช้งานอยู่", + "server_banner.administered_by": "ดูแลโดย:", + "server_banner.introduction": "{domain} เป็นส่วนหนึ่งของเครือข่ายสังคมแบบกระจายศูนย์ที่ขับเคลื่อนโดย {mastodon}", + "server_banner.learn_more": "เรียนรู้เพิ่มเติม", + "server_banner.server_stats": "สถิติเซิร์ฟเวอร์:", "sign_in_banner.create_account": "สร้างบัญชี", "sign_in_banner.sign_in": "ลงชื่อเข้า", - "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", + "sign_in_banner.text": "ลงชื่อเข้าเพื่อติดตามโปรไฟล์หรือแฮชแท็ก ชื่นชอบ แบ่งปัน และตอบกลับโพสต์ หรือโต้ตอบจากบัญชีของคุณในเซิร์ฟเวอร์อื่น", "status.admin_account": "เปิดส่วนติดต่อการควบคุมสำหรับ @{name}", "status.admin_status": "เปิดโพสต์นี้ในส่วนติดต่อการควบคุม", "status.block": "ปิดกั้น @{name}", @@ -512,6 +573,7 @@ "status.reblogs.empty": "ยังไม่มีใครดันโพสต์นี้ เมื่อใครสักคนดัน เขาจะปรากฏที่นี่", "status.redraft": "ลบแล้วร่างใหม่", "status.remove_bookmark": "เอาที่คั่นหน้าออก", + "status.replied_to": "Replied to {name}", "status.reply": "ตอบกลับ", "status.replyAll": "ตอบกลับกระทู้", "status.report": "รายงาน @{name}", @@ -523,9 +585,8 @@ "status.show_more": "แสดงเพิ่มเติม", "status.show_more_all": "แสดงเพิ่มเติมทั้งหมด", "status.show_original": "แสดงดั้งเดิม", - "status.show_thread": "แสดงกระทู้", "status.translate": "แปล", - "status.translated_from": "แปลจาก {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "ไม่พร้อมใช้งาน", "status.unmute_conversation": "เลิกซ่อนการสนทนา", "status.unpin": "ถอนหมุดจากโปรไฟล์", @@ -538,7 +599,6 @@ "tabs_bar.home": "หน้าแรก", "tabs_bar.local_timeline": "ในเซิร์ฟเวอร์", "tabs_bar.notifications": "การแจ้งเตือน", - "tabs_bar.search": "ค้นหา", "time_remaining.days": "เหลืออีก {number, plural, other {# วัน}}", "time_remaining.hours": "เหลืออีก {number, plural, other {# ชั่วโมง}}", "time_remaining.minutes": "เหลืออีก {number, plural, other {# นาที}}", diff --git a/app/javascript/mastodon/locales/tr.json b/app/javascript/mastodon/locales/tr.json index d7f07b9c3..4c1e7c066 100644 --- a/app/javascript/mastodon/locales/tr.json +++ b/app/javascript/mastodon/locales/tr.json @@ -1,4 +1,17 @@ { + "about.blocks": "Denetlenen sunucular", + "about.contact": "İletişim:", + "about.domain_blocks.comment": "Gerekçe", + "about.domain_blocks.domain": "Alan adı", + "about.domain_blocks.preamble": "Mastodon, genel olarak fediverse'teki herhangi bir sunucudan içerik görüntülemenize ve kullanıcılarıyla etkileşim kurmanıza izin verir. Bunlar, bu sunucuda yapılmış olan istisnalardır.", + "about.domain_blocks.severity": "Önem derecesi", + "about.domain_blocks.silenced.explanation": "Açık bir şekilde aramadığınız veya takip ederek abone olmadığınız sürece, bu sunucudaki profilleri veya içerikleri genelde göremeyeceksiniz.", + "about.domain_blocks.silenced.title": "Sınırlı", + "about.domain_blocks.suspended.explanation": "Bu sunucudaki hiçbir veri işlenmeyecek, saklanmayacak veya değiş tokuş edilmeyecektir, dolayısıyla bu sunucudaki kullanıcılarla herhangi bir etkileşim veya iletişim imkansız olacaktır.", + "about.domain_blocks.suspended.title": "Askıya alındı", + "about.not_available": "Bu sunucuda bu bilgi kullanıma sunulmadı.", + "about.powered_by": "{mastodon} destekli ademi merkeziyetçi sosyal medya", + "about.rules": "Sunucu kuralları", "account.account_note_header": "Not", "account.add_or_remove_from_list": "Listelere ekle veya kaldır", "account.badges.bot": "Bot", @@ -7,13 +20,16 @@ "account.block_domain": "{domain} alan adını engelle", "account.blocked": "Engellendi", "account.browse_more_on_origin_server": "Orijinal profilde daha fazlasına göz atın", - "account.cancel_follow_request": "Takip isteğini iptal et", + "account.cancel_follow_request": "Takip isteğini geri çek", "account.direct": "@{name} adlı kişiye mesaj gönder", "account.disable_notifications": "@{name} kişisinin gönderi bildirimlerini kapat", "account.domain_blocked": "Alan adı engellendi", "account.edit_profile": "Profili düzenle", "account.enable_notifications": "@{name}'in gönderilerini bana bildir", "account.endorse": "Profilimde öne çıkar", + "account.featured_tags.last_status_at": "Son gönderinin tarihi {date}", + "account.featured_tags.last_status_never": "Gönderi yok", + "account.featured_tags.title": "{name} kişisinin öne çıkan etiketleri", "account.follow": "Takip et", "account.followers": "Takipçi", "account.followers.empty": "Henüz kimse bu kullanıcıyı takip etmiyor.", @@ -23,7 +39,7 @@ "account.follows.empty": "Bu kullanıcı henüz hiçkimseyi takip etmiyor.", "account.follows_you": "Seni takip ediyor", "account.hide_reblogs": "@{name} kişisinin boostlarını gizle", - "account.joined": "{date} tarihinde katıldı", + "account.joined_short": "Joined", "account.languages": "Abone olunan dilleri değiştir", "account.link_verified_on": "Bu bağlantının sahipliği {date} tarihinde kontrol edildi", "account.locked_info": "Bu hesabın gizlilik durumu gizli olarak ayarlanmış. Sahibi, onu kimin takip edebileceğini manuel olarak onaylıyor.", @@ -63,12 +79,24 @@ "audio.hide": "Sesi gizle", "autosuggest_hashtag.per_week": "Haftada {count}", "boost_modal.combo": "Bir daha ki sefere {combo} tuşuna basabilirsin", - "bundle_column_error.body": "Bu bileşen yüklenirken bir şeyler ters gitti.", + "bundle_column_error.copy_stacktrace": "Hata raporunu kopyala", + "bundle_column_error.error.body": "İstenen sayfa gösterilemiyor. Bu durum kodumuzdaki bir hatadan veya tarayıcı uyum sorunundan kaynaklanıyor olabilir.", + "bundle_column_error.error.title": "Ah, hayır!", + "bundle_column_error.network.body": "Sayfayı yüklemeye çalışırken bir hata oluştu. Bu durum internet bağlantınızdaki veya bu sunucudaki geçici bir sorundan kaynaklanıyor olabilir.", + "bundle_column_error.network.title": "Ağ hatası", "bundle_column_error.retry": "Tekrar deneyin", - "bundle_column_error.title": "Ağ hatası", + "bundle_column_error.return": "Anasayfaya geri dön", + "bundle_column_error.routing.body": "İstenen sayfa bulunamadı. Adres çubuğundaki URL'nin doğru olduğundan emin misiniz?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Kapat", "bundle_modal_error.message": "Bu bileşen yüklenirken bir şeyler ters gitti.", "bundle_modal_error.retry": "Tekrar deneyin", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "Hakkında", "column.blocks": "Engellenen kullanıcılar", "column.bookmarks": "Yer İmleri", "column.community": "Yerel zaman tüneli", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "Engelle ve Bildir", "confirmations.block.confirm": "Engelle", "confirmations.block.message": "{name} adlı kullanıcıyı engellemek istediğinden emin misin?", + "confirmations.cancel_follow_request.confirm": "İsteği geri çek", + "confirmations.cancel_follow_request.message": "{name} kişisini takip etme isteğini geri çekmek istediğinden emin misin?", "confirmations.delete.confirm": "Sil", "confirmations.delete.message": "Bu tootu silmek istediğinden emin misin?", "confirmations.delete_list.confirm": "Sil", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Okundu olarak işaretle", "conversation.open": "Sohbeti görüntüle", "conversation.with": "{names} ile", + "copypaste.copied": "Kopyalandı", + "copypaste.copy": "Kopyala", "directory.federated": "Bilinen fediverse'lerden", "directory.local": "Yalnızca {domain} adresinden", "directory.new_arrivals": "Yeni gelenler", "directory.recently_active": "Son zamanlarda aktif", + "dismissable_banner.community_timeline": "Bunlar, {domain} sunucusunda hesabı olanların yakın zamandaki herkese açık gönderileridir.", + "dismissable_banner.dismiss": "Yoksay", + "dismissable_banner.explore_links": "Bunlar, ademi merkeziyetçi ağda bu ve diğer sunucularda şimdilerde insanların hakkında konuştuğu haber öyküleridir.", + "dismissable_banner.explore_statuses": "Ademi merkeziyetçi ağın bu ve diğer sunucularındaki bu gönderiler, mevcut sunucuda şimdilerde ilgi çekiyorlar.", + "dismissable_banner.explore_tags": "Bu etiketler, ademi merkeziyetçi ağdaki bu ve diğer sunuculardaki insanların şimdilerde ilgisini çekiyor.", + "dismissable_banner.public_timeline": "Bunlar, ademi merkeziyetçi ağdaki bu ve diğer sunuculardaki insanların son zamanlardaki herkese açık gönderilerinden bu sunucunun haberdar olduklarıdır.", "embed.instructions": "Aşağıdaki kodu kopyalayarak bu durumu sitenize gömün.", "embed.preview": "İşte nasıl görüneceği:", "emoji_button.activity": "Aktivite", @@ -221,14 +259,14 @@ "follow_request.reject": "Reddet", "follow_requests.unlocked_explanation": "Hesabınız kilitli olmasa bile, {domain} personeli bu hesaplardan gelen takip isteklerini gözden geçirmek isteyebileceğinizi düşündü.", "generic.saved": "Kaydedildi", - "getting_started.developers": "Geliştiriciler", - "getting_started.directory": "Profil Dizini", + "getting_started.directory": "Dizin", "getting_started.documentation": "Belgeler", + "getting_started.free_software_notice": "Mastodon özgür ve açık kaynak bir yazılımdır. {repository} deposunda kaynak kodunu görebilir, katkı verebilir veya sorunları bildirebilirsiniz.", "getting_started.heading": "Başlarken", "getting_started.invite": "İnsanları davet et", - "getting_started.open_source_notice": "Mastodon açık kaynaklı bir yazılımdır. GitHub'taki {github} üzerinden katkıda bulunabilir veya sorunları bildirebilirsiniz.", "getting_started.privacy_policy": "Gizlilik Politikası", "getting_started.security": "Hesap ayarları", + "getting_started.what_is_mastodon": "Mastodon Hakkında", "hashtag.column_header.tag_mode.all": "ve {additional}", "hashtag.column_header.tag_mode.any": "ya da {additional}", "hashtag.column_header.tag_mode.none": "{additional} olmadan", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Yanıtları göster", "home.hide_announcements": "Duyuruları gizle", "home.show_announcements": "Duyuruları göster", + "interaction_modal.description.favourite": "Mastodon'da bir hesapla, bu gönderiyi, yazarın onu beğendiğinizi bilmesi ve daha sonrası saklamak için beğenebilirsiniz.", + "interaction_modal.description.follow": "Mastodon'daki bir hesapla, {name} kişisini, ana akışınızdaki gönderilerini görmek üzere takip edebilirsiniz.", + "interaction_modal.description.reblog": "Mastodon'daki bir hesapla, bu gönderiyi takipçilerinizle paylaşmak için yükseltebilirsiniz.", + "interaction_modal.description.reply": "Mastodon'daki bir hesapla, bu gönderiye yanıt verebilirsiniz.", + "interaction_modal.on_another_server": "Farklı bir sunucuda", + "interaction_modal.on_this_server": "Bu sunucuda", + "interaction_modal.other_server_instructions": "Basitçe bu URL'yi kopyalayın ve beğendiğiniz uygulamanın veya giriş yapmış olduğunuz bir web arayüzünün arama çubuğuna yapıştırın.", + "interaction_modal.preamble": "Mastodon ademi merkeziyetçi olduğu için, bu sunucuda bir hesabınız yoksa bile başka bir Mastodon sunucusu veya uyumlu bir platformda barındırılan mevcut hesabınızı kullanabilirsiniz.", + "interaction_modal.title.favourite": "{name} kişisinin gönderisini favorilerine ekle", + "interaction_modal.title.follow": "{name} kişisini takip et", + "interaction_modal.title.reblog": "{name} kişisinin gönderisini yükselt", + "interaction_modal.title.reply": "{name} kişisinin gönderisine yanıt ver", "intervals.full.days": "{number, plural, one {# gün} other {# gün}}", "intervals.full.hours": "{number, plural, one {# saat} other {# saat}}", "intervals.full.minutes": "{number, plural, one {# dakika} other {# dakika}}", @@ -257,8 +307,8 @@ "keyboard_shortcuts.direct": "doğrudan iletiler sütununu açmak için", "keyboard_shortcuts.down": "listede aşağıya inmek için", "keyboard_shortcuts.enter": "gönderiyi aç", - "keyboard_shortcuts.favourite": "gönderiyi favorilerine ekle", - "keyboard_shortcuts.favourites": "favoriler listesini açmak için", + "keyboard_shortcuts.favourite": "Gönderiyi favorilerine ekle", + "keyboard_shortcuts.favourites": "Favoriler listesini aç", "keyboard_shortcuts.federated": "federe akışı aç", "keyboard_shortcuts.heading": "Klavye kısayolları", "keyboard_shortcuts.home": "ana akışı aç", @@ -310,7 +360,8 @@ "mute_modal.duration": "Süre", "mute_modal.hide_notifications": "Bu kullanıcıdan bildirimler gizlensin mı?", "mute_modal.indefinite": "Belirsiz", - "navigation_bar.apps": "Mobil uygulamalar", + "navigation_bar.about": "Hakkında", + "navigation_bar.apps": "Uygulamayı indir", "navigation_bar.blocks": "Engellenen kullanıcılar", "navigation_bar.bookmarks": "Yer İmleri", "navigation_bar.community_timeline": "Yerel Zaman Tüneli", @@ -324,7 +375,7 @@ "navigation_bar.filters": "Sessize alınmış kelimeler", "navigation_bar.follow_requests": "Takip istekleri", "navigation_bar.follows_and_followers": "Takip edilenler ve takipçiler", - "navigation_bar.info": "Bu sunucu hakkında", + "navigation_bar.info": "Hakkında", "navigation_bar.keyboard_shortcuts": "Klavye kısayolları", "navigation_bar.lists": "Listeler", "navigation_bar.logout": "Oturumu kapat", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Sabitlenmiş gönderiler", "navigation_bar.preferences": "Tercihler", "navigation_bar.public_timeline": "Federe zaman tüneli", + "navigation_bar.search": "Search", "navigation_bar.security": "Güvenlik", + "not_signed_in_indicator.not_signed_in": "Bu kaynağa erişmek için oturum açmanız gerekir.", "notification.admin.report": "{name}, {target} kişisini bildirdi", "notification.admin.sign_up": "{name} kaydoldu", "notification.favourite": "{name} gönderini favorilerine ekledi", @@ -401,6 +454,8 @@ "privacy.public.short": "Herkese açık", "privacy.unlisted.long": "Keşfet harici herkese açık", "privacy.unlisted.short": "Listelenmemiş", + "privacy_policy.last_updated": "Son güncelleme {date}", + "privacy_policy.title": "Gizlilik Politikası", "refresh": "Yenile", "regeneration_indicator.label": "Yükleniyor…", "regeneration_indicator.sublabel": "Ana akışın hazırlanıyor!", @@ -460,7 +515,7 @@ "report_notification.open": "Bildirim aç", "search.placeholder": "Ara", "search_popout.search_format": "Gelişmiş arama biçimi", - "search_popout.tips.full_text": "Basit metin yazdığınız, beğendiğiniz, teşvik ettiğiniz veya söz edilen gönderilerin yanı sıra kullanıcı adlarını, görünen adları ve hashtag'leri eşleştiren gönderileri de döndürür.", + "search_popout.tips.full_text": "Basit metin yazdığınız, beğendiğiniz, teşvik ettiğiniz veya söz edilen gönderilerin yanı sıra kullanıcı adlarını, görünen adları ve etiketleri eşleşen gönderileri de döndürür.", "search_popout.tips.hashtag": "etiket", "search_popout.tips.status": "gönderi", "search_popout.tips.text": "Basit metin, eşleşen görünen adları, kullanıcı adlarını ve hashtag'leri döndürür", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "Bu Mastodon sunucusunda gönderi içeriğine göre arama etkin değil.", "search_results.title": "{q} araması", "search_results.total": "{count, number} {count, plural, one {sonuç} other {sonuç}}", + "server_banner.about_active_users": "Bu sunucuyu son 30 günde kullanan insanlar (Aylık Etkin Kullanıcılar)", + "server_banner.active_users": "etkin kullanıcılar", + "server_banner.administered_by": "Yönetici:", + "server_banner.introduction": "{domain}, {mastodon} destekli ademi merkeziyetçi sosyal ağın bir parçasıdır.", + "server_banner.learn_more": "Daha fazlasını öğrenin", + "server_banner.server_stats": "Sunucu istatistikleri:", "sign_in_banner.create_account": "Hesap oluştur", "sign_in_banner.sign_in": "Giriş yap", "sign_in_banner.text": "Profilleri veya etiketleri izlemek, gönderileri beğenmek, paylaşmak ve yanıtlamak için veya başka bir sunucunuzdaki hesabınızla etkileşmek için giriş yapın.", @@ -502,16 +563,17 @@ "status.more": "Daha fazla", "status.mute": "@{name} kişisini sessize al", "status.mute_conversation": "Sohbeti sessize al", - "status.open": "Bu tootu genişlet", + "status.open": "Bu gönderiyi genişlet", "status.pin": "Profile sabitle", - "status.pinned": "Sabitlenmiş toot", + "status.pinned": "Sabitlenmiş gönderi", "status.read_more": "Devamını okuyun", "status.reblog": "Boostla", "status.reblog_private": "Orijinal görünürlük ile boostla", "status.reblogged_by": "{name} boostladı", - "status.reblogs.empty": "Henüz kimse bu tootu boostlamadı. Biri yaptığında burada görünecek.", + "status.reblogs.empty": "Henüz kimse bu gönderiyi teşvik etmedi. Biri yaptığında burada görünecek.", "status.redraft": "Sil ve yeniden taslak yap", "status.remove_bookmark": "Yer imini kaldır", + "status.replied_to": "Replied to {name}", "status.reply": "Yanıtla", "status.replyAll": "Konuyu yanıtla", "status.report": "@{name} adlı kişiyi bildir", @@ -523,9 +585,8 @@ "status.show_more": "Daha fazlasını göster", "status.show_more_all": "Hepsi için daha fazla göster", "status.show_original": "Orijinali göster", - "status.show_thread": "Konuyu göster", "status.translate": "Çevir", - "status.translated_from": "{lang} dilinden çevrildi", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Mevcut değil", "status.unmute_conversation": "Sohbet sesini aç", "status.unpin": "Profilden sabitlemeyi kaldır", @@ -538,7 +599,6 @@ "tabs_bar.home": "Ana Sayfa", "tabs_bar.local_timeline": "Yerel", "tabs_bar.notifications": "Bildirimler", - "tabs_bar.search": "Ara", "time_remaining.days": "{number, plural, one {# gün} other {# gün}} kaldı", "time_remaining.hours": "{number, plural, one {# saat} other {# saat}} kaldı", "time_remaining.minutes": "{number, plural, one {# dakika} other {# dakika}} kaldı", @@ -547,7 +607,7 @@ "timeline_hint.remote_resource_not_displayed": "diğer sunucudaki {resource} gösterilemiyor.", "timeline_hint.resources.followers": "Takipçiler", "timeline_hint.resources.follows": "Takip Edilenler", - "timeline_hint.resources.statuses": "Eski tootlar", + "timeline_hint.resources.statuses": "Eski gönderiler", "trends.counter_by_accounts": "Son {days, plural, one {gündeki} other {{days} gündeki}} {count, plural, one {{counter} kişi} other {{counter} kişi}}", "trends.trending_now": "Şu an gündemde", "ui.beforeunload": "Mastodon'u terk ederseniz taslağınız kaybolacak.", diff --git a/app/javascript/mastodon/locales/tt.json b/app/javascript/mastodon/locales/tt.json index 462eda6e1..eba18f8fc 100644 --- a/app/javascript/mastodon/locales/tt.json +++ b/app/javascript/mastodon/locales/tt.json @@ -1,4 +1,17 @@ { + "about.blocks": "Moderated servers", + "about.contact": "Contact:", + "about.domain_blocks.comment": "Reason", + "about.domain_blocks.domain": "Domain", + "about.domain_blocks.preamble": "Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.", + "about.domain_blocks.severity": "Severity", + "about.domain_blocks.silenced.explanation": "You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.", + "about.domain_blocks.silenced.title": "Limited", + "about.domain_blocks.suspended.explanation": "No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.", + "about.domain_blocks.suspended.title": "Suspended", + "about.not_available": "This information has not been made available on this server.", + "about.powered_by": "Decentralized social media powered by {mastodon}", + "about.rules": "Server rules", "account.account_note_header": "Язма", "account.add_or_remove_from_list": "Исемлеккә кертү я бетерү", "account.badges.bot": "Бот", @@ -7,13 +20,16 @@ "account.block_domain": "{domain} доменын блоклау", "account.blocked": "Блокланган", "account.browse_more_on_origin_server": "Тулырак оригинал профилендә карап була", - "account.cancel_follow_request": "Язылуга сорауны бетерү", + "account.cancel_follow_request": "Withdraw follow request", "account.direct": "@{name} өчен яңа хат", "account.disable_notifications": "@{name} язулары өчен белдерүләр сүндерү", "account.domain_blocked": "Домен блокланган", "account.edit_profile": "Профильны үзгәртү", "account.enable_notifications": "@{name} язулары өчен белдерүләр яндыру", "account.endorse": "Профильдә рекомендацияләү", + "account.featured_tags.last_status_at": "Last post on {date}", + "account.featured_tags.last_status_never": "No posts", + "account.featured_tags.title": "{name}'s featured hashtags", "account.follow": "Языл", "account.followers": "Язылучылар", "account.followers.empty": "Әле беркем дә язылмаган.", @@ -23,7 +39,7 @@ "account.follows.empty": "Беркемгә дә язылмаган әле.", "account.follows_you": "Сезгә язылган", "account.hide_reblogs": "Hide boosts from @{name}", - "account.joined": "{date} көнендә теркәлде", + "account.joined_short": "Joined", "account.languages": "Change subscribed languages", "account.link_verified_on": "Ownership of this link was checked on {date}", "account.locked_info": "Бу - ябык аккаунт. Аны язылучылар гына күрә ала.", @@ -63,12 +79,24 @@ "audio.hide": "Hide audio", "autosuggest_hashtag.per_week": "{count} per week", "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.copy_stacktrace": "Copy error report", + "bundle_column_error.error.body": "The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.", + "bundle_column_error.error.title": "Oh, no!", + "bundle_column_error.network.body": "There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.", + "bundle_column_error.network.title": "Network error", "bundle_column_error.retry": "Try again", - "bundle_column_error.title": "Network error", + "bundle_column_error.return": "Go back home", + "bundle_column_error.routing.body": "The requested page could not be found. Are you sure the URL in the address bar is correct?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Ябу", "bundle_modal_error.message": "Something went wrong while loading this component.", "bundle_modal_error.retry": "Try again", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "About", "column.blocks": "Blocked users", "column.bookmarks": "Кыстыргычлар", "column.community": "Local timeline", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "Block & Report", "confirmations.block.confirm": "Блоклау", "confirmations.block.message": "Are you sure you want to block {name}?", + "confirmations.cancel_follow_request.confirm": "Withdraw request", + "confirmations.cancel_follow_request.message": "Are you sure you want to withdraw your request to follow {name}?", "confirmations.delete.confirm": "Бетерү", "confirmations.delete.message": "Are you sure you want to delete this status?", "confirmations.delete_list.confirm": "Бетерү", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Mark as read", "conversation.open": "View conversation", "conversation.with": "With {names}", + "copypaste.copied": "Copied", + "copypaste.copy": "Copy", "directory.federated": "From known fediverse", "directory.local": "From {domain} only", "directory.new_arrivals": "New arrivals", "directory.recently_active": "Recently active", + "dismissable_banner.community_timeline": "These are the most recent public posts from people whose accounts are hosted by {domain}.", + "dismissable_banner.dismiss": "Dismiss", + "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", + "dismissable_banner.explore_statuses": "These posts from this and other servers in the decentralized network are gaining traction on this server right now.", + "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", + "dismissable_banner.public_timeline": "These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.", "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": "Активлык", @@ -221,14 +259,14 @@ "follow_request.reject": "Reject", "follow_requests.unlocked_explanation": "Even though your account is not locked, the {domain} staff thought you might want to review follow requests from these accounts manually.", "generic.saved": "Сакланды", - "getting_started.developers": "Developers", - "getting_started.directory": "Profile directory", + "getting_started.directory": "Directory", "getting_started.documentation": "Documentation", + "getting_started.free_software_notice": "Mastodon is free, open source software. You can view the source code, contribute or report issues at {repository}.", "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.privacy_policy": "Privacy Policy", "getting_started.security": "Security", + "getting_started.what_is_mastodon": "About Mastodon", "hashtag.column_header.tag_mode.all": "and {additional}", "hashtag.column_header.tag_mode.any": "or {additional}", "hashtag.column_header.tag_mode.none": "without {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Show replies", "home.hide_announcements": "Hide announcements", "home.show_announcements": "Show announcements", + "interaction_modal.description.favourite": "With an account on Mastodon, you can favourite this post to let the author know you appreciate it and save it for later.", + "interaction_modal.description.follow": "With an account on Mastodon, you can follow {name} to receive their posts in your home feed.", + "interaction_modal.description.reblog": "With an account on Mastodon, you can boost this post to share it with your own followers.", + "interaction_modal.description.reply": "With an account on Mastodon, you can respond to this post.", + "interaction_modal.on_another_server": "On a different server", + "interaction_modal.on_this_server": "On this server", + "interaction_modal.other_server_instructions": "Simply copy and paste this URL into the search bar of your favourite app or the web interface where you are signed in.", + "interaction_modal.preamble": "Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one.", + "interaction_modal.title.favourite": "Favourite {name}'s post", + "interaction_modal.title.follow": "Follow {name}", + "interaction_modal.title.reblog": "Boost {name}'s post", + "interaction_modal.title.reply": "Reply to {name}'s post", "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}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Дәвамлык", "mute_modal.hide_notifications": "Hide notifications from this user?", "mute_modal.indefinite": "Indefinite", - "navigation_bar.apps": "Mobile apps", + "navigation_bar.about": "About", + "navigation_bar.apps": "Get the app", "navigation_bar.blocks": "Blocked users", "navigation_bar.bookmarks": "Кыстыргычлар", "navigation_bar.community_timeline": "Local timeline", @@ -324,7 +375,7 @@ "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.info": "About", "navigation_bar.keyboard_shortcuts": "Hotkeys", "navigation_bar.lists": "Lists", "navigation_bar.logout": "Logout", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Pinned toots", "navigation_bar.preferences": "Caylaw", "navigation_bar.public_timeline": "Federated timeline", + "navigation_bar.search": "Search", "navigation_bar.security": "Хәвефсезлек", + "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", "notification.admin.report": "{name} reported {target}", "notification.admin.sign_up": "{name} signed up", "notification.favourite": "{name} favourited your status", @@ -401,6 +454,8 @@ "privacy.public.short": "Public", "privacy.unlisted.long": "Visible for all, but opted-out of discovery features", "privacy.unlisted.short": "Unlisted", + "privacy_policy.last_updated": "Last updated {date}", + "privacy_policy.title": "Privacy Policy", "refresh": "Яңарту", "regeneration_indicator.label": "Йөкләү...", "regeneration_indicator.sublabel": "Your home feed is being prepared!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.title": "Search for {q}", "search_results.total": "{count, number} {count, plural, one {result} other {results}}", + "server_banner.about_active_users": "People using this server during the last 30 days (Monthly Active Users)", + "server_banner.active_users": "active users", + "server_banner.administered_by": "Administered by:", + "server_banner.introduction": "{domain} is part of the decentralized social network powered by {mastodon}.", + "server_banner.learn_more": "Learn more", + "server_banner.server_stats": "Server stats:", "sign_in_banner.create_account": "Create account", "sign_in_banner.sign_in": "Sign in", "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "No one has boosted this toot yet. When someone does, they will show up here.", "status.redraft": "Delete & re-draft", "status.remove_bookmark": "Remove bookmark", + "status.replied_to": "Replied to {name}", "status.reply": "Reply", "status.replyAll": "Reply to thread", "status.report": "Report @{name}", @@ -523,9 +585,8 @@ "status.show_more": "Күбрәк күрсәтү", "status.show_more_all": "Show more for all", "status.show_original": "Show original", - "status.show_thread": "Show thread", "status.translate": "Translate", - "status.translated_from": "Translated from {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Not available", "status.unmute_conversation": "Unmute conversation", "status.unpin": "Unpin from profile", @@ -538,7 +599,6 @@ "tabs_bar.home": "Баш бит", "tabs_bar.local_timeline": "Җирле", "tabs_bar.notifications": "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", diff --git a/app/javascript/mastodon/locales/ug.json b/app/javascript/mastodon/locales/ug.json index de4e76507..cc0fa7069 100644 --- a/app/javascript/mastodon/locales/ug.json +++ b/app/javascript/mastodon/locales/ug.json @@ -1,4 +1,17 @@ { + "about.blocks": "Moderated servers", + "about.contact": "Contact:", + "about.domain_blocks.comment": "Reason", + "about.domain_blocks.domain": "Domain", + "about.domain_blocks.preamble": "Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.", + "about.domain_blocks.severity": "Severity", + "about.domain_blocks.silenced.explanation": "You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.", + "about.domain_blocks.silenced.title": "Limited", + "about.domain_blocks.suspended.explanation": "No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.", + "about.domain_blocks.suspended.title": "Suspended", + "about.not_available": "This information has not been made available on this server.", + "about.powered_by": "Decentralized social media powered by {mastodon}", + "about.rules": "Server rules", "account.account_note_header": "Note", "account.add_or_remove_from_list": "Add or Remove from lists", "account.badges.bot": "Bot", @@ -7,13 +20,16 @@ "account.block_domain": "Block domain {domain}", "account.blocked": "Blocked", "account.browse_more_on_origin_server": "Browse more on the original profile", - "account.cancel_follow_request": "Cancel follow request", + "account.cancel_follow_request": "Withdraw follow request", "account.direct": "Direct message @{name}", "account.disable_notifications": "Stop notifying me when @{name} posts", "account.domain_blocked": "Domain blocked", "account.edit_profile": "Edit profile", "account.enable_notifications": "Notify me when @{name} posts", "account.endorse": "Feature on profile", + "account.featured_tags.last_status_at": "Last post on {date}", + "account.featured_tags.last_status_never": "No posts", + "account.featured_tags.title": "{name}'s featured hashtags", "account.follow": "Follow", "account.followers": "Followers", "account.followers.empty": "No one follows this user yet.", @@ -23,7 +39,7 @@ "account.follows.empty": "This user doesn't follow anyone yet.", "account.follows_you": "Follows you", "account.hide_reblogs": "Hide boosts from @{name}", - "account.joined": "Joined {date}", + "account.joined_short": "Joined", "account.languages": "Change subscribed languages", "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.", @@ -63,12 +79,24 @@ "audio.hide": "Hide audio", "autosuggest_hashtag.per_week": "{count} per week", "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.copy_stacktrace": "Copy error report", + "bundle_column_error.error.body": "The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.", + "bundle_column_error.error.title": "Oh, no!", + "bundle_column_error.network.body": "There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.", + "bundle_column_error.network.title": "Network error", "bundle_column_error.retry": "Try again", - "bundle_column_error.title": "Network error", + "bundle_column_error.return": "Go back home", + "bundle_column_error.routing.body": "The requested page could not be found. Are you sure the URL in the address bar is correct?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Close", "bundle_modal_error.message": "Something went wrong while loading this component.", "bundle_modal_error.retry": "Try again", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "About", "column.blocks": "Blocked users", "column.bookmarks": "Bookmarks", "column.community": "Local timeline", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "Block & Report", "confirmations.block.confirm": "Block", "confirmations.block.message": "Are you sure you want to block {name}?", + "confirmations.cancel_follow_request.confirm": "Withdraw request", + "confirmations.cancel_follow_request.message": "Are you sure you want to withdraw your request to follow {name}?", "confirmations.delete.confirm": "Delete", "confirmations.delete.message": "Are you sure you want to delete this status?", "confirmations.delete_list.confirm": "Delete", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Mark as read", "conversation.open": "View conversation", "conversation.with": "With {names}", + "copypaste.copied": "Copied", + "copypaste.copy": "Copy", "directory.federated": "From known fediverse", "directory.local": "From {domain} only", "directory.new_arrivals": "New arrivals", "directory.recently_active": "Recently active", + "dismissable_banner.community_timeline": "These are the most recent public posts from people whose accounts are hosted by {domain}.", + "dismissable_banner.dismiss": "Dismiss", + "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", + "dismissable_banner.explore_statuses": "These posts from this and other servers in the decentralized network are gaining traction on this server right now.", + "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", + "dismissable_banner.public_timeline": "These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.", "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", @@ -221,14 +259,14 @@ "follow_request.reject": "Reject", "follow_requests.unlocked_explanation": "Even though your account is not locked, the {domain} staff thought you might want to review follow requests from these accounts manually.", "generic.saved": "Saved", - "getting_started.developers": "Developers", - "getting_started.directory": "Profile directory", + "getting_started.directory": "Directory", "getting_started.documentation": "Documentation", + "getting_started.free_software_notice": "Mastodon is free, open source software. You can view the source code, contribute or report issues at {repository}.", "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.privacy_policy": "Privacy Policy", "getting_started.security": "Security", + "getting_started.what_is_mastodon": "About Mastodon", "hashtag.column_header.tag_mode.all": "and {additional}", "hashtag.column_header.tag_mode.any": "or {additional}", "hashtag.column_header.tag_mode.none": "without {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Show replies", "home.hide_announcements": "Hide announcements", "home.show_announcements": "Show announcements", + "interaction_modal.description.favourite": "With an account on Mastodon, you can favourite this post to let the author know you appreciate it and save it for later.", + "interaction_modal.description.follow": "With an account on Mastodon, you can follow {name} to receive their posts in your home feed.", + "interaction_modal.description.reblog": "With an account on Mastodon, you can boost this post to share it with your own followers.", + "interaction_modal.description.reply": "With an account on Mastodon, you can respond to this post.", + "interaction_modal.on_another_server": "On a different server", + "interaction_modal.on_this_server": "On this server", + "interaction_modal.other_server_instructions": "Simply copy and paste this URL into the search bar of your favourite app or the web interface where you are signed in.", + "interaction_modal.preamble": "Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one.", + "interaction_modal.title.favourite": "Favourite {name}'s post", + "interaction_modal.title.follow": "Follow {name}", + "interaction_modal.title.reblog": "Boost {name}'s post", + "interaction_modal.title.reply": "Reply to {name}'s post", "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}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Duration", "mute_modal.hide_notifications": "Hide notifications from this user?", "mute_modal.indefinite": "Indefinite", - "navigation_bar.apps": "Mobile apps", + "navigation_bar.about": "About", + "navigation_bar.apps": "Get the app", "navigation_bar.blocks": "Blocked users", "navigation_bar.bookmarks": "Bookmarks", "navigation_bar.community_timeline": "Local timeline", @@ -324,7 +375,7 @@ "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.info": "About", "navigation_bar.keyboard_shortcuts": "Hotkeys", "navigation_bar.lists": "Lists", "navigation_bar.logout": "Logout", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Pinned toots", "navigation_bar.preferences": "Preferences", "navigation_bar.public_timeline": "Federated timeline", + "navigation_bar.search": "Search", "navigation_bar.security": "Security", + "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", "notification.admin.report": "{name} reported {target}", "notification.admin.sign_up": "{name} signed up", "notification.favourite": "{name} favourited your status", @@ -401,6 +454,8 @@ "privacy.public.short": "Public", "privacy.unlisted.long": "Visible for all, but opted-out of discovery features", "privacy.unlisted.short": "Unlisted", + "privacy_policy.last_updated": "Last updated {date}", + "privacy_policy.title": "Privacy Policy", "refresh": "Refresh", "regeneration_indicator.label": "Loading…", "regeneration_indicator.sublabel": "Your home feed is being prepared!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.title": "Search for {q}", "search_results.total": "{count, number} {count, plural, one {result} other {results}}", + "server_banner.about_active_users": "People using this server during the last 30 days (Monthly Active Users)", + "server_banner.active_users": "active users", + "server_banner.administered_by": "Administered by:", + "server_banner.introduction": "{domain} is part of the decentralized social network powered by {mastodon}.", + "server_banner.learn_more": "Learn more", + "server_banner.server_stats": "Server stats:", "sign_in_banner.create_account": "Create account", "sign_in_banner.sign_in": "Sign in", "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "No one has boosted this toot yet. When someone does, they will show up here.", "status.redraft": "Delete & re-draft", "status.remove_bookmark": "Remove bookmark", + "status.replied_to": "Replied to {name}", "status.reply": "Reply", "status.replyAll": "Reply to thread", "status.report": "Report @{name}", @@ -523,9 +585,8 @@ "status.show_more": "Show more", "status.show_more_all": "Show more for all", "status.show_original": "Show original", - "status.show_thread": "Show thread", "status.translate": "Translate", - "status.translated_from": "Translated from {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Not available", "status.unmute_conversation": "Unmute conversation", "status.unpin": "Unpin from profile", @@ -538,7 +599,6 @@ "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", diff --git a/app/javascript/mastodon/locales/uk.json b/app/javascript/mastodon/locales/uk.json index a1590779c..995d2afcc 100644 --- a/app/javascript/mastodon/locales/uk.json +++ b/app/javascript/mastodon/locales/uk.json @@ -1,4 +1,17 @@ { + "about.blocks": "Модеровані сервери", + "about.contact": "Kонтакти:", + "about.domain_blocks.comment": "Причина", + "about.domain_blocks.domain": "Домен", + "about.domain_blocks.preamble": "Mastodon зазвичай дозволяє вам взаємодіяти з користувачами будь-яких серверів у Федіверсі та переглядати їх вміст. Ось винятки, які було зроблено на цьому конкретному сервері.", + "about.domain_blocks.severity": "Важливість", + "about.domain_blocks.silenced.explanation": "Ви загалом не побачите профілі та вміст цього сервера, якщо тільки Ви не обрали його явним або не обрали його наступним чином.", + "about.domain_blocks.silenced.title": "Обмежені", + "about.domain_blocks.suspended.explanation": "Дані з цього сервера не обробляться, зберігаються чи обмінюються, взаємодію чи спілкування з користувачами цього сервера неможливі.", + "about.domain_blocks.suspended.title": "Призупинено", + "about.not_available": "Ця інформація не доступна на цьому сервері.", + "about.powered_by": "Децентралізовані соціальні мережі від {mastodon}", + "about.rules": "Правила сервера", "account.account_note_header": "Примітка", "account.add_or_remove_from_list": "Додати або видалити зі списків", "account.badges.bot": "Бот", @@ -7,13 +20,16 @@ "account.block_domain": "Заблокувати домен {domain}", "account.blocked": "Заблоковані", "account.browse_more_on_origin_server": "Переглянути більше в оригінальному профілі", - "account.cancel_follow_request": "Скасувати запит на підписку", + "account.cancel_follow_request": "Відкликати запит на стеження", "account.direct": "Надіслати пряме повідомлення @{name}", "account.disable_notifications": "Не повідомляти мене про дописи @{name}", "account.domain_blocked": "Домен заблоковано", "account.edit_profile": "Редагувати профіль", "account.enable_notifications": "Повідомляти мене про дописи @{name}", "account.endorse": "Рекомендувати у профілі", + "account.featured_tags.last_status_at": "Останній допис {date}", + "account.featured_tags.last_status_never": "Немає дописів", + "account.featured_tags.title": "{name} виділяє хештеґи", "account.follow": "Підписатися", "account.followers": "Підписники", "account.followers.empty": "Ніхто ще не підписаний на цього користувача.", @@ -23,7 +39,7 @@ "account.follows.empty": "Цей користувач ще ні на кого не підписався.", "account.follows_you": "Підписані на вас", "account.hide_reblogs": "Сховати поширення від @{name}", - "account.joined": "Долучилися {date}", + "account.joined_short": "Joined", "account.languages": "Змінити підписані мови", "account.link_verified_on": "Права власності на це посилання були перевірені {date}", "account.locked_info": "Це закритий обліковий запис. Власник вручну обирає, хто може на нього підписуватися.", @@ -63,12 +79,24 @@ "audio.hide": "Сховати аудіо", "autosuggest_hashtag.per_week": "{count} в тиждень", "boost_modal.combo": "Ви можете натиснути {combo}, щоб пропустити це наступного разу", - "bundle_column_error.body": "Щось пішло не так під час завантаження цього компоненту.", + "bundle_column_error.copy_stacktrace": "Копіювати звіт про помилку", + "bundle_column_error.error.body": "Неможливо показати запитану сторінку. Це може бути спричинено помилкою у нашому коді, або через проблему сумісності з браузером.", + "bundle_column_error.error.title": "О, ні!", + "bundle_column_error.network.body": "Під час завантаження цієї сторінки сталася помилка. Це могло статися через тимчасову проблему з вашим інтернетом чи цим сервером.", + "bundle_column_error.network.title": "Помилка мережі", "bundle_column_error.retry": "Спробуйте ще раз", - "bundle_column_error.title": "Помилка мережі", + "bundle_column_error.return": "На головну", + "bundle_column_error.routing.body": "Запитувана сторінка не знайдена. Ви впевнені, що URL-адреса у панелі адрес правильна?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Закрити", "bundle_modal_error.message": "Щось пішло не так під час завантаження цього компоненту.", "bundle_modal_error.retry": "Спробувати ще раз", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "Про застосунок", "column.blocks": "Заблоковані користувачі", "column.bookmarks": "Закладки", "column.community": "Локальна стрічка", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "Заблокувати та поскаржитися", "confirmations.block.confirm": "Заблокувати", "confirmations.block.message": "Ви впевнені, що хочете заблокувати {name}?", + "confirmations.cancel_follow_request.confirm": "Відкликати запит", + "confirmations.cancel_follow_request.message": "Ви дійсно бажаєте відкликати запит на стеження за {name}?", "confirmations.delete.confirm": "Видалити", "confirmations.delete.message": "Ви впевнені, що хочете видалити цей допис?", "confirmations.delete_list.confirm": "Видалити", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Позначити як прочитане", "conversation.open": "Переглянути бесіду", "conversation.with": "З {names}", + "copypaste.copied": "Скопійовано", + "copypaste.copy": "Копіювати", "directory.federated": "З відомого федесвіту", "directory.local": "Лише з домену {domain}", "directory.new_arrivals": "Нові надходження", "directory.recently_active": "Нещодавно активні", + "dismissable_banner.community_timeline": "Це останні публічні дописи від людей, чиї облікові записи розміщені на {domain}.", + "dismissable_banner.dismiss": "Відхилити", + "dismissable_banner.explore_links": "Ці новини розповідають історії про людей на цих та інших серверах децентралізованої мережі прямо зараз.", + "dismissable_banner.explore_statuses": "Ці дописи з цього та інших серверів децентралізованої мережі зараз набирають популярності на цьому сервері.", + "dismissable_banner.explore_tags": "Ці хештеги зараз набирають популярності серед людей на цьому та інших серверах децентралізованої мережі.", + "dismissable_banner.public_timeline": "Це останні публічні дописи від людей на цьому та інших серверах децентралізованої мережі, про які відомо цьому серверу.", "embed.instructions": "Вбудуйте цей допис до вашого вебсайту, скопіювавши код нижче.", "embed.preview": "Ось як він виглядатиме:", "emoji_button.activity": "Діяльність", @@ -221,14 +259,14 @@ "follow_request.reject": "Відмовити", "follow_requests.unlocked_explanation": "Хоча ваш обліковий запис не заблоковано, працівники {domain} припускають, що, можливо, ви хотіли б переглянути ці запити на підписку.", "generic.saved": "Збережено", - "getting_started.developers": "Розробникам", - "getting_started.directory": "Каталог профілів", + "getting_started.directory": "Каталог", "getting_started.documentation": "Документація", + "getting_started.free_software_notice": "Mastodon — це вільне програмне забезпечення з відкритим кодом. Ви можете переглянути код, внести зміни або повідомити про помилки на {repository}.", "getting_started.heading": "Розпочати", "getting_started.invite": "Запросити людей", - "getting_started.open_source_notice": "Mastodon — програма з відкритим сирцевим кодом. Ви можете допомогти проєкту, або повідомити про проблеми на GitHub: {github}.", "getting_started.privacy_policy": "Політика конфіденційності", "getting_started.security": "Налаштування облікового запису", + "getting_started.what_is_mastodon": "Про Mastodon", "hashtag.column_header.tag_mode.all": "та {additional}", "hashtag.column_header.tag_mode.any": "або {additional}", "hashtag.column_header.tag_mode.none": "без {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Показувати відповіді", "home.hide_announcements": "Приховати оголошення", "home.show_announcements": "Показати оголошення", + "interaction_modal.description.favourite": "Маючи обліковий запис на Mastodon, ви можете вподобати цей допис, щоб дати автору знати, що ви його цінуєте, і зберегти його на потім.", + "interaction_modal.description.follow": "Маючи обліковий запис на Mastodon, ви можете підписатися на {name}, щоб отримувати дописи цього користувача у свою стрічку.", + "interaction_modal.description.reblog": "Маючи обліковий запис на Mastodon, ви можете поширити цей допис, щоб поділитися ним зі своїми підписниками.", + "interaction_modal.description.reply": "Маючи обліковий запис на Mastodon, ви можете відповісти на цей допис.", + "interaction_modal.on_another_server": "На іншому сервері", + "interaction_modal.on_this_server": "На цьому сервері", + "interaction_modal.other_server_instructions": "Просто скопіюйте і вставте цей URL у панель пошуку вашого улюбленого застосунку або вебінтерфейсу, до якого ви ввійшли.", + "interaction_modal.preamble": "Оскільки Mastodon децентралізований, ви можете використовувати свій наявний обліковий запис, розміщений на іншому сервері Mastodon або сумісній платформі, якщо у вас немає облікового запису на цьому сервері.", + "interaction_modal.title.favourite": "Вибраний допис {name}", + "interaction_modal.title.follow": "Підписатися на {name}", + "interaction_modal.title.reblog": "Пришвидшити пост {name}", + "interaction_modal.title.reply": "Відповісти на допис {name}", "intervals.full.days": "{number, plural, one {# день} few {# дні} other {# днів}}", "intervals.full.hours": "{number, plural, one {# година} few {# години} other {# годин}}", "intervals.full.minutes": "{number, plural, one {# хвилина} few {# хвилини} other {# хвилин}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Тривалість", "mute_modal.hide_notifications": "Сховати сповіщення від користувача?", "mute_modal.indefinite": "Не визначено", - "navigation_bar.apps": "Мобільні застосунки", + "navigation_bar.about": "Про програму", + "navigation_bar.apps": "Завантажити застосунок", "navigation_bar.blocks": "Заблоковані користувачі", "navigation_bar.bookmarks": "Закладки", "navigation_bar.community_timeline": "Локальна стрічка", @@ -324,7 +375,7 @@ "navigation_bar.filters": "Приховані слова", "navigation_bar.follow_requests": "Запити на підписку", "navigation_bar.follows_and_followers": "Підписки та підписники", - "navigation_bar.info": "Про цей сервер", + "navigation_bar.info": "Про застосунок", "navigation_bar.keyboard_shortcuts": "Гарячі клавіші", "navigation_bar.lists": "Списки", "navigation_bar.logout": "Вийти", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Закріплені дописи", "navigation_bar.preferences": "Налаштування", "navigation_bar.public_timeline": "Глобальна стрічка", + "navigation_bar.search": "Search", "navigation_bar.security": "Безпека", + "not_signed_in_indicator.not_signed_in": "Для доступу до цього ресурсу вам потрібно увійти.", "notification.admin.report": "Скарга від {name} на {target}", "notification.admin.sign_up": "{name} приєдналися", "notification.favourite": "{name} вподобали ваш допис", @@ -401,6 +454,8 @@ "privacy.public.short": "Публічно", "privacy.unlisted.long": "Видимий для всіх, але не через можливості виявлення", "privacy.unlisted.short": "Прихований", + "privacy_policy.last_updated": "Оновлено {date}", + "privacy_policy.title": "Політика приватності", "refresh": "Оновити", "regeneration_indicator.label": "Завантаження…", "regeneration_indicator.sublabel": "Хвилинку, ми готуємо вашу стрічку!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "Пошук дописів за вмістом недоступний на даному сервері Mastodon.", "search_results.title": "Шукати {q}", "search_results.total": "{count, number} {count, plural, one {результат} few {результати} many {результатів} other {результатів}}", + "server_banner.about_active_users": "Люди, які використовують цей сервер протягом останніх 30 днів (Щомісячні Активні Користувачі)", + "server_banner.active_users": "активні користувачі", + "server_banner.administered_by": "Адміністратор:", + "server_banner.introduction": "{domain} є частиною децентралізованої соціальної мережі від {mastodon}.", + "server_banner.learn_more": "Дізнайтесь більше", + "server_banner.server_stats": "Статистика сервера:", "sign_in_banner.create_account": "Створити обліковий запис", "sign_in_banner.sign_in": "Увійти", "sign_in_banner.text": "Увійдіть, щоб слідкувати за профілями або хештеґами, вподобаними, ділитися і відповідати на повідомлення або взаємодіяти з вашого облікового запису на іншому сервері.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "Ніхто ще не передмухнув цього дмуху. Коли якісь користувачі це зроблять, вони будуть відображені тут.", "status.redraft": "Видалити та перестворити", "status.remove_bookmark": "Видалити закладку", + "status.replied_to": "Replied to {name}", "status.reply": "Відповісти", "status.replyAll": "Відповісти на ланцюжок", "status.report": "Поскаржитися на @{name}", @@ -523,9 +585,8 @@ "status.show_more": "Розгорнути", "status.show_more_all": "Показувати більше для всіх", "status.show_original": "Показати оригінал", - "status.show_thread": "Показати ланцюжок", "status.translate": "Перекласти", - "status.translated_from": "Перекладено з {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Недоступно", "status.unmute_conversation": "Не ігнорувати діалог", "status.unpin": "Відкріпити від профілю", @@ -538,7 +599,6 @@ "tabs_bar.home": "Головна", "tabs_bar.local_timeline": "Локальна", "tabs_bar.notifications": "Сповіщення", - "tabs_bar.search": "Пошук", "time_remaining.days": "{number, plural, one {# день} few {# дні} other {# днів}}", "time_remaining.hours": "{number, plural, one {# година} few {# години} other {# годин}}", "time_remaining.minutes": "{number, plural, one {# хвилина} few {# хвилини} other {# хвилин}}", diff --git a/app/javascript/mastodon/locales/ur.json b/app/javascript/mastodon/locales/ur.json index 36dc6563b..03b648fe9 100644 --- a/app/javascript/mastodon/locales/ur.json +++ b/app/javascript/mastodon/locales/ur.json @@ -1,4 +1,17 @@ { + "about.blocks": "Moderated servers", + "about.contact": "Contact:", + "about.domain_blocks.comment": "Reason", + "about.domain_blocks.domain": "Domain", + "about.domain_blocks.preamble": "Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.", + "about.domain_blocks.severity": "Severity", + "about.domain_blocks.silenced.explanation": "You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.", + "about.domain_blocks.silenced.title": "Limited", + "about.domain_blocks.suspended.explanation": "No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.", + "about.domain_blocks.suspended.title": "Suspended", + "about.not_available": "This information has not been made available on this server.", + "about.powered_by": "Decentralized social media powered by {mastodon}", + "about.rules": "Server rules", "account.account_note_header": "نوٹ", "account.add_or_remove_from_list": "فہرست میں شامل یا برطرف کریں", "account.badges.bot": "روبوٹ", @@ -7,13 +20,16 @@ "account.block_domain": "{domain} سے سب چھپائیں", "account.blocked": "مسدود کردہ", "account.browse_more_on_origin_server": "اصل پروفائل پر مزید براؤز کریں", - "account.cancel_follow_request": "درخواستِ پیروی منسوخ کریں", + "account.cancel_follow_request": "Withdraw follow request", "account.direct": "راست پیغام @{name}", "account.disable_notifications": "جب @{name} پوسٹ کرے تو مجھ مطلع نہ کریں", "account.domain_blocked": "پوشیدہ ڈومین", "account.edit_profile": "مشخص ترمیم کریں", "account.enable_notifications": "جب @{name} پوسٹ کرے تو مجھ مطلع کریں", "account.endorse": "مشکص پر نمایاں کریں", + "account.featured_tags.last_status_at": "Last post on {date}", + "account.featured_tags.last_status_never": "No posts", + "account.featured_tags.title": "{name}'s featured hashtags", "account.follow": "پیروی کریں", "account.followers": "پیروکار", "account.followers.empty": "\"ہنوز اس صارف کی کوئی پیروی نہیں کرتا\".", @@ -23,7 +39,7 @@ "account.follows.empty": "\"یہ صارف ہنوز کسی کی پیروی نہیں کرتا ہے\".", "account.follows_you": "آپ کا پیروکار ہے", "account.hide_reblogs": "@{name} سے فروغ چھپائیں", - "account.joined": "{date} شامل ہوئے", + "account.joined_short": "Joined", "account.languages": "Change subscribed languages", "account.link_verified_on": "اس لنک کی ملکیت کی توثیق {date} پر کی گئی تھی", "account.locked_info": "اس اکاونٹ کا اخفائی ضابطہ مقفل ہے۔ صارف کی پیروی کون کر سکتا ہے اس کا جائزہ وہ خود لیتا ہے.", @@ -63,12 +79,24 @@ "audio.hide": "Hide audio", "autosuggest_hashtag.per_week": "{count} فی ہفتہ", "boost_modal.combo": "آئیندہ یہ نہ دیکھنے کیلئے آپ {combo} دبا سکتے ہیں", - "bundle_column_error.body": "اس عنصر کو برآمد کرتے وقت کچھ خرابی پیش آئی ہے.", + "bundle_column_error.copy_stacktrace": "Copy error report", + "bundle_column_error.error.body": "The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.", + "bundle_column_error.error.title": "Oh, no!", + "bundle_column_error.network.body": "There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.", + "bundle_column_error.network.title": "Network error", "bundle_column_error.retry": "دوبارہ کوشش کریں", - "bundle_column_error.title": "نیٹ ورک کی خرابی", + "bundle_column_error.return": "Go back home", + "bundle_column_error.routing.body": "The requested page could not be found. Are you sure the URL in the address bar is correct?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "بند کریں", "bundle_modal_error.message": "اس عنصر کو برآمد کرتے وقت کچھ خرابی پیش آئی ہے.", "bundle_modal_error.retry": "دوبارہ کوشش کریں", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "About", "column.blocks": "مسدود صارفین", "column.bookmarks": "بُک مارکس", "column.community": "مقامی زمانی جدول", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "شکایت کریں اور بلاک کریں", "confirmations.block.confirm": "بلاک", "confirmations.block.message": "کیا واقعی آپ {name} کو بلاک کرنا چاہتے ہیں؟", + "confirmations.cancel_follow_request.confirm": "Withdraw request", + "confirmations.cancel_follow_request.message": "Are you sure you want to withdraw your request to follow {name}?", "confirmations.delete.confirm": "ڈیلیٹ", "confirmations.delete.message": "Are you sure you want to delete this status?", "confirmations.delete_list.confirm": "ڈیلیٹ", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "بطور پڑھا ہوا دکھائیں", "conversation.open": "گفتگو دیکھیں", "conversation.with": "{names} کے ساتھ", + "copypaste.copied": "Copied", + "copypaste.copy": "Copy", "directory.federated": "معروف فیڈی ورس سے", "directory.local": "صرف {domain} سے", "directory.new_arrivals": "نئے آنے والے", "directory.recently_active": "حال میں میں ایکٹیو", + "dismissable_banner.community_timeline": "These are the most recent public posts from people whose accounts are hosted by {domain}.", + "dismissable_banner.dismiss": "Dismiss", + "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", + "dismissable_banner.explore_statuses": "These posts from this and other servers in the decentralized network are gaining traction on this server right now.", + "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", + "dismissable_banner.public_timeline": "These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.", "embed.instructions": "Embed this status on your website by copying the code below.", "embed.preview": "یہ اس طرح نظر آئے گا:", "emoji_button.activity": "سرگرمی", @@ -221,14 +259,14 @@ "follow_request.reject": "انکار کریں", "follow_requests.unlocked_explanation": "Even though your account is not locked, the {domain} staff thought you might want to review follow requests from these accounts manually.", "generic.saved": "Saved", - "getting_started.developers": "Developers", - "getting_started.directory": "فہرست مشخصات", + "getting_started.directory": "Directory", "getting_started.documentation": "اسناد", + "getting_started.free_software_notice": "Mastodon is free, open source software. You can view the source code, contribute or report issues at {repository}.", "getting_started.heading": "آغاز کریں", "getting_started.invite": "دوستوں کو دعوت دیں", - "getting_started.open_source_notice": "ماسٹوڈون آزاد منبع سوفٹویر ہے. آپ {github} گِٹ ہب پر مسائل میں معاونت یا مشکلات کی اطلاع دے سکتے ہیں.", "getting_started.privacy_policy": "Privacy Policy", "getting_started.security": "ترتیباتِ اکاؤنٹ", + "getting_started.what_is_mastodon": "About Mastodon", "hashtag.column_header.tag_mode.all": "اور {additional}", "hashtag.column_header.tag_mode.any": "یا {additional}", "hashtag.column_header.tag_mode.none": "بغیر {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "جوابات دکھائیں", "home.hide_announcements": "Hide announcements", "home.show_announcements": "Show announcements", + "interaction_modal.description.favourite": "With an account on Mastodon, you can favourite this post to let the author know you appreciate it and save it for later.", + "interaction_modal.description.follow": "With an account on Mastodon, you can follow {name} to receive their posts in your home feed.", + "interaction_modal.description.reblog": "With an account on Mastodon, you can boost this post to share it with your own followers.", + "interaction_modal.description.reply": "With an account on Mastodon, you can respond to this post.", + "interaction_modal.on_another_server": "On a different server", + "interaction_modal.on_this_server": "On this server", + "interaction_modal.other_server_instructions": "Simply copy and paste this URL into the search bar of your favourite app or the web interface where you are signed in.", + "interaction_modal.preamble": "Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one.", + "interaction_modal.title.favourite": "Favourite {name}'s post", + "interaction_modal.title.follow": "Follow {name}", + "interaction_modal.title.reblog": "Boost {name}'s post", + "interaction_modal.title.reply": "Reply to {name}'s post", "intervals.full.days": "{number, plural, one {# روز} other {# روز}}", "intervals.full.hours": "{number, plural, one {# ساعت} other {# ساعت}}", "intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Duration", "mute_modal.hide_notifications": "Hide notifications from this user?", "mute_modal.indefinite": "غیر معینہ", - "navigation_bar.apps": "موبائل ایپس", + "navigation_bar.about": "About", + "navigation_bar.apps": "Get the app", "navigation_bar.blocks": "مسدود صارفین", "navigation_bar.bookmarks": "بُک مارکس", "navigation_bar.community_timeline": "مقامی ٹائم لائن", @@ -324,7 +375,7 @@ "navigation_bar.filters": "خاموش کردہ الفاظ", "navigation_bar.follow_requests": "پیروی کی درخواستیں", "navigation_bar.follows_and_followers": "پیروی کردہ اور پیروکار", - "navigation_bar.info": "اس سرور کے بارے میں", + "navigation_bar.info": "About", "navigation_bar.keyboard_shortcuts": "ہوٹ کیز", "navigation_bar.lists": "فہرستیں", "navigation_bar.logout": "لاگ آؤٹ", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Pinned toots", "navigation_bar.preferences": "ترجیحات", "navigation_bar.public_timeline": "وفاقی ٹائم لائن", + "navigation_bar.search": "Search", "navigation_bar.security": "سیکورٹی", + "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", "notification.admin.report": "{name} reported {target}", "notification.admin.sign_up": "{name} signed up", "notification.favourite": "{name} favourited your status", @@ -401,6 +454,8 @@ "privacy.public.short": "Public", "privacy.unlisted.long": "Visible for all, but opted-out of discovery features", "privacy.unlisted.short": "Unlisted", + "privacy_policy.last_updated": "Last updated {date}", + "privacy_policy.title": "Privacy Policy", "refresh": "Refresh", "regeneration_indicator.label": "Loading…", "regeneration_indicator.sublabel": "Your home feed is being prepared!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.title": "Search for {q}", "search_results.total": "{count, number} {count, plural, one {result} other {results}}", + "server_banner.about_active_users": "People using this server during the last 30 days (Monthly Active Users)", + "server_banner.active_users": "active users", + "server_banner.administered_by": "Administered by:", + "server_banner.introduction": "{domain} is part of the decentralized social network powered by {mastodon}.", + "server_banner.learn_more": "Learn more", + "server_banner.server_stats": "Server stats:", "sign_in_banner.create_account": "Create account", "sign_in_banner.sign_in": "Sign in", "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "No one has boosted this toot yet. When someone does, they will show up here.", "status.redraft": "Delete & re-draft", "status.remove_bookmark": "Remove bookmark", + "status.replied_to": "Replied to {name}", "status.reply": "Reply", "status.replyAll": "Reply to thread", "status.report": "Report @{name}", @@ -523,9 +585,8 @@ "status.show_more": "Show more", "status.show_more_all": "Show more for all", "status.show_original": "Show original", - "status.show_thread": "Show thread", "status.translate": "Translate", - "status.translated_from": "Translated from {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Not available", "status.unmute_conversation": "Unmute conversation", "status.unpin": "Unpin from profile", @@ -538,7 +599,6 @@ "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", diff --git a/app/javascript/mastodon/locales/vi.json b/app/javascript/mastodon/locales/vi.json index d184a41bc..b05bed774 100644 --- a/app/javascript/mastodon/locales/vi.json +++ b/app/javascript/mastodon/locales/vi.json @@ -1,4 +1,17 @@ { + "about.blocks": "Giới hạn chung", + "about.contact": "Liên lạc:", + "about.domain_blocks.comment": "Lý do", + "about.domain_blocks.domain": "Máy chủ", + "about.domain_blocks.preamble": "Mastodon cho phép bạn tương tác nội dung và giao tiếp với người dùng từ bất kỳ máy chủ nào khác trong mạng liên hợp. Còn máy chủ này có những ngoại lệ riêng.", + "about.domain_blocks.severity": "Mức độ", + "about.domain_blocks.silenced.explanation": "Nói chung, bạn sẽ không thấy người dùng và nội dung từ máy chủ này, trừ khi bạn tự tìm kiếm hoặc tự theo dõi.", + "about.domain_blocks.silenced.title": "Hạn chế", + "about.domain_blocks.suspended.explanation": "Dữ liệu từ máy chủ này sẽ không được xử lý, lưu trữ hoặc trao đổi. Mọi tương tác hoặc giao tiếp với người dùng từ máy chủ này đều bị cấm.", + "about.domain_blocks.suspended.title": "Vô hiệu hóa", + "about.not_available": "Máy chủ này chưa cung cấp thông tin.", + "about.powered_by": "Mạng xã hội liên hợp {mastodon}", + "about.rules": "Quy tắc máy chủ", "account.account_note_header": "Ghi chú", "account.add_or_remove_from_list": "Thêm hoặc Xóa khỏi danh sách", "account.badges.bot": "Bot", @@ -7,13 +20,16 @@ "account.block_domain": "Ẩn mọi thứ từ {domain}", "account.blocked": "Đã chặn", "account.browse_more_on_origin_server": "Truy cập trang của người này", - "account.cancel_follow_request": "Hủy yêu cầu theo dõi", + "account.cancel_follow_request": "Thu hồi yêu cầu theo dõi", "account.direct": "Nhắn riêng @{name}", "account.disable_notifications": "Tắt thông báo khi @{name} đăng tút", "account.domain_blocked": "Người đã chặn", "account.edit_profile": "Sửa hồ sơ", "account.enable_notifications": "Nhận thông báo khi @{name} đăng tút", "account.endorse": "Tôn vinh người này", + "account.featured_tags.last_status_at": "Tút gần nhất {date}", + "account.featured_tags.last_status_never": "Chưa có tút", + "account.featured_tags.title": "Hashtag {name} thường dùng", "account.follow": "Theo dõi", "account.followers": "Người theo dõi", "account.followers.empty": "Chưa có người theo dõi nào.", @@ -23,10 +39,10 @@ "account.follows.empty": "Người này chưa theo dõi ai.", "account.follows_you": "Đang theo dõi bạn", "account.hide_reblogs": "Ẩn tút @{name} đăng lại", - "account.joined": "Đã tham gia {date}", + "account.joined_short": "Joined", "account.languages": "Đổi ngôn ngữ mong muốn", "account.link_verified_on": "Liên kết này đã được xác minh vào {date}", - "account.locked_info": "Đây là tài khoản riêng tư. Họ sẽ tự mình xét duyệt các yêu cầu theo dõi.", + "account.locked_info": "Đây là tài khoản riêng tư. Chủ tài khoản tự mình xét duyệt các yêu cầu theo dõi.", "account.media": "Media", "account.mention": "Nhắc đến @{name}", "account.moved_to": "{name} đã chuyển sang:", @@ -63,15 +79,27 @@ "audio.hide": "Ẩn âm thanh", "autosuggest_hashtag.per_week": "{count} mỗi tuần", "boost_modal.combo": "Nhấn {combo} để bỏ qua bước này", - "bundle_column_error.body": "Đã có lỗi xảy ra trong khi tải nội dung này.", + "bundle_column_error.copy_stacktrace": "Sao chép báo lỗi", + "bundle_column_error.error.body": "Không thể hiện trang này. Đây có thể là một lỗi trong mã lập trình của chúng tôi, hoặc là vấn đề tương thích của trình duyệt.", + "bundle_column_error.error.title": "Ôi không!", + "bundle_column_error.network.body": "Đã xảy ra lỗi khi tải trang này. Đây có thể là vấn đề tạm thời rớt mạng của bạn hoặc máy chủ này.", + "bundle_column_error.network.title": "Lỗi mạng", "bundle_column_error.retry": "Thử lại", - "bundle_column_error.title": "Không có kết nối internet", + "bundle_column_error.return": "Quay lại trang chủ", + "bundle_column_error.routing.body": "Không thể tìm thấy trang cần tìm. Bạn có chắc URL trong thanh địa chỉ là chính xác?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Đóng", "bundle_modal_error.message": "Đã có lỗi xảy ra trong khi tải nội dung này.", "bundle_modal_error.retry": "Thử lại", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "Giới thiệu", "column.blocks": "Người đã chặn", "column.bookmarks": "Đã lưu", - "column.community": "Máy chủ của bạn", + "column.community": "Máy chủ này", "column.direct": "Nhắn riêng", "column.directory": "Tìm người cùng sở thích", "column.domain_blocks": "Máy chủ đã chặn", @@ -82,7 +110,7 @@ "column.mutes": "Người đã ẩn", "column.notifications": "Thông báo", "column.pins": "Tút ghim", - "column.public": "Mạng liên hợp", + "column.public": "Liên hợp", "column_back_button.label": "Quay lại", "column_header.hide_settings": "Ẩn bộ lọc", "column_header.moveLeft_settings": "Dời cột sang bên trái", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "Chặn & Báo cáo", "confirmations.block.confirm": "Chặn", "confirmations.block.message": "Bạn có thật sự muốn chặn {name}?", + "confirmations.cancel_follow_request.confirm": "Thu hồi yêu cầu", + "confirmations.cancel_follow_request.message": "Bạn có chắc muốn thu hồi yêu cầu theo dõi của bạn với {name}?", "confirmations.delete.confirm": "Xóa bỏ", "confirmations.delete.message": "Bạn thật sự muốn xóa tút này?", "confirmations.delete_list.confirm": "Xóa bỏ", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Đánh dấu là đã đọc", "conversation.open": "Xem toàn bộ tin nhắn", "conversation.with": "Với {names}", + "copypaste.copied": "Đã sao chép", + "copypaste.copy": "Sao chép", "directory.federated": "Từ mạng liên hợp", "directory.local": "Từ {domain}", "directory.new_arrivals": "Mới tham gia", "directory.recently_active": "Hoạt động gần đây", + "dismissable_banner.community_timeline": "Những tút gần đây của những người có tài khoản thuộc máy chủ {domain}.", + "dismissable_banner.dismiss": "Bỏ qua", + "dismissable_banner.explore_links": "Những sự kiện đang được thảo luận nhiều trên máy chủ này và những máy chủ khác thuộc mạng liên hợp của nó.", + "dismissable_banner.explore_statuses": "Những tút đang phổ biến trên máy chủ này và những máy chủ khác thuộc mạng liên hợp của nó.", + "dismissable_banner.explore_tags": "Những hashtag đang được sử dụng nhiều trên máy chủ này và và những máy chủ khác thuộc mạng liên hợp của nó.", + "dismissable_banner.public_timeline": "Những tút công khai gần đây nhất trên máy chủ này và những máy chủ khác thuộc mạng liên hợp của nó.", "embed.instructions": "Sao chép đoạn mã dưới đây và chèn vào trang web của bạn.", "embed.preview": "Nó sẽ hiển thị như vầy:", "emoji_button.activity": "Hoạt động", @@ -221,14 +259,14 @@ "follow_request.reject": "Từ chối", "follow_requests.unlocked_explanation": "Mặc dù tài khoản của bạn đang ở chế độ công khai, quản trị viên của {domain} vẫn tin rằng bạn sẽ muốn xem lại yêu cầu theo dõi từ những người khác.", "generic.saved": "Đã lưu", - "getting_started.developers": "Nhà phát triển", - "getting_started.directory": "Cộng đồng", + "getting_started.directory": "Danh bạ", "getting_started.documentation": "Tài liệu", + "getting_started.free_software_notice": "Mastodon là phần mềm tự do nguồn mở. Bạn có thể xem, đóng góp mã nguồn hoặc báo lỗi tại {repository}.", "getting_started.heading": "Quản lý", "getting_started.invite": "Mời bạn bè", - "getting_started.open_source_notice": "Mastodon là phần mềm mã nguồn mở. Bạn có thể đóng góp hoặc báo lỗi trên GitHub tại {github}.", "getting_started.privacy_policy": "Chính sách bảo mật", "getting_started.security": "Bảo mật", + "getting_started.what_is_mastodon": "Về Mastodon", "hashtag.column_header.tag_mode.all": "và {additional}", "hashtag.column_header.tag_mode.any": "hoặc {additional}", "hashtag.column_header.tag_mode.none": "mà không {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Hiện những tút dạng trả lời", "home.hide_announcements": "Ẩn thông báo máy chủ", "home.show_announcements": "Hiện thông báo máy chủ", + "interaction_modal.description.favourite": "Với tài khoản Mastodon, bạn có thể yêu thích tút này để cho người đăng biết bạn thích nó và lưu lại tút.", + "interaction_modal.description.follow": "Với tài khoản Mastodon, bạn có thể theo dõi {name} để nhận những tút của họ trên bảng tin của mình.", + "interaction_modal.description.reblog": "Với tài khoản Mastodon, bạn có thể đăng lại tút này để chia sẻ nó với những người đang theo dõi bạn.", + "interaction_modal.description.reply": "Với tài khoản Mastodon, bạn có thể bình luận tút này.", + "interaction_modal.on_another_server": "Trên một máy chủ khác", + "interaction_modal.on_this_server": "Trên máy chủ này", + "interaction_modal.other_server_instructions": "Sao chép và dán URL này vào thanh tìm kiếm của ứng dụng bạn yêu thích hay trang web mà bạn đã đăng nhập vào.", + "interaction_modal.preamble": "Do Mastodon phi tập trung, bạn có thể sử dụng tài khoản hiện có trên một máy chủ Mastodon khác hoặc một nền tảng tương thích nếu bạn chưa có tài khoản trên máy chủ này.", + "interaction_modal.title.favourite": "Thích tút của {name}", + "interaction_modal.title.follow": "Theo dõi {name}", + "interaction_modal.title.reblog": "Đăng lại tút của {name}", + "interaction_modal.title.reply": "Trả lời tút của {name}", "intervals.full.days": "{number, plural, other {# ngày}}", "intervals.full.hours": "{number, plural, other {# giờ}}", "intervals.full.minutes": "{number, plural, other {# phút}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Thời hạn", "mute_modal.hide_notifications": "Ẩn thông báo từ người này?", "mute_modal.indefinite": "Vĩnh viễn", - "navigation_bar.apps": "Apps", + "navigation_bar.about": "Giới thiệu", + "navigation_bar.apps": "Tải ứng dụng", "navigation_bar.blocks": "Người đã chặn", "navigation_bar.bookmarks": "Đã lưu", "navigation_bar.community_timeline": "Cộng đồng", @@ -324,7 +375,7 @@ "navigation_bar.filters": "Bộ lọc từ ngữ", "navigation_bar.follow_requests": "Yêu cầu theo dõi", "navigation_bar.follows_and_followers": "Quan hệ", - "navigation_bar.info": "Về máy chủ này", + "navigation_bar.info": "Giới thiệu", "navigation_bar.keyboard_shortcuts": "Phím tắt", "navigation_bar.lists": "Danh sách", "navigation_bar.logout": "Đăng xuất", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Tút ghim", "navigation_bar.preferences": "Cài đặt", "navigation_bar.public_timeline": "Thế giới", + "navigation_bar.search": "Search", "navigation_bar.security": "Bảo mật", + "not_signed_in_indicator.not_signed_in": "Bạn cần đăng nhập để truy cập mục này.", "notification.admin.report": "{name} đã báo cáo {target}", "notification.admin.sign_up": "{name} đăng ký máy chủ của bạn", "notification.favourite": "{name} thích tút của bạn", @@ -401,6 +454,8 @@ "privacy.public.short": "Công khai", "privacy.unlisted.long": "Công khai nhưng không hiện trên bảng tin", "privacy.unlisted.short": "Hạn chế", + "privacy_policy.last_updated": "Cập nhật lần cuối {date}", + "privacy_policy.title": "Chính sách bảo mật", "refresh": "Làm mới", "regeneration_indicator.label": "Đang tải…", "regeneration_indicator.sublabel": "Bảng tin của bạn đang được cập nhật!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "Máy chủ của bạn không bật tính năng tìm kiếm tút.", "search_results.title": "Tìm kiếm {q}", "search_results.total": "{count, number} {count, plural, one {kết quả} other {kết quả}}", + "server_banner.about_active_users": "Những người dùng máy chủ này trong 30 ngày qua (MAU)", + "server_banner.active_users": "người dùng hoạt động", + "server_banner.administered_by": "Quản trị bởi:", + "server_banner.introduction": "{domain} là một phần của mạng xã hội liên hợp {mastodon}.", + "server_banner.learn_more": "Tìm hiểu", + "server_banner.server_stats": "Thống kê:", "sign_in_banner.create_account": "Tạo tài khoản", "sign_in_banner.sign_in": "Đăng nhập", "sign_in_banner.text": "Đăng nhập để theo dõi hồ sơ hoặc hashtag; thích, chia sẻ và trả lời tút hoặc tương tác bằng tài khoản của bạn trên một máy chủ khác.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "Tút này chưa có ai đăng lại. Nếu có, nó sẽ hiển thị ở đây.", "status.redraft": "Xóa và viết lại", "status.remove_bookmark": "Bỏ lưu", + "status.replied_to": "Replied to {name}", "status.reply": "Trả lời", "status.replyAll": "Trả lời người đăng tút", "status.report": "Báo cáo @{name}", @@ -523,9 +585,8 @@ "status.show_more": "Xem thêm", "status.show_more_all": "Hiển thị tất cả", "status.show_original": "Bản gốc", - "status.show_thread": "Xem chuỗi tút này", "status.translate": "Dịch", - "status.translated_from": "Dịch từ {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Uncached", "status.unmute_conversation": "Quan tâm", "status.unpin": "Bỏ ghim trên hồ sơ", @@ -538,7 +599,6 @@ "tabs_bar.home": "Bảng tin", "tabs_bar.local_timeline": "Máy chủ", "tabs_bar.notifications": "Thông báo", - "tabs_bar.search": "Tìm kiếm", "time_remaining.days": "{number, plural, other {# ngày}}", "time_remaining.hours": "{number, plural, other {# giờ}}", "time_remaining.minutes": "{number, plural, other {# phút}}", diff --git a/app/javascript/mastodon/locales/zgh.json b/app/javascript/mastodon/locales/zgh.json index 6150412a8..681667a2f 100644 --- a/app/javascript/mastodon/locales/zgh.json +++ b/app/javascript/mastodon/locales/zgh.json @@ -1,4 +1,17 @@ { + "about.blocks": "Moderated servers", + "about.contact": "Contact:", + "about.domain_blocks.comment": "Reason", + "about.domain_blocks.domain": "Domain", + "about.domain_blocks.preamble": "Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.", + "about.domain_blocks.severity": "Severity", + "about.domain_blocks.silenced.explanation": "You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.", + "about.domain_blocks.silenced.title": "Limited", + "about.domain_blocks.suspended.explanation": "No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.", + "about.domain_blocks.suspended.title": "Suspended", + "about.not_available": "This information has not been made available on this server.", + "about.powered_by": "Decentralized social media powered by {mastodon}", + "about.rules": "Server rules", "account.account_note_header": "ⵍⵎⴷ ⵓⴳⴳⴰⵔ", "account.add_or_remove_from_list": "ⵔⵏⵓ ⵏⵖ ⵙⵉⵜⵜⵢ ⵙⴳ ⵜⵍⴳⴰⵎⵜ", "account.badges.bot": "ⴰⴱⵓⵜ", @@ -7,13 +20,16 @@ "account.block_domain": "ⴳⴷⵍ ⵉⴳⵔ {domain}", "account.blocked": "ⵉⵜⵜⵓⴳⴷⵍ", "account.browse_more_on_origin_server": "ⵙⵜⴰⵔⴰ ⵓⴳⴳⴰⵔ ⴳ ⵉⴼⵔⵙ ⴰⵏⵚⵍⵉ", - "account.cancel_follow_request": "ⵙⵔ ⵜⵓⵜⵔⴰ ⵏ ⵓⴹⴼⵕ", + "account.cancel_follow_request": "Withdraw follow request", "account.direct": "ⵜⵓⵣⵉⵏⵜ ⵜⵓⵙⵔⵉⴷⵜ @{name}", "account.disable_notifications": "Stop notifying me when @{name} posts", "account.domain_blocked": "ⵉⵜⵜⵓⴳⴷⵍ ⵉⴳⵔ", "account.edit_profile": "ⵙⵏⴼⵍ ⵉⴼⵔⵙ", "account.enable_notifications": "Notify me when @{name} posts", "account.endorse": "Feature on profile", + "account.featured_tags.last_status_at": "Last post on {date}", + "account.featured_tags.last_status_never": "No posts", + "account.featured_tags.title": "{name}'s featured hashtags", "account.follow": "ⴹⴼⵕ", "account.followers": "ⵉⵎⴹⴼⴰⵕⵏ", "account.followers.empty": "No one follows this user yet.", @@ -23,7 +39,7 @@ "account.follows.empty": "This user doesn't follow anyone yet.", "account.follows_you": "ⴹⴼⵕⵏ ⴽⵯⵏ", "account.hide_reblogs": "Hide boosts from @{name}", - "account.joined": "Joined {date}", + "account.joined_short": "Joined", "account.languages": "Change subscribed languages", "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.", @@ -63,12 +79,24 @@ "audio.hide": "Hide audio", "autosuggest_hashtag.per_week": "{count} ⵙ ⵉⵎⴰⵍⴰⵙⵙ", "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.copy_stacktrace": "Copy error report", + "bundle_column_error.error.body": "The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.", + "bundle_column_error.error.title": "Oh, no!", + "bundle_column_error.network.body": "There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.", + "bundle_column_error.network.title": "Network error", "bundle_column_error.retry": "ⴰⵍⵙ ⴰⵔⵎ", - "bundle_column_error.title": "ⴰⵣⴳⴰⵍ ⵏ ⵓⵥⵟⵟⴰ", + "bundle_column_error.return": "Go back home", + "bundle_column_error.routing.body": "The requested page could not be found. Are you sure the URL in the address bar is correct?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "ⵔⴳⵍ", "bundle_modal_error.message": "Something went wrong while loading this component.", "bundle_modal_error.retry": "ⴰⵍⵙ ⴰⵔⵎ", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "About", "column.blocks": "ⵉⵏⵙⵙⵎⵔⵙⵏ ⵜⵜⵓⴳⴷⵍⵏⵉⵏ", "column.bookmarks": "Bookmarks", "column.community": "Local timeline", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "Block & Report", "confirmations.block.confirm": "ⴳⴷⵍ", "confirmations.block.message": "ⵉⵙ ⵏⵉⵜ ⵜⵅⵙⴷ ⴰⴷ ⵜⴳⴷⵍⴷ {name}?", + "confirmations.cancel_follow_request.confirm": "Withdraw request", + "confirmations.cancel_follow_request.message": "Are you sure you want to withdraw your request to follow {name}?", "confirmations.delete.confirm": "ⴽⴽⵙ", "confirmations.delete.message": "ⵉⵙ ⵏⵉⵜ ⵜⵅⵙⴷ ⴰⴷ ⵜⴽⴽⵙⴷ ⵜⴰⵥⵕⵉⴳⵜ ⴰ?", "confirmations.delete_list.confirm": "ⴽⴽⵙ", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "Mark as read", "conversation.open": "View conversation", "conversation.with": "ⴰⴽⴷ {names}", + "copypaste.copied": "Copied", + "copypaste.copy": "Copy", "directory.federated": "From known fediverse", "directory.local": "From {domain} only", "directory.new_arrivals": "New arrivals", "directory.recently_active": "Recently active", + "dismissable_banner.community_timeline": "These are the most recent public posts from people whose accounts are hosted by {domain}.", + "dismissable_banner.dismiss": "Dismiss", + "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", + "dismissable_banner.explore_statuses": "These posts from this and other servers in the decentralized network are gaining traction on this server right now.", + "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", + "dismissable_banner.public_timeline": "These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.", "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", @@ -221,14 +259,14 @@ "follow_request.reject": "ⴰⴳⵢ", "follow_requests.unlocked_explanation": "Even though your account is not locked, the {domain} staff thought you might want to review follow requests from these accounts manually.", "generic.saved": "Saved", - "getting_started.developers": "Developers", - "getting_started.directory": "Profile directory", + "getting_started.directory": "Directory", "getting_started.documentation": "Documentation", + "getting_started.free_software_notice": "Mastodon is free, open source software. You can view the source code, contribute or report issues at {repository}.", "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.privacy_policy": "Privacy Policy", "getting_started.security": "ⵜⵉⵙⵖⴰⵍ ⵏ ⵓⵎⵉⴹⴰⵏ", + "getting_started.what_is_mastodon": "About Mastodon", "hashtag.column_header.tag_mode.all": "ⴷ {additional}", "hashtag.column_header.tag_mode.any": "ⵏⵖ {additional}", "hashtag.column_header.tag_mode.none": "without {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "Show replies", "home.hide_announcements": "Hide announcements", "home.show_announcements": "Show announcements", + "interaction_modal.description.favourite": "With an account on Mastodon, you can favourite this post to let the author know you appreciate it and save it for later.", + "interaction_modal.description.follow": "With an account on Mastodon, you can follow {name} to receive their posts in your home feed.", + "interaction_modal.description.reblog": "With an account on Mastodon, you can boost this post to share it with your own followers.", + "interaction_modal.description.reply": "With an account on Mastodon, you can respond to this post.", + "interaction_modal.on_another_server": "On a different server", + "interaction_modal.on_this_server": "On this server", + "interaction_modal.other_server_instructions": "Simply copy and paste this URL into the search bar of your favourite app or the web interface where you are signed in.", + "interaction_modal.preamble": "Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one.", + "interaction_modal.title.favourite": "Favourite {name}'s post", + "interaction_modal.title.follow": "Follow {name}", + "interaction_modal.title.reblog": "Boost {name}'s post", + "interaction_modal.title.reply": "Reply to {name}'s post", "intervals.full.days": "{number, plural, one {# ⵡⴰⵙⵙ} other {# ⵡⵓⵙⵙⴰⵏ}}", "intervals.full.hours": "{number, plural, one {# hour} other {# hours}}", "intervals.full.minutes": "{number, plural, one {# ⵜⵓⵙⴷⵉⴷⵜ} other {# ⵜⵓⵙⴷⵉⴷⵉⵏ}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "Duration", "mute_modal.hide_notifications": "Hide notifications from this user?", "mute_modal.indefinite": "Indefinite", - "navigation_bar.apps": "Mobile apps", + "navigation_bar.about": "About", + "navigation_bar.apps": "Get the app", "navigation_bar.blocks": "Blocked users", "navigation_bar.bookmarks": "Bookmarks", "navigation_bar.community_timeline": "Local timeline", @@ -324,7 +375,7 @@ "navigation_bar.filters": "Muted words", "navigation_bar.follow_requests": "ⵜⵓⵜⵔⴰⵡⵉⵏ ⵏ ⵓⴹⴼⴰⵕ", "navigation_bar.follows_and_followers": "Follows and followers", - "navigation_bar.info": "ⵅⴼ ⵓⵎⴰⴽⴽⴰⵢ ⴰ", + "navigation_bar.info": "About", "navigation_bar.keyboard_shortcuts": "Hotkeys", "navigation_bar.lists": "ⵜⵉⵍⴳⴰⵎⵉⵏ", "navigation_bar.logout": "ⴼⴼⵖ", @@ -333,7 +384,9 @@ "navigation_bar.pins": "Pinned toots", "navigation_bar.preferences": "Preferences", "navigation_bar.public_timeline": "Federated timeline", + "navigation_bar.search": "Search", "navigation_bar.security": "Security", + "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", "notification.admin.report": "{name} reported {target}", "notification.admin.sign_up": "{name} signed up", "notification.favourite": "{name} favourited your status", @@ -401,6 +454,8 @@ "privacy.public.short": "ⵜⴰⴳⴷⵓⴷⴰⵏⵜ", "privacy.unlisted.long": "Visible for all, but opted-out of discovery features", "privacy.unlisted.short": "Unlisted", + "privacy_policy.last_updated": "Last updated {date}", + "privacy_policy.title": "Privacy Policy", "refresh": "Refresh", "regeneration_indicator.label": "ⴰⵣⴷⴰⵎ…", "regeneration_indicator.sublabel": "Your home feed is being prepared!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.title": "Search for {q}", "search_results.total": "{count, number} {count, plural, one {result} other {results}}", + "server_banner.about_active_users": "People using this server during the last 30 days (Monthly Active Users)", + "server_banner.active_users": "active users", + "server_banner.administered_by": "Administered by:", + "server_banner.introduction": "{domain} is part of the decentralized social network powered by {mastodon}.", + "server_banner.learn_more": "Learn more", + "server_banner.server_stats": "Server stats:", "sign_in_banner.create_account": "Create account", "sign_in_banner.sign_in": "Sign in", "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "No one has boosted this toot yet. When someone does, they will show up here.", "status.redraft": "Delete & re-draft", "status.remove_bookmark": "Remove bookmark", + "status.replied_to": "Replied to {name}", "status.reply": "ⵔⴰⵔ", "status.replyAll": "Reply to thread", "status.report": "Report @{name}", @@ -523,9 +585,8 @@ "status.show_more": "ⵙⵎⴰⵍ ⵓⴳⴳⴰⵔ", "status.show_more_all": "ⵙⵎⴰⵍ ⵓⴳⴳⴰⵔ ⵉ ⵎⴰⵕⵕⴰ", "status.show_original": "Show original", - "status.show_thread": "Show thread", "status.translate": "Translate", - "status.translated_from": "Translated from {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "Not available", "status.unmute_conversation": "Unmute conversation", "status.unpin": "Unpin from profile", @@ -538,7 +599,6 @@ "tabs_bar.home": "ⴰⵙⵏⵓⴱⴳ", "tabs_bar.local_timeline": "ⴰⴷⵖⴰⵔⴰⵏ", "tabs_bar.notifications": "ⵜⵉⵏⵖⵎⵉⵙⵉⵏ", - "tabs_bar.search": "ⵔⵣⵓ", "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", diff --git a/app/javascript/mastodon/locales/zh-CN.json b/app/javascript/mastodon/locales/zh-CN.json index 1279ef6a5..bbc124907 100644 --- a/app/javascript/mastodon/locales/zh-CN.json +++ b/app/javascript/mastodon/locales/zh-CN.json @@ -1,4 +1,17 @@ { + "about.blocks": "被限制的服务器", + "about.contact": "联系方式:", + "about.domain_blocks.comment": "原因", + "about.domain_blocks.domain": "域名", + "about.domain_blocks.preamble": "通常来说,在 Mastodon 上,你可以浏览联邦宇宙中任何一台服务器上的内容,并且和上面的用户互动。但其中一些在本服务器上被设置为例外。", + "about.domain_blocks.severity": "级别", + "about.domain_blocks.silenced.explanation": "除非明确地搜索并关注对方,否则你不会看到来自此服务器的用户信息与内容。", + "about.domain_blocks.silenced.title": "已隐藏", + "about.domain_blocks.suspended.explanation": "此服务器的数据将不会被处理、存储或者交换,本站也将无法和来自此服务器的用户互动或者交流。", + "about.domain_blocks.suspended.title": "已封禁", + "about.not_available": "此信息在当前服务器尚不可用。", + "about.powered_by": "由 {mastodon} 驱动的分布式社交媒体", + "about.rules": "站点规则", "account.account_note_header": "备注", "account.add_or_remove_from_list": "从列表中添加或移除", "account.badges.bot": "机器人", @@ -7,13 +20,16 @@ "account.block_domain": "屏蔽 {domain} 实例", "account.blocked": "已屏蔽", "account.browse_more_on_origin_server": "在原始个人资料页面上浏览详情", - "account.cancel_follow_request": "取消关注请求", + "account.cancel_follow_request": "撤回关注请求", "account.direct": "发送私信给 @{name}", "account.disable_notifications": "当 @{name} 发嘟时不要通知我", "account.domain_blocked": "域名已屏蔽", "account.edit_profile": "修改个人资料", "account.enable_notifications": "当 @{name} 发嘟时通知我", "account.endorse": "在个人资料中推荐此用户", + "account.featured_tags.last_status_at": "最近发言于 {date}", + "account.featured_tags.last_status_never": "暂无嘟文", + "account.featured_tags.title": "{name} 的精选标签", "account.follow": "关注", "account.followers": "关注者", "account.followers.empty": "目前无人关注此用户。", @@ -23,7 +39,7 @@ "account.follows.empty": "此用户目前尚未关注任何人。", "account.follows_you": "关注了你", "account.hide_reblogs": "隐藏来自 @{name} 的转贴", - "account.joined": "加入于 {date}", + "account.joined_short": "Joined", "account.languages": "更改订阅语言", "account.link_verified_on": "此链接的所有权已在 {date} 检查", "account.locked_info": "此账户已锁嘟。账户所有者会手动审核关注者。", @@ -63,12 +79,24 @@ "audio.hide": "隐藏音频", "autosuggest_hashtag.per_week": "每星期 {count} 条", "boost_modal.combo": "下次按住 {combo} 即可跳过此提示", - "bundle_column_error.body": "载入这个组件时发生了错误。", + "bundle_column_error.copy_stacktrace": "复制错误报告", + "bundle_column_error.error.body": "请求的页面无法渲染。这可能是由于代码错误或浏览器兼容性等问题造成。", + "bundle_column_error.error.title": "糟糕!", + "bundle_column_error.network.body": "尝试加载此页面时出错。这可能是由于你到此服务器的网络连接存在问题。", + "bundle_column_error.network.title": "网络错误", "bundle_column_error.retry": "重试", - "bundle_column_error.title": "网络错误", + "bundle_column_error.return": "返回首页", + "bundle_column_error.routing.body": "找不到请求的页面。你确定地址栏中的 URL 正确吗?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "关闭", "bundle_modal_error.message": "载入这个组件时发生了错误。", "bundle_modal_error.retry": "重试", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "关于", "column.blocks": "已屏蔽的用户", "column.bookmarks": "书签", "column.community": "本站时间轴", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "屏蔽与举报", "confirmations.block.confirm": "屏蔽", "confirmations.block.message": "你确定要屏蔽 {name} 吗?", + "confirmations.cancel_follow_request.confirm": "撤回请求", + "confirmations.cancel_follow_request.message": "确定要撤回对 {name} 的关注请求吗?", "confirmations.delete.confirm": "删除", "confirmations.delete.message": "你确定要删除这条嘟文吗?", "confirmations.delete_list.confirm": "删除", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "标记为已读", "conversation.open": "查看对话", "conversation.with": "与 {names}", + "copypaste.copied": "已复制", + "copypaste.copy": "复制", "directory.federated": "来自已知联邦宇宙", "directory.local": "仅来自 {domain}", "directory.new_arrivals": "新来者", "directory.recently_active": "最近活跃", + "dismissable_banner.community_timeline": "这些是来自 {domain} 用户的最新公共嘟文。", + "dismissable_banner.dismiss": "忽略", + "dismissable_banner.explore_links": "这些新闻故事正被本站和分布式网络上其他站点的用户谈论。", + "dismissable_banner.explore_statuses": "来自本站和分布式网络上其他站点的这些嘟文正在本站引起关注。", + "dismissable_banner.explore_tags": "这些标签正在本站和分布式网络上其他站点的用户中引起关注。", + "dismissable_banner.public_timeline": "这些是来自本站和分布式网络上其他已知站点用户的最新公共嘟文。", "embed.instructions": "复制下列代码以在你的网站中嵌入此嘟文。", "embed.preview": "它会像这样显示出来:", "emoji_button.activity": "活动", @@ -221,14 +259,14 @@ "follow_request.reject": "拒绝", "follow_requests.unlocked_explanation": "尽管你没有锁嘟,但是 {domain} 的工作人员认为你也许会想手动审核审核这些账号的关注请求。", "generic.saved": "已保存", - "getting_started.developers": "开发者", - "getting_started.directory": "个人资料目录", + "getting_started.directory": "目录", "getting_started.documentation": "文档", + "getting_started.free_software_notice": "Mastodon 是免费的开源软件。 你可以在 {repository} 查看源代码、贡献或报告问题。", "getting_started.heading": "开始使用", "getting_started.invite": "邀请用户", - "getting_started.open_source_notice": "Mastodon 是开源软件。欢迎前往 GitHub({github})贡献代码或反馈问题。", "getting_started.privacy_policy": "隐私政策", "getting_started.security": "账号设置", + "getting_started.what_is_mastodon": "关于 Mastodon", "hashtag.column_header.tag_mode.all": "以及 {additional}", "hashtag.column_header.tag_mode.any": "或是 {additional}", "hashtag.column_header.tag_mode.none": "而不用 {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "显示回复", "home.hide_announcements": "隐藏公告", "home.show_announcements": "显示公告", + "interaction_modal.description.favourite": "拥有一个 Mastodon 账号,你可以对此嘟文点赞及收藏,并让其作者收到你的赞赏。", + "interaction_modal.description.follow": "拥有一个 Mastodon 账号,你可以关注 {name} 并在自己的首页上接收对方的新嘟文。", + "interaction_modal.description.reblog": "拥有一个 Mastodon 账号,你可以向自己的关注者们转发此嘟文。", + "interaction_modal.description.reply": "拥有一个 Mastodon 账号,你可以回复此嘟文。", + "interaction_modal.on_another_server": "在另一服务器", + "interaction_modal.on_this_server": "在此服务器", + "interaction_modal.other_server_instructions": "只需复制此 URL 并将其粘贴在搜索栏中,使用你喜欢的应用或网页界面均可。", + "interaction_modal.preamble": "由于 Mastodon 是去中心化的,如果你在本站没有账号,也可以使用在另一 Mastodon 服务器或其他兼容平台上的已有账号。", + "interaction_modal.title.favourite": "喜欢 {name} 的嘟文", + "interaction_modal.title.follow": "关注 {name}", + "interaction_modal.title.reblog": "转发 {name} 的嘟文", + "interaction_modal.title.reply": "回复 {name} 的嘟文", "intervals.full.days": "{number} 天", "intervals.full.hours": "{number} 小时", "intervals.full.minutes": "{number} 分钟", @@ -310,7 +360,8 @@ "mute_modal.duration": "持续时长", "mute_modal.hide_notifications": "同时隐藏来自这个用户的通知?", "mute_modal.indefinite": "无期限", - "navigation_bar.apps": "移动应用", + "navigation_bar.about": "关于", + "navigation_bar.apps": "获取应用程序", "navigation_bar.blocks": "已屏蔽的用户", "navigation_bar.bookmarks": "书签", "navigation_bar.community_timeline": "本站时间轴", @@ -324,7 +375,7 @@ "navigation_bar.filters": "隐藏关键词", "navigation_bar.follow_requests": "关注请求", "navigation_bar.follows_and_followers": "关注管理", - "navigation_bar.info": "关于本站", + "navigation_bar.info": "关于", "navigation_bar.keyboard_shortcuts": "快捷键列表", "navigation_bar.lists": "列表", "navigation_bar.logout": "登出", @@ -333,7 +384,9 @@ "navigation_bar.pins": "置顶嘟文", "navigation_bar.preferences": "首选项", "navigation_bar.public_timeline": "跨站公共时间轴", + "navigation_bar.search": "Search", "navigation_bar.security": "安全", + "not_signed_in_indicator.not_signed_in": "您需要登录才能访问此资源。", "notification.admin.report": "{name} 已报告 {target}", "notification.admin.sign_up": "{name} 注册了", "notification.favourite": "{name} 喜欢了你的嘟文", @@ -401,6 +454,8 @@ "privacy.public.short": "公开", "privacy.unlisted.long": "对所有人可见,但不加入探索功能", "privacy.unlisted.short": "不公开", + "privacy_policy.last_updated": "最近更新于 {date}", + "privacy_policy.title": "隐私政策", "refresh": "刷新", "regeneration_indicator.label": "加载中……", "regeneration_indicator.sublabel": "你的主页动态正在准备中!", @@ -473,9 +528,15 @@ "search_results.statuses_fts_disabled": "此 Mastodon 服务器未启用帖子内容搜索。", "search_results.title": "搜索 {q}", "search_results.total": "共 {count, number} 个结果", + "server_banner.about_active_users": "过去 30 天内使用此服务器的人(每月活跃用户)", + "server_banner.active_users": "活跃用户", + "server_banner.administered_by": "本站管理员:", + "server_banner.introduction": "{domain} 是由 {mastodon} 驱动的去中心化社交网络的一部分。", + "server_banner.learn_more": "了解更多", + "server_banner.server_stats": "服务器统计数据:", "sign_in_banner.create_account": "创建账户", "sign_in_banner.sign_in": "登录", - "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", + "sign_in_banner.text": "登录以关注个人资料或主题标签、喜欢、分享和嘟文,或与在不同服务器上的帐号进行互动。", "status.admin_account": "打开 @{name} 的管理界面", "status.admin_status": "打开此帖的管理界面", "status.block": "屏蔽 @{name}", @@ -512,6 +573,7 @@ "status.reblogs.empty": "没有人转嘟过此条嘟文。如果有人转嘟了,就会显示在这里。", "status.redraft": "删除并重新编辑", "status.remove_bookmark": "移除书签", + "status.replied_to": "Replied to {name}", "status.reply": "回复", "status.replyAll": "回复所有人", "status.report": "举报 @{name}", @@ -523,9 +585,8 @@ "status.show_more": "显示更多", "status.show_more_all": "显示全部内容", "status.show_original": "显示原文", - "status.show_thread": "显示全部对话", "status.translate": "翻译", - "status.translated_from": "翻译自 {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "暂不可用", "status.unmute_conversation": "恢复此对话的通知提醒", "status.unpin": "在个人资料页面取消置顶", @@ -538,7 +599,6 @@ "tabs_bar.home": "主页", "tabs_bar.local_timeline": "本地", "tabs_bar.notifications": "通知", - "tabs_bar.search": "搜索", "time_remaining.days": "剩余 {number, plural, one {# 天} other {# 天}}", "time_remaining.hours": "剩余 {number, plural, one {# 小时} other {# 小时}}", "time_remaining.minutes": "剩余 {number, plural, one {# 分钟} other {# 分钟}}", diff --git a/app/javascript/mastodon/locales/zh-HK.json b/app/javascript/mastodon/locales/zh-HK.json index e20098fc7..7fd51bfa7 100644 --- a/app/javascript/mastodon/locales/zh-HK.json +++ b/app/javascript/mastodon/locales/zh-HK.json @@ -1,4 +1,17 @@ { + "about.blocks": "Moderated servers", + "about.contact": "Contact:", + "about.domain_blocks.comment": "Reason", + "about.domain_blocks.domain": "Domain", + "about.domain_blocks.preamble": "Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.", + "about.domain_blocks.severity": "Severity", + "about.domain_blocks.silenced.explanation": "You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.", + "about.domain_blocks.silenced.title": "Limited", + "about.domain_blocks.suspended.explanation": "No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.", + "about.domain_blocks.suspended.title": "Suspended", + "about.not_available": "This information has not been made available on this server.", + "about.powered_by": "Decentralized social media powered by {mastodon}", + "about.rules": "Server rules", "account.account_note_header": "筆記", "account.add_or_remove_from_list": "從列表中新增或移除", "account.badges.bot": "機械人", @@ -7,13 +20,16 @@ "account.block_domain": "封鎖來自 {domain} 的一切文章", "account.blocked": "已封鎖", "account.browse_more_on_origin_server": "瀏覽原服務站上的個人資料頁", - "account.cancel_follow_request": "取消關注請求", + "account.cancel_follow_request": "Withdraw follow request", "account.direct": "私訊 @{name}", "account.disable_notifications": "如果 @{name} 發文請不要再通知我", "account.domain_blocked": "服務站被封鎖", "account.edit_profile": "修改個人資料", "account.enable_notifications": "如果 @{name} 發文請通知我", "account.endorse": "在個人資料頁推薦對方", + "account.featured_tags.last_status_at": "Last post on {date}", + "account.featured_tags.last_status_never": "No posts", + "account.featured_tags.title": "{name}'s featured hashtags", "account.follow": "關注", "account.followers": "關注者", "account.followers.empty": "尚未有人關注這位使用者。", @@ -23,7 +39,7 @@ "account.follows.empty": "這位使用者尚未關注任何人。", "account.follows_you": "關注你", "account.hide_reblogs": "隱藏 @{name} 的轉推", - "account.joined": "於 {date} 加入", + "account.joined_short": "Joined", "account.languages": "Change subscribed languages", "account.link_verified_on": "此連結的所有權已在 {date} 檢查過", "account.locked_info": "這位使用者將私隱設定為「不公開」,會手動審批誰能關注他/她。", @@ -63,12 +79,24 @@ "audio.hide": "Hide audio", "autosuggest_hashtag.per_week": "{count} / 週", "boost_modal.combo": "如你想在下次路過這顯示,請按{combo},", - "bundle_column_error.body": "加載本組件出錯。", + "bundle_column_error.copy_stacktrace": "Copy error report", + "bundle_column_error.error.body": "The requested page could not be rendered. It could be due to a bug in our code, or a browser compatibility issue.", + "bundle_column_error.error.title": "Oh, no!", + "bundle_column_error.network.body": "There was an error when trying to load this page. This could be due to a temporary problem with your internet connection or this server.", + "bundle_column_error.network.title": "Network error", "bundle_column_error.retry": "重試", - "bundle_column_error.title": "網絡錯誤", + "bundle_column_error.return": "Go back home", + "bundle_column_error.routing.body": "The requested page could not be found. Are you sure the URL in the address bar is correct?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "關閉", "bundle_modal_error.message": "加載本組件出錯。", "bundle_modal_error.retry": "重試", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "About", "column.blocks": "封鎖名單", "column.bookmarks": "書籤", "column.community": "本站時間軸", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "封鎖並檢舉", "confirmations.block.confirm": "封鎖", "confirmations.block.message": "你確定要封鎖{name}嗎?", + "confirmations.cancel_follow_request.confirm": "Withdraw request", + "confirmations.cancel_follow_request.message": "Are you sure you want to withdraw your request to follow {name}?", "confirmations.delete.confirm": "刪除", "confirmations.delete.message": "你確定要刪除這文章嗎?", "confirmations.delete_list.confirm": "刪除", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "標為已讀", "conversation.open": "檢視對話", "conversation.with": "與 {names}", + "copypaste.copied": "Copied", + "copypaste.copy": "Copy", "directory.federated": "來自已知的聯盟網絡", "directory.local": "僅來自 {domain}", "directory.new_arrivals": "新內容", "directory.recently_active": "最近活躍", + "dismissable_banner.community_timeline": "These are the most recent public posts from people whose accounts are hosted by {domain}.", + "dismissable_banner.dismiss": "Dismiss", + "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", + "dismissable_banner.explore_statuses": "These posts from this and other servers in the decentralized network are gaining traction on this server right now.", + "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", + "dismissable_banner.public_timeline": "These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.", "embed.instructions": "要內嵌此文章,請將以下代碼貼進你的網站。", "embed.preview": "看上去會是這樣:", "emoji_button.activity": "活動", @@ -221,14 +259,14 @@ "follow_request.reject": "拒絕", "follow_requests.unlocked_explanation": "即使您的帳戶未上鎖,{domain} 的工作人員認為您可能想手動審核來自這些帳戶的關注請求。", "generic.saved": "已儲存", - "getting_started.developers": "開發者", - "getting_started.directory": "個人資料目錄", + "getting_started.directory": "Directory", "getting_started.documentation": "文件", + "getting_started.free_software_notice": "Mastodon is free, open source software. You can view the source code, contribute or report issues at {repository}.", "getting_started.heading": "開始使用", "getting_started.invite": "邀請使用者", - "getting_started.open_source_notice": "Mastodon(萬象)是一個開放源碼的軟件。你可以在官方 GitHub {github} 貢獻或者回報問題。", "getting_started.privacy_policy": "Privacy Policy", "getting_started.security": "帳戶設定", + "getting_started.what_is_mastodon": "About Mastodon", "hashtag.column_header.tag_mode.all": "以及{additional}", "hashtag.column_header.tag_mode.any": "或是{additional}", "hashtag.column_header.tag_mode.none": "而無需{additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "顯示回應文章", "home.hide_announcements": "隱藏公告", "home.show_announcements": "顯示公告", + "interaction_modal.description.favourite": "With an account on Mastodon, you can favourite this post to let the author know you appreciate it and save it for later.", + "interaction_modal.description.follow": "With an account on Mastodon, you can follow {name} to receive their posts in your home feed.", + "interaction_modal.description.reblog": "With an account on Mastodon, you can boost this post to share it with your own followers.", + "interaction_modal.description.reply": "With an account on Mastodon, you can respond to this post.", + "interaction_modal.on_another_server": "On a different server", + "interaction_modal.on_this_server": "On this server", + "interaction_modal.other_server_instructions": "Simply copy and paste this URL into the search bar of your favourite app or the web interface where you are signed in.", + "interaction_modal.preamble": "Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one.", + "interaction_modal.title.favourite": "Favourite {name}'s post", + "interaction_modal.title.follow": "Follow {name}", + "interaction_modal.title.reblog": "Boost {name}'s post", + "interaction_modal.title.reply": "Reply to {name}'s post", "intervals.full.days": "{number, plural, one {# 天} other {# 天}}", "intervals.full.hours": "{number, plural, one {# 小時} other {# 小時}}", "intervals.full.minutes": "{number, plural, one {# 分鐘} other {# 分鐘}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "時間", "mute_modal.hide_notifications": "需要隱藏這使用者的通知嗎?", "mute_modal.indefinite": "沒期限", - "navigation_bar.apps": "手機 App", + "navigation_bar.about": "About", + "navigation_bar.apps": "Get the app", "navigation_bar.blocks": "封鎖名單", "navigation_bar.bookmarks": "書籤", "navigation_bar.community_timeline": "本站時間軸", @@ -324,7 +375,7 @@ "navigation_bar.filters": "靜音詞彙", "navigation_bar.follow_requests": "關注請求", "navigation_bar.follows_and_followers": "關注及關注者", - "navigation_bar.info": "關於本服務站", + "navigation_bar.info": "About", "navigation_bar.keyboard_shortcuts": "鍵盤快速鍵", "navigation_bar.lists": "列表", "navigation_bar.logout": "登出", @@ -333,7 +384,9 @@ "navigation_bar.pins": "置頂文章", "navigation_bar.preferences": "偏好設定", "navigation_bar.public_timeline": "跨站時間軸", + "navigation_bar.search": "Search", "navigation_bar.security": "安全", + "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", "notification.admin.report": "{name} reported {target}", "notification.admin.sign_up": "{name} signed up", "notification.favourite": "{name} 喜歡你的文章", @@ -401,6 +454,8 @@ "privacy.public.short": "公共", "privacy.unlisted.long": "Visible for all, but opted-out of discovery features", "privacy.unlisted.short": "公開", + "privacy_policy.last_updated": "Last updated {date}", + "privacy_policy.title": "Privacy Policy", "refresh": "重新整理", "regeneration_indicator.label": "載入中……", "regeneration_indicator.sublabel": "你的主頁時間軸正在準備中!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "此 Mastodon 伺服器並未啟用「搜尋文章內章」功能。", "search_results.title": "Search for {q}", "search_results.total": "{count, number} 項結果", + "server_banner.about_active_users": "People using this server during the last 30 days (Monthly Active Users)", + "server_banner.active_users": "active users", + "server_banner.administered_by": "Administered by:", + "server_banner.introduction": "{domain} is part of the decentralized social network powered by {mastodon}.", + "server_banner.learn_more": "Learn more", + "server_banner.server_stats": "Server stats:", "sign_in_banner.create_account": "Create account", "sign_in_banner.sign_in": "Sign in", "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.", @@ -512,6 +573,7 @@ "status.reblogs.empty": "還未有人轉推。有的話會顯示在這裡。", "status.redraft": "刪除並編輯", "status.remove_bookmark": "移除書籤", + "status.replied_to": "Replied to {name}", "status.reply": "回應", "status.replyAll": "回應所有人", "status.report": "舉報 @{name}", @@ -523,9 +585,8 @@ "status.show_more": "展開", "status.show_more_all": "全部展開", "status.show_original": "Show original", - "status.show_thread": "顯示討論串", "status.translate": "Translate", - "status.translated_from": "Translated from {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "無法使用", "status.unmute_conversation": "對話解除靜音", "status.unpin": "解除置頂", @@ -538,7 +599,6 @@ "tabs_bar.home": "主頁", "tabs_bar.local_timeline": "本站", "tabs_bar.notifications": "通知", - "tabs_bar.search": "搜尋", "time_remaining.days": "剩餘 {number, plural, one {# 天} other {# 天}}", "time_remaining.hours": "剩餘 {number, plural, one {# 小時} other {# 小時}}", "time_remaining.minutes": "剩餘 {number, plural, one {# 分鐘} other {# 分鐘}}", diff --git a/app/javascript/mastodon/locales/zh-TW.json b/app/javascript/mastodon/locales/zh-TW.json index 11c6747e3..d75a57e32 100644 --- a/app/javascript/mastodon/locales/zh-TW.json +++ b/app/javascript/mastodon/locales/zh-TW.json @@ -1,4 +1,17 @@ { + "about.blocks": "受管制的伺服器", + "about.contact": "聯絡我們:", + "about.domain_blocks.comment": "原因", + "about.domain_blocks.domain": "網域", + "about.domain_blocks.preamble": "Mastodon 一般來說允許您閱讀並和聯邦宇宙上任何伺服器的使用者互動。這些伺服器是這個站台設下的例外。", + "about.domain_blocks.severity": "嚴重性", + "about.domain_blocks.silenced.explanation": "一般來說您不會看到來自這個伺服器的個人檔案和內容,除非您明確地打開或著跟隨此個人檔案。", + "about.domain_blocks.silenced.title": "受限的", + "about.domain_blocks.suspended.explanation": "來自此伺服器的資料都不會被處理、儲存或交換,也無法和此伺服器上的使用者互動與溝通。", + "about.domain_blocks.suspended.title": "已停權", + "about.not_available": "這個資料於此伺服器上不可存取。", + "about.powered_by": "由 {mastodon} 提供之去中心化社群媒體", + "about.rules": "伺服器規則", "account.account_note_header": "備註", "account.add_or_remove_from_list": "從列表中新增或移除", "account.badges.bot": "機器人", @@ -7,13 +20,16 @@ "account.block_domain": "封鎖來自 {domain} 網域的所有內容", "account.blocked": "已封鎖", "account.browse_more_on_origin_server": "於該伺服器的個人檔案頁上瀏覽更多", - "account.cancel_follow_request": "取消跟隨請求", + "account.cancel_follow_request": "收回跟隨請求", "account.direct": "傳私訊給 @{name}", "account.disable_notifications": "取消來自 @{name} 嘟文的通知", "account.domain_blocked": "已封鎖網域", "account.edit_profile": "編輯個人檔案", "account.enable_notifications": "當 @{name} 嘟文時通知我", "account.endorse": "在個人檔案推薦對方", + "account.featured_tags.last_status_at": "上次嘟文於 {date}", + "account.featured_tags.last_status_never": "沒有嘟文", + "account.featured_tags.title": "{name} 的特色主題標籤", "account.follow": "跟隨", "account.followers": "跟隨者", "account.followers.empty": "尚未有人跟隨這位使用者。", @@ -23,7 +39,7 @@ "account.follows.empty": "這位使用者尚未跟隨任何人。", "account.follows_you": "跟隨了您", "account.hide_reblogs": "隱藏來自 @{name} 的轉嘟", - "account.joined": "加入於 {date}", + "account.joined_short": "Joined", "account.languages": "變更訂閱的語言", "account.link_verified_on": "已在 {date} 檢查此連結的擁有者權限", "account.locked_info": "此帳戶的隱私狀態被設為鎖定。該擁有者會手動審核能跟隨此帳號的人。", @@ -63,12 +79,24 @@ "audio.hide": "隱藏音訊", "autosuggest_hashtag.per_week": "{count} / 週", "boost_modal.combo": "下次您可以按 {combo} 跳過", - "bundle_column_error.body": "載入此元件時發生錯誤。", + "bundle_column_error.copy_stacktrace": "複製錯誤報告", + "bundle_column_error.error.body": "無法繪製請求的頁面。這可能是因為我們程式碼中的臭蟲或是瀏覽器的相容問題。", + "bundle_column_error.error.title": "糟糕!", + "bundle_column_error.network.body": "嘗試載入此頁面時發生錯誤。這可能是因為您的網際網路連線或此伺服器有暫時性的問題。", + "bundle_column_error.network.title": "網路錯誤", "bundle_column_error.retry": "重試", - "bundle_column_error.title": "網路錯誤", + "bundle_column_error.return": "返回首頁", + "bundle_column_error.routing.body": "找不到請求的頁面。您確定網址列中的 URL 是正確的嗎?", + "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "關閉", "bundle_modal_error.message": "載入此元件時發生錯誤。", "bundle_modal_error.retry": "重試", + "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", + "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", + "closed_registrations_modal.find_another_server": "Find another server", + "closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", + "closed_registrations_modal.title": "Signing up on Mastodon", + "column.about": "關於", "column.blocks": "已封鎖的使用者", "column.bookmarks": "書籤", "column.community": "本站時間軸", @@ -121,6 +149,8 @@ "confirmations.block.block_and_report": "封鎖並檢舉", "confirmations.block.confirm": "封鎖", "confirmations.block.message": "您確定要封鎖 {name} ?", + "confirmations.cancel_follow_request.confirm": "收回請求", + "confirmations.cancel_follow_request.message": "您確定要收回跟隨 {name} 的請求嗎?", "confirmations.delete.confirm": "刪除", "confirmations.delete.message": "您確定要刪除這則嘟文?", "confirmations.delete_list.confirm": "刪除", @@ -144,10 +174,18 @@ "conversation.mark_as_read": "標記為已讀", "conversation.open": "檢視對話", "conversation.with": "與 {names}", + "copypaste.copied": "已複製", + "copypaste.copy": "複製", "directory.federated": "來自已知聯邦宇宙", "directory.local": "僅來自 {domain} 網域", "directory.new_arrivals": "新人", "directory.recently_active": "最近活躍", + "dismissable_banner.community_timeline": "這些是 {domain} 上面託管帳號之最新公開嘟文。", + "dismissable_banner.dismiss": "關閉", + "dismissable_banner.explore_links": "這些新聞故事正在被此伺服器以及去中心化網路上的人們熱烈討論著。", + "dismissable_banner.explore_statuses": "這些於這裡以及去中心化網路中其他伺服器發出的嘟文正在被此伺服器上的人們熱烈討論著。", + "dismissable_banner.explore_tags": "這些主題標籤正在被此伺服器以及去中心化網路上的人們熱烈討論著。", + "dismissable_banner.public_timeline": "這些是來自這裡以及去中心網路中其他已知伺服器之最新公開嘟文。", "embed.instructions": "要在您的網站嵌入此嘟文,請複製以下程式碼。", "embed.preview": "它將顯示成這樣:", "emoji_button.activity": "活動", @@ -221,14 +259,14 @@ "follow_request.reject": "拒絕", "follow_requests.unlocked_explanation": "即便您的帳號未被鎖定,{domain} 的管理員認為您可能想要自己審核這些帳號的跟隨請求。", "generic.saved": "已儲存", - "getting_started.developers": "開發者", - "getting_started.directory": "個人檔案目錄", + "getting_started.directory": "目錄", "getting_started.documentation": "文件", + "getting_started.free_software_notice": "Mastodon 是自由的開源軟體。您可以於 {repository} 檢查其程式碼、貢獻或是回報問題。", "getting_started.heading": "開始使用", "getting_started.invite": "邀請使用者", - "getting_started.open_source_notice": "Mastodon 是開源軟體。您可以在 GitHub {github} 上貢獻或是回報問題。", "getting_started.privacy_policy": "隱私權政策", "getting_started.security": "帳號安全性設定", + "getting_started.what_is_mastodon": "關於 Mastodon", "hashtag.column_header.tag_mode.all": "以及 {additional}", "hashtag.column_header.tag_mode.any": "或是 {additional}", "hashtag.column_header.tag_mode.none": "而無需 {additional}", @@ -245,6 +283,18 @@ "home.column_settings.show_replies": "顯示回覆", "home.hide_announcements": "隱藏公告", "home.show_announcements": "顯示公告", + "interaction_modal.description.favourite": "在 Mastodon 上有個帳號的話,您可以將此嘟文加入最愛以讓作者知道您欣賞它且將它儲存下來。", + "interaction_modal.description.follow": "在 Mastodon 上有個帳號的話,您可以跟隨 {name} 以於首頁時間軸接收他們的嘟文。", + "interaction_modal.description.reblog": "在 Mastodon 上有個帳號的話,您可以轉嘟此嘟文以分享給您的跟隨者們。", + "interaction_modal.description.reply": "在 Mastodon 上有個帳號的話,您可以回覆此嘟文。", + "interaction_modal.on_another_server": "於不同伺服器", + "interaction_modal.on_this_server": "於此伺服器", + "interaction_modal.other_server_instructions": "簡單地於您慣用的應用程式或有登入您帳號之網頁介面的搜尋欄中複製並貼上此 URL。", + "interaction_modal.preamble": "由於 Mastodon 是去中心化的,即便您於此沒有帳號,仍可以利用託管於其他 Mastodon 伺服器或相容平台上的既存帳號。", + "interaction_modal.title.favourite": "將 {name} 的嘟文加入最愛", + "interaction_modal.title.follow": "跟隨 {name}", + "interaction_modal.title.reblog": "轉嘟 {name} 的嘟文", + "interaction_modal.title.reply": "回覆 {name} 的嘟文", "intervals.full.days": "{number, plural, one {# 天} other {# 天}}", "intervals.full.hours": "{number, plural, one {# 小時} other {# 小時}}", "intervals.full.minutes": "{number, plural, one {# 分鐘} other {# 分鐘}}", @@ -310,7 +360,8 @@ "mute_modal.duration": "持續時間", "mute_modal.hide_notifications": "是否隱藏來自這位使用者的通知?", "mute_modal.indefinite": "無期限", - "navigation_bar.apps": "行動應用程式", + "navigation_bar.about": "關於", + "navigation_bar.apps": "取得應用程式", "navigation_bar.blocks": "封鎖使用者", "navigation_bar.bookmarks": "書籤", "navigation_bar.community_timeline": "本站時間軸", @@ -324,7 +375,7 @@ "navigation_bar.filters": "靜音詞彙", "navigation_bar.follow_requests": "跟隨請求", "navigation_bar.follows_and_followers": "跟隨中與跟隨者", - "navigation_bar.info": "關於此伺服器", + "navigation_bar.info": "關於", "navigation_bar.keyboard_shortcuts": "快速鍵", "navigation_bar.lists": "列表", "navigation_bar.logout": "登出", @@ -333,7 +384,9 @@ "navigation_bar.pins": "釘選的嘟文", "navigation_bar.preferences": "偏好設定", "navigation_bar.public_timeline": "聯邦時間軸", + "navigation_bar.search": "Search", "navigation_bar.security": "安全性", + "not_signed_in_indicator.not_signed_in": "您需要登入才能存取此資源。", "notification.admin.report": "{name} 檢舉了 {target}", "notification.admin.sign_up": "{name} 已經註冊", "notification.favourite": "{name} 把您的嘟文加入了最愛", @@ -401,6 +454,8 @@ "privacy.public.short": "公開", "privacy.unlisted.long": "對所有人可見,但選擇退出探索功能", "privacy.unlisted.short": "不公開", + "privacy_policy.last_updated": "最後更新:{date}", + "privacy_policy.title": "隱私權政策", "refresh": "重新整理", "regeneration_indicator.label": "載入中…", "regeneration_indicator.sublabel": "您的首頁時間軸正在準備中!", @@ -473,6 +528,12 @@ "search_results.statuses_fts_disabled": "「依內容搜尋嘟文」未在此 Mastodon 伺服器啟用。", "search_results.title": "搜尋:{q}", "search_results.total": "{count, number} 項結果", + "server_banner.about_active_users": "最近三十日內使用此伺服器的人 (月活躍使用者)", + "server_banner.active_users": "活躍使用者", + "server_banner.administered_by": "管理者:", + "server_banner.introduction": "{domain} 是由 {mastodon} 提供之去中心化社群網路一部分。", + "server_banner.learn_more": "了解更多", + "server_banner.server_stats": "伺服器統計:", "sign_in_banner.create_account": "新增帳號", "sign_in_banner.sign_in": "登入", "sign_in_banner.text": "登入以追蹤個人檔案、主題標籤、最愛,分享和回覆嘟文,或以您其他伺服器之帳號進行互動:", @@ -512,6 +573,7 @@ "status.reblogs.empty": "還沒有人轉嘟過這則嘟文。當有人轉嘟時,它將於此顯示。", "status.redraft": "刪除並重新編輯", "status.remove_bookmark": "移除書籤", + "status.replied_to": "Replied to {name}", "status.reply": "回覆", "status.replyAll": "回覆討論串", "status.report": "檢舉 @{name}", @@ -523,9 +585,8 @@ "status.show_more": "顯示更多", "status.show_more_all": "顯示更多這類嘟文", "status.show_original": "顯示原文", - "status.show_thread": "顯示討論串", "status.translate": "翻譯", - "status.translated_from": "翻譯自 {lang}", + "status.translated_from_with": "Translated from {lang} using {provider}", "status.uncached_media_warning": "無法使用", "status.unmute_conversation": "解除此對話的靜音", "status.unpin": "從個人檔案頁面解除釘選", @@ -538,7 +599,6 @@ "tabs_bar.home": "首頁", "tabs_bar.local_timeline": "本站", "tabs_bar.notifications": "通知", - "tabs_bar.search": "搜尋", "time_remaining.days": "剩餘 {number, plural, one {# 天} other {# 天}}", "time_remaining.hours": "剩餘 {number, plural, one {# 小時} other {# 小時}}", "time_remaining.minutes": "剩餘 {number, plural, one {# 分鐘} other {# 分鐘}}", diff --git a/app/javascript/mastodon/main.js b/app/javascript/mastodon/main.js index f33375b50..d0337ce0c 100644 --- a/app/javascript/mastodon/main.js +++ b/app/javascript/mastodon/main.js @@ -12,14 +12,6 @@ const perf = require('mastodon/performance'); function main() { perf.start('main()'); - if (window.history && history.replaceState) { - const { pathname, search, hash } = window.location; - const path = pathname + search + hash; - if (!(/^\/web($|\/)/).test(path)) { - history.replaceState(null, document.title, `/web${path}`); - } - } - return ready(async () => { const mountNode = document.getElementById('mastodon'); const props = JSON.parse(mountNode.getAttribute('data-props')); diff --git a/app/javascript/mastodon/reducers/accounts_map.js b/app/javascript/mastodon/reducers/accounts_map.js index e0d42e9cd..53e08c8fb 100644 --- a/app/javascript/mastodon/reducers/accounts_map.js +++ b/app/javascript/mastodon/reducers/accounts_map.js @@ -1,14 +1,16 @@ import { ACCOUNT_IMPORT, ACCOUNTS_IMPORT } from '../actions/importer'; import { Map as ImmutableMap } from 'immutable'; +export const normalizeForLookup = str => str.toLowerCase(); + const initialState = ImmutableMap(); export default function accountsMap(state = initialState, action) { switch(action.type) { case ACCOUNT_IMPORT: - return state.set(action.account.acct, action.account.id); + return state.set(normalizeForLookup(action.account.acct), action.account.id); case ACCOUNTS_IMPORT: - return state.withMutations(map => action.accounts.forEach(account => map.set(account.acct, account.id))); + return state.withMutations(map => action.accounts.forEach(account => map.set(normalizeForLookup(account.acct), account.id))); default: return state; } diff --git a/app/javascript/mastodon/reducers/compose.js b/app/javascript/mastodon/reducers/compose.js index 7aac87b5c..e4601e471 100644 --- a/app/javascript/mastodon/reducers/compose.js +++ b/app/javascript/mastodon/reducers/compose.js @@ -14,6 +14,7 @@ import { COMPOSE_UPLOAD_FAIL, COMPOSE_UPLOAD_UNDO, COMPOSE_UPLOAD_PROGRESS, + COMPOSE_UPLOAD_PROCESSING, THUMBNAIL_UPLOAD_REQUEST, THUMBNAIL_UPLOAD_SUCCESS, THUMBNAIL_UPLOAD_FAIL, @@ -136,6 +137,7 @@ function appendMedia(state, media, file) { } map.update('media_attachments', list => list.push(media)); map.set('is_uploading', false); + map.set('is_processing', false); map.set('resetFileKey', Math.floor((Math.random() * 0x10000))); map.set('idempotencyKey', uuid()); map.update('pending_media_attachments', n => n - 1); @@ -354,10 +356,12 @@ export default function compose(state = initialState, action) { return state.set('is_changing_upload', false); case COMPOSE_UPLOAD_REQUEST: return state.set('is_uploading', true).update('pending_media_attachments', n => n + 1); + case COMPOSE_UPLOAD_PROCESSING: + return state.set('is_processing', true); case COMPOSE_UPLOAD_SUCCESS: return appendMedia(state, fromJS(action.media), action.file); case COMPOSE_UPLOAD_FAIL: - return state.set('is_uploading', false).update('pending_media_attachments', n => n - 1); + return state.set('is_uploading', false).set('is_processing', false).update('pending_media_attachments', n => n - 1); case COMPOSE_UPLOAD_UNDO: return removeMedia(state, action.media_id); case COMPOSE_UPLOAD_PROGRESS: diff --git a/app/javascript/mastodon/reducers/server.js b/app/javascript/mastodon/reducers/server.js index 68131c6dd..db9f2b5e6 100644 --- a/app/javascript/mastodon/reducers/server.js +++ b/app/javascript/mastodon/reducers/server.js @@ -1,18 +1,52 @@ -import { SERVER_FETCH_REQUEST, SERVER_FETCH_SUCCESS, SERVER_FETCH_FAIL } from 'mastodon/actions/server'; -import { Map as ImmutableMap, fromJS } from 'immutable'; +import { + SERVER_FETCH_REQUEST, + SERVER_FETCH_SUCCESS, + SERVER_FETCH_FAIL, + EXTENDED_DESCRIPTION_REQUEST, + EXTENDED_DESCRIPTION_SUCCESS, + EXTENDED_DESCRIPTION_FAIL, + SERVER_DOMAIN_BLOCKS_FETCH_REQUEST, + SERVER_DOMAIN_BLOCKS_FETCH_SUCCESS, + SERVER_DOMAIN_BLOCKS_FETCH_FAIL, +} from 'mastodon/actions/server'; +import { Map as ImmutableMap, List as ImmutableList, fromJS } from 'immutable'; const initialState = ImmutableMap({ - isLoading: true, + server: ImmutableMap({ + isLoading: true, + }), + + extendedDescription: ImmutableMap({ + isLoading: true, + }), + + domainBlocks: ImmutableMap({ + isLoading: true, + isAvailable: true, + items: ImmutableList(), + }), }); export default function server(state = initialState, action) { switch (action.type) { case SERVER_FETCH_REQUEST: - return state.set('isLoading', true); + return state.setIn(['server', 'isLoading'], true); case SERVER_FETCH_SUCCESS: - return fromJS(action.server).set('isLoading', false); + return state.set('server', fromJS(action.server)).setIn(['server', 'isLoading'], false); case SERVER_FETCH_FAIL: - return state.set('isLoading', false); + return state.setIn(['server', 'isLoading'], false); + case EXTENDED_DESCRIPTION_REQUEST: + return state.setIn(['extendedDescription', 'isLoading'], true); + case EXTENDED_DESCRIPTION_SUCCESS: + return state.set('extendedDescription', fromJS(action.description)).setIn(['extendedDescription', 'isLoading'], false); + case EXTENDED_DESCRIPTION_FAIL: + return state.setIn(['extendedDescription', 'isLoading'], false); + case SERVER_DOMAIN_BLOCKS_FETCH_REQUEST: + return state.setIn(['domainBlocks', 'isLoading'], true); + case SERVER_DOMAIN_BLOCKS_FETCH_SUCCESS: + return state.setIn(['domainBlocks', 'items'], fromJS(action.blocks)).setIn(['domainBlocks', 'isLoading'], false).setIn(['domainBlocks', 'isAvailable'], action.isAvailable); + case SERVER_DOMAIN_BLOCKS_FETCH_FAIL: + return state.setIn(['domainBlocks', 'isLoading'], false); default: return state; } diff --git a/app/javascript/mastodon/reducers/statuses.js b/app/javascript/mastodon/reducers/statuses.js index 7efb49d85..c30c1e2cc 100644 --- a/app/javascript/mastodon/reducers/statuses.js +++ b/app/javascript/mastodon/reducers/statuses.js @@ -15,6 +15,8 @@ import { STATUS_COLLAPSE, STATUS_TRANSLATE_SUCCESS, STATUS_TRANSLATE_UNDO, + STATUS_FETCH_REQUEST, + STATUS_FETCH_FAIL, } from '../actions/statuses'; import { TIMELINE_DELETE } from '../actions/timelines'; import { STATUS_IMPORT, STATUSES_IMPORT } from '../actions/importer'; @@ -37,6 +39,10 @@ const initialState = ImmutableMap(); export default function statuses(state = initialState, action) { switch(action.type) { + case STATUS_FETCH_REQUEST: + return state.setIn([action.id, 'isLoading'], true); + case STATUS_FETCH_FAIL: + return state.delete(action.id); case STATUS_IMPORT: return importStatus(state, action.status); case STATUSES_IMPORT: diff --git a/app/javascript/mastodon/reducers/user_lists.js b/app/javascript/mastodon/reducers/user_lists.js index 10aaa2d68..f19c1e2e9 100644 --- a/app/javascript/mastodon/reducers/user_lists.js +++ b/app/javascript/mastodon/reducers/user_lists.js @@ -22,7 +22,7 @@ import { FOLLOW_REQUESTS_EXPAND_FAIL, FOLLOW_REQUEST_AUTHORIZE_SUCCESS, FOLLOW_REQUEST_REJECT_SUCCESS, -} from '../actions/accounts'; + } from '../actions/accounts'; import { REBLOGS_FETCH_SUCCESS, FAVOURITES_FETCH_SUCCESS, @@ -51,7 +51,12 @@ import { DIRECTORY_EXPAND_SUCCESS, DIRECTORY_EXPAND_FAIL, } from 'mastodon/actions/directory'; -import { Map as ImmutableMap, List as ImmutableList } from 'immutable'; +import { + FEATURED_TAGS_FETCH_REQUEST, + FEATURED_TAGS_FETCH_SUCCESS, + FEATURED_TAGS_FETCH_FAIL, +} from 'mastodon/actions/featured_tags'; +import { Map as ImmutableMap, List as ImmutableList, fromJS } from 'immutable'; const initialListState = ImmutableMap({ next: null, @@ -67,6 +72,7 @@ const initialState = ImmutableMap({ follow_requests: initialListState, blocks: initialListState, mutes: initialListState, + featured_tags: initialListState, }); const normalizeList = (state, path, accounts, next) => { @@ -89,6 +95,18 @@ const normalizeFollowRequest = (state, notification) => { }); }; +const normalizeFeaturedTag = (featuredTags, accountId) => { + const normalizeFeaturedTag = { ...featuredTags, accountId: accountId }; + return fromJS(normalizeFeaturedTag); +}; + +const normalizeFeaturedTags = (state, path, featuredTags, accountId) => { + return state.setIn(path, ImmutableMap({ + items: ImmutableList(featuredTags.map(featuredTag => normalizeFeaturedTag(featuredTag, accountId)).sort((a, b) => b.get('statuses_count') - a.get('statuses_count'))), + isLoading: false, + })); +}; + export default function userLists(state = initialState, action) { switch(action.type) { case FOLLOWERS_FETCH_SUCCESS: @@ -160,6 +178,12 @@ export default function userLists(state = initialState, action) { case DIRECTORY_FETCH_FAIL: case DIRECTORY_EXPAND_FAIL: return state.setIn(['directory', 'isLoading'], false); + case FEATURED_TAGS_FETCH_SUCCESS: + return normalizeFeaturedTags(state, ['featured_tags', action.id], action.tags, action.id); + case FEATURED_TAGS_FETCH_REQUEST: + return state.setIn(['featured_tags', action.id, 'isLoading'], true); + case FEATURED_TAGS_FETCH_FAIL: + return state.setIn(['featured_tags', action.id, 'isLoading'], false); default: return state; } diff --git a/app/javascript/mastodon/selectors/index.js b/app/javascript/mastodon/selectors/index.js index 3dd7f4897..bf46c810e 100644 --- a/app/javascript/mastodon/selectors/index.js +++ b/app/javascript/mastodon/selectors/index.js @@ -41,7 +41,7 @@ export const makeGetStatus = () => { ], (statusBase, statusReblog, accountBase, accountReblog, filters) => { - if (!statusBase) { + if (!statusBase || statusBase.get('isLoading')) { return null; } diff --git a/app/javascript/mastodon/service_worker/entry.js b/app/javascript/mastodon/service_worker/entry.js index e4c66cc00..9026012fe 100644 --- a/app/javascript/mastodon/service_worker/entry.js +++ b/app/javascript/mastodon/service_worker/entry.js @@ -43,7 +43,7 @@ registerRoute( ); registerRoute( - ({ request }) => ['audio', 'image', 'track', 'video'].includes(request.destination), + ({ request }) => request.destination === 'image', new CacheFirst({ cacheName: `m${CACHE_NAME_PREFIX}media`, plugins: [ @@ -60,24 +60,15 @@ registerRoute( self.addEventListener('install', function(event) { event.waitUntil(Promise.all([openWebCache(), fetchRoot()]).then(([cache, root]) => cache.put('/', root))); }); + self.addEventListener('activate', function(event) { event.waitUntil(self.clients.claim()); }); + self.addEventListener('fetch', function(event) { const url = new URL(event.request.url); - if (url.pathname.startsWith('/web/')) { - const asyncResponse = fetchRoot(); - const asyncCache = openWebCache(); - - event.respondWith(asyncResponse.then( - response => { - const clonedResponse = response.clone(); - asyncCache.then(cache => cache.put('/', clonedResponse)).catch(); - return response; - }, - () => asyncCache.then(cache => cache.match('/')))); - } else if (url.pathname === '/auth/sign_out') { + if (url.pathname === '/auth/sign_out') { const asyncResponse = fetch(event.request); const asyncCache = openWebCache(); diff --git a/app/javascript/mastodon/service_worker/web_push_notifications.js b/app/javascript/mastodon/service_worker/web_push_notifications.js index 9b75e9b9d..f12595777 100644 --- a/app/javascript/mastodon/service_worker/web_push_notifications.js +++ b/app/javascript/mastodon/service_worker/web_push_notifications.js @@ -15,7 +15,7 @@ const notify = options => icon: '/android-chrome-192x192.png', tag: GROUP_TAG, data: { - url: (new URL('/web/notifications', self.location)).href, + url: (new URL('/notifications', self.location)).href, count: notifications.length + 1, preferred_locale: options.data.preferred_locale, }, @@ -90,7 +90,7 @@ export const handlePush = (event) => { options.tag = notification.id; options.badge = '/badge.png'; options.image = notification.status && notification.status.media_attachments.length > 0 && notification.status.media_attachments[0].preview_url || undefined; - options.data = { access_token, preferred_locale, id: notification.status ? notification.status.id : notification.account.id, url: notification.status ? `/web/@${notification.account.acct}/${notification.status.id}` : `/web/@${notification.account.acct}` }; + options.data = { access_token, preferred_locale, id: notification.status ? notification.status.id : notification.account.id, url: notification.status ? `/@${notification.account.acct}/${notification.status.id}` : `/@${notification.account.acct}` }; if (notification.status && notification.status.spoiler_text || notification.status.sensitive) { options.data.hiddenBody = htmlToPlainText(notification.status.content); @@ -115,7 +115,7 @@ export const handlePush = (event) => { tag: notification_id, timestamp: new Date(), badge: '/badge.png', - data: { access_token, preferred_locale, url: '/web/notifications' }, + data: { access_token, preferred_locale, url: '/notifications' }, }); }), ); @@ -166,24 +166,10 @@ const removeActionFromNotification = (notification, action) => { const openUrl = url => self.clients.matchAll({ type: 'window' }).then(clientList => { - if (clientList.length !== 0) { - const webClients = clientList.filter(client => /\/web\//.test(client.url)); - - if (webClients.length !== 0) { - const client = findBestClient(webClients); - const { pathname } = new URL(url, self.location); - - if (pathname.startsWith('/web/')) { - return client.focus().then(client => client.postMessage({ - type: 'navigate', - path: pathname.slice('/web/'.length - 1), - })); - } - } else if ('navigate' in clientList[0]) { // Chrome 42-48 does not support navigate - const client = findBestClient(clientList); + if (clientList.length !== 0 && 'navigate' in clientList[0]) { // Chrome 42-48 does not support navigate + const client = findBestClient(clientList); - return client.navigate(url).then(client => client.focus()); - } + return client.navigate(url).then(client => client.focus()); } return self.clients.openWindow(url); diff --git a/app/javascript/mastodon/settings.js b/app/javascript/mastodon/settings.js index 7643a508e..46cfadfa3 100644 --- a/app/javascript/mastodon/settings.js +++ b/app/javascript/mastodon/settings.js @@ -45,3 +45,4 @@ export default class Settings { export const pushNotificationsSetting = new Settings('mastodon_push_notification_data'); export const tagHistory = new Settings('mastodon_tag_history'); +export const bannerSettings = new Settings('mastodon_banner_settings'); diff --git a/app/javascript/packs/about.js b/app/javascript/packs/about.js deleted file mode 100644 index 892d825ec..000000000 --- a/app/javascript/packs/about.js +++ /dev/null @@ -1,26 +0,0 @@ -import './public-path'; -import loadPolyfills from '../mastodon/load_polyfills'; -import { start } from '../mastodon/common'; - -start(); - -function loaded() { - const TimelineContainer = require('../mastodon/containers/timeline_container').default; - const React = require('react'); - const ReactDOM = require('react-dom'); - const mountNode = document.getElementById('mastodon-timeline'); - - if (mountNode !== null) { - const props = JSON.parse(mountNode.getAttribute('data-props')); - ReactDOM.render(<TimelineContainer {...props} />, mountNode); - } -} - -function main() { - const ready = require('../mastodon/ready').default; - ready(loaded); -} - -loadPolyfills().then(main).catch(error => { - console.error(error); -}); diff --git a/app/javascript/packs/public.js b/app/javascript/packs/public.js index 4f60f04c1..ab7c4a3f3 100644 --- a/app/javascript/packs/public.js +++ b/app/javascript/packs/public.js @@ -16,7 +16,6 @@ function main() { const { messages } = getLocale(); const React = require('react'); const ReactDOM = require('react-dom'); - const Rellax = require('rellax'); const { createBrowserHistory } = require('history'); const scrollToDetailedStatus = () => { @@ -95,12 +94,6 @@ function main() { scrollToDetailedStatus(); } - const parallaxComponents = document.querySelectorAll('.parallax'); - - if (parallaxComponents.length > 0 ) { - new Rellax('.parallax', { speed: -1 }); - } - delegate(document, '#registration_user_password_confirmation,#registration_user_password', 'input', () => { const password = document.getElementById('registration_user_password'); const confirmation = document.getElementById('registration_user_password_confirmation'); @@ -151,8 +144,31 @@ function main() { }); }); + const toggleSidebar = () => { + const sidebar = document.querySelector('.sidebar ul'); + const toggleButton = document.querySelector('.sidebar__toggle__icon'); + + if (sidebar.classList.contains('visible')) { + document.body.style.overflow = null; + toggleButton.setAttribute('aria-expanded', false); + } else { + document.body.style.overflow = 'hidden'; + toggleButton.setAttribute('aria-expanded', true); + } + + toggleButton.classList.toggle('active'); + sidebar.classList.toggle('visible'); + }; + delegate(document, '.sidebar__toggle__icon', 'click', () => { - document.querySelector('.sidebar ul').classList.toggle('visible'); + toggleSidebar(); + }); + + delegate(document, '.sidebar__toggle__icon', 'keydown', e => { + if (e.key === ' ' || e.key === 'Enter') { + e.preventDefault(); + toggleSidebar(); + } }); // Empty the honeypot fields in JS in case something like an extension diff --git a/app/javascript/styles/application.scss b/app/javascript/styles/application.scss index bbea06195..81a040108 100644 --- a/app/javascript/styles/application.scss +++ b/app/javascript/styles/application.scss @@ -2,15 +2,12 @@ @import 'mastodon/variables'; @import 'fonts/roboto'; @import 'fonts/roboto-mono'; -@import 'fonts/montserrat'; @import 'mastodon/reset'; @import 'mastodon/basics'; @import 'mastodon/branding'; @import 'mastodon/containers'; @import 'mastodon/lists'; -@import 'mastodon/footer'; -@import 'mastodon/compact_header'; @import 'mastodon/widgets'; @import 'mastodon/forms'; @import 'mastodon/accounts'; diff --git a/app/javascript/styles/contrast/diff.scss b/app/javascript/styles/contrast/diff.scss index 841ed6648..27eb837df 100644 --- a/app/javascript/styles/contrast/diff.scss +++ b/app/javascript/styles/contrast/diff.scss @@ -13,10 +13,6 @@ } } -.rich-formatting a, -.rich-formatting p a, -.rich-formatting li a, -.landing-page__short-description p a, .status__content a, .reply-indicator__content a { color: lighten($ui-highlight-color, 12%); @@ -72,10 +68,6 @@ color: $darker-text-color; } -.public-layout .public-account-header__tabs__tabs .counter.active::after { - border-bottom: 4px solid $ui-highlight-color; -} - .compose-form .autosuggest-textarea__textarea::placeholder, .compose-form .spoiler-input__input::placeholder { color: $inverted-text-color; diff --git a/app/javascript/styles/fonts/montserrat.scss b/app/javascript/styles/fonts/montserrat.scss deleted file mode 100644 index 03f67ed3f..000000000 --- a/app/javascript/styles/fonts/montserrat.scss +++ /dev/null @@ -1,21 +0,0 @@ -@font-face { - font-family: mastodon-font-display; - src: - local('Montserrat'), - url('~fonts/montserrat/Montserrat-Regular.woff2') format('woff2'), - url('~fonts/montserrat/Montserrat-Regular.woff') format('woff'), - url('~fonts/montserrat/Montserrat-Regular.ttf') format('truetype'); - font-weight: 400; - font-display: swap; - font-style: normal; -} - -@font-face { - font-family: mastodon-font-display; - src: - local('Montserrat Medium'), - url('~fonts/montserrat/Montserrat-Medium.ttf') format('truetype'); - font-weight: 500; - font-display: swap; - font-style: normal; -} diff --git a/app/javascript/styles/mastodon-light/diff.scss b/app/javascript/styles/mastodon-light/diff.scss index 0bc6247ef..20e973b8b 100644 --- a/app/javascript/styles/mastodon-light/diff.scss +++ b/app/javascript/styles/mastodon-light/diff.scss @@ -36,6 +36,20 @@ html { border-top: 0; } +.column > .scrollable.about { + border-top: 1px solid lighten($ui-base-color, 8%); +} + +.about__meta, +.about__section__title { + background: $white; + border: 1px solid lighten($ui-base-color, 8%); +} + +.rules-list li::before { + background: $ui-highlight-color; +} + .directory__card__img { background: lighten($ui-base-color, 12%); } @@ -45,10 +59,6 @@ html { border-bottom: 1px solid lighten($ui-base-color, 8%); } -.table-of-contents { - border: 1px solid lighten($ui-base-color, 8%); -} - .column-back-button, .column-header { background: $white; @@ -138,11 +148,6 @@ html { .compose-form__poll-wrapper select, .search__input, .setting-text, -.box-widget input[type="text"], -.box-widget input[type="email"], -.box-widget input[type="password"], -.box-widget textarea, -.statuses-grid .detailed-status, .report-dialog-modal__textarea, .audio-player { border: 1px solid lighten($ui-base-color, 8%); @@ -480,52 +485,16 @@ html { background: $white; } -.tabs-bar { - background: $white; - border: 1px solid lighten($ui-base-color, 8%); - border-bottom: 0; - - @media screen and (max-width: $no-gap-breakpoint) { - border-top: 0; - } - - &__link { - padding-bottom: 14px; - border-bottom-width: 1px; - border-bottom-color: lighten($ui-base-color, 8%); - - &:hover, - &:active, - &:focus { - background: $ui-base-color; - } - - &.active { - &:hover, - &:active, - &:focus { - background: transparent; - border-bottom-color: $ui-highlight-color; - } - } - } -} - // Change the default colors used on some parts of the profile pages .activity-stream-tabs { background: $account-background-color; border-bottom-color: lighten($ui-base-color, 8%); } -.box-widget, .nothing-here, .page-header, .directory__tag > a, -.directory__tag > div, -.landing-page__call-to-action, -.contact-widget, -.landing .hero-widget__text, -.landing-page__information.contact-widget { +.directory__tag > div { background: $white; border: 1px solid lighten($ui-base-color, 8%); @@ -536,11 +505,6 @@ html { } } -.landing .hero-widget__text { - border-top: 0; - border-bottom: 0; -} - .simple_form { input[type="text"], input[type="number"], @@ -553,26 +517,12 @@ html { } } -.landing .hero-widget__footer { - background: $white; - border: 1px solid lighten($ui-base-color, 8%); - border-top: 0; - - @media screen and (max-width: $no-gap-breakpoint) { - border: 0; - } -} - .picture-in-picture-placeholder { background: $white; border-color: lighten($ui-base-color, 8%); color: lighten($ui-base-color, 8%); } -.brand__tagline { - color: $ui-secondary-color; -} - .directory__tag > a { &:hover, &:active, @@ -666,8 +616,7 @@ html { } } -.simple_form, -.table-form { +.simple_form { .warning { box-shadow: none; background: rgba($error-red, 0.5); @@ -706,104 +655,12 @@ html { } } -.public-layout { - .account__section-headline { - border: 1px solid lighten($ui-base-color, 8%); - - @media screen and (max-width: $no-gap-breakpoint) { - border-top: 0; - } - } - - .header, - .public-account-header, - .public-account-bio { - box-shadow: none; - } - - .public-account-bio, - .hero-widget__text { - background: $account-background-color; - } - - .header { - background: $ui-base-color; - border: 1px solid lighten($ui-base-color, 8%); - - @media screen and (max-width: $no-gap-breakpoint) { - border: 0; - } - - .brand { - &:hover, - &:focus, - &:active { - background: lighten($ui-base-color, 4%); - } - } - } - - .public-account-header { - &__image { - background: lighten($ui-base-color, 12%); - - &::after { - box-shadow: none; - } - } - - &__bar { - &::before { - background: $account-background-color; - border: 1px solid lighten($ui-base-color, 8%); - border-top: 0; - } - - .avatar img { - border-color: $account-background-color; - } - - @media screen and (max-width: $no-columns-breakpoint) { - background: $account-background-color; - border: 1px solid lighten($ui-base-color, 8%); - border-top: 0; - } - } - - &__tabs { - &__name { - h1, - h1 small { - color: $white; - - @media screen and (max-width: $no-columns-breakpoint) { - color: $primary-text-color; - } - } - } - } - - &__extra { - .public-account-bio { - border: 0; - } - - .public-account-bio .account__header__fields { - border-color: lighten($ui-base-color, 8%); - } - } - } -} - .notification__filter-bar button.active::after, .account__section-headline a.active::after { border-color: transparent transparent $white; } .hero-widget, -.box-widget, -.contact-widget, -.landing-page__information.contact-widget, .moved-account-widget, .memoriam-widget, .activity-stream, diff --git a/app/javascript/styles/mastodon/about.scss b/app/javascript/styles/mastodon/about.scss index c82be742d..0183c43d5 100644 --- a/app/javascript/styles/mastodon/about.scss +++ b/app/javascript/styles/mastodon/about.scss @@ -1,7 +1,5 @@ $maximum-width: 1235px; $fluid-breakpoint: $maximum-width + 20px; -$column-breakpoint: 700px; -$small-breakpoint: 960px; .container { box-sizing: border-box; @@ -15,892 +13,44 @@ $small-breakpoint: 960px; } } -.rich-formatting { - font-family: $font-sans-serif, sans-serif; - font-size: 14px; - font-weight: 400; - line-height: 1.7; - word-wrap: break-word; - color: $darker-text-color; - - a { - color: $highlight-text-color; - text-decoration: underline; - - &:hover, - &:focus, - &:active { - text-decoration: none; - } - } - - p, - li { - color: $darker-text-color; - } - - p { - margin-top: 0; - margin-bottom: 0.85em; - - &:last-child { - margin-bottom: 0; - } - } - - strong { - font-weight: 700; - color: $secondary-text-color; - } - - em { - font-style: italic; - color: $secondary-text-color; - } - - code { - font-size: 0.85em; - background: darken($ui-base-color, 8%); - border-radius: 4px; - padding: 0.2em 0.3em; - } - - h1, - h2, - h3, - h4, - h5, - h6 { - font-family: $font-display, sans-serif; - margin-top: 1.275em; - margin-bottom: 0.85em; - font-weight: 500; - color: $secondary-text-color; - } - - h1 { - font-size: 2em; - } - - h2 { - font-size: 1.75em; - } - - h3 { - font-size: 1.5em; - } - - h4 { - font-size: 1.25em; - } - - h5, - h6 { - font-size: 1em; - } - - ul { - list-style: disc; - } - - ol { - list-style: decimal; - } - - ul, - ol { - margin: 0; - padding: 0; - padding-left: 2em; - margin-bottom: 0.85em; - - &[type='a'] { - list-style-type: lower-alpha; - } - - &[type='i'] { - list-style-type: lower-roman; - } - } - - hr { - width: 100%; - height: 0; - border: 0; - border-bottom: 1px solid lighten($ui-base-color, 4%); - margin: 1.7em 0; - - &.spacer { - height: 1px; - border: 0; - } - } - - table { - width: 100%; - border-collapse: collapse; - break-inside: auto; - margin-top: 24px; - margin-bottom: 32px; - - thead tr, - tbody tr { - border-bottom: 1px solid lighten($ui-base-color, 4%); - font-size: 1em; - line-height: 1.625; - font-weight: 400; - text-align: left; - color: $darker-text-color; - } - - thead tr { - border-bottom-width: 2px; - line-height: 1.5; - font-weight: 500; - color: $dark-text-color; - } - - th, - td { - padding: 8px; - align-self: start; - align-items: start; - word-break: break-all; - - &.nowrap { - width: 25%; - position: relative; - - &::before { - content: ' '; - visibility: hidden; - } - - span { - position: absolute; - left: 8px; - right: 8px; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - } - } - } - } - - & > :first-child { - margin-top: 0; - } +.brand { + position: relative; + text-decoration: none; } -.information-board { - background: darken($ui-base-color, 4%); - padding: 20px 0; - - .container-alt { - position: relative; - padding-right: 280px + 15px; - } - - &__sections { - display: flex; - justify-content: space-between; - flex-wrap: wrap; - } - - &__section { - flex: 1 0 0; - font-family: $font-sans-serif, sans-serif; - font-size: 16px; - line-height: 28px; - color: $primary-text-color; - text-align: right; - padding: 10px 15px; - - span, - strong { - display: block; - } - - span { - &:last-child { - color: $secondary-text-color; - } - } - - strong { - font-family: $font-display, sans-serif; - font-weight: 500; - font-size: 32px; - line-height: 48px; - } - - @media screen and (max-width: $column-breakpoint) { - text-align: center; - } - } - - .panel { - position: absolute; - width: 280px; - box-sizing: border-box; - background: darken($ui-base-color, 8%); - padding: 20px; - padding-top: 10px; - border-radius: 4px 4px 0 0; - right: 0; - bottom: -40px; - - .panel-header { - font-family: $font-display, sans-serif; - font-size: 14px; - line-height: 24px; - font-weight: 500; - color: $darker-text-color; - padding-bottom: 5px; - margin-bottom: 15px; - border-bottom: 1px solid lighten($ui-base-color, 4%); - text-overflow: ellipsis; - white-space: nowrap; - overflow: hidden; - - a, - span { - font-weight: 400; - color: darken($darker-text-color, 10%); - } - - a { - text-decoration: none; - } - } - } - - .owner { - text-align: center; - - .avatar { - width: 80px; - height: 80px; - margin: 0 auto; - margin-bottom: 15px; - - img { - display: block; - width: 80px; - height: 80px; - border-radius: 48px; - } - } - - .name { - font-size: 14px; - - a { - display: block; - color: $primary-text-color; - text-decoration: none; - - &:hover { - .display_name { - text-decoration: underline; - } - } - } - - .username { - display: block; - color: $darker-text-color; - } - } - } -} +.rules-list { + font-size: 15px; + line-height: 22px; + color: $primary-text-color; + counter-reset: list-counter; -.landing-page { - p, li { - font-family: $font-sans-serif, sans-serif; - font-size: 16px; - font-weight: 400; - line-height: 30px; - margin-bottom: 12px; - color: $darker-text-color; - - a { - color: $highlight-text-color; - text-decoration: underline; - } - } - - em { - display: inline; - margin: 0; - padding: 0; - font-weight: 700; - background: transparent; - font-family: inherit; - font-size: inherit; - line-height: inherit; - color: lighten($darker-text-color, 10%); - } - - h1 { - font-family: $font-display, sans-serif; - font-size: 26px; - line-height: 30px; - font-weight: 500; - margin-bottom: 20px; - color: $secondary-text-color; - - small { - font-family: $font-sans-serif, sans-serif; - display: block; - font-size: 18px; - font-weight: 400; - color: lighten($darker-text-color, 10%); - } - } - - h2 { - font-family: $font-display, sans-serif; - font-size: 22px; - line-height: 26px; - font-weight: 500; - margin-bottom: 20px; - color: $secondary-text-color; - } - - h3 { - font-family: $font-display, sans-serif; - font-size: 18px; - line-height: 24px; - font-weight: 500; - margin-bottom: 20px; - color: $secondary-text-color; - } - - h4 { - font-family: $font-display, sans-serif; - font-size: 16px; - line-height: 24px; - font-weight: 500; - margin-bottom: 20px; - color: $secondary-text-color; - } - - h5 { - font-family: $font-display, sans-serif; - font-size: 14px; - line-height: 24px; - font-weight: 500; - margin-bottom: 20px; - color: $secondary-text-color; - } - - h6 { - font-family: $font-display, sans-serif; - font-size: 12px; - line-height: 24px; + position: relative; + border-bottom: 1px solid lighten($ui-base-color, 8%); + padding: 1em 1.75em; + padding-left: 3em; font-weight: 500; - margin-bottom: 20px; - color: $secondary-text-color; - } - - ul, - ol { - margin-left: 20px; - - &[type='a'] { - list-style-type: lower-alpha; - } - - &[type='i'] { - list-style-type: lower-roman; - } - } - - ul { - list-style: disc; - } - - ol { - list-style: decimal; - } - - li > ol, - li > ul { - margin-top: 6px; - } - - hr { - width: 100%; - height: 0; - border: 0; - border-bottom: 1px solid rgba($ui-base-lighter-color, 0.6); - margin: 20px 0; - - &.spacer { - height: 1px; - border: 0; - } - } - - &__information, - &__forms { - padding: 20px; - } - - &__call-to-action { - background: $ui-base-color; - border-radius: 4px; - padding: 25px 40px; - overflow: hidden; - box-sizing: border-box; - - .row { - width: 100%; - display: flex; - flex-direction: row-reverse; - flex-wrap: nowrap; - justify-content: space-between; - align-items: center; - } - - .row__information-board { - display: flex; - justify-content: flex-end; - align-items: flex-end; - - .information-board__section { - flex: 1 0 auto; - padding: 0 10px; - } - - @media screen and (max-width: $no-gap-breakpoint) { - width: 100%; - justify-content: space-between; - } - } - - .row__mascot { - flex: 1; - margin: 10px -50px 0 0; - - @media screen and (max-width: $no-gap-breakpoint) { - display: none; - } - } - } - - &__logo { - margin-right: 20px; - - img { - height: 50px; - width: auto; - mix-blend-mode: lighten; - } - } - - &__information { - padding: 45px 40px; - margin-bottom: 10px; - - &:last-child { - margin-bottom: 0; - } - - strong { + counter-increment: list-counter; + + &::before { + content: counter(list-counter); + position: absolute; + left: 0; + top: 50%; + transform: translateY(-50%); + background: $highlight-text-color; + color: $ui-base-color; + border-radius: 50%; + width: 4ch; + height: 4ch; font-weight: 500; - color: lighten($darker-text-color, 10%); - } - - .account { - border-bottom: 0; - padding: 0; - - &__display-name { - align-items: center; - display: flex; - margin-right: 5px; - } - - div.account__display-name { - &:hover { - .display-name strong { - text-decoration: none; - } - } - - .account__avatar { - cursor: default; - } - } - - &__avatar-wrapper { - margin-left: 0; - flex: 0 0 auto; - } - - .display-name { - font-size: 15px; - - &__account { - font-size: 14px; - } - } - } - - @media screen and (max-width: $small-breakpoint) { - .contact { - margin-top: 30px; - } - } - - @media screen and (max-width: $column-breakpoint) { - padding: 25px 20px; - } - } - - &__information, - &__forms, - #mastodon-timeline { - box-sizing: border-box; - background: $ui-base-color; - border-radius: 4px; - box-shadow: 0 0 6px rgba($black, 0.1); - } - - &__mascot { - height: 104px; - position: relative; - left: -40px; - bottom: 25px; - - img { - height: 190px; - width: auto; - } - } - - &__short-description { - .row { display: flex; - flex-wrap: wrap; + justify-content: center; align-items: center; - margin-bottom: 40px; - } - - @media screen and (max-width: $column-breakpoint) { - .row { - margin-bottom: 20px; - } - } - - p a { - color: $secondary-text-color; - } - - h1 { - font-weight: 500; - color: $primary-text-color; - margin-bottom: 0; - - small { - color: $darker-text-color; - - span { - color: $secondary-text-color; - } - } - } - - p:last-child { - margin-bottom: 0; - } - } - - &__hero { - margin-bottom: 10px; - - img { - display: block; - margin: 0; - max-width: 100%; - height: auto; - border-radius: 4px; - } - } - - @media screen and (max-width: 840px) { - .information-board { - .container-alt { - padding-right: 20px; - } - - .panel { - position: static; - margin-top: 20px; - width: 100%; - border-radius: 4px; - - .panel-header { - text-align: center; - } - } - } - } - - @media screen and (max-width: 675px) { - .header-wrapper { - padding-top: 0; - - &.compact { - padding-bottom: 0; - } - - &.compact .hero .heading { - text-align: initial; - } } - .header .container-alt, - .features .container-alt { - display: block; - } - } - - .cta { - margin: 20px; - } -} - -.landing { - margin-bottom: 100px; - - @media screen and (max-width: 738px) { - margin-bottom: 0; - } - - &__brand { - display: flex; - justify-content: center; - align-items: center; - padding: 50px; - - .logo { - fill: $primary-text-color; - height: 52px; - } - - @media screen and (max-width: $no-gap-breakpoint) { - padding: 0; - margin-bottom: 30px; - } - } - - .directory { - margin-top: 30px; - background: transparent; - box-shadow: none; - border-radius: 0; - } - - .hero-widget { - margin-top: 30px; - margin-bottom: 0; - - h4 { - padding: 10px; - text-transform: uppercase; - font-weight: 700; - font-size: 13px; - color: $darker-text-color; - } - - &__text { - border-radius: 0; - padding-bottom: 0; - } - - &__footer { - background: $ui-base-color; - padding: 10px; - border-radius: 0 0 4px 4px; - display: flex; - - &__column { - flex: 1 1 50%; - overflow-x: hidden; - } - } - - .account { - padding: 10px 0; - border-bottom: 0; - - .account__display-name { - display: flex; - align-items: center; - } - } - - &__counters__wrapper { - display: flex; - } - - &__counter { - padding: 10px; - width: 50%; - - strong { - font-family: $font-display, sans-serif; - font-size: 15px; - font-weight: 700; - display: block; - } - - span { - font-size: 14px; - color: $darker-text-color; - } - } - } - - .simple_form .user_agreement .label_input > label { - font-weight: 400; - color: $darker-text-color; - } - - .simple_form p.lead { - color: $darker-text-color; - font-size: 15px; - line-height: 20px; - font-weight: 400; - margin-bottom: 25px; - } - - &__grid { - max-width: 960px; - margin: 0 auto; - display: grid; - grid-template-columns: minmax(0, 50%) minmax(0, 50%); - grid-gap: 30px; - - @media screen and (max-width: 738px) { - grid-template-columns: minmax(0, 100%); - grid-gap: 10px; - - &__column-login { - grid-row: 1; - display: flex; - flex-direction: column; - - .box-widget { - order: 2; - flex: 0 0 auto; - } - - .hero-widget { - margin-top: 0; - margin-bottom: 10px; - order: 1; - flex: 0 0 auto; - } - } - - &__column-registration { - grid-row: 2; - } - - .directory { - margin-top: 10px; - } - } - - @media screen and (max-width: $no-gap-breakpoint) { - grid-gap: 0; - - .hero-widget { - display: block; - margin-bottom: 0; - box-shadow: none; - - &__img, - &__img img, - &__footer { - border-radius: 0; - } - } - - .hero-widget, - .box-widget, - .directory__tag { - border-bottom: 1px solid lighten($ui-base-color, 8%); - } - - .directory { - margin-top: 0; - - &__tag { - margin-bottom: 0; - - & > a, - & > div { - border-radius: 0; - box-shadow: none; - } - - &:last-child { - border-bottom: 0; - } - } - } - } - } -} - -.brand { - position: relative; - text-decoration: none; -} - -.brand__tagline { - display: block; - position: absolute; - bottom: -10px; - left: 50px; - width: 300px; - color: $ui-primary-color; - text-decoration: none; - font-size: 14px; - - @media screen and (max-width: $no-gap-breakpoint) { - position: static; - width: auto; - margin-top: 20px; - color: $dark-text-color; - } -} - -.rules-list { - background: darken($ui-base-color, 2%); - border: 1px solid darken($ui-base-color, 8%); - border-radius: 4px; - padding: 0.5em 2.5em !important; - margin-top: 1.85em !important; - - li { - border-bottom: 1px solid lighten($ui-base-color, 4%); - color: $dark-text-color; - padding: 1em; - &:last-child { border-bottom: 0; } } - - &__text { - color: $primary-text-color; - } } diff --git a/app/javascript/styles/mastodon/admin.scss b/app/javascript/styles/mastodon/admin.scss index 08845123a..2372573d5 100644 --- a/app/javascript/styles/mastodon/admin.scss +++ b/app/javascript/styles/mastodon/admin.scss @@ -31,23 +31,17 @@ $content-width: 840px; &__toggle { display: none; - background: lighten($ui-base-color, 8%); - height: 48px; + background: darken($ui-base-color, 4%); + border-bottom: 1px solid lighten($ui-base-color, 4%); + align-items: center; &__logo { flex: 1 1 auto; a { - display: inline-block; + display: block; padding: 15px; } - - svg { - fill: $primary-text-color; - height: 20px; - position: relative; - bottom: -2px; - } } &__icon { @@ -55,15 +49,27 @@ $content-width: 840px; color: $darker-text-color; text-decoration: none; flex: 0 0 auto; - font-size: 20px; - padding: 15px; - } + font-size: 18px; + padding: 10px; + margin: 5px 10px; + border-radius: 4px; - a { - &:hover, - &:focus, - &:active { - background: lighten($ui-base-color, 12%); + &:focus { + background: $ui-base-color; + } + + .fa-times { + display: none; + } + + &.active { + .fa-times { + display: block; + } + + .fa-bars { + display: none; + } } } } @@ -79,7 +85,7 @@ $content-width: 840px; display: inherit; margin: inherit; width: inherit; - height: 20px; + height: 25px; } @media screen and (max-width: $no-columns-breakpoint) { @@ -188,21 +194,65 @@ $content-width: 840px; padding-top: 30px; } - &-heading { - display: flex; - padding-bottom: 36px; - border-bottom: 1px solid lighten($ui-base-color, 8%); - margin: -15px -15px 40px 0; - flex-wrap: wrap; - align-items: center; - justify-content: space-between; + &__heading { + margin-bottom: 45px; - & > * { - margin-top: 15px; - margin-right: 15px; + &__row { + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: space-between; + margin: -15px -15px 0 0; + + & > * { + margin-top: 15px; + margin-right: 15px; + } + } + + &__tabs { + margin-top: 30px; + width: 100%; + + & > div { + display: flex; + flex-wrap: wrap; + gap: 5px; + } + + a { + font-size: 14px; + display: inline-flex; + align-items: center; + padding: 7px 10px; + border-radius: 4px; + color: $darker-text-color; + text-decoration: none; + font-weight: 500; + gap: 5px; + white-space: nowrap; + + &:hover, + &:focus, + &:active { + background: lighten($ui-base-color, 4%); + } + + &.selected { + font-weight: 700; + color: $primary-text-color; + background: $ui-highlight-color; + + &:hover, + &:focus, + &:active { + background: lighten($ui-highlight-color, 4%); + } + } + } } - &-actions { + &__actions { display: inline-flex; & > :not(:first-child) { @@ -228,11 +278,7 @@ $content-width: 840px; color: $secondary-text-color; font-size: 24px; line-height: 36px; - font-weight: 400; - - @media screen and (max-width: $no-columns-breakpoint) { - font-weight: 700; - } + font-weight: 700; } h3 { @@ -337,6 +383,14 @@ $content-width: 840px; &.visible { display: block; + position: fixed; + z-index: 10; + width: 100%; + height: calc(100vh - 56px); + left: 0; + bottom: 0; + overflow-y: auto; + background: $ui-base-color; } } @@ -437,6 +491,11 @@ body, } } + & > div { + display: flex; + gap: 5px; + } + strong { font-weight: 500; text-transform: uppercase; @@ -1159,7 +1218,7 @@ a.name-tag, path:first-child { fill: rgba($highlight-text-color, 0.25) !important; - fill-opacity: 1 !important; + fill-opacity: 100% !important; } path:last-child { @@ -1718,3 +1777,67 @@ a.sparkline { } } } + +.history { + counter-reset: step 0; + font-size: 15px; + line-height: 22px; + + li { + counter-increment: step 1; + padding-left: 2.5rem; + padding-bottom: 8px; + position: relative; + margin-bottom: 8px; + + &::before { + position: absolute; + content: counter(step); + font-size: 0.625rem; + font-weight: 500; + left: 0; + display: flex; + justify-content: center; + align-items: center; + width: calc(1.375rem + 1px); + height: calc(1.375rem + 1px); + background: $ui-base-color; + border: 1px solid $highlight-text-color; + color: $highlight-text-color; + border-radius: 8px; + } + + &::after { + position: absolute; + content: ""; + width: 1px; + background: $highlight-text-color; + bottom: 0; + top: calc(1.875rem + 1px); + left: 0.6875rem; + } + + &:last-child { + margin-bottom: 0; + + &::after { + display: none; + } + } + } + + &__entry { + h5 { + font-weight: 500; + color: $primary-text-color; + line-height: 25px; + margin-bottom: 16px; + } + + .status { + border: 1px solid lighten($ui-base-color, 4%); + background: $ui-base-color; + border-radius: 4px; + } + } +} diff --git a/app/javascript/styles/mastodon/compact_header.scss b/app/javascript/styles/mastodon/compact_header.scss deleted file mode 100644 index 4980ab5f1..000000000 --- a/app/javascript/styles/mastodon/compact_header.scss +++ /dev/null @@ -1,34 +0,0 @@ -.compact-header { - h1 { - font-size: 24px; - line-height: 28px; - color: $darker-text-color; - font-weight: 500; - margin-bottom: 20px; - padding: 0 10px; - word-wrap: break-word; - - @media screen and (max-width: 740px) { - text-align: center; - padding: 20px 10px 0; - } - - a { - color: inherit; - text-decoration: none; - } - - small { - font-weight: 400; - color: $secondary-text-color; - } - - img { - display: inline-block; - margin-bottom: -5px; - margin-right: 15px; - width: 36px; - height: 36px; - } - } -} diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index b906117db..b57f6802d 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -24,11 +24,16 @@ display: block; font-size: 15px; line-height: 20px; - color: $ui-highlight-color; + color: $highlight-text-color; border: 0; background: transparent; padding: 0; cursor: pointer; + text-decoration: none; + + &--destructive { + color: $error-value-color; + } &:hover, &:active { @@ -84,6 +89,15 @@ cursor: default; } + &.copyable { + transition: background 300ms linear; + } + + &.copied { + background: $valid-value-color; + transition: none; + } + &::-moz-focus-inner { border: 0; } @@ -265,11 +279,12 @@ display: inline-flex; align-items: center; width: auto !important; + padding: 0 4px 0 2px; } &__counter { display: inline-block; - width: 14px; + width: auto; margin-left: 4px; font-size: 12px; font-weight: 500; @@ -353,7 +368,7 @@ } .compose-form { - padding: 10px; + padding: 15px; &__sensitive-button { padding: 10px; @@ -700,7 +715,7 @@ .compose-form__publish-button-wrapper { overflow: hidden; - padding-top: 10px; + padding-top: 15px; } } } @@ -794,7 +809,7 @@ .reply-indicator__content { position: relative; font-size: 15px; - line-height: 20px; + line-height: 22px; word-wrap: break-word; font-weight: 400; overflow: hidden; @@ -941,12 +956,12 @@ .status__content__read-more-button { display: block; font-size: 15px; - line-height: 20px; + line-height: 22px; color: $highlight-text-color; border: 0; background: transparent; padding: 0; - padding-top: 8px; + padding-top: 16px; text-decoration: none; &:hover, @@ -955,15 +970,13 @@ } } -.status__content__edited-label { - display: block; - cursor: default; +.translate-button { + margin-top: 16px; font-size: 15px; - line-height: 20px; - padding: 0; - padding-top: 8px; + line-height: 22px; + display: flex; + justify-content: space-between; color: $dark-text-color; - font-weight: 500; } .status__content__spoiler-link { @@ -1010,11 +1023,6 @@ } } -.status__prepend-icon-wrapper { - left: -26px; - position: absolute; -} - .focusable { &:focus { outline: 0; @@ -1028,19 +1036,11 @@ } .status { - padding: 8px 10px; - padding-left: 68px; - position: relative; + padding: 16px; min-height: 54px; border-bottom: 1px solid lighten($ui-base-color, 8%); cursor: auto; - @supports (-ms-overflow-style: -ms-autohiding-scrollbar) { - // Add margin to avoid Edge auto-hiding scrollbar appearing over content. - // On Edge 16 this is 16px and Edge <=15 it's 12px, so aim for 16px. - padding-right: 26px; // 10px + 16px - } - @keyframes fade { 0% { opacity: 0; } 100% { opacity: 1; } @@ -1049,9 +1049,11 @@ opacity: 1; animation: fade 150ms linear; + .media-gallery, .video-player, - .audio-player { - margin-top: 8px; + .audio-player, + .attachment-list { + margin-top: 16px; } &.light { @@ -1079,7 +1081,7 @@ color: $highlight-text-color; } - a.status__content__spoiler-link { + &__spoiler-link { color: $primary-text-color; background: $ui-primary-color; @@ -1092,7 +1094,16 @@ } } -.status__relative-time, +.status__relative-time { + display: block; + font-size: 15px; + line-height: 22px; + height: 40px; + order: 2; + flex: 0 0 auto; + color: $dark-text-color; +} + .notification__relative_time { color: $dark-text-color; float: right; @@ -1109,13 +1120,36 @@ } .status__info .status__display-name { - display: block; max-width: 100%; - padding-right: 25px; + display: flex; + font-size: 15px; + line-height: 22px; + align-items: center; + gap: 10px; + overflow: hidden; + + .display-name { + bdi { + overflow: hidden; + text-overflow: ellipsis; + } + + &__account { + white-space: nowrap; + display: block; + overflow: hidden; + text-overflow: ellipsis; + } + } } .status__info { font-size: 15px; + margin-bottom: 10px; + display: flex; + align-items: center; + justify-content: space-between; + gap: 10px; } .status-check-box__status { @@ -1154,12 +1188,14 @@ } .status__prepend { - margin-left: 68px; + padding: 16px; + padding-bottom: 0; + display: flex; + gap: 10px; + font-size: 15px; + line-height: 22px; + font-weight: 500; color: $dark-text-color; - padding: 8px 0; - padding-bottom: 2px; - font-size: 14px; - position: relative; .status__display-name strong { color: $dark-text-color; @@ -1173,22 +1209,11 @@ } .status__action-bar { - align-items: center; display: flex; - margin-top: 8px; -} - -.status__action-bar-button { - margin-right: 18px; - - &.icon-button--with-counter { - margin-right: 14px; - } -} - -.status__action-bar-dropdown { - height: 23.15px; - width: 23.15px; + justify-content: space-between; + align-items: center; + gap: 18px; + margin-top: 16px; } .detailed-status__action-bar-dropdown { @@ -1201,7 +1226,7 @@ .detailed-status { background: lighten($ui-base-color, 4%); - padding: 14px 10px; + padding: 16px; &--flex { display: flex; @@ -1231,14 +1256,15 @@ } } + .media-gallery, .video-player, .audio-player { - margin-top: 8px; + margin-top: 16px; } } .detailed-status__meta { - margin-top: 15px; + margin-top: 16px; color: $dark-text-color; font-size: 14px; line-height: 18px; @@ -1300,7 +1326,7 @@ } .account { - padding: 10px; + padding: 16px; border-bottom: 1px solid lighten($ui-base-color, 8%); &.compact { @@ -1314,7 +1340,9 @@ .account__display-name { flex: 1 1 auto; - display: block; + display: flex; + align-items: center; + gap: 10px; color: $darker-text-color; overflow: hidden; text-decoration: none; @@ -1347,12 +1375,7 @@ .account__wrapper { display: flex; -} - -.account__avatar-wrapper { - float: left; - margin-left: 12px; - margin-right: 12px; + gap: 10px; } .account__avatar { @@ -1360,9 +1383,14 @@ display: block; position: relative; - width: 36px; - height: 36px; - background-size: 36px 36px; + overflow: hidden; + + img { + display: block; + width: 100%; + height: 100%; + object-fit: cover; + } &-inline { display: inline-block; @@ -1371,8 +1399,6 @@ } &-composite { - @include avatar-radius; - border-radius: 50%; overflow: hidden; position: relative; @@ -1383,6 +1409,11 @@ box-sizing: border-box; } + .account__avatar { + width: 100% !important; + height: 100% !important; + } + &__label { display: block; position: absolute; @@ -1402,37 +1433,13 @@ a .account__avatar { } .account__avatar-overlay { - @include avatar-size(48px); - position: relative; - &-base { - @include avatar-radius; - @include avatar-size(36px); - - img { - @include avatar-radius; - - width: 100%; - height: 100%; - } - } - &-overlay { - @include avatar-radius; - @include avatar-size(24px); - position: absolute; bottom: 0; right: 0; z-index: 1; - - img { - @include avatar-radius; - - width: 100%; - height: 100%; - } } } @@ -1603,10 +1610,13 @@ a.account__display-name { } .detailed-status__display-name { - color: $secondary-text-color; - display: block; - line-height: 24px; - margin-bottom: 15px; + color: $darker-text-color; + display: flex; + align-items: center; + gap: 10px; + font-size: 15px; + line-height: 22px; + margin-bottom: 16px; overflow: hidden; strong, @@ -1617,31 +1627,13 @@ a.account__display-name { } strong { - font-size: 16px; color: $primary-text-color; } } -.detailed-status__display-avatar { - float: left; - margin-right: 10px; -} - .status__avatar { - height: 48px; - left: 10px; - position: absolute; - top: 10px; - width: 48px; -} - -.status__expand { - width: 68px; - position: absolute; - left: 0; - top: 0; - height: 100%; - cursor: pointer; + width: 46px; + height: 46px; } .muted { @@ -1672,40 +1664,52 @@ a.account__display-name { } .notification__report { - padding: 8px 10px; - padding-left: 68px; - position: relative; + padding: 16px; border-bottom: 1px solid lighten($ui-base-color, 8%); - min-height: 54px; + display: flex; + gap: 10px; + + &__avatar { + flex: 0 0 auto; + } &__details { + flex: 1 1 auto; display: flex; justify-content: space-between; align-items: center; color: $darker-text-color; + gap: 10px; font-size: 15px; line-height: 22px; + white-space: nowrap; + overflow: hidden; + + & > div { + overflow: hidden; + text-overflow: ellipsis; + } strong { font-weight: 500; } } - &__avatar { - position: absolute; - left: 10px; - top: 10px; + &__actions { + flex: 0 0 auto; } } .notification__message { - margin: 0 10px 0 68px; - padding: 8px 0 0; + padding: 16px; + padding-bottom: 0; cursor: default; color: $darker-text-color; font-size: 15px; line-height: 22px; - position: relative; + font-weight: 500; + display: flex; + gap: 10px; .fa { color: $highlight-text-color; @@ -1719,9 +1723,6 @@ a.account__display-name { } .notification__favourite-icon-wrapper { - left: -26px; - position: absolute; - .star-icon { color: $gold-star; } @@ -1755,15 +1756,10 @@ a.account__display-name { text-decoration: none; &:hover { - color: $primary-text-color; text-decoration: underline; } } -.notification__relative_time { - float: right; -} - .display-name { display: block; max-width: 100%; @@ -1776,10 +1772,6 @@ a.account__display-name { font-weight: 500; } -.display-name__account { - font-size: 14px; -} - .status__relative-time, .detailed-status__datetime { &:hover { @@ -1848,11 +1840,12 @@ a.account__display-name { } .navigation-bar { - padding: 10px; + padding: 15px; display: flex; align-items: center; flex-shrink: 0; cursor: default; + gap: 10px; color: $darker-text-color; strong { @@ -1887,9 +1880,7 @@ a.account__display-name { .navigation-bar__profile { flex: 1 1 auto; - margin-left: 8px; line-height: 20px; - margin-top: -1px; overflow: hidden; } @@ -2191,27 +2182,62 @@ a.account__display-name { &__main { box-sizing: border-box; width: 100%; - max-width: 600px; flex: 0 0 auto; display: flex; flex-direction: column; @media screen and (min-width: $no-gap-breakpoint) { padding: 0 10px; + max-width: 600px; } } } } +$ui-header-height: 55px; + +.ui__header { + display: none; + box-sizing: border-box; + height: $ui-header-height; + position: sticky; + top: 0; + z-index: 2; + justify-content: space-between; + align-items: center; + + &__logo { + display: inline-flex; + padding: 15px; + + .logo { + height: $ui-header-height - 30px; + width: auto; + } + } + + &__links { + display: flex; + align-items: center; + gap: 10px; + padding: 0 10px; + + .button { + flex: 0 0 auto; + } + } +} + .tabs-bar__wrapper { background: darken($ui-base-color, 8%); position: sticky; - top: 0; + top: $ui-header-height; z-index: 2; padding-top: 0; @media screen and (min-width: $no-gap-breakpoint) { padding-top: 10px; + top: 0; } .tabs-bar { @@ -2248,7 +2274,8 @@ a.account__display-name { > .scrollable { background: $ui-base-color; - border-radius: 0 0 4px 4px; + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; } } @@ -2418,174 +2445,120 @@ a.account__display-name { padding: 10px 0; padding-top: 0; } +} - @media screen and (min-width: 630px) { - .detailed-status { - padding: 15px; - - .media-gallery, - .video-player, - .audio-player { - margin-top: 15px; - } - } - - .account__header__bar { - padding: 5px 10px; - } +@media screen and (min-width: $no-gap-breakpoint) { + .tabs-bar { + width: 100%; + } - .navigation-bar, - .compose-form { - padding: 15px; - } + .react-swipeable-view-container .columns-area--mobile { + height: calc(100% - 10px) !important; + } - .compose-form .compose-form__publish .compose-form__publish-button-wrapper { - padding-top: 15px; - } + .getting-started__wrapper, + .search { + margin-bottom: 10px; + } - .notification__report { - padding: 15px 15px 15px (48px + 15px * 2); - min-height: 48px + 2px; + .tabs-bar__link.optional { + display: none; + } - &__avatar { - left: 15px; - top: 17px; - } - } + .search-page .search { + display: none; + } - .status { - padding: 15px 15px 15px (48px + 15px * 2); - min-height: 48px + 2px; + .navigation-panel__legal { + display: none; + } +} - &__avatar { - left: 15px; - top: 17px; - } +@media screen and (max-width: $no-gap-breakpoint - 1px) { + $sidebar-width: 285px; - &__content { - padding-top: 5px; - } + .columns-area__panels__main { + width: calc(100% - $sidebar-width); + } - &__prepend { - margin-left: 48px + 15px * 2; - padding-top: 15px; - } + .columns-area__panels { + min-height: calc(100vh - $ui-header-height); + } - &__prepend-icon-wrapper { - left: -32px; - } + .columns-area__panels__pane--navigational { + min-width: $sidebar-width; - .media-gallery, - &__action-bar, - .video-player, - .audio-player { - margin-top: 10px; - } + .columns-area__panels__pane__inner { + width: $sidebar-width; } - .account { - padding: 15px 10px; - - &__header__bio { - margin: 0 -10px; - } + .navigation-panel { + margin: 0; + background: $ui-base-color; + border-left: 1px solid lighten($ui-base-color, 8%); + height: 100vh; } - .notification { - &__message { - margin-left: 48px + 15px * 2; - padding-top: 15px; - } - - &__favourite-icon-wrapper { - left: -32px; - } - - .status { - padding-top: 8px; - } - - .account { - padding-top: 8px; - } + .navigation-panel__sign-in-banner, + .navigation-panel__logo, + .getting-started__trends { + display: none; + } - .account__avatar-wrapper { - margin-left: 17px; - margin-right: 15px; - } + .column-link__icon { + font-size: 18px; } } -} -.floating-action-button { - position: fixed; - display: flex; - justify-content: center; - align-items: center; - width: 3.9375rem; - height: 3.9375rem; - bottom: 1.3125rem; - right: 1.3125rem; - background: darken($ui-highlight-color, 2%); - color: $white; - border-radius: 50%; - font-size: 21px; - line-height: 21px; - text-decoration: none; - box-shadow: 2px 3px 9px rgba($base-shadow-color, 0.4); + .ui__header { + display: flex; + background: $ui-base-color; + border-bottom: 1px solid lighten($ui-base-color, 8%); + } - &:hover, - &:focus, - &:active { - background: $ui-highlight-color; + .column-header, + .column-back-button, + .scrollable, + .error-column { + border-radius: 0 !important; } } -@media screen and (min-width: $no-gap-breakpoint) { - .tabs-bar { - width: 100%; - } +@media screen and (max-width: $no-gap-breakpoint - 285px - 1px) { + $sidebar-width: 55px; - .react-swipeable-view-container .columns-area--mobile { - height: calc(100% - 10px) !important; + .columns-area__panels__main { + width: calc(100% - $sidebar-width); } - .getting-started__wrapper, - .search { - margin-bottom: 10px; - } -} + .columns-area__panels__pane--navigational { + min-width: $sidebar-width; -@media screen and (max-width: 600px + (285px * 1) + (10px * 1)) { - .columns-area__panels__pane--compositional { - display: none; - } + .columns-area__panels__pane__inner { + width: $sidebar-width; + } - .with-fab .scrollable .item-list:last-child { - padding-bottom: 5.25rem; - } -} + .column-link span { + display: none; + } -@media screen and (min-width: 600px + (285px * 1) + (10px * 1)) { - .floating-action-button, - .tabs-bar__link.optional { - display: none; + .list-panel { + display: none; + } } +} - .search-page .search { - display: none; - } +.explore__search-header { + display: none; } -@media screen and (max-width: 600px + (285px * 2) + (10px * 2)) { - .columns-area__panels__pane--navigational { +@media screen and (max-width: $no-gap-breakpoint - 1px) { + .columns-area__panels__pane--compositional { display: none; } -} -@media screen and (min-width: 600px + (285px * 2) + (10px * 2)) { - .tabs-bar { - display: none; + .explore__search-header { + display: flex; } } @@ -2654,7 +2627,7 @@ a.account__display-name { .column-actions { display: flex; - align-items: start; + align-items: flex-start; justify-content: center; padding: 40px; padding-top: 40px; @@ -2716,10 +2689,7 @@ a.account__display-name { } .navigation-bar { - padding-top: 20px; - padding-bottom: 20px; flex: 0 1 48px; - min-height: 20px; } .compose-form { @@ -3065,6 +3035,8 @@ a.account__display-name { font-size: 16px; padding: 15px; text-decoration: none; + overflow: hidden; + white-space: nowrap; &:hover, &:focus, @@ -3153,6 +3125,7 @@ a.account__display-name { padding: 10px; padding-top: 20px; z-index: 1; + font-size: 13px; ul { margin-bottom: 10px; @@ -3164,7 +3137,6 @@ a.account__display-name { p { color: $dark-text-color; - font-size: 13px; margin-bottom: 20px; a { @@ -4180,7 +4152,6 @@ a.status-card.compact:hover { } .empty-column-indicator, -.error-column, .follow_requests-unlocked_explanation { color: $dark-text-color; background: $ui-base-color; @@ -4218,7 +4189,48 @@ a.status-card.compact:hover { } .error-column { + padding: 20px; + background: $ui-base-color; + border-radius: 4px; + display: flex; + flex: 1 1 auto; + align-items: center; + justify-content: center; flex-direction: column; + cursor: default; + + &__image { + width: 70%; + max-width: 350px; + margin-top: -50px; + } + + &__message { + text-align: center; + color: $darker-text-color; + font-size: 15px; + line-height: 22px; + + h1 { + font-size: 28px; + line-height: 33px; + font-weight: 700; + margin-bottom: 15px; + color: $primary-text-color; + } + + p { + max-width: 48ch; + } + + &__actions { + margin-top: 30px; + display: flex; + gap: 10px; + align-items: center; + justify-content: center; + } + } } @keyframes heartbeat { @@ -4677,10 +4689,6 @@ a.status-card.compact:hover { &:focus { background: lighten($ui-base-color, 4%); } - - @media screen and (max-width: 600px) { - font-size: 16px; - } } .search__icon { @@ -4820,6 +4828,7 @@ a.status-card.compact:hover { left: 0; width: 100%; height: 100%; + box-sizing: border-box; display: flex; flex-direction: column; align-items: center; @@ -5175,24 +5184,6 @@ a.status-card.compact:hover { width: 480px; position: relative; flex-direction: column; - - .status__display-name { - display: block; - max-width: 100%; - padding-right: 25px; - } - - .status__avatar { - height: 28px; - left: 10px; - position: absolute; - top: 10px; - width: 48px; - } - - .status__content__spoiler-link { - color: lighten($secondary-text-color, 8%); - } } .actions-modal { @@ -5224,9 +5215,9 @@ a.status-card.compact:hover { .block-modal__action-bar { display: flex; justify-content: space-between; + align-items: center; background: $ui-secondary-color; - padding: 10px; - line-height: 36px; + padding: 15px; & > div { flex: 1 1 auto; @@ -5240,15 +5231,6 @@ a.status-card.compact:hover { } } -.boost-modal__status-header { - font-size: 15px; -} - -.boost-modal__status-time { - float: right; - font-size: 14px; -} - .mute-modal, .block-modal { line-height: 24px; @@ -5860,7 +5842,7 @@ a.status-card.compact:hover { font-size: 14px; border: 1px solid lighten($ui-base-color, 8%); border-radius: 4px; - margin-top: 14px; + margin-top: 16px; overflow: hidden; &__icon { @@ -5906,7 +5888,6 @@ a.status-card.compact:hover { &.compact { border: 0; - margin-top: 4px; .attachment-list__list { padding: 0; @@ -7049,6 +7030,7 @@ noscript { .account__header { overflow: hidden; + background: lighten($ui-base-color, 4%); &.inactive { opacity: 0.5; @@ -7082,8 +7064,7 @@ noscript { &__bar { position: relative; - background: lighten($ui-base-color, 4%); - padding: 5px; + padding: 0 20px; border-bottom: 1px solid lighten($ui-base-color, 12%); .avatar { @@ -7102,12 +7083,13 @@ noscript { &__tabs { display: flex; align-items: flex-start; - padding: 7px 10px; margin-top: -55px; + padding-top: 10px; &__buttons { display: flex; align-items: center; + gap: 8px; padding-top: 55px; overflow: hidden; @@ -7117,18 +7099,11 @@ noscript { box-sizing: content-box; padding: 2px; } - - & > .icon-button { - margin-right: 8px; - } - - .button { - margin: 0 8px; - } } &__name { - padding: 5px 10px; + margin-top: 16px; + margin-bottom: 16px; .account-role { vertical-align: top; @@ -7140,17 +7115,17 @@ noscript { } h1 { - font-size: 16px; - line-height: 24px; + font-size: 17px; + line-height: 22px; color: $primary-text-color; - font-weight: 500; + font-weight: 700; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; small { display: block; - font-size: 14px; + font-size: 15px; color: $darker-text-color; font-weight: 400; overflow: hidden; @@ -7165,34 +7140,41 @@ noscript { } &__bio { - overflow: hidden; - margin: 0 -5px; - .account__header__content { - padding: 20px 15px; - padding-bottom: 5px; color: $primary-text-color; + } + + .account__header__fields { + margin: 0; + margin-top: 16px; + border-radius: 4px; + background: darken($ui-base-color, 4%); + border: 0; - .columns-area--mobile & { - padding-left: 20px; - padding-right: 20px; + dl { + display: block; + padding: 11px 16px; + border-bottom-color: lighten($ui-base-color, 4%); } - } - .account__header__joined { - font-size: 14px; - padding: 5px 15px; - color: $darker-text-color; + dd, + dt { + font-size: 13px; + line-height: 18px; + padding: 0; + text-align: initial; + } - .columns-area--mobile & { - padding-left: 20px; - padding-right: 20px; + dt { + width: auto; + background: transparent; + text-transform: uppercase; + color: $dark-text-color; } - } - .account__header__fields { - margin: 0; - border-top: 1px solid lighten($ui-base-color, 12%); + dd { + color: $darker-text-color; + } a { color: lighten($ui-highlight-color, 8%); @@ -7209,12 +7191,14 @@ noscript { } &__extra { - margin-top: 4px; + margin-top: 16px; &__links { font-size: 14px; color: $darker-text-color; - padding: 10px 0; + margin: 0 -10px; + padding-top: 16px; + padding-bottom: 10px; a { display: inline-block; @@ -7232,17 +7216,10 @@ noscript { } &__account-note { - padding: 15px; - padding-bottom: 10px; color: $primary-text-color; font-size: 14px; font-weight: 400; - border-bottom: 1px solid lighten($ui-base-color, 12%); - - .columns-area--mobile & { - padding-left: 20px; - padding-right: 20px; - } + margin-bottom: 10px; label { display: block; @@ -7301,6 +7278,7 @@ noscript { align-items: center; padding: 15px; border-bottom: 1px solid lighten($ui-base-color, 8%); + gap: 15px; &:last-child { border-bottom: 0; @@ -7342,16 +7320,8 @@ noscript { font-size: 24px; font-weight: 500; text-align: right; - padding-right: 15px; - margin-left: 5px; color: $secondary-text-color; text-decoration: none; - - &__asterisk { - color: $darker-text-color; - font-size: 18px; - vertical-align: super; - } } &__sparkline { @@ -7360,7 +7330,7 @@ noscript { path:first-child { fill: rgba($highlight-text-color, 0.25) !important; - fill-opacity: 1 !important; + fill-opacity: 100% !important; } path:last-child { @@ -7832,10 +7802,9 @@ noscript { } .explore__search-header { - background: $ui-base-color; - display: flex; - align-items: flex-start; + background: darken($ui-base-color, 4%); justify-content: center; + align-items: center; padding: 15px; .search { @@ -7844,14 +7813,8 @@ noscript { } .search__input { - border-radius: 4px; - color: $inverted-text-color; - background: $simple-background-color; + border: 1px solid lighten($ui-base-color, 8%); padding: 10px; - - &::placeholder { - color: $dark-text-color; - } } .search .fa { @@ -8004,11 +7967,13 @@ noscript { &__number { font-weight: 600; color: $primary-text-color; + font-size: 14px; } &__number-label { color: $darker-text-color; font-weight: 500; + font-size: 14px; } h4 { @@ -8031,3 +7996,595 @@ noscript { margin: 10px 0; } } + +.interaction-modal { + max-width: 90vw; + width: 600px; + background: $ui-base-color; + border-radius: 8px; + overflow: hidden; + position: relative; + display: block; + padding: 20px; + + h3 { + font-size: 22px; + line-height: 33px; + font-weight: 700; + text-align: center; + } + + &__icon { + color: $highlight-text-color; + margin: 0 5px; + } + + &__lead { + padding: 20px; + text-align: center; + + h3 { + margin-bottom: 15px; + } + + p { + font-size: 17px; + line-height: 22px; + color: $darker-text-color; + } + } + + &__choices { + display: flex; + + &__choice { + flex: 0 0 auto; + width: 50%; + box-sizing: border-box; + padding: 20px; + + h3 { + margin-bottom: 20px; + } + + p { + color: $darker-text-color; + margin-bottom: 20px; + } + + .button { + margin-bottom: 10px; + + &:last-child { + margin-bottom: 0; + } + } + } + } + + @media screen and (max-width: $no-gap-breakpoint - 1px) { + &__choices { + display: block; + + &__choice { + width: auto; + margin-bottom: 20px; + } + } + } +} + +.copypaste { + display: flex; + align-items: center; + gap: 10px; + + input { + display: block; + font-family: inherit; + background: darken($ui-base-color, 8%); + border: 1px solid $highlight-text-color; + color: $darker-text-color; + border-radius: 4px; + padding: 6px 9px; + line-height: 22px; + font-size: 14px; + transition: border-color 300ms linear; + flex: 1 1 auto; + overflow: hidden; + + &:focus { + outline: 0; + background: darken($ui-base-color, 4%); + } + } + + .button { + flex: 0 0 auto; + transition: background 300ms linear; + } + + &.copied { + input { + border: 1px solid $valid-value-color; + transition: none; + } + + .button { + background: $valid-value-color; + transition: none; + } + } +} + +.privacy-policy { + background: $ui-base-color; + padding: 20px; + + @media screen and (min-width: $no-gap-breakpoint) { + border-radius: 4px; + } + + &__body { + margin-top: 20px; + } +} + +.prose { + color: $secondary-text-color; + font-size: 15px; + line-height: 22px; + + p, + ul, + ol { + margin-top: 1.25em; + margin-bottom: 1.25em; + } + + img { + margin-top: 2em; + margin-bottom: 2em; + } + + video { + margin-top: 2em; + margin-bottom: 2em; + } + + figure { + margin-top: 2em; + margin-bottom: 2em; + + figcaption { + font-size: 0.875em; + line-height: 1.4285714; + margin-top: 0.8571429em; + } + } + + figure > * { + margin-top: 0; + margin-bottom: 0; + } + + h1 { + font-size: 1.5em; + margin-top: 0; + margin-bottom: 1em; + line-height: 1.33; + } + + h2 { + font-size: 1.25em; + margin-top: 1.6em; + margin-bottom: 0.6em; + line-height: 1.6; + } + + h3, + h4, + h5, + h6 { + margin-top: 1.5em; + margin-bottom: 0.5em; + line-height: 1.5; + } + + ol { + counter-reset: list-counter; + } + + li { + margin-top: 0.5em; + margin-bottom: 0.5em; + } + + ol > li { + counter-increment: list-counter; + + &::before { + content: counter(list-counter) "."; + position: absolute; + left: 0; + } + } + + ul > li::before { + content: ""; + position: absolute; + background-color: $darker-text-color; + border-radius: 50%; + width: 0.375em; + height: 0.375em; + top: 0.5em; + left: 0.25em; + } + + ul > li, + ol > li { + position: relative; + padding-left: 1.75em; + } + + & > ul > li p { + margin-top: 0.75em; + margin-bottom: 0.75em; + } + + & > ul > li > *:first-child { + margin-top: 1.25em; + } + + & > ul > li > *:last-child { + margin-bottom: 1.25em; + } + + & > ol > li > *:first-child { + margin-top: 1.25em; + } + + & > ol > li > *:last-child { + margin-bottom: 1.25em; + } + + ul ul, + ul ol, + ol ul, + ol ol { + margin-top: 0.75em; + margin-bottom: 0.75em; + } + + h1, + h2, + h3, + h4, + h5, + h6, + strong, + b { + color: $primary-text-color; + font-weight: 700; + } + + em, + i { + font-style: italic; + } + + a { + color: $highlight-text-color; + text-decoration: underline; + + &:focus, + &:hover, + &:active { + text-decoration: none; + } + } + + code { + font-size: 0.875em; + background: darken($ui-base-color, 8%); + border-radius: 4px; + padding: 0.2em 0.3em; + } + + hr { + border: 0; + border-top: 1px solid lighten($ui-base-color, 4%); + margin-top: 3em; + margin-bottom: 3em; + } + + hr + * { + margin-top: 0; + } + + h2 + * { + margin-top: 0; + } + + h3 + * { + margin-top: 0; + } + + h4 + *, + h5 + *, + h6 + * { + margin-top: 0; + } + + & > :first-child { + margin-top: 0; + } + + & > :last-child { + margin-bottom: 0; + } +} + +.dismissable-banner { + background: $ui-base-color; + border-bottom: 1px solid lighten($ui-base-color, 8%); + display: flex; + align-items: center; + gap: 30px; + + &__message { + flex: 1 1 auto; + padding: 20px 15px; + cursor: default; + font-size: 14px; + line-height: 18px; + color: $primary-text-color; + } + + &__action { + padding: 15px; + flex: 0 0 auto; + display: flex; + align-items: center; + justify-content: center; + } +} + +.image { + position: relative; + overflow: hidden; + + &__preview { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + object-fit: cover; + } + + &.loaded &__preview { + display: none; + } + + img { + display: block; + width: 100%; + height: 100%; + object-fit: cover; + border: 0; + background: transparent; + opacity: 0; + } + + &.loaded img { + opacity: 1; + } +} + +.about { + padding: 20px; + + @media screen and (min-width: $no-gap-breakpoint) { + border-radius: 4px; + } + + &__header { + margin-bottom: 30px; + + &__hero { + width: 100%; + height: auto; + aspect-ratio: 1.9; + background: lighten($ui-base-color, 4%); + border-radius: 8px; + margin-bottom: 30px; + } + + h1, + p { + text-align: center; + } + + h1 { + font-size: 24px; + line-height: 1.5; + font-weight: 700; + margin-bottom: 10px; + } + + p { + font-size: 16px; + line-height: 24px; + font-weight: 400; + color: $darker-text-color; + } + } + + &__meta { + background: lighten($ui-base-color, 4%); + border-radius: 4px; + display: flex; + margin-bottom: 30px; + font-size: 15px; + + &__column { + box-sizing: border-box; + width: 50%; + padding: 20px; + } + + &__divider { + width: 0; + border: 0; + border-style: solid; + border-color: lighten($ui-base-color, 8%); + border-left-width: 1px; + min-height: calc(100% - 60px); + flex: 0 0 auto; + } + + h4 { + font-size: 15px; + text-transform: uppercase; + color: $darker-text-color; + font-weight: 500; + margin-bottom: 20px; + } + + @media screen and (max-width: 600px) { + display: block; + + h4 { + text-align: center; + } + + &__column { + width: 100%; + display: flex; + flex-direction: column; + align-items: center; + } + + &__divider { + min-height: 0; + width: 100%; + border-left-width: 0; + border-top-width: 1px; + } + } + + .layout-multiple-columns & { + display: block; + + h4 { + text-align: center; + } + + &__column { + width: 100%; + display: flex; + flex-direction: column; + align-items: center; + } + + &__divider { + min-height: 0; + width: 100%; + border-left-width: 0; + border-top-width: 1px; + } + } + } + + &__mail { + color: $primary-text-color; + text-decoration: none; + font-weight: 500; + + &:hover, + &:focus, + &:active { + text-decoration: underline; + } + } + + .getting-started__footer { + padding: 0; + margin-top: 60px; + text-align: center; + font-size: 15px; + line-height: 22px; + + @media screen and (min-width: $no-gap-breakpoint) { + display: none; + } + } + + .account { + padding: 0; + border: 0; + } + + .account__avatar-wrapper { + margin-left: 0; + } + + .account__relationship { + display: none; + } + + &__section { + margin-bottom: 10px; + + &__title { + font-size: 17px; + font-weight: 600; + line-height: 22px; + padding: 20px; + border-radius: 4px; + background: lighten($ui-base-color, 4%); + color: $highlight-text-color; + cursor: pointer; + } + + &.active &__title { + border-radius: 4px 4px 0 0; + } + + &__body { + border: 1px solid lighten($ui-base-color, 4%); + border-top: 0; + padding: 20px; + font-size: 15px; + line-height: 22px; + } + } + + &__domain-blocks { + margin-top: 30px; + width: 100%; + border-collapse: collapse; + break-inside: auto; + + th { + text-align: left; + font-weight: 500; + color: $darker-text-color; + } + + thead tr, + tbody tr { + border-bottom: 1px solid lighten($ui-base-color, 8%); + } + + tbody tr:last-child { + border-bottom: 0; + } + + th, + td { + padding: 8px; + } + } +} diff --git a/app/javascript/styles/mastodon/containers.scss b/app/javascript/styles/mastodon/containers.scss index 5703a64e3..b49b93984 100644 --- a/app/javascript/styles/mastodon/containers.scss +++ b/app/javascript/styles/mastodon/containers.scss @@ -9,11 +9,7 @@ } .logo-container { - margin: 100px auto 50px; - - @media screen and (max-width: 500px) { - margin: 40px auto 0; - } + margin: 50px auto; h1 { display: flex; @@ -34,7 +30,6 @@ outline: 0; padding: 12px 16px; line-height: 32px; - font-family: $font-display, sans-serif; font-weight: 500; font-size: 14px; } @@ -109,785 +104,3 @@ margin-left: 10px; } } - -.grid-3 { - display: grid; - grid-gap: 10px; - grid-template-columns: 3fr 1fr; - grid-auto-columns: 25%; - grid-auto-rows: max-content; - - .column-0 { - grid-column: 1 / 3; - grid-row: 1; - } - - .column-1 { - grid-column: 1; - grid-row: 2; - } - - .column-2 { - grid-column: 2; - grid-row: 2; - } - - .column-3 { - grid-column: 1 / 3; - grid-row: 3; - } - - @media screen and (max-width: $no-gap-breakpoint) { - grid-gap: 0; - grid-template-columns: minmax(0, 100%); - - .column-0 { - grid-column: 1; - } - - .column-1 { - grid-column: 1; - grid-row: 3; - } - - .column-2 { - grid-column: 1; - grid-row: 2; - } - - .column-3 { - grid-column: 1; - grid-row: 4; - } - } -} - -.grid-4 { - display: grid; - grid-gap: 10px; - grid-template-columns: repeat(4, minmax(0, 1fr)); - grid-auto-columns: 25%; - grid-auto-rows: max-content; - - .column-0 { - grid-column: 1 / 5; - grid-row: 1; - } - - .column-1 { - grid-column: 1 / 4; - grid-row: 2; - } - - .column-2 { - grid-column: 4; - grid-row: 2; - } - - .column-3 { - grid-column: 2 / 5; - grid-row: 3; - } - - .column-4 { - grid-column: 1; - grid-row: 3; - } - - .landing-page__call-to-action { - min-height: 100%; - } - - .flash-message { - margin-bottom: 10px; - } - - @media screen and (max-width: 738px) { - grid-template-columns: minmax(0, 50%) minmax(0, 50%); - - .landing-page__call-to-action { - padding: 20px; - display: flex; - align-items: center; - justify-content: center; - } - - .row__information-board { - width: 100%; - justify-content: center; - align-items: center; - } - - .row__mascot { - display: none; - } - } - - @media screen and (max-width: $no-gap-breakpoint) { - grid-gap: 0; - grid-template-columns: minmax(0, 100%); - - .column-0 { - grid-column: 1; - } - - .column-1 { - grid-column: 1; - grid-row: 3; - } - - .column-2 { - grid-column: 1; - grid-row: 2; - } - - .column-3 { - grid-column: 1; - grid-row: 5; - } - - .column-4 { - grid-column: 1; - grid-row: 4; - } - } -} - -.public-layout { - @media screen and (max-width: $no-gap-breakpoint) { - padding-top: 48px; - } - - .container { - max-width: 960px; - - @media screen and (max-width: $no-gap-breakpoint) { - padding: 0; - } - } - - .header { - background: lighten($ui-base-color, 8%); - box-shadow: 0 0 15px rgba($base-shadow-color, 0.2); - border-radius: 4px; - height: 48px; - margin: 10px 0; - display: flex; - align-items: stretch; - justify-content: center; - flex-wrap: nowrap; - overflow: hidden; - - @media screen and (max-width: $no-gap-breakpoint) { - position: fixed; - width: 100%; - top: 0; - left: 0; - margin: 0; - border-radius: 0; - box-shadow: none; - z-index: 110; - } - - & > div { - flex: 1 1 33.3%; - min-height: 1px; - } - - .nav-left { - display: flex; - align-items: stretch; - justify-content: flex-start; - flex-wrap: nowrap; - } - - .nav-center { - display: flex; - align-items: stretch; - justify-content: center; - flex-wrap: nowrap; - } - - .nav-right { - display: flex; - align-items: stretch; - justify-content: flex-end; - flex-wrap: nowrap; - } - - .brand { - display: block; - padding: 15px; - - .logo { - display: block; - height: 18px; - width: auto; - position: relative; - bottom: -2px; - fill: $primary-text-color; - - @media screen and (max-width: $no-gap-breakpoint) { - height: 20px; - } - } - - &:hover, - &:focus, - &:active { - background: lighten($ui-base-color, 12%); - } - } - - .nav-link { - display: flex; - align-items: center; - padding: 0 1rem; - font-size: 12px; - font-weight: 500; - text-decoration: none; - color: $darker-text-color; - white-space: nowrap; - text-align: center; - - &:hover, - &:focus, - &:active { - text-decoration: underline; - color: $primary-text-color; - } - - @media screen and (max-width: 550px) { - &.optional { - display: none; - } - } - } - - .nav-button { - background: lighten($ui-base-color, 16%); - margin: 8px; - margin-left: 0; - border-radius: 4px; - - &:hover, - &:focus, - &:active { - text-decoration: none; - background: lighten($ui-base-color, 20%); - } - } - } - - $no-columns-breakpoint: 600px; - - .grid { - display: grid; - grid-gap: 10px; - grid-template-columns: minmax(300px, 3fr) minmax(298px, 1fr); - grid-auto-columns: 25%; - grid-auto-rows: max-content; - - .column-0 { - grid-row: 1; - grid-column: 1; - } - - .column-1 { - grid-row: 1; - grid-column: 2; - } - - @media screen and (max-width: $no-columns-breakpoint) { - grid-template-columns: 100%; - grid-gap: 0; - - .column-1 { - display: none; - } - } - } - - .page-header { - @media screen and (max-width: $no-gap-breakpoint) { - border-bottom: 0; - } - } - - .public-account-header { - overflow: hidden; - margin-bottom: 10px; - box-shadow: 0 0 15px rgba($base-shadow-color, 0.2); - - &.inactive { - opacity: 0.5; - - .public-account-header__image, - .avatar { - filter: grayscale(100%); - } - - .logo-button { - background-color: $secondary-text-color; - } - } - - .logo-button { - padding: 3px 15px; - } - - &__image { - border-radius: 4px 4px 0 0; - overflow: hidden; - height: 300px; - position: relative; - background: darken($ui-base-color, 12%); - - &::after { - content: ""; - display: block; - position: absolute; - width: 100%; - height: 100%; - box-shadow: inset 0 -1px 1px 1px rgba($base-shadow-color, 0.15); - top: 0; - left: 0; - } - - img { - object-fit: cover; - display: block; - width: 100%; - height: 100%; - margin: 0; - border-radius: 4px 4px 0 0; - } - - @media screen and (max-width: 600px) { - height: 200px; - } - } - - &--no-bar { - margin-bottom: 0; - - .public-account-header__image, - .public-account-header__image img { - border-radius: 4px; - - @media screen and (max-width: $no-gap-breakpoint) { - border-radius: 0; - } - } - } - - @media screen and (max-width: $no-gap-breakpoint) { - margin-bottom: 0; - box-shadow: none; - - &__image::after { - display: none; - } - - &__image, - &__image img { - border-radius: 0; - } - } - - &__bar { - position: relative; - margin-top: -80px; - display: flex; - justify-content: flex-start; - - &::before { - content: ""; - display: block; - background: lighten($ui-base-color, 4%); - position: absolute; - bottom: 0; - left: 0; - right: 0; - height: 60px; - border-radius: 0 0 4px 4px; - z-index: -1; - } - - .avatar { - display: block; - width: 120px; - height: 120px; - padding-left: 20px - 4px; - flex: 0 0 auto; - - img { - display: block; - width: 100%; - height: 100%; - margin: 0; - border-radius: 50%; - border: 4px solid lighten($ui-base-color, 4%); - background: darken($ui-base-color, 8%); - } - } - - @media screen and (max-width: 600px) { - margin-top: 0; - background: lighten($ui-base-color, 4%); - border-radius: 0 0 4px 4px; - padding: 5px; - - &::before { - display: none; - } - - .avatar { - width: 48px; - height: 48px; - padding: 7px 0; - padding-left: 10px; - - img { - border: 0; - border-radius: 4px; - } - - @media screen and (max-width: 360px) { - display: none; - } - } - } - - @media screen and (max-width: $no-gap-breakpoint) { - border-radius: 0; - } - - @media screen and (max-width: $no-columns-breakpoint) { - flex-wrap: wrap; - } - } - - &__tabs { - flex: 1 1 auto; - margin-left: 20px; - - &__name { - padding-top: 20px; - padding-bottom: 8px; - - h1 { - font-size: 20px; - line-height: 18px * 1.5; - color: $primary-text-color; - font-weight: 500; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - text-shadow: 1px 1px 1px $base-shadow-color; - - small { - display: block; - font-size: 14px; - color: $primary-text-color; - font-weight: 400; - overflow: hidden; - text-overflow: ellipsis; - } - } - } - - @media screen and (max-width: 600px) { - margin-left: 15px; - display: flex; - justify-content: space-between; - align-items: center; - - &__name { - padding-top: 0; - padding-bottom: 0; - - h1 { - font-size: 16px; - line-height: 24px; - text-shadow: none; - - small { - color: $darker-text-color; - } - } - } - } - - &__tabs { - display: flex; - justify-content: flex-start; - align-items: stretch; - height: 58px; - - .details-counters { - display: flex; - flex-direction: row; - min-width: 300px; - } - - @media screen and (max-width: $no-columns-breakpoint) { - .details-counters { - display: none; - } - } - - .counter { - min-width: 33.3%; - box-sizing: border-box; - flex: 0 0 auto; - color: $darker-text-color; - padding: 10px; - border-right: 1px solid lighten($ui-base-color, 4%); - cursor: default; - text-align: center; - position: relative; - - a { - display: block; - } - - &:last-child { - border-right: 0; - } - - &::after { - display: block; - content: ""; - position: absolute; - bottom: 0; - left: 0; - width: 100%; - border-bottom: 4px solid $ui-primary-color; - opacity: 0.5; - transition: all 400ms ease; - } - - &.active { - &::after { - border-bottom: 4px solid $highlight-text-color; - opacity: 1; - } - - &.inactive::after { - border-bottom-color: $secondary-text-color; - } - } - - &:hover { - &::after { - opacity: 1; - transition-duration: 100ms; - } - } - - a { - text-decoration: none; - color: inherit; - } - - .counter-label { - font-size: 12px; - display: block; - } - - .counter-number { - font-weight: 500; - font-size: 18px; - margin-bottom: 5px; - color: $primary-text-color; - font-family: $font-display, sans-serif; - } - } - - .spacer { - flex: 1 1 auto; - height: 1px; - } - - &__buttons { - padding: 7px 8px; - } - } - } - - &__extra { - display: none; - margin-top: 4px; - - .public-account-bio { - border-radius: 0; - box-shadow: none; - background: transparent; - margin: 0 -5px; - - .account__header__fields { - border-top: 1px solid lighten($ui-base-color, 12%); - } - - .roles { - display: none; - } - } - - &__links { - margin-top: -15px; - font-size: 14px; - color: $darker-text-color; - - a { - display: inline-block; - color: $darker-text-color; - text-decoration: none; - padding: 15px; - font-weight: 500; - - strong { - font-weight: 700; - color: $primary-text-color; - } - } - } - - @media screen and (max-width: $no-columns-breakpoint) { - display: block; - flex: 100%; - } - } - } - - .account__section-headline { - border-radius: 4px 4px 0 0; - - @media screen and (max-width: $no-gap-breakpoint) { - border-radius: 0; - } - } - - .detailed-status__meta { - margin-top: 25px; - } - - .public-account-bio { - background: lighten($ui-base-color, 8%); - box-shadow: 0 0 15px rgba($base-shadow-color, 0.2); - border-radius: 4px; - overflow: hidden; - margin-bottom: 10px; - - @media screen and (max-width: $no-gap-breakpoint) { - box-shadow: none; - margin-bottom: 0; - border-radius: 0; - } - - .account__header__fields { - margin: 0; - border-top: 0; - - a { - color: $highlight-text-color; - } - - dl:first-child .verified { - border-radius: 0 4px 0 0; - } - - .verified a { - color: $valid-value-color; - } - } - - .account__header__content { - padding: 20px; - padding-bottom: 0; - color: $primary-text-color; - } - - &__extra, - .roles { - padding: 20px; - font-size: 14px; - color: $darker-text-color; - } - - .roles { - padding-bottom: 0; - } - } - - .directory__list { - display: grid; - grid-gap: 10px; - grid-template-columns: minmax(0, 50%) minmax(0, 50%); - - .account-card { - display: flex; - flex-direction: column; - } - - @media screen and (max-width: $no-gap-breakpoint) { - display: block; - - .account-card { - margin-bottom: 10px; - display: block; - } - } - } - - .card-grid { - display: flex; - flex-wrap: wrap; - min-width: 100%; - margin: 0 -5px; - - & > div { - box-sizing: border-box; - flex: 1 0 auto; - width: 300px; - padding: 0 5px; - margin-bottom: 10px; - max-width: 33.333%; - - @media screen and (max-width: 900px) { - max-width: 50%; - } - - @media screen and (max-width: 600px) { - max-width: 100%; - } - } - - @media screen and (max-width: $no-gap-breakpoint) { - margin: 0; - border-top: 1px solid lighten($ui-base-color, 8%); - - & > div { - width: 100%; - padding: 0; - margin-bottom: 0; - border-bottom: 1px solid lighten($ui-base-color, 8%); - - &:last-child { - border-bottom: 0; - } - - .card__bar { - background: $ui-base-color; - - &:hover, - &:active, - &:focus { - background: lighten($ui-base-color, 4%); - } - } - } - } - } -} diff --git a/app/javascript/styles/mastodon/dashboard.scss b/app/javascript/styles/mastodon/dashboard.scss index c21fc9eba..f25765d1d 100644 --- a/app/javascript/styles/mastodon/dashboard.scss +++ b/app/javascript/styles/mastodon/dashboard.scss @@ -38,7 +38,6 @@ font-weight: 500; font-size: 24px; color: $primary-text-color; - font-family: $font-display, sans-serif; margin-bottom: 20px; line-height: 30px; } diff --git a/app/javascript/styles/mastodon/emoji_picker.scss b/app/javascript/styles/mastodon/emoji_picker.scss index 24061d2ca..e4ec96d89 100644 --- a/app/javascript/styles/mastodon/emoji_picker.scss +++ b/app/javascript/styles/mastodon/emoji_picker.scss @@ -111,7 +111,7 @@ position: relative; input { - font-size: 14px; + font-size: 16px; font-weight: 400; padding: 7px 9px; padding-right: 25px; diff --git a/app/javascript/styles/mastodon/footer.scss b/app/javascript/styles/mastodon/footer.scss deleted file mode 100644 index 0c3e42033..000000000 --- a/app/javascript/styles/mastodon/footer.scss +++ /dev/null @@ -1,152 +0,0 @@ -.public-layout { - .footer { - text-align: left; - padding-top: 20px; - padding-bottom: 60px; - font-size: 12px; - color: lighten($ui-base-color, 34%); - - @media screen and (max-width: $no-gap-breakpoint) { - padding-left: 20px; - padding-right: 20px; - } - - .grid { - display: grid; - grid-gap: 10px; - grid-template-columns: 1fr 1fr 2fr 1fr 1fr; - - .column-0 { - grid-column: 1; - grid-row: 1; - min-width: 0; - } - - .column-1 { - grid-column: 2; - grid-row: 1; - min-width: 0; - } - - .column-2 { - grid-column: 3; - grid-row: 1; - min-width: 0; - text-align: center; - - h4 a { - color: lighten($ui-base-color, 34%); - } - } - - .column-3 { - grid-column: 4; - grid-row: 1; - min-width: 0; - } - - .column-4 { - grid-column: 5; - grid-row: 1; - min-width: 0; - } - - @media screen and (max-width: 690px) { - grid-template-columns: 1fr 2fr 1fr; - - .column-0, - .column-1 { - grid-column: 1; - } - - .column-1 { - grid-row: 2; - } - - .column-2 { - grid-column: 2; - } - - .column-3, - .column-4 { - grid-column: 3; - } - - .column-4 { - grid-row: 2; - } - } - - @media screen and (max-width: 600px) { - .column-1 { - display: block; - } - } - - @media screen and (max-width: $no-gap-breakpoint) { - .column-0, - .column-1, - .column-3, - .column-4 { - display: none; - } - - .column-2 h4 { - display: none; - } - } - } - - .legal-xs { - display: none; - text-align: center; - padding-top: 20px; - - @media screen and (max-width: $no-gap-breakpoint) { - display: block; - } - } - - h4 { - text-transform: uppercase; - font-weight: 700; - margin-bottom: 8px; - color: $darker-text-color; - - a { - color: inherit; - text-decoration: none; - } - } - - ul a, - .legal-xs a { - text-decoration: none; - color: lighten($ui-base-color, 34%); - - &:hover, - &:active, - &:focus { - text-decoration: underline; - } - } - - .brand { - .logo { - display: block; - height: 36px; - width: auto; - margin: 0 auto; - color: lighten($ui-base-color, 34%); - } - - &:hover, - &:focus, - &:active { - .logo { - color: lighten($ui-base-color, 38%); - } - } - } - } -} diff --git a/app/javascript/styles/mastodon/forms.scss b/app/javascript/styles/mastodon/forms.scss index 990903859..4c731be43 100644 --- a/app/javascript/styles/mastodon/forms.scss +++ b/app/javascript/styles/mastodon/forms.scss @@ -6,9 +6,10 @@ code { } .form-container { - max-width: 400px; + max-width: 450px; padding: 20px; - margin: 0 auto; + padding-bottom: 50px; + margin: 50px auto; } .indicator-icon { @@ -123,10 +124,22 @@ code { } .title { - color: #d9e1e8; - font-size: 20px; - line-height: 28px; - font-weight: 400; + font-size: 28px; + line-height: 33px; + font-weight: 700; + margin-bottom: 15px; + } + + .lead { + font-size: 17px; + line-height: 22px; + color: $secondary-text-color; + margin-bottom: 30px; + } + + .rules-list { + font-size: 17px; + line-height: 22px; margin-bottom: 30px; } @@ -240,7 +253,7 @@ code { & > label { font-family: inherit; - font-size: 16px; + font-size: 14px; color: $primary-text-color; display: block; font-weight: 500; @@ -277,6 +290,20 @@ code { .input:last-child { margin-bottom: 0; } + + &__thumbnail { + display: block; + margin: 0; + margin-bottom: 10px; + max-width: 100%; + height: auto; + border-radius: 4px; + background: url("images/void.png"); + + &:last-child { + margin-bottom: 0; + } + } } .fields-row { @@ -377,6 +404,7 @@ code { input[type="email"], input[type="password"], input[type="url"], + input[type="datetime-local"], textarea { box-sizing: border-box; font-size: 16px; @@ -417,7 +445,8 @@ code { input[type="text"], input[type="number"], input[type="email"], - input[type="password"] { + input[type="password"], + input[type="datetime-local"] { &:focus:invalid:not(:placeholder-shown), &:required:invalid:not(:placeholder-shown) { border-color: lighten($error-red, 12%); @@ -433,6 +462,7 @@ code { input[type="number"], input[type="email"], input[type="password"], + input[type="datetime-local"], textarea, select { border-color: lighten($error-red, 12%); @@ -460,6 +490,11 @@ code { } } + .stacked-actions { + margin-top: 30px; + margin-bottom: 15px; + } + button, .button, .block-button { @@ -511,6 +546,16 @@ code { } } + .button.button-tertiary { + padding: 9px; + + &:hover, + &:focus, + &:active { + padding: 10px; + } + } + select { appearance: none; box-sizing: border-box; @@ -565,41 +610,6 @@ code { } } } - - &__overlay-area { - position: relative; - - &__blurred form { - filter: blur(2px); - } - - &__overlay { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - display: flex; - justify-content: center; - align-items: center; - background: rgba($ui-base-color, 0.65); - border-radius: 4px; - margin-left: -4px; - margin-top: -4px; - padding: 4px; - - &__content { - text-align: center; - - &.rich-formatting { - &, - p { - color: $primary-text-color; - } - } - } - } - } } .block-icon { @@ -870,24 +880,7 @@ code { } } -.table-form { - p { - margin-bottom: 15px; - - strong { - font-weight: 500; - - @each $lang in $cjk-langs { - &:lang(#{$lang}) { - font-weight: 700; - } - } - } - } -} - -.simple_form, -.table-form { +.simple_form { .warning { box-sizing: border-box; background: rgba($error-value-color, 0.5); diff --git a/app/javascript/styles/mastodon/rtl.scss b/app/javascript/styles/mastodon/rtl.scss index 98eb1511c..ccec8e95e 100644 --- a/app/javascript/styles/mastodon/rtl.scss +++ b/app/javascript/styles/mastodon/rtl.scss @@ -53,16 +53,6 @@ body.rtl { right: -26px; } - .landing-page__logo { - margin-right: 0; - margin-left: 20px; - } - - .landing-page .features-list .features-list__row .visual { - margin-left: 0; - margin-right: 15px; - } - .column-link__icon, .column-header__icon { margin-right: 0; @@ -350,44 +340,6 @@ body.rtl { margin-left: 45px; } - .landing-page .header-wrapper .mascot { - right: 60px; - left: auto; - } - - .landing-page__call-to-action .row__information-board { - direction: rtl; - } - - .landing-page .header .hero .floats .float-1 { - left: -120px; - right: auto; - } - - .landing-page .header .hero .floats .float-2 { - left: 210px; - right: auto; - } - - .landing-page .header .hero .floats .float-3 { - left: 110px; - right: auto; - } - - .landing-page .header .links .brand img { - left: 0; - } - - .landing-page .fa-external-link { - padding-right: 5px; - padding-left: 0 !important; - } - - .landing-page .features #mastodon-timeline { - margin-right: 0; - margin-left: 30px; - } - @media screen and (min-width: 631px) { .column, .drawer { @@ -415,32 +367,6 @@ body.rtl { padding-right: 0; } - .public-layout { - .header { - .nav-button { - margin-left: 8px; - margin-right: 0; - } - } - - .public-account-header__tabs { - margin-left: 0; - margin-right: 20px; - } - } - - .landing-page__information { - .account__display-name { - margin-right: 0; - margin-left: 5px; - } - - .account__avatar-wrapper { - margin-left: 12px; - margin-right: 0; - } - } - .card__bar .display-name { margin-left: 0; margin-right: 15px; diff --git a/app/javascript/styles/mastodon/statuses.scss b/app/javascript/styles/mastodon/statuses.scss index a3237a630..ce71d11e4 100644 --- a/app/javascript/styles/mastodon/statuses.scss +++ b/app/javascript/styles/mastodon/statuses.scss @@ -137,8 +137,7 @@ a.button.logo-button { justify-content: center; } -.embed, -.public-layout { +.embed { .status__content[data-spoiler="folded"] { .e-content { display: none; diff --git a/app/javascript/styles/mastodon/variables.scss b/app/javascript/styles/mastodon/variables.scss index be2c900ea..2f6c41d5f 100644 --- a/app/javascript/styles/mastodon/variables.scss +++ b/app/javascript/styles/mastodon/variables.scss @@ -53,7 +53,7 @@ $media-modal-media-max-width: 100%; // put margins on top and bottom of image to avoid the screen covered by image. $media-modal-media-max-height: 80%; -$no-gap-breakpoint: 415px; +$no-gap-breakpoint: 1175px; $font-sans-serif: 'mastodon-font-sans-serif' !default; $font-display: 'mastodon-font-display' !default; diff --git a/app/javascript/styles/mastodon/widgets.scss b/app/javascript/styles/mastodon/widgets.scss index 43284eb48..0e39dc87b 100644 --- a/app/javascript/styles/mastodon/widgets.scss +++ b/app/javascript/styles/mastodon/widgets.scss @@ -112,13 +112,6 @@ } } -.box-widget { - padding: 20px; - border-radius: 4px; - background: $ui-base-color; - box-shadow: 0 0 15px rgba($base-shadow-color, 0.2); -} - .placeholder-widget { padding: 16px; border-radius: 4px; @@ -128,47 +121,6 @@ margin-bottom: 10px; } -.contact-widget { - min-height: 100%; - font-size: 15px; - color: $darker-text-color; - line-height: 20px; - word-wrap: break-word; - font-weight: 400; - padding: 0; - - h4 { - padding: 10px; - text-transform: uppercase; - font-weight: 700; - font-size: 13px; - color: $darker-text-color; - } - - .account { - border-bottom: 0; - padding: 10px 0; - padding-top: 5px; - } - - & > a { - display: inline-block; - padding: 10px; - padding-top: 0; - color: $darker-text-color; - text-decoration: none; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - - &:hover, - &:focus, - &:active { - text-decoration: underline; - } - } -} - .moved-account-widget { padding: 15px; padding-bottom: 20px; @@ -249,37 +201,6 @@ margin-bottom: 10px; } -.page-header { - background: lighten($ui-base-color, 8%); - box-shadow: 0 0 15px rgba($base-shadow-color, 0.2); - border-radius: 4px; - padding: 60px 15px; - text-align: center; - margin: 10px 0; - - h1 { - color: $primary-text-color; - font-size: 36px; - line-height: 1.1; - font-weight: 700; - margin-bottom: 10px; - } - - p { - font-size: 15px; - color: $darker-text-color; - } - - @media screen and (max-width: $no-gap-breakpoint) { - margin-top: 0; - background: lighten($ui-base-color, 4%); - - h1 { - font-size: 24px; - } - } -} - .directory { background: $ui-base-color; border-radius: 4px; @@ -366,34 +287,6 @@ } } -.avatar-stack { - display: flex; - justify-content: flex-end; - - .account__avatar { - flex: 0 0 auto; - width: 36px; - height: 36px; - border-radius: 50%; - position: relative; - margin-left: -10px; - background: darken($ui-base-color, 8%); - border: 2px solid $ui-base-color; - - &:nth-child(1) { - z-index: 1; - } - - &:nth-child(2) { - z-index: 2; - } - - &:nth-child(3) { - z-index: 3; - } - } -} - .accounts-table { width: 100%; @@ -466,8 +359,9 @@ vertical-align: initial !important; } - &__interrelationships { + tbody td.accounts-table__interrelationships { width: 21px; + padding-right: 16px; } .fa { @@ -495,11 +389,7 @@ .moved-account-widget, .memoriam-widget, -.box-widget, -.contact-widget, -.landing-page__information.contact-widget, -.directory, -.page-header { +.directory { @media screen and (max-width: $no-gap-breakpoint) { margin-bottom: 0; box-shadow: none; @@ -507,88 +397,6 @@ } } -$maximum-width: 1235px; -$fluid-breakpoint: $maximum-width + 20px; - -.statuses-grid { - min-height: 600px; - - @media screen and (max-width: 640px) { - width: 100% !important; // Masonry layout is unnecessary at this width - } - - &__item { - width: math.div(960px - 20px, 3); - - @media screen and (max-width: $fluid-breakpoint) { - width: math.div(940px - 20px, 3); - } - - @media screen and (max-width: 640px) { - width: 100%; - } - - @media screen and (max-width: $no-gap-breakpoint) { - width: 100vw; - } - } - - .detailed-status { - border-radius: 4px; - - @media screen and (max-width: $no-gap-breakpoint) { - border-top: 1px solid lighten($ui-base-color, 16%); - } - - &.compact { - .detailed-status__meta { - margin-top: 15px; - } - - .status__content { - font-size: 15px; - line-height: 20px; - - .emojione { - width: 20px; - height: 20px; - margin: -3px 0 0; - } - - .status__content__spoiler-link { - line-height: 20px; - margin: 0; - } - } - - .media-gallery, - .status-card, - .video-player { - margin-top: 15px; - } - } - } -} - -.notice-widget { - margin-bottom: 10px; - color: $darker-text-color; - - p { - margin-bottom: 10px; - - &:last-child { - margin-bottom: 0; - } - } - - a { - font-size: 14px; - line-height: 20px; - } -} - -.notice-widget, .placeholder-widget { a { text-decoration: none; @@ -602,37 +410,3 @@ $fluid-breakpoint: $maximum-width + 20px; } } } - -.table-of-contents { - background: darken($ui-base-color, 4%); - min-height: 100%; - font-size: 14px; - border-radius: 4px; - - li a { - display: block; - font-weight: 500; - padding: 15px; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - text-decoration: none; - color: $primary-text-color; - border-bottom: 1px solid lighten($ui-base-color, 4%); - - &:hover, - &:focus, - &:active { - text-decoration: underline; - } - } - - li:last-child a { - border-bottom: 0; - } - - li ul { - padding-left: 20px; - border-bottom: 1px solid lighten($ui-base-color, 4%); - } -} diff --git a/app/lib/activitypub/activity/add.rb b/app/lib/activitypub/activity/add.rb index 845eeaef7..9e2483983 100644 --- a/app/lib/activitypub/activity/add.rb +++ b/app/lib/activitypub/activity/add.rb @@ -2,12 +2,32 @@ class ActivityPub::Activity::Add < ActivityPub::Activity def perform - return unless @json['target'].present? && value_or_id(@json['target']) == @account.featured_collection_url + return if @json['target'].blank? + case value_or_id(@json['target']) + when @account.featured_collection_url + case @object['type'] + when 'Hashtag' + add_featured_tags + else + add_featured + end + end + end + + private + + def add_featured status = status_from_object return unless !status.nil? && status.account_id == @account.id && !@account.pinned?(status) StatusPin.create!(account: @account, status: status) end + + def add_featured_tags + name = @object['name']&.delete_prefix('#') + + FeaturedTag.create!(account: @account, name: name) if name.present? + end end diff --git a/app/lib/activitypub/activity/remove.rb b/app/lib/activitypub/activity/remove.rb index f523ead9f..f5cbef675 100644 --- a/app/lib/activitypub/activity/remove.rb +++ b/app/lib/activitypub/activity/remove.rb @@ -2,8 +2,22 @@ class ActivityPub::Activity::Remove < ActivityPub::Activity def perform - return unless @json['target'].present? && value_or_id(@json['target']) == @account.featured_collection_url + return if @json['target'].blank? + case value_or_id(@json['target']) + when @account.featured_collection_url + case @object['type'] + when 'Hashtag' + remove_featured_tags + else + remove_featured + end + end + end + + private + + def remove_featured status = status_from_uri(object_uri) return unless !status.nil? && status.account_id == @account.id @@ -11,4 +25,13 @@ class ActivityPub::Activity::Remove < ActivityPub::Activity pin = StatusPin.find_by(account: @account, status: status) pin&.destroy! end + + def remove_featured_tags + name = @object['name']&.delete_prefix('#') + + return if name.blank? + + featured_tag = FeaturedTag.by_name(name).find_by(account: @account) + featured_tag&.destroy! + end end diff --git a/app/lib/feed_manager.rb b/app/lib/feed_manager.rb index 0bc7e254e..9fe9ec346 100644 --- a/app/lib/feed_manager.rb +++ b/app/lib/feed_manager.rb @@ -278,7 +278,7 @@ class FeedManager next if last_status_score < oldest_home_score end - statuses = target_account.statuses.where(visibility: [:public, :unlisted, :private]).includes(:preloadable_poll, :media_attachments, reblog: :account).limit(limit) + statuses = target_account.statuses.where(visibility: [:public, :unlisted, :private]).includes(:preloadable_poll, :media_attachments, :account, reblog: :account).limit(limit) crutches = build_crutches(account.id, statuses) statuses.each do |status| @@ -484,7 +484,7 @@ class FeedManager # @param [Hash] crutches # @return [Boolean] def filter_from_tags?(status, receiver_id, crutches) - receiver_id != status.account_id && (((crutches[:active_mentions][status.id] || []) + [status.account_id]).any? { |target_account_id| crutches[:blocking][target_account_id] || crutches[:muting][target_account_id] } || crutches[:blocked_by][status.account_id] || crutches[:domain_blocking][status.account.domain]) + receiver_id == status.account_id || ((crutches[:active_mentions][status.id] || []) + [status.account_id]).any? { |target_account_id| crutches[:blocking][target_account_id] || crutches[:muting][target_account_id] } || crutches[:blocked_by][status.account_id] || crutches[:domain_blocking][status.account.domain] end # Adds a status to an account's feed, returning true if a status was @@ -605,7 +605,7 @@ class FeedManager crutches[:hiding_reblogs] = Follow.where(account_id: receiver_id, target_account_id: statuses.map { |s| s.account_id if s.reblog? }.compact, show_reblogs: false).pluck(:target_account_id).index_with(true) crutches[:blocking] = Block.where(account_id: receiver_id, target_account_id: check_for_blocks).pluck(:target_account_id).index_with(true) crutches[:muting] = Mute.where(account_id: receiver_id, target_account_id: check_for_blocks).pluck(:target_account_id).index_with(true) - crutches[:domain_blocking] = AccountDomainBlock.where(account_id: receiver_id, domain: statuses.map { |s| s.reblog&.account&.domain }.compact).pluck(:domain).index_with(true) + crutches[:domain_blocking] = AccountDomainBlock.where(account_id: receiver_id, domain: statuses.flat_map { |s| [s.account.domain, s.reblog&.account&.domain] }.compact).pluck(:domain).index_with(true) crutches[:blocked_by] = Block.where(target_account_id: receiver_id, account_id: statuses.map { |s| s.reblog&.account_id }.compact).pluck(:account_id).index_with(true) crutches diff --git a/app/lib/permalink_redirector.rb b/app/lib/permalink_redirector.rb index 6d15f3963..cf1a37625 100644 --- a/app/lib/permalink_redirector.rb +++ b/app/lib/permalink_redirector.rb @@ -8,16 +8,14 @@ class PermalinkRedirector end def redirect_path - if path_segments[0] == 'web' - if path_segments[1].present? && path_segments[1].start_with?('@') && path_segments[2] =~ /\d/ - find_status_url_by_id(path_segments[2]) - elsif path_segments[1].present? && path_segments[1].start_with?('@') - find_account_url_by_name(path_segments[1]) - elsif path_segments[1] == 'statuses' && path_segments[2] =~ /\d/ - find_status_url_by_id(path_segments[2]) - elsif path_segments[1] == 'accounts' && path_segments[2] =~ /\d/ - find_account_url_by_id(path_segments[2]) - end + if path_segments[0].present? && path_segments[0].start_with?('@') && path_segments[1] =~ /\d/ + find_status_url_by_id(path_segments[1]) + elsif path_segments[0].present? && path_segments[0].start_with?('@') + find_account_url_by_name(path_segments[0]) + elsif path_segments[0] == 'statuses' && path_segments[1] =~ /\d/ + find_status_url_by_id(path_segments[1]) + elsif path_segments[0] == 'accounts' && path_segments[1] =~ /\d/ + find_account_url_by_id(path_segments[1]) end end @@ -29,18 +27,12 @@ class PermalinkRedirector def find_status_url_by_id(id) status = Status.find_by(id: id) - - return unless status&.distributable? - - ActivityPub::TagManager.instance.url_for(status) + ActivityPub::TagManager.instance.url_for(status) if status&.distributable? && !status.account.local? end def find_account_url_by_id(id) account = Account.find_by(id: id) - - return unless account - - ActivityPub::TagManager.instance.url_for(account) + ActivityPub::TagManager.instance.url_for(account) if account.present? && !account.local? end def find_account_url_by_name(name) @@ -48,12 +40,6 @@ class PermalinkRedirector domain = nil if TagManager.instance.local_domain?(domain) account = Account.find_remote(username, domain) - return unless account - - ActivityPub::TagManager.instance.url_for(account) - end - - def find_tag_url_by_name(name) - tag_path(CGI.unescape(name)) + ActivityPub::TagManager.instance.url_for(account) if account.present? && !account.local? end end diff --git a/app/lib/translation_service.rb b/app/lib/translation_service.rb index 526e26ae5..285f30939 100644 --- a/app/lib/translation_service.rb +++ b/app/lib/translation_service.rb @@ -17,6 +17,10 @@ class TranslationService end end + def self.configured? + ENV['DEEPL_API_KEY'].present? || ENV['LIBRE_TRANSLATE_ENDPOINT'].present? + end + def translate(_text, _source_language, _target_language) raise NotImplementedError end diff --git a/app/lib/translation_service/deepl.rb b/app/lib/translation_service/deepl.rb index b75b604a8..537fd24c0 100644 --- a/app/lib/translation_service/deepl.rb +++ b/app/lib/translation_service/deepl.rb @@ -46,7 +46,7 @@ class TranslationService::DeepL < TranslationService raise UnexpectedResponseError unless json.is_a?(Hash) - Translation.new(text: json.dig('translations', 0, 'text'), detected_source_language: json.dig('translations', 0, 'detected_source_language')&.downcase) + Translation.new(text: json.dig('translations', 0, 'text'), detected_source_language: json.dig('translations', 0, 'detected_source_language')&.downcase, provider: 'DeepL.com') rescue Oj::ParseError raise UnexpectedResponseError end diff --git a/app/lib/translation_service/libre_translate.rb b/app/lib/translation_service/libre_translate.rb index 8cf26f868..43576e306 100644 --- a/app/lib/translation_service/libre_translate.rb +++ b/app/lib/translation_service/libre_translate.rb @@ -37,7 +37,7 @@ class TranslationService::LibreTranslate < TranslationService raise UnexpectedResponseError unless json.is_a?(Hash) - Translation.new(text: json['translatedText'], detected_source_language: source_language) + Translation.new(text: json['translatedText'], detected_source_language: source_language, provider: 'LibreTranslate') rescue Oj::ParseError raise UnexpectedResponseError end diff --git a/app/lib/translation_service/translation.rb b/app/lib/translation_service/translation.rb index a55b82574..19318c7e9 100644 --- a/app/lib/translation_service/translation.rb +++ b/app/lib/translation_service/translation.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true class TranslationService::Translation < ActiveModelSerializers::Model - attributes :text, :detected_source_language + attributes :text, :detected_source_language, :provider end diff --git a/app/lib/vacuum/media_attachments_vacuum.rb b/app/lib/vacuum/media_attachments_vacuum.rb index 7fb347ce4..7c0a85a9d 100644 --- a/app/lib/vacuum/media_attachments_vacuum.rb +++ b/app/lib/vacuum/media_attachments_vacuum.rb @@ -8,8 +8,8 @@ class Vacuum::MediaAttachmentsVacuum end def perform - vacuum_cached_files! if retention_period? vacuum_orphaned_records! + vacuum_cached_files! if retention_period? end private diff --git a/app/lib/vacuum/preview_cards_vacuum.rb b/app/lib/vacuum/preview_cards_vacuum.rb index 84ef100ed..14fdeda1c 100644 --- a/app/lib/vacuum/preview_cards_vacuum.rb +++ b/app/lib/vacuum/preview_cards_vacuum.rb @@ -9,7 +9,6 @@ class Vacuum::PreviewCardsVacuum def perform vacuum_cached_images! if retention_period? - vacuum_orphaned_records! end private @@ -21,18 +20,10 @@ class Vacuum::PreviewCardsVacuum end end - def vacuum_orphaned_records! - orphaned_preview_cards.in_batches.destroy_all - end - def preview_cards_past_retention_period PreviewCard.cached.where(PreviewCard.arel_table[:updated_at].lt(@retention_period.ago)) end - def orphaned_preview_cards - PreviewCard.where('NOT EXISTS (SELECT 1 FROM preview_cards_statuses WHERE preview_cards_statuses.preview_card_id = preview_cards.id)').where(PreviewCard.arel_table[:created_at].lt(TTL.ago)) - end - def retention_period? @retention_period.present? end diff --git a/app/mailers/admin_mailer.rb b/app/mailers/admin_mailer.rb index f416977d8..bc6d87ae6 100644 --- a/app/mailers/admin_mailer.rb +++ b/app/mailers/admin_mailer.rb @@ -4,6 +4,7 @@ class AdminMailer < ApplicationMailer layout 'plain_mailer' helper :accounts + helper :languages def new_report(recipient, report) @report = report @@ -37,11 +38,8 @@ class AdminMailer < ApplicationMailer def new_trends(recipient, links, tags, statuses) @links = links - @lowest_trending_link = Trends.links.query.allowed.limit(Trends.links.options[:review_threshold]).last @tags = tags - @lowest_trending_tag = Trends.tags.query.allowed.limit(Trends.tags.options[:review_threshold]).last @statuses = statuses - @lowest_trending_status = Trends.statuses.query.allowed.limit(Trends.statuses.options[:review_threshold]).last @me = recipient @instance = Rails.configuration.x.local_domain diff --git a/app/models/account.rb b/app/models/account.rb index f75750838..8ff4e5951 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -138,6 +138,7 @@ class Account < ApplicationRecord :role, :locale, :shows_application?, + :prefers_noindex?, to: :user, prefix: true, allow_nil: true @@ -194,10 +195,6 @@ class Account < ApplicationRecord "acct:#{local_username_and_domain}" end - def searchable? - !(suspended? || moved?) && (!local? || (approved? && confirmed?)) - end - def possibly_stale? last_webfingered_at.nil? || last_webfingered_at <= 1.day.ago end @@ -446,7 +443,12 @@ class Account < ApplicationRecord class << self DISALLOWED_TSQUERY_CHARACTERS = /['?\\:‘’]/.freeze - TEXTSEARCH = "(setweight(to_tsvector('simple', accounts.display_name), 'A') || setweight(to_tsvector('simple', accounts.username), 'B') || setweight(to_tsvector('simple', coalesce(accounts.domain, '')), 'C'))" + TEXTSEARCH = "(setweight(to_tsvector('simple', accounts.display_name), 'A') || setweight(to_tsvector('simple', accounts.username), 'A') || setweight(to_tsvector('simple', coalesce(accounts.domain, '')), 'C'))" + + REPUTATION_SCORE_FUNCTION = '(greatest(0, coalesce(s.followers_count, 0)) / (greatest(0, coalesce(s.following_count, 0)) + 1.0))' + FOLLOWERS_SCORE_FUNCTION = 'log(greatest(0, coalesce(s.followers_count, 0)) + 2)' + TIME_DISTANCE_FUNCTION = '(case when s.last_status_at is null then 0 else exp(-1.0 * ((greatest(0, abs(extract(DAY FROM age(s.last_status_at))) - 30.0)^2) / (2.0 * ((-1.0 * 30^2) / (2.0 * ln(0.3)))))) end)' + BOOST = "((#{REPUTATION_SCORE_FUNCTION} + #{FOLLOWERS_SCORE_FUNCTION} + #{TIME_DISTANCE_FUNCTION}) / 3.0)" def readonly_attributes super - %w(statuses_count following_count followers_count) @@ -463,9 +465,10 @@ class Account < ApplicationRecord sql = <<-SQL.squish SELECT accounts.*, - ts_rank_cd(#{TEXTSEARCH}, to_tsquery('simple', :tsquery), 32) AS rank + #{BOOST} * ts_rank_cd(#{TEXTSEARCH}, to_tsquery('simple', :tsquery), 32) AS rank FROM accounts LEFT JOIN users ON accounts.id = users.account_id + LEFT JOIN account_stats AS s ON accounts.id = s.account_id WHERE to_tsquery('simple', :tsquery) @@ #{TEXTSEARCH} AND accounts.suspended_at IS NULL AND accounts.moved_to_account_id IS NULL @@ -527,14 +530,15 @@ class Account < ApplicationRecord ) SELECT accounts.*, - (count(f.id) + 1) * ts_rank_cd(#{TEXTSEARCH}, to_tsquery('simple', :tsquery), 32) AS rank + (count(f.id) + 1) * #{BOOST} * ts_rank_cd(#{TEXTSEARCH}, to_tsquery('simple', :tsquery), 32) AS rank FROM accounts LEFT OUTER JOIN follows AS f ON (accounts.id = f.account_id AND f.target_account_id = :id) + LEFT JOIN account_stats AS s ON accounts.id = s.account_id WHERE accounts.id IN (SELECT * FROM first_degree) AND to_tsquery('simple', :tsquery) @@ #{TEXTSEARCH} AND accounts.suspended_at IS NULL AND accounts.moved_to_account_id IS NULL - GROUP BY accounts.id + GROUP BY accounts.id, s.id ORDER BY rank DESC LIMIT :limit OFFSET :offset SQL @@ -542,15 +546,16 @@ class Account < ApplicationRecord <<-SQL.squish SELECT accounts.*, - (count(f.id) + 1) * ts_rank_cd(#{TEXTSEARCH}, to_tsquery('simple', :tsquery), 32) AS rank + (count(f.id) + 1) * #{BOOST} * ts_rank_cd(#{TEXTSEARCH}, to_tsquery('simple', :tsquery), 32) AS rank FROM accounts LEFT OUTER JOIN follows AS f ON (accounts.id = f.account_id AND f.target_account_id = :id) OR (accounts.id = f.target_account_id AND f.account_id = :id) LEFT JOIN users ON accounts.id = users.account_id + LEFT JOIN account_stats AS s ON accounts.id = s.account_id WHERE to_tsquery('simple', :tsquery) @@ #{TEXTSEARCH} AND accounts.suspended_at IS NULL AND accounts.moved_to_account_id IS NULL AND (accounts.domain IS NOT NULL OR (users.approved = TRUE AND users.confirmed_at IS NOT NULL)) - GROUP BY accounts.id + GROUP BY accounts.id, s.id ORDER BY rank DESC LIMIT :limit OFFSET :offset SQL diff --git a/app/models/admin/account_action.rb b/app/models/admin/account_action.rb index aed3bc0c7..bce0d6e17 100644 --- a/app/models/admin/account_action.rb +++ b/app/models/admin/account_action.rb @@ -25,6 +25,8 @@ class Admin::AccountAction alias send_email_notification? send_email_notification alias include_statuses? include_statuses + validates :type, :target_account, :current_account, presence: true + def initialize(attributes = {}) @send_email_notification = true @include_statuses = true @@ -41,13 +43,15 @@ class Admin::AccountAction end def save! + raise ActiveRecord::RecordInvalid, self unless valid? + ApplicationRecord.transaction do process_action! process_strike! + process_reports! end process_email! - process_reports! process_queue! end @@ -106,9 +110,8 @@ class Admin::AccountAction # Otherwise, we will mark all unresolved reports about # the account as resolved. - reports.each { |report| authorize(report, :update?) } - reports.each do |report| + authorize(report, :update?) log_action(:resolve, report) report.resolve!(current_account) end diff --git a/app/models/admin/status_batch_action.rb b/app/models/admin/status_batch_action.rb index 7bf6fa6da..0ec4fef82 100644 --- a/app/models/admin/status_batch_action.rb +++ b/app/models/admin/status_batch_action.rb @@ -40,7 +40,7 @@ class Admin::StatusBatchAction end def handle_delete! - statuses.each { |status| authorize(status, :destroy?) } + statuses.each { |status| authorize([:admin, status], :destroy?) } ApplicationRecord.transaction do statuses.each do |status| @@ -75,7 +75,7 @@ class Admin::StatusBatchAction statuses.includes(:media_attachments, :preview_cards).find_each do |status| next unless status.with_media? || status.with_preview_card? - authorize(status, :update?) + authorize([:admin, status], :update?) if target_account.local? UpdateStatusService.new.call(status, representative_account.id, sensitive: true) diff --git a/app/models/admin/status_filter.rb b/app/models/admin/status_filter.rb index 4fba612a6..d7a16f760 100644 --- a/app/models/admin/status_filter.rb +++ b/app/models/admin/status_filter.rb @@ -3,7 +3,6 @@ class Admin::StatusFilter KEYS = %i( media - id report_id ).freeze @@ -28,12 +27,10 @@ class Admin::StatusFilter private - def scope_for(key, value) + def scope_for(key, _value) case key.to_s when 'media' Status.joins(:media_attachments).merge(@account.media_attachments.reorder(nil)).group(:id).reorder('statuses.id desc') - when 'id' - Status.where(id: value) else raise "Unknown filter: #{key}" end diff --git a/app/models/announcement.rb b/app/models/announcement.rb index bedced9de..4b2cb4c6d 100644 --- a/app/models/announcement.rb +++ b/app/models/announcement.rb @@ -31,7 +31,6 @@ class Announcement < ApplicationRecord validates :starts_at, presence: true, if: -> { ends_at.present? } validates :ends_at, presence: true, if: -> { starts_at.present? } - before_validation :set_all_day before_validation :set_published, on: :create def to_log_human_identifier @@ -89,10 +88,6 @@ class Announcement < ApplicationRecord private - def set_all_day - self.all_day = false if starts_at.blank? || ends_at.blank? - end - def set_published return unless scheduled_at.blank? || scheduled_at.past? diff --git a/app/models/domain_block.rb b/app/models/domain_block.rb index b08687787..8e298ac9d 100644 --- a/app/models/domain_block.rb +++ b/app/models/domain_block.rb @@ -28,8 +28,9 @@ class DomainBlock < ApplicationRecord delegate :count, to: :accounts, prefix: true scope :matches_domain, ->(value) { where(arel_table[:domain].matches("%#{value}%")) } - scope :with_user_facing_limitations, -> { where(severity: [:silence, :suspend]).or(where(reject_media: true)) } - scope :by_severity, -> { order(Arel.sql('(CASE severity WHEN 0 THEN 1 WHEN 1 THEN 2 WHEN 2 THEN 0 END), reject_media, domain')) } + scope :with_user_facing_limitations, -> { where(severity: [:silence, :suspend]) } + scope :with_limitations, -> { where(severity: [:silence, :suspend]).or(where(reject_media: true)) } + scope :by_severity, -> { order(Arel.sql('(CASE severity WHEN 0 THEN 1 WHEN 1 THEN 2 WHEN 2 THEN 0 END), domain')) } def to_log_human_identifier domain diff --git a/app/models/extended_description.rb b/app/models/extended_description.rb new file mode 100644 index 000000000..6e5c0d1b6 --- /dev/null +++ b/app/models/extended_description.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +class ExtendedDescription < ActiveModelSerializers::Model + attributes :updated_at, :text + + def self.current + custom = Setting.find_by(var: 'site_extended_description') + + if custom&.value.present? + new(text: custom.value, updated_at: custom.updated_at) + else + new + end + end +end diff --git a/app/models/featured_tag.rb b/app/models/featured_tag.rb index 201ce75f5..d4ed74302 100644 --- a/app/models/featured_tag.rb +++ b/app/models/featured_tag.rb @@ -19,13 +19,23 @@ class FeaturedTag < ApplicationRecord validate :validate_tag_name, on: :create validate :validate_featured_tags_limit, on: :create + before_validation :strip_name + before_create :set_tag before_create :reset_data + scope :by_name, ->(name) { joins(:tag).where(tag: { name: HashtagNormalizer.new.normalize(name) }) } + delegate :display_name, to: :tag attr_writer :name + LIMIT = 10 + + def sign? + true + end + def name tag_id.present? ? tag.name : @name end @@ -40,6 +50,12 @@ class FeaturedTag < ApplicationRecord private + def strip_name + return unless defined?(@name) + + @name = @name&.strip&.gsub(/\A#/, '') + end + def set_tag self.tag = Tag.find_or_create_by_names(@name)&.first end @@ -50,11 +66,12 @@ class FeaturedTag < ApplicationRecord end def validate_featured_tags_limit - errors.add(:base, I18n.t('featured_tags.errors.limit')) if account.featured_tags.count >= 10 + errors.add(:base, I18n.t('featured_tags.errors.limit')) if account.featured_tags.count >= LIMIT end def validate_tag_name errors.add(:name, :blank) if @name.blank? errors.add(:name, :invalid) unless @name.match?(/\A(#{Tag::HASHTAG_NAME_RE})\z/i) + errors.add(:name, :taken) if FeaturedTag.by_name(@name).where(account_id: account_id).exists? end end diff --git a/app/models/form/admin_settings.rb b/app/models/form/admin_settings.rb index 68c98d43f..b53a82db2 100644 --- a/app/models/form/admin_settings.rb +++ b/app/models/form/admin_settings.rb @@ -8,26 +8,22 @@ class Form::AdminSettings site_contact_email site_title site_short_description - site_description site_extended_description site_terms registrations_mode closed_registrations_message - open_deletion timeline_preview bootstrap_timeline_accounts flavour skin activity_api_enabled peers_api_enabled - show_known_fediverse_at_about_page preview_sensitive_media custom_css profile_directory hide_followers_count flavour_and_skin thumbnail - hero mascot show_reblogs_in_public_timelines show_replies_in_public_timelines @@ -45,12 +41,16 @@ class Form::AdminSettings backups_retention_period ).freeze + INTEGER_KEYS = %i( + media_cache_retention_period + content_cache_retention_period + backups_retention_period + ).freeze + BOOLEAN_KEYS = %i( - open_deletion timeline_preview activity_api_enabled peers_api_enabled - show_known_fediverse_at_about_page preview_sensitive_media profile_directory hide_followers_count @@ -66,7 +66,6 @@ class Form::AdminSettings UPLOAD_KEYS = %i( thumbnail - hero mascot ).freeze @@ -76,34 +75,49 @@ class Form::AdminSettings attr_accessor(*KEYS) - validates :site_short_description, :site_description, html: { wrap_with: :p } - validates :site_extended_description, :site_terms, :closed_registrations_message, html: true - validates :registrations_mode, inclusion: { in: %w(open approved none) } - validates :site_contact_email, :site_contact_username, presence: true - validates :site_contact_username, existing_username: true - validates :bootstrap_timeline_accounts, existing_username: { multiple: true } - validates :show_domain_blocks, inclusion: { in: %w(disabled users all) } - validates :show_domain_blocks_rationale, inclusion: { in: %w(disabled users all) } - validates :media_cache_retention_period, :content_cache_retention_period, :backups_retention_period, numericality: { only_integer: true }, allow_blank: true - - def initialize(_attributes = {}) - super - initialize_attributes + validates :registrations_mode, inclusion: { in: %w(open approved none) }, if: -> { defined?(@registrations_mode) } + validates :site_contact_email, :site_contact_username, presence: true, if: -> { defined?(@site_contact_username) || defined?(@site_contact_email) } + validates :site_contact_username, existing_username: true, if: -> { defined?(@site_contact_username) } + validates :bootstrap_timeline_accounts, existing_username: { multiple: true }, if: -> { defined?(@bootstrap_timeline_accounts) } + validates :show_domain_blocks, inclusion: { in: %w(disabled users all) }, if: -> { defined?(@show_domain_blocks) } + validates :show_domain_blocks_rationale, inclusion: { in: %w(disabled users all) }, if: -> { defined?(@show_domain_blocks_rationale) } + validates :media_cache_retention_period, :content_cache_retention_period, :backups_retention_period, numericality: { only_integer: true }, allow_blank: true, if: -> { defined?(@media_cache_retention_period) || defined?(@content_cache_retention_period) || defined?(@backups_retention_period) } + validates :site_short_description, length: { maximum: 200 }, if: -> { defined?(@site_short_description) } + + KEYS.each do |key| + define_method(key) do + return instance_variable_get("@#{key}") if instance_variable_defined?("@#{key}") + + stored_value = begin + if UPLOAD_KEYS.include?(key) + SiteUpload.where(var: key).first_or_initialize(var: key) + else + Setting.public_send(key) + end + end + + instance_variable_set("@#{key}", stored_value) + end + end + + UPLOAD_KEYS.each do |key| + define_method("#{key}=") do |file| + value = public_send(key) + value.file = file + end end def save return false unless valid? KEYS.each do |key| - next if PSEUDO_KEYS.include?(key) - value = instance_variable_get("@#{key}") + next if PSEUDO_KEYS.include?(key) || !instance_variable_defined?("@#{key}") - if UPLOAD_KEYS.include?(key) && !value.nil? - upload = SiteUpload.where(var: key).first_or_initialize(var: key) - upload.update(file: value) + if UPLOAD_KEYS.include?(key) + public_send(key).save else setting = Setting.where(var: key).first_or_initialize(var: key) - setting.update(value: typecast_value(key, value)) + setting.update(value: typecast_value(key, instance_variable_get("@#{key}"))) end end end @@ -118,16 +132,11 @@ class Form::AdminSettings private - def initialize_attributes - KEYS.each do |key| - next if PSEUDO_KEYS.include?(key) - instance_variable_set("@#{key}", Setting.public_send(key)) if instance_variable_get("@#{key}").nil? - end - end - def typecast_value(key, value) if BOOLEAN_KEYS.include?(key) value == '1' + elsif INTEGER_KEYS.include?(key) + value.blank? ? value : Integer(value) else value end diff --git a/app/models/form/redirect.rb b/app/models/form/redirect.rb index 19ee9faed..795fdd057 100644 --- a/app/models/form/redirect.rb +++ b/app/models/form/redirect.rb @@ -31,7 +31,7 @@ class Form::Redirect private def set_target_account - @target_account = ResolveAccountService.new.call(acct) + @target_account = ResolveAccountService.new.call(acct, skip_cache: true) rescue Webfinger::Error, HTTP::Error, OpenSSL::SSL::SSLError, Mastodon::Error # Validation will take care of it end diff --git a/app/models/ip_block.rb b/app/models/ip_block.rb index 8666f4248..31343f0e1 100644 --- a/app/models/ip_block.rb +++ b/app/models/ip_block.rb @@ -25,6 +25,7 @@ class IpBlock < ApplicationRecord } validates :ip, :severity, presence: true + validates :ip, uniqueness: true after_commit :reset_cache diff --git a/app/models/preview_card.rb b/app/models/preview_card.rb index c49c51a1b..b5d3f9c8f 100644 --- a/app/models/preview_card.rb +++ b/app/models/preview_card.rb @@ -48,6 +48,7 @@ class PreviewCard < ApplicationRecord enum link_type: [:unknown, :article] has_and_belongs_to_many :statuses + has_one :trend, class_name: 'PreviewCardTrend', inverse_of: :preview_card, dependent: :destroy has_attached_file :image, processors: [:thumbnail, :blurhash_transcoder], styles: ->(f) { image_styles(f) }, convert_options: { all: '-quality 80 -strip' }, validate_media_type: false diff --git a/app/models/preview_card_trend.rb b/app/models/preview_card_trend.rb new file mode 100644 index 000000000..018400dfa --- /dev/null +++ b/app/models/preview_card_trend.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +# == Schema Information +# +# Table name: preview_card_trends +# +# id :bigint(8) not null, primary key +# preview_card_id :bigint(8) not null +# score :float default(0.0), not null +# rank :integer default(0), not null +# allowed :boolean default(FALSE), not null +# language :string +# +class PreviewCardTrend < ApplicationRecord + belongs_to :preview_card + scope :allowed, -> { where(allowed: true) } +end diff --git a/app/models/privacy_policy.rb b/app/models/privacy_policy.rb new file mode 100644 index 000000000..36cbf1882 --- /dev/null +++ b/app/models/privacy_policy.rb @@ -0,0 +1,77 @@ +# frozen_string_literal: true + +class PrivacyPolicy < ActiveModelSerializers::Model + DEFAULT_PRIVACY_POLICY = <<~TXT + This privacy policy describes how %{domain} ("%{domain}", "we", "us") collects, protects and uses the personally identifiable information you may provide through the %{domain} website or its API. The policy also describes the choices available to you regarding our use of your personal information and how you can access and update this information. This policy does not apply to the practices of companies that %{domain} does not own or control, or to individuals that %{domain} does not employ or manage. + + # What information do we collect? + + - **Basic account information**: If you register on this server, you may be asked to enter a username, an e-mail address and a password. You may also enter additional profile information such as a display name and biography, and upload a profile picture and header image. The username, display name, biography, profile picture and header image are always listed publicly. + - **Posts, following and other public information**: The list of people you follow is listed publicly, the same is true for your followers. When you submit a message, the date and time is stored as well as the application you submitted the message from. Messages may contain media attachments, such as pictures and videos. Public and unlisted posts are available publicly. When you feature a post on your profile, that is also publicly available information. Your posts are delivered to your followers, in some cases it means they are delivered to different servers and copies are stored there. When you delete posts, this is likewise delivered to your followers. The action of reblogging or favouriting another post is always public. + - **Direct and followers-only posts**: All posts are stored and processed on the server. Followers-only posts are delivered to your followers and users who are mentioned in them, and direct posts are delivered only to users mentioned in them. In some cases it means they are delivered to different servers and copies are stored there. We make a good faith effort to limit the access to those posts only to authorized persons, but other servers may fail to do so. Therefore it's important to review servers your followers belong to. You may toggle an option to approve and reject new followers manually in the settings. **Please keep in mind that the operators of the server and any receiving server may view such messages**, and that recipients may screenshot, copy or otherwise re-share them. **Do not share any sensitive information over Mastodon.** + - **IPs and other metadata**: When you log in, we record the IP address you log in from, as well as the name of your browser application. All the logged in sessions are available for your review and revocation in the settings. The latest IP address used is stored for up to 12 months. We also may retain server logs which include the IP address of every request to our server. + + # What do we use your information for? + + Any of the information we collect from you may be used in the following ways: + + - To provide the core functionality of Mastodon. You can only interact with other people's content and post your own content when you are logged in. For example, you may follow other people to view their combined posts in your own personalized home timeline. + - To aid moderation of the community, for example comparing your IP address with other known ones to determine ban evasion or other violations. + - The email address you provide may be used to send you information, notifications about other people interacting with your content or sending you messages, and to respond to inquiries, and/or other requests or questions. + + # How do we protect your information? + + We implement a variety of security measures to maintain the safety of your personal information when you enter, submit, or access your personal information. Among other things, your browser session, as well as the traffic between your applications and the API, are secured with SSL, and your password is hashed using a strong one-way algorithm. You may enable two-factor authentication to further secure access to your account. + + # What is our data retention policy? + + We will make a good faith effort to: + + - Retain server logs containing the IP address of all requests to this server, in so far as such logs are kept, no more than 90 days. + - Retain the IP addresses associated with registered users no more than 12 months. + + You can request and download an archive of your content, including your posts, media attachments, profile picture, and header image. + + You may irreversibly delete your account at any time. + + # Do we use cookies? + + Yes. Cookies are small files that a site or its service provider transfers to your computer's hard drive through your Web browser (if you allow). These cookies enable the site to recognize your browser and, if you have a registered account, associate it with your registered account. + + We use cookies to understand and save your preferences for future visits. + + # Do we disclose any information to outside parties? + + We do not sell, trade, or otherwise transfer to outside parties your personally identifiable information. This does not include trusted third parties who assist us in operating our site, conducting our business, or servicing you, so long as those parties agree to keep this information confidential. We may also release your information when we believe release is appropriate to comply with the law, enforce our site policies, or protect ours or others rights, property, or safety. + + Your public content may be downloaded by other servers in the network. Your public and followers-only posts are delivered to the servers where your followers reside, and direct messages are delivered to the servers of the recipients, in so far as those followers or recipients reside on a different server than this. + + When you authorize an application to use your account, depending on the scope of permissions you approve, it may access your public profile information, your following list, your followers, your lists, all your posts, and your favourites. Applications can never access your e-mail address or password. + + # Site usage by children + + If this server is in the EU or the EEA: Our site, products and services are all directed to people who are at least 16 years old. If you are under the age of 16, per the requirements of the GDPR (General Data Protection Regulation) do not use this site. + + If this server is in the USA: Our site, products and services are all directed to people who are at least 13 years old. If you are under the age of 13, per the requirements of COPPA (Children's Online Privacy Protection Act) do not use this site. + + Law requirements can be different if this server is in another jurisdiction. + + ___ + + This document is CC-BY-SA. Originally adapted from the [Discourse privacy policy](https://github.com/discourse/discourse). + TXT + + DEFAULT_UPDATED_AT = DateTime.new(2022, 10, 7).freeze + + attributes :updated_at, :text + + def self.current + custom = Setting.find_by(var: 'site_terms') + + if custom&.value.present? + new(text: custom.value, updated_at: custom.updated_at) + else + new(text: DEFAULT_PRIVACY_POLICY, updated_at: DEFAULT_UPDATED_AT) + end + end +end diff --git a/app/models/public_feed.rb b/app/models/public_feed.rb index 2528ef1b6..bc8281ef2 100644 --- a/app/models/public_feed.rb +++ b/app/models/public_feed.rb @@ -9,6 +9,7 @@ class PublicFeed # @option [Boolean] :remote # @option [Boolean] :only_media # @option [Boolean] :allow_local_only + # @option [String] :locale def initialize(account, options = {}) @account = account @options = options @@ -29,6 +30,7 @@ class PublicFeed scope.merge!(remote_only_scope) if remote_only? scope.merge!(account_filters_scope) if account? scope.merge!(media_only_scope) if media_only? + scope.merge!(language_scope) scope.cache_ids.to_a_paginated_by_id(limit, max_id: max_id, since_id: since_id, min_id: min_id) end @@ -97,10 +99,19 @@ class PublicFeed Status.not_local_only end + def language_scope + if account&.chosen_languages.present? + Status.where(language: account.chosen_languages) + elsif @options[:locale].present? + Status.where(language: @options[:locale]) + else + Status.all + end + end + def account_filters_scope Status.not_excluded_by_account(account).tap do |scope| scope.merge!(Status.not_domain_blocked_by_account(account)) unless local_only? - scope.merge!(Status.in_chosen_languages(account)) if account.chosen_languages.present? end end end diff --git a/app/models/report.rb b/app/models/report.rb index 42c869dd4..525d22ad5 100644 --- a/app/models/report.rb +++ b/app/models/report.rb @@ -33,6 +33,7 @@ class Report < ApplicationRecord belongs_to :assigned_account, class_name: 'Account', optional: true has_many :notes, class_name: 'ReportNote', foreign_key: :report_id, inverse_of: :report, dependent: :destroy + has_many :notifications, as: :activity, dependent: :destroy scope :unresolved, -> { where(action_taken_at: nil) } scope :resolved, -> { where.not(action_taken_at: nil) } diff --git a/app/models/site_upload.rb b/app/models/site_upload.rb index cf10b30fc..d3b81d4d5 100644 --- a/app/models/site_upload.rb +++ b/app/models/site_upload.rb @@ -12,10 +12,35 @@ # meta :json # created_at :datetime not null # updated_at :datetime not null +# blurhash :string # class SiteUpload < ApplicationRecord - has_attached_file :file + include Attachmentable + + STYLES = { + thumbnail: { + '@1x': { + format: 'png', + geometry: '1200x630#', + file_geometry_parser: FastGeometryParser, + blurhash: { + x_comp: 4, + y_comp: 4, + }.freeze, + }, + + '@2x': { + format: 'png', + geometry: '2400x1260#', + file_geometry_parser: FastGeometryParser, + }.freeze, + }.freeze, + + mascot: {}.freeze, + }.freeze + + has_attached_file :file, styles: ->(file) { STYLES[file.instance.var.to_sym] }, convert_options: { all: '-coalesce -strip' }, processors: [:lazy_thumbnail, :blurhash_transcoder, :type_corrector] validates_attachment_content_type :file, content_type: /\Aimage\/.*\z/ validates :file, presence: true diff --git a/app/models/status.rb b/app/models/status.rb index c1e8862ca..745a1401c 100644 --- a/app/models/status.rb +++ b/app/models/status.rb @@ -77,6 +77,7 @@ class Status < ApplicationRecord has_one :notification, as: :activity, dependent: :destroy has_one :status_stat, inverse_of: :status has_one :poll, inverse_of: :status, dependent: :destroy + has_one :trend, class_name: 'StatusTrend', inverse_of: :status validates :uri, uniqueness: true, presence: true, unless: :local? validates :text, presence: true, unless: -> { with_media? || reblog? } @@ -98,7 +99,6 @@ class Status < ApplicationRecord scope :without_reblogs, -> { where('statuses.reblog_of_id IS NULL') } scope :with_public_visibility, -> { where(visibility: :public) } scope :tagged_with, ->(tag_ids) { joins(:statuses_tags).where(statuses_tags: { tag_id: tag_ids }) } - scope :in_chosen_languages, ->(account) { where(language: nil).or where(language: account.chosen_languages) } scope :excluding_silenced_accounts, -> { left_outer_joins(:account).where(accounts: { silenced_at: nil }) } scope :including_silenced_accounts, -> { left_outer_joins(:account).where.not(accounts: { silenced_at: nil }) } scope :not_excluded_by_account, ->(account) { where.not(account_id: account.excluded_from_timeline_account_ids) } diff --git a/app/models/status_edit.rb b/app/models/status_edit.rb index 33528eb0d..c2330c04f 100644 --- a/app/models/status_edit.rb +++ b/app/models/status_edit.rb @@ -31,7 +31,7 @@ class StatusEdit < ApplicationRecord :preview_remote_url, :text_url, :meta, :blurhash, :not_processed?, :needs_redownload?, :local?, :file, :thumbnail, :thumbnail_remote_url, - :shortcode, to: :media_attachment + :shortcode, :video?, :audio?, to: :media_attachment end rate_limit by: :account, family: :statuses @@ -41,7 +41,8 @@ class StatusEdit < ApplicationRecord default_scope { order(id: :asc) } - delegate :local?, to: :status + delegate :local?, :application, :edited?, :edited_at, + :discarded?, :visibility, to: :status def emojis return @emojis if defined?(@emojis) @@ -60,4 +61,12 @@ class StatusEdit < ApplicationRecord end end end + + def proper + self + end + + def reblog? + false + end end diff --git a/app/models/status_trend.rb b/app/models/status_trend.rb new file mode 100644 index 000000000..b0f1b6942 --- /dev/null +++ b/app/models/status_trend.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +# == Schema Information +# +# Table name: status_trends +# +# id :bigint(8) not null, primary key +# status_id :bigint(8) not null +# account_id :bigint(8) not null +# score :float default(0.0), not null +# rank :integer default(0), not null +# allowed :boolean default(FALSE), not null +# language :string +# + +class StatusTrend < ApplicationRecord + belongs_to :status + belongs_to :account + + scope :allowed, -> { joins('INNER JOIN (SELECT account_id, MAX(score) AS max_score FROM status_trends GROUP BY account_id) AS grouped_status_trends ON status_trends.account_id = grouped_status_trends.account_id AND status_trends.score = grouped_status_trends.max_score').where(allowed: true) } +end diff --git a/app/models/tag_feed.rb b/app/models/tag_feed.rb index fbbdbaae2..761a43bb1 100644 --- a/app/models/tag_feed.rb +++ b/app/models/tag_feed.rb @@ -12,6 +12,7 @@ class TagFeed < PublicFeed # @option [Boolean] :local # @option [Boolean] :remote # @option [Boolean] :only_media + # @option [String] :locale def initialize(tag, account, options = {}) @tag = tag super(account, options) diff --git a/app/models/trends.rb b/app/models/trends.rb index 5d5f2eb22..b09db940e 100644 --- a/app/models/trends.rb +++ b/app/models/trends.rb @@ -26,7 +26,7 @@ module Trends end def self.request_review! - return unless enabled? + return if skip_review? || !enabled? links_requiring_review = links.request_review tags_requiring_review = tags.request_review @@ -46,6 +46,10 @@ module Trends Setting.trends end + def self.skip_review? + Setting.trendable_by_default + end + def self.available_locales @available_locales ||= I18n.available_locales.map { |locale| locale.to_s.split(/[_-]/).first }.uniq end diff --git a/app/models/trends/base.rb b/app/models/trends/base.rb index 047111248..a189f11f2 100644 --- a/app/models/trends/base.rb +++ b/app/models/trends/base.rb @@ -98,4 +98,8 @@ class Trends::Base pipeline.rename(from_key, to_key) end end + + def skip_review? + Setting.trendable_by_default + end end diff --git a/app/models/trends/links.rb b/app/models/trends/links.rb index 604894cd6..8808b3ab6 100644 --- a/app/models/trends/links.rb +++ b/app/models/trends/links.rb @@ -11,6 +11,40 @@ class Trends::Links < Trends::Base decay_threshold: 1, } + class Query < Trends::Query + def filtered_for!(account) + @account = account + self + end + + def filtered_for(account) + clone.filtered_for!(account) + end + + def to_arel + scope = PreviewCard.joins(:trend).reorder(score: :desc) + scope = scope.reorder(language_order_clause.desc, score: :desc) if preferred_languages.present? + scope = scope.merge(PreviewCardTrend.allowed) if @allowed + scope = scope.offset(@offset) if @offset.present? + scope = scope.limit(@limit) if @limit.present? + scope + end + + private + + def language_order_clause + Arel::Nodes::Case.new.when(PreviewCardTrend.arel_table[:language].in(preferred_languages)).then(1).else(0) + end + + def preferred_languages + if @account&.chosen_languages.present? + @account.chosen_languages + else + @locale + end + end + end + def register(status, at_time = Time.now.utc) original_status = status.proper @@ -28,24 +62,33 @@ class Trends::Links < Trends::Base record_used_id(preview_card.id, at_time) end + def query + Query.new(key_prefix, klass) + end + def refresh(at_time = Time.now.utc) - preview_cards = PreviewCard.where(id: (recently_used_ids(at_time) + currently_trending_ids(false, -1)).uniq) + preview_cards = PreviewCard.where(id: (recently_used_ids(at_time) + PreviewCardTrend.pluck(:preview_card_id)).uniq) calculate_scores(preview_cards, at_time) end def request_review - preview_cards = PreviewCard.where(id: currently_trending_ids(false, -1)) + PreviewCardTrend.pluck('distinct language').flat_map do |language| + score_at_threshold = PreviewCardTrend.where(language: language, allowed: true).order(rank: :desc).where('rank <= ?', options[:review_threshold]).first&.score || 0 + preview_card_trends = PreviewCardTrend.where(language: language, allowed: false).joins(:preview_card) - preview_cards.filter_map do |preview_card| - next unless would_be_trending?(preview_card.id) && !preview_card.trendable? && preview_card.requires_review_notification? + preview_card_trends.filter_map do |trend| + preview_card = trend.preview_card - if preview_card.provider.nil? - preview_card.provider = PreviewCardProvider.create(domain: preview_card.domain, requested_review_at: Time.now.utc) - else - preview_card.provider.touch(:requested_review_at) - end + next unless trend.score > score_at_threshold && !preview_card.trendable? && preview_card.requires_review_notification? + + if preview_card.provider.nil? + preview_card.provider = PreviewCardProvider.create(domain: preview_card.domain, requested_review_at: Time.now.utc) + else + preview_card.provider.touch(:requested_review_at) + end - preview_card + preview_card + end end end @@ -62,10 +105,7 @@ class Trends::Links < Trends::Base private def calculate_scores(preview_cards, at_time) - global_items = [] - locale_items = Hash.new { |h, key| h[key] = [] } - - preview_cards.each do |preview_card| + items = preview_cards.map do |preview_card| expected = preview_card.history.get(at_time - 1.day).accounts.to_f expected = 1.0 if expected.zero? observed = preview_card.history.get(at_time).accounts.to_f @@ -89,26 +129,24 @@ class Trends::Links < Trends::Base preview_card.update_columns(max_score: max_score, max_score_at: max_time) end - decaying_score = max_score * (0.5**((at_time.to_f - max_time.to_f) / options[:max_score_halflife].to_f)) - - next unless decaying_score >= options[:decay_threshold] + decaying_score = begin + if max_score.zero? || !valid_locale?(preview_card.language) + 0 + else + max_score * (0.5**((at_time.to_f - max_time.to_f) / options[:max_score_halflife].to_f)) + end + end - global_items << { score: decaying_score, item: preview_card } - locale_items[preview_card.language] << { score: decaying_score, item: preview_card } if valid_locale?(preview_card.language) + [decaying_score, preview_card] end - replace_items('', global_items) + to_insert = items.filter { |(score, _)| score >= options[:decay_threshold] } + to_delete = items.filter { |(score, _)| score < options[:decay_threshold] } - Trends.available_locales.each do |locale| - replace_items(":#{locale}", locale_items[locale]) + PreviewCardTrend.transaction do + PreviewCardTrend.upsert_all(to_insert.map { |(score, preview_card)| { preview_card_id: preview_card.id, score: score, language: preview_card.language, allowed: preview_card.trendable? || false } }, unique_by: :preview_card_id) if to_insert.any? + PreviewCardTrend.where(preview_card_id: to_delete.map { |(_, preview_card)| preview_card.id }).delete_all if to_delete.any? + PreviewCardTrend.connection.exec_update('UPDATE preview_card_trends SET rank = t0.calculated_rank FROM (SELECT id, row_number() OVER w AS calculated_rank FROM preview_card_trends WINDOW w AS (PARTITION BY language ORDER BY score DESC)) t0 WHERE preview_card_trends.id = t0.id') end end - - def filter_for_allowed_items(items) - items.select { |item| item[:item].trendable? } - end - - def would_be_trending?(id) - score(id) > score_at_rank(options[:review_threshold] - 1) - end end diff --git a/app/models/trends/preview_card_filter.rb b/app/models/trends/preview_card_filter.rb index 25add58c8..0a81146d4 100644 --- a/app/models/trends/preview_card_filter.rb +++ b/app/models/trends/preview_card_filter.rb @@ -13,10 +13,10 @@ class Trends::PreviewCardFilter end def results - scope = PreviewCard.unscoped + scope = initial_scope params.each do |key, value| - next if %w(page locale).include?(key.to_s) + next if %w(page).include?(key.to_s) scope.merge!(scope_for(key, value.to_s.strip)) if value.present? end @@ -26,21 +26,30 @@ class Trends::PreviewCardFilter private + def initial_scope + PreviewCard.select(PreviewCard.arel_table[Arel.star]) + .joins(:trend) + .eager_load(:trend) + .reorder(score: :desc) + end + def scope_for(key, value) case key.to_s when 'trending' trending_scope(value) + when 'locale' + PreviewCardTrend.where(language: value) else raise "Unknown filter: #{key}" end end def trending_scope(value) - scope = Trends.links.query - - scope = scope.in_locale(@params[:locale].to_s) if @params[:locale].present? - scope = scope.allowed if value == 'allowed' - - scope.to_arel + case value + when 'allowed' + PreviewCardTrend.allowed + else + PreviewCardTrend.all + end end end diff --git a/app/models/trends/status_batch.rb b/app/models/trends/status_batch.rb index 78d93bed4..f9b97b224 100644 --- a/app/models/trends/status_batch.rb +++ b/app/models/trends/status_batch.rb @@ -30,7 +30,7 @@ class Trends::StatusBatch end def approve! - statuses.each { |status| authorize(status, :review?) } + statuses.each { |status| authorize([:admin, status], :review?) } statuses.update_all(trendable: true) end @@ -45,7 +45,7 @@ class Trends::StatusBatch end def reject! - statuses.each { |status| authorize(status, :review?) } + statuses.each { |status| authorize([:admin, status], :review?) } statuses.update_all(trendable: false) end diff --git a/app/models/trends/status_filter.rb b/app/models/trends/status_filter.rb index 7c453e339..cb0f75d67 100644 --- a/app/models/trends/status_filter.rb +++ b/app/models/trends/status_filter.rb @@ -13,10 +13,10 @@ class Trends::StatusFilter end def results - scope = Status.unscoped.kept + scope = initial_scope params.each do |key, value| - next if %w(page locale).include?(key.to_s) + next if %w(page).include?(key.to_s) scope.merge!(scope_for(key, value.to_s.strip)) if value.present? end @@ -26,21 +26,30 @@ class Trends::StatusFilter private + def initial_scope + Status.select(Status.arel_table[Arel.star]) + .joins(:trend) + .eager_load(:trend) + .reorder(score: :desc) + end + def scope_for(key, value) case key.to_s when 'trending' trending_scope(value) + when 'locale' + StatusTrend.where(language: value) else raise "Unknown filter: #{key}" end end def trending_scope(value) - scope = Trends.statuses.query - - scope = scope.in_locale(@params[:locale].to_s) if @params[:locale].present? - scope = scope.allowed if value == 'allowed' - - scope.to_arel + case value + when 'allowed' + StatusTrend.allowed + else + StatusTrend.all + end end end diff --git a/app/models/trends/statuses.rb b/app/models/trends/statuses.rb index 1b9e9259a..14a05e6d8 100644 --- a/app/models/trends/statuses.rb +++ b/app/models/trends/statuses.rb @@ -20,13 +20,27 @@ class Trends::Statuses < Trends::Base clone.filtered_for!(account) end + def to_arel + scope = Status.joins(:trend).reorder(score: :desc) + scope = scope.reorder(language_order_clause.desc, score: :desc) if preferred_languages.present? + scope = scope.merge(StatusTrend.allowed) if @allowed + scope = scope.not_excluded_by_account(@account).not_domain_blocked_by_account(@account) if @account.present? + scope = scope.offset(@offset) if @offset.present? + scope = scope.limit(@limit) if @limit.present? + scope + end + private - def apply_scopes(scope) - if @account.nil? - scope + def language_order_clause + Arel::Nodes::Case.new.when(StatusTrend.arel_table[:language].in(preferred_languages)).then(1).else(0) + end + + def preferred_languages + if @account&.chosen_languages.present? + @account.chosen_languages else - scope.not_excluded_by_account(@account).not_domain_blocked_by_account(@account) + @locale end end end @@ -36,9 +50,6 @@ class Trends::Statuses < Trends::Base end def add(status, _account_id, at_time = Time.now.utc) - # We rely on the total reblogs and favourites count, so we - # don't record which account did the what and when here - record_used_id(status.id, at_time) end @@ -47,18 +58,23 @@ class Trends::Statuses < Trends::Base end def refresh(at_time = Time.now.utc) - statuses = Status.where(id: (recently_used_ids(at_time) + currently_trending_ids(false, -1)).uniq).includes(:account, :media_attachments) + statuses = Status.where(id: (recently_used_ids(at_time) + StatusTrend.pluck(:status_id)).uniq).includes(:status_stat, :account) calculate_scores(statuses, at_time) end def request_review - statuses = Status.where(id: currently_trending_ids(false, -1)).includes(:account) + StatusTrend.pluck('distinct language').flat_map do |language| + score_at_threshold = StatusTrend.where(language: language, allowed: true).order(rank: :desc).where('rank <= ?', options[:review_threshold]).first&.score || 0 + status_trends = StatusTrend.where(language: language, allowed: false).joins(:status).includes(status: :account) - statuses.filter_map do |status| - next unless would_be_trending?(status.id) && !status.trendable? && status.requires_review_notification? + status_trends.filter_map do |trend| + status = trend.status - status.account.touch(:requested_review_at) - status + if trend.score > score_at_threshold && !status.trendable? && status.requires_review_notification? + status.account.touch(:requested_review_at) + status + end + end end end @@ -75,14 +91,11 @@ class Trends::Statuses < Trends::Base private def eligible?(status) - status.public_visibility? && status.account.discoverable? && !status.account.silenced? && (status.spoiler_text.blank? || Setting.trending_status_cw) && !status.sensitive? && !status.reply? + status.public_visibility? && status.account.discoverable? && !status.account.silenced? && (status.spoiler_text.blank? || Setting.trending_status_cw) && !status.sensitive? && !status.reply? && valid_locale?(status.language) end def calculate_scores(statuses, at_time) - global_items = [] - locale_items = Hash.new { |h, key| h[key] = [] } - - statuses.each do |status| + items = statuses.map do |status| expected = 1.0 observed = (status.reblogs_count + status.favourites_count).to_f @@ -94,29 +107,24 @@ class Trends::Statuses < Trends::Base end end - decaying_score = score * (0.5**((at_time.to_f - status.created_at.to_f) / options[:score_halflife].to_f)) - - next unless decaying_score >= options[:decay_threshold] + decaying_score = begin + if score.zero? || !eligible?(status) + 0 + else + score * (0.5**((at_time.to_f - status.created_at.to_f) / options[:score_halflife].to_f)) + end + end - global_items << { score: decaying_score, item: status } - locale_items[status.language] << { account_id: status.account_id, score: decaying_score, item: status } if valid_locale?(status.language) + [decaying_score, status] end - replace_items('', global_items) + to_insert = items.filter { |(score, _)| score >= options[:decay_threshold] } + to_delete = items.filter { |(score, _)| score < options[:decay_threshold] } - Trends.available_locales.each do |locale| - replace_items(":#{locale}", locale_items[locale]) + StatusTrend.transaction do + StatusTrend.upsert_all(to_insert.map { |(score, status)| { status_id: status.id, account_id: status.account_id, score: score, language: status.language, allowed: status.trendable? || false } }, unique_by: :status_id) if to_insert.any? + StatusTrend.where(status_id: to_delete.map { |(_, status)| status.id }).delete_all if to_delete.any? + StatusTrend.connection.exec_update('UPDATE status_trends SET rank = t0.calculated_rank FROM (SELECT id, row_number() OVER w AS calculated_rank FROM status_trends WINDOW w AS (PARTITION BY language ORDER BY score DESC)) t0 WHERE status_trends.id = t0.id') end end - - def filter_for_allowed_items(items) - # Show only one status per account, pick the one with the highest score - # that's also eligible to trend - - items.group_by { |item| item[:account_id] }.values.filter_map { |account_items| account_items.select { |item| item[:item].trendable? && item[:item].account.discoverable? }.max_by { |item| item[:score] } } - end - - def would_be_trending?(id) - score(id) > score_at_rank(options[:review_threshold] - 1) - end end diff --git a/app/models/user.rb b/app/models/user.rb index de59fe4b3..0e8a87aea 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -281,6 +281,10 @@ class User < ApplicationRecord save! end + def prefers_noindex? + setting_noindex + end + def preferred_posting_language valid_locale_cascade(settings.default_language, locale, I18n.locale) end diff --git a/app/policies/admin/status_policy.rb b/app/policies/admin/status_policy.rb new file mode 100644 index 000000000..ffaa30f13 --- /dev/null +++ b/app/policies/admin/status_policy.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +class Admin::StatusPolicy < ApplicationPolicy + def initialize(current_account, record, preloaded_relations = {}) + super(current_account, record) + + @preloaded_relations = preloaded_relations + end + + def index? + role.can?(:manage_reports, :manage_users) + end + + def show? + role.can?(:manage_reports, :manage_users) && (record.public_visibility? || record.unlisted_visibility? || record.reported?) + end + + def destroy? + role.can?(:manage_reports) + end + + def update? + role.can?(:manage_reports) + end + + def review? + role.can?(:manage_taxonomies) + end +end diff --git a/app/policies/status_policy.rb b/app/policies/status_policy.rb index 134721f95..52cfd5050 100644 --- a/app/policies/status_policy.rb +++ b/app/policies/status_policy.rb @@ -7,10 +7,6 @@ class StatusPolicy < ApplicationPolicy @preloaded_relations = preloaded_relations end - def index? - role.can?(:manage_reports, :manage_users) - end - def show? return false if author.suspended? return false if local_only? && (current_account.nil? || !current_account.local?) @@ -33,17 +29,13 @@ class StatusPolicy < ApplicationPolicy end def destroy? - role.can?(:manage_reports) || owned? + owned? end alias unreblog? destroy? def update? - role.can?(:manage_reports) || owned? - end - - def review? - role.can?(:manage_taxonomies) + owned? end private diff --git a/app/presenters/initial_state_presenter.rb b/app/presenters/initial_state_presenter.rb index 129ea2a46..ed0479211 100644 --- a/app/presenters/initial_state_presenter.rb +++ b/app/presenters/initial_state_presenter.rb @@ -2,7 +2,7 @@ class InitialStatePresenter < ActiveModelSerializers::Model attributes :settings, :push_subscription, :token, - :current_account, :admin, :text, :visibility + :current_account, :admin, :owner, :text, :visibility def role current_account&.user_role diff --git a/app/presenters/instance_presenter.rb b/app/presenters/instance_presenter.rb index c461ac55f..fba3cc734 100644 --- a/app/presenters/instance_presenter.rb +++ b/app/presenters/instance_presenter.rb @@ -12,7 +12,9 @@ class InstancePresenter < ActiveModelSerializers::Model end def account - Account.find_local(Setting.site_contact_username.strip.gsub(/\A@/, '')) + username, domain = Setting.site_contact_username.strip.gsub(/\A@/, '').split('@', 2) + domain = nil if TagManager.instance.local_domain?(domain) + Account.find_remote(username, domain) if username.present? end end @@ -84,10 +86,6 @@ class InstancePresenter < ActiveModelSerializers::Model @thumbnail ||= Rails.cache.fetch('site_uploads/thumbnail') { SiteUpload.find_by(var: 'thumbnail') } end - def hero - @hero ||= Rails.cache.fetch('site_uploads/hero') { SiteUpload.find_by(var: 'hero') } - end - def mascot @mascot ||= Rails.cache.fetch('site_uploads/mascot') { SiteUpload.find_by(var: 'mascot') } end diff --git a/app/serializers/activitypub/add_serializer.rb b/app/serializers/activitypub/add_serializer.rb index 6f5aab17f..436b05086 100644 --- a/app/serializers/activitypub/add_serializer.rb +++ b/app/serializers/activitypub/add_serializer.rb @@ -1,10 +1,29 @@ # frozen_string_literal: true class ActivityPub::AddSerializer < ActivityPub::Serializer + class UriSerializer < ActiveModel::Serializer + include RoutingHelper + + def serializable_hash(*_args) + ActivityPub::TagManager.instance.uri_for(object) + end + end + + def self.serializer_for(model, options) + case model.class.name + when 'Status' + UriSerializer + when 'FeaturedTag' + ActivityPub::HashtagSerializer + else + super + end + end + include RoutingHelper attributes :type, :actor, :target - attribute :proper_object, key: :object + has_one :proper_object, key: :object def type 'Add' @@ -15,7 +34,7 @@ class ActivityPub::AddSerializer < ActivityPub::Serializer end def proper_object - ActivityPub::TagManager.instance.uri_for(object) + object end def target diff --git a/app/serializers/activitypub/hashtag_serializer.rb b/app/serializers/activitypub/hashtag_serializer.rb index 90929c57f..2b24eb8cc 100644 --- a/app/serializers/activitypub/hashtag_serializer.rb +++ b/app/serializers/activitypub/hashtag_serializer.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true class ActivityPub::HashtagSerializer < ActivityPub::Serializer + context_extensions :hashtag + include RoutingHelper attributes :type, :href, :name diff --git a/app/serializers/activitypub/remove_serializer.rb b/app/serializers/activitypub/remove_serializer.rb index 7fefda59d..fb224f8a9 100644 --- a/app/serializers/activitypub/remove_serializer.rb +++ b/app/serializers/activitypub/remove_serializer.rb @@ -1,10 +1,29 @@ # frozen_string_literal: true class ActivityPub::RemoveSerializer < ActivityPub::Serializer + class UriSerializer < ActiveModel::Serializer + include RoutingHelper + + def serializable_hash(*_args) + ActivityPub::TagManager.instance.uri_for(object) + end + end + + def self.serializer_for(model, options) + case model.class.name + when 'Status' + UriSerializer + when 'FeaturedTag' + ActivityPub::HashtagSerializer + else + super + end + end + include RoutingHelper attributes :type, :actor, :target - attribute :proper_object, key: :object + has_one :proper_object, key: :object def type 'Remove' @@ -15,7 +34,7 @@ class ActivityPub::RemoveSerializer < ActivityPub::Serializer end def proper_object - ActivityPub::TagManager.instance.uri_for(object) + object end def target diff --git a/app/serializers/initial_state_serializer.rb b/app/serializers/initial_state_serializer.rb index aa36f82a1..7e57ce4bf 100644 --- a/app/serializers/initial_state_serializer.rb +++ b/app/serializers/initial_state_serializer.rb @@ -42,6 +42,10 @@ class InitialStateSerializer < ActiveModel::Serializer profile_directory: Setting.profile_directory, trends: Setting.trends, registrations_open: Setting.registrations_mode != 'none' && !Rails.configuration.x.single_user_mode, + timeline_preview: Setting.timeline_preview, + activity_api_enabled: Setting.activity_api_enabled, + single_user_mode: Rails.configuration.x.single_user_mode, + translation_enabled: TranslationService.configured?, } if object.current_account @@ -70,6 +74,10 @@ class InitialStateSerializer < ActiveModel::Serializer store[:crop_images] = Setting.crop_images end + if Rails.configuration.x.single_user_mode + store[:owner] = object.owner&.id&.to_s + end + store end # rubocop:enable Metrics/AbcSize @@ -93,6 +101,7 @@ class InitialStateSerializer < ActiveModel::Serializer store = {} store[object.current_account.id.to_s] = ActiveModelSerializers::SerializableResource.new(object.current_account, serializer: REST::AccountSerializer) if object.current_account store[object.admin.id.to_s] = ActiveModelSerializers::SerializableResource.new(object.admin, serializer: REST::AccountSerializer) if object.admin + store[object.owner.id.to_s] = ActiveModelSerializers::SerializableResource.new(object.owner, serializer: REST::AccountSerializer) if object.owner store end diff --git a/app/serializers/manifest_serializer.rb b/app/serializers/manifest_serializer.rb index 6b5296480..5604325be 100644 --- a/app/serializers/manifest_serializer.rb +++ b/app/serializers/manifest_serializer.rb @@ -40,7 +40,7 @@ class ManifestSerializer < ActiveModel::Serializer end def theme_color - '#6364FF' + '#191b22' end def background_color @@ -52,7 +52,7 @@ class ManifestSerializer < ActiveModel::Serializer end def start_url - '/web/home' + '/home' end def scope @@ -77,11 +77,11 @@ class ManifestSerializer < ActiveModel::Serializer [ { name: 'Compose new post', - url: '/web/publish', + url: '/publish', }, { name: 'Notifications', - url: '/web/notifications', + url: '/notifications', }, ] end diff --git a/app/serializers/rest/account_serializer.rb b/app/serializers/rest/account_serializer.rb index e644a3f91..9a3ca75dc 100644 --- a/app/serializers/rest/account_serializer.rb +++ b/app/serializers/rest/account_serializer.rb @@ -14,6 +14,7 @@ class REST::AccountSerializer < ActiveModel::Serializer attribute :suspended, if: :suspended? attribute :silenced, key: :limited, if: :silenced? + attribute :noindex, if: :local? class FieldSerializer < ActiveModel::Serializer include FormattingHelper @@ -107,7 +108,11 @@ class REST::AccountSerializer < ActiveModel::Serializer object.silenced? end - delegate :suspended?, :silenced?, to: :object + def noindex + object.user_prefers_noindex? + end + + delegate :suspended?, :silenced?, :local?, to: :object def moved_and_not_nested? object.moved? && object.moved_to_account.moved_to_account_id.nil? diff --git a/app/serializers/rest/domain_block_serializer.rb b/app/serializers/rest/domain_block_serializer.rb new file mode 100644 index 000000000..678463e13 --- /dev/null +++ b/app/serializers/rest/domain_block_serializer.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class REST::DomainBlockSerializer < ActiveModel::Serializer + attributes :domain, :digest, :severity, :comment + + def domain + object.public_domain + end + + def digest + object.domain_digest + end + + def comment + object.public_comment if instance_options[:with_comment] + end +end diff --git a/app/serializers/rest/extended_description_serializer.rb b/app/serializers/rest/extended_description_serializer.rb new file mode 100644 index 000000000..c0fa3450d --- /dev/null +++ b/app/serializers/rest/extended_description_serializer.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +class REST::ExtendedDescriptionSerializer < ActiveModel::Serializer + attributes :updated_at, :content + + def updated_at + object.updated_at&.iso8601 + end + + def content + if object.text.present? + markdown.render(object.text) + else + '' + end + end + + private + + def markdown + @markdown ||= Redcarpet::Markdown.new(Redcarpet::Render::HTML) + end +end diff --git a/app/serializers/rest/featured_tag_serializer.rb b/app/serializers/rest/featured_tag_serializer.rb index 8abcd9b90..c4b35ab03 100644 --- a/app/serializers/rest/featured_tag_serializer.rb +++ b/app/serializers/rest/featured_tag_serializer.rb @@ -16,4 +16,12 @@ class REST::FeaturedTagSerializer < ActiveModel::Serializer def name object.display_name end + + def statuses_count + object.statuses_count.to_s + end + + def last_status_at + object.last_status_at&.to_date&.iso8601 + end end diff --git a/app/serializers/rest/instance_serializer.rb b/app/serializers/rest/instance_serializer.rb index f4ea49427..5ae1099d0 100644 --- a/app/serializers/rest/instance_serializer.rb +++ b/app/serializers/rest/instance_serializer.rb @@ -17,7 +17,20 @@ class REST::InstanceSerializer < ActiveModel::Serializer has_many :rules, serializer: REST::RuleSerializer def thumbnail - object.thumbnail ? full_asset_url(object.thumbnail.file.url) : full_pack_url('media/images/preview.png') + if object.thumbnail + { + url: full_asset_url(object.thumbnail.file.url(:'@1x')), + blurhash: object.thumbnail.blurhash, + versions: { + '@1x': full_asset_url(object.thumbnail.file.url(:'@1x')), + '@2x': full_asset_url(object.thumbnail.file.url(:'@2x')), + }, + } + else + { + url: full_pack_url('media/images/preview.png'), + } + end end def usage @@ -34,6 +47,10 @@ class REST::InstanceSerializer < ActiveModel::Serializer streaming: Rails.configuration.x.streaming_api_base_url, }, + accounts: { + max_featured_tags: FeaturedTag::LIMIT, + }, + statuses: { max_characters: StatusLengthValidator::MAX_CHARS, max_media_attachments: 4, @@ -55,13 +72,36 @@ class REST::InstanceSerializer < ActiveModel::Serializer min_expiration: PollValidator::MIN_EXPIRATION, max_expiration: PollValidator::MAX_EXPIRATION, }, + + translation: { + enabled: TranslationService.configured?, + }, } end def registrations { - enabled: Setting.registrations_mode != 'none' && !Rails.configuration.x.single_user_mode, + enabled: registrations_enabled?, approval_required: Setting.registrations_mode == 'approved', + message: registrations_enabled? ? nil : registrations_message, } end + + private + + def registrations_enabled? + Setting.registrations_mode != 'none' && !Rails.configuration.x.single_user_mode + end + + def registrations_message + if Setting.closed_registrations_message.present? + markdown.render(Setting.closed_registrations_message) + else + nil + end + end + + def markdown + @markdown ||= Redcarpet::Markdown.new(Redcarpet::Render::HTML, no_images: true) + end end diff --git a/app/serializers/rest/privacy_policy_serializer.rb b/app/serializers/rest/privacy_policy_serializer.rb new file mode 100644 index 000000000..f0572e714 --- /dev/null +++ b/app/serializers/rest/privacy_policy_serializer.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +class REST::PrivacyPolicySerializer < ActiveModel::Serializer + attributes :updated_at, :content + + def updated_at + object.updated_at.iso8601 + end + + def content + markdown.render(object.text % { domain: Rails.configuration.x.local_domain }) + end + + private + + def markdown + @markdown ||= Redcarpet::Markdown.new(Redcarpet::Render::HTML, escape_html: true, no_images: true) + end +end diff --git a/app/serializers/rest/translation_serializer.rb b/app/serializers/rest/translation_serializer.rb index a06f23f32..05ededc95 100644 --- a/app/serializers/rest/translation_serializer.rb +++ b/app/serializers/rest/translation_serializer.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class REST::TranslationSerializer < ActiveModel::Serializer - attributes :content, :detected_source_language + attributes :content, :detected_source_language, :provider def content object.text diff --git a/app/serializers/rest/v1/instance_serializer.rb b/app/serializers/rest/v1/instance_serializer.rb index fefbed8ee..389ec7dff 100644 --- a/app/serializers/rest/v1/instance_serializer.rb +++ b/app/serializers/rest/v1/instance_serializer.rb @@ -33,7 +33,7 @@ class REST::V1::InstanceSerializer < ActiveModel::Serializer end def thumbnail - instance_presenter.thumbnail ? full_asset_url(instance_presenter.thumbnail.file.url) : full_pack_url('media/images/preview.png') + instance_presenter.thumbnail ? full_asset_url(instance_presenter.thumbnail.file.url(:'@1x')) : full_pack_url('media/images/preview.png') end def max_toot_chars @@ -71,6 +71,10 @@ class REST::V1::InstanceSerializer < ActiveModel::Serializer def configuration { + accounts: { + max_featured_tags: FeaturedTag::LIMIT, + }, + statuses: { max_characters: StatusLengthValidator::MAX_CHARS, max_media_attachments: 4, diff --git a/app/services/account_search_service.rb b/app/services/account_search_service.rb index 4dcae20eb..9f2330a94 100644 --- a/app/services/account_search_service.rb +++ b/app/services/account_search_service.rb @@ -3,6 +3,9 @@ class AccountSearchService < BaseService attr_reader :query, :limit, :offset, :options, :account + # Min. number of characters to look for non-exact matches + MIN_QUERY_LENGTH = 5 + def call(query, account = nil, options = {}) @acct_hint = query&.start_with?('@') @query = query&.strip&.gsub(/\A@/, '') @@ -102,7 +105,7 @@ class AccountSearchService < BaseService { script_score: { script: { - source: "(doc['followers_count'].value + 0.0) / (doc['followers_count'].value + doc['following_count'].value + 1)", + source: "(Math.max(doc['followers_count'].value, 0) + 0.0) / (Math.max(doc['followers_count'].value, 0) + Math.max(doc['following_count'].value, 0) + 1)", }, }, } @@ -110,10 +113,10 @@ class AccountSearchService < BaseService def followers_score_function { - field_value_factor: { - field: 'followers_count', - modifier: 'log2p', - missing: 0, + script_score: { + script: { + source: "Math.log10(Math.max(doc['followers_count'].value, 0) + 2)", + }, }, } end @@ -135,6 +138,8 @@ class AccountSearchService < BaseService end def limit_for_non_exact_results + return 0 if @account.nil? && query.size < MIN_QUERY_LENGTH + if exact_match? limit - 1 else diff --git a/app/services/activitypub/fetch_featured_collection_service.rb b/app/services/activitypub/fetch_featured_collection_service.rb index 37d05e055..50a187ad9 100644 --- a/app/services/activitypub/fetch_featured_collection_service.rb +++ b/app/services/activitypub/fetch_featured_collection_service.rb @@ -3,10 +3,11 @@ class ActivityPub::FetchFeaturedCollectionService < BaseService include JsonLdHelper - def call(account) + def call(account, **options) return if account.featured_collection_url.blank? || account.suspended? || account.local? @account = account + @options = options @json = fetch_resource(@account.featured_collection_url, true, local_follower) return unless supported_context?(@json) @@ -36,7 +37,14 @@ class ActivityPub::FetchFeaturedCollectionService < BaseService end def process_items(items) + process_note_items(items) if @options[:note] + process_hashtag_items(items) if @options[:hashtag] + end + + def process_note_items(items) status_ids = items.filter_map do |item| + next unless item.is_a?(String) || item['type'] == 'Note' + uri = value_or_id(item) next if ActivityPub::TagManager.instance.local_uri?(uri) @@ -67,6 +75,26 @@ class ActivityPub::FetchFeaturedCollectionService < BaseService end end + def process_hashtag_items(items) + names = items.filter_map { |item| item['type'] == 'Hashtag' && item['name']&.delete_prefix('#') }.map { |name| HashtagNormalizer.new.normalize(name) } + to_remove = [] + to_add = names + + FeaturedTag.where(account: @account).map(&:name).each do |name| + if names.include?(name) + to_add.delete(name) + else + to_remove << name + end + end + + FeaturedTag.includes(:tag).where(account: @account, tags: { name: to_remove }).delete_all unless to_remove.empty? + + to_add.each do |name| + FeaturedTag.create!(account: @account, name: name) + end + end + def local_follower return @local_follower if defined?(@local_follower) diff --git a/app/services/activitypub/fetch_featured_tags_collection_service.rb b/app/services/activitypub/fetch_featured_tags_collection_service.rb new file mode 100644 index 000000000..555919938 --- /dev/null +++ b/app/services/activitypub/fetch_featured_tags_collection_service.rb @@ -0,0 +1,78 @@ +# frozen_string_literal: true + +class ActivityPub::FetchFeaturedTagsCollectionService < BaseService + include JsonLdHelper + + def call(account, url) + return if url.blank? || account.suspended? || account.local? + + @account = account + @json = fetch_resource(url, true, local_follower) + + return unless supported_context?(@json) + + process_items(collection_items(@json)) + end + + private + + def collection_items(collection) + all_items = [] + + collection = fetch_collection(collection['first']) if collection['first'].present? + + while collection.is_a?(Hash) + items = begin + case collection['type'] + when 'Collection', 'CollectionPage' + collection['items'] + when 'OrderedCollection', 'OrderedCollectionPage' + collection['orderedItems'] + end + end + + break if items.blank? + + all_items.concat(items) + + break if all_items.size >= FeaturedTag::LIMIT + + collection = collection['next'].present? ? fetch_collection(collection['next']) : nil + end + + all_items + end + + def fetch_collection(collection_or_uri) + return collection_or_uri if collection_or_uri.is_a?(Hash) + return if invalid_origin?(collection_or_uri) + + fetch_resource_without_id_validation(collection_or_uri, local_follower, true) + end + + def process_items(items) + names = items.filter_map { |item| item['type'] == 'Hashtag' && item['name']&.delete_prefix('#') }.map { |name| HashtagNormalizer.new.normalize(name) } + to_remove = [] + to_add = names + + FeaturedTag.where(account: @account).map(&:name).each do |name| + if names.include?(name) + to_add.delete(name) + else + to_remove << name + end + end + + FeaturedTag.includes(:tag).where(account: @account, tags: { name: to_remove }).delete_all unless to_remove.empty? + + to_add.each do |name| + FeaturedTag.create!(account: @account, name: name) + end + end + + def local_follower + return @local_follower if defined?(@local_follower) + + @local_follower = @account.followers.local.without_suspended.first + end +end diff --git a/app/services/activitypub/process_account_service.rb b/app/services/activitypub/process_account_service.rb index 456b3524b..3834d79cc 100644 --- a/app/services/activitypub/process_account_service.rb +++ b/app/services/activitypub/process_account_service.rb @@ -39,6 +39,7 @@ class ActivityPub::ProcessAccountService < BaseService unless @options[:only_key] || @account.suspended? check_featured_collection! if @account.featured_collection_url.present? + check_featured_tags_collection! if @json['featuredTags'].present? check_links! unless @account.fields.empty? end @@ -149,7 +150,11 @@ class ActivityPub::ProcessAccountService < BaseService end def check_featured_collection! - ActivityPub::SynchronizeFeaturedCollectionWorker.perform_async(@account.id) + ActivityPub::SynchronizeFeaturedCollectionWorker.perform_async(@account.id, { 'hashtag' => @json['featuredTags'].blank? }) + end + + def check_featured_tags_collection! + ActivityPub::SynchronizeFeaturedTagsCollectionWorker.perform_async(@account.id, @json['featuredTags']) end def check_links! diff --git a/app/services/create_featured_tag_service.rb b/app/services/create_featured_tag_service.rb new file mode 100644 index 000000000..3cc59156d --- /dev/null +++ b/app/services/create_featured_tag_service.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +class CreateFeaturedTagService < BaseService + include Payloadable + + def call(account, name, force: true) + @account = account + + FeaturedTag.create!(account: account, name: name).tap do |featured_tag| + ActivityPub::AccountRawDistributionWorker.perform_async(build_json(featured_tag), account.id) if @account.local? + end + rescue ActiveRecord::RecordNotUnique, ActiveRecord::RecordInvalid => e + if force && e.is_a(ActiveRecord::RecordNotUnique) + FeaturedTag.by_name(name).find_by!(account: account) + else + account.featured_tags.new(name: name) + end + end + + private + + def build_json(featured_tag) + Oj.dump(serialize_payload(featured_tag, ActivityPub::AddSerializer, signer: @account)) + end +end diff --git a/app/services/remove_featured_tag_service.rb b/app/services/remove_featured_tag_service.rb new file mode 100644 index 000000000..2aa70e8fc --- /dev/null +++ b/app/services/remove_featured_tag_service.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +class RemoveFeaturedTagService < BaseService + include Payloadable + + def call(account, featured_tag) + @account = account + + featured_tag.destroy! + ActivityPub::AccountRawDistributionWorker.perform_async(build_json(featured_tag), account.id) if @account.local? + end + + private + + def build_json(featured_tag) + Oj.dump(serialize_payload(featured_tag, ActivityPub::RemoveSerializer, signer: @account)) + end +end diff --git a/app/services/remove_status_service.rb b/app/services/remove_status_service.rb index 97afc3f61..3d0825f08 100644 --- a/app/services/remove_status_service.rb +++ b/app/services/remove_status_service.rb @@ -21,6 +21,8 @@ class RemoveStatusService < BaseService with_lock("distribute:#{@status.id}") do @status.discard + StatusPin.find_by(status: @status)&.destroy + remove_from_self if @account.local? remove_from_followers remove_from_lists diff --git a/app/services/resolve_account_service.rb b/app/services/resolve_account_service.rb index e3b370968..d8b81a7b9 100644 --- a/app/services/resolve_account_service.rb +++ b/app/services/resolve_account_service.rb @@ -12,6 +12,7 @@ class ResolveAccountService < BaseService # @param [Hash] options # @option options [Boolean] :redirected Do not follow further Webfinger redirects # @option options [Boolean] :skip_webfinger Do not attempt any webfinger query or refreshing account data + # @option options [Boolean] :skip_cache Get the latest data from origin even if cache is not due to update yet # @option options [Boolean] :suppress_errors When failing, return nil instead of raising an error # @return [Account] def call(uri, options = {}) @@ -120,7 +121,7 @@ class ResolveAccountService < BaseService return false if @options[:check_delivery_availability] && !DeliveryFailureTracker.available?(@domain) return false if @options[:skip_webfinger] - @account.nil? || @account.possibly_stale? + @options[:skip_cache] || @account.nil? || @account.possibly_stale? end def activitypub_ready? diff --git a/app/validators/existing_username_validator.rb b/app/validators/existing_username_validator.rb index 8f7d96b8e..1c5596821 100644 --- a/app/validators/existing_username_validator.rb +++ b/app/validators/existing_username_validator.rb @@ -6,7 +6,7 @@ class ExistingUsernameValidator < ActiveModel::EachValidator usernames_and_domains = begin value.split(',').map do |str| - username, domain = str.strip.gsub(/\A@/, '').split('@') + username, domain = str.strip.gsub(/\A@/, '').split('@', 2) domain = nil if TagManager.instance.local_domain?(domain) next if username.blank? @@ -21,8 +21,8 @@ class ExistingUsernameValidator < ActiveModel::EachValidator if options[:multiple] record.errors.add(attribute, I18n.t('existing_username_validator.not_found_multiple', usernames: usernames_with_no_accounts.join(', '))) if usernames_with_no_accounts.any? - else - record.errors.add(attribute, I18n.t('existing_username_validator.not_found')) if usernames_with_no_accounts.any? || usernames_and_domains.size > 1 + elsif usernames_with_no_accounts.any? || usernames_and_domains.size > 1 + record.errors.add(attribute, I18n.t('existing_username_validator.not_found')) end end end diff --git a/app/validators/import_validator.rb b/app/validators/import_validator.rb index 9f19aee2a..cbad56df6 100644 --- a/app/validators/import_validator.rb +++ b/app/validators/import_validator.rb @@ -26,6 +26,8 @@ class ImportValidator < ActiveModel::Validator when 'following' validate_following_import(import, row_count) end + rescue CSV::MalformedCSVError + import.errors.add(:data, :malformed) end private diff --git a/app/views/about/_domain_blocks.html.haml b/app/views/about/_domain_blocks.html.haml deleted file mode 100644 index 35a30f16e..000000000 --- a/app/views/about/_domain_blocks.html.haml +++ /dev/null @@ -1,12 +0,0 @@ -%table - %thead - %tr - %th= t('about.unavailable_content_description.domain') - %th= t('about.unavailable_content_description.reason') - %tbody - - domain_blocks.each do |domain_block| - %tr - %td.nowrap - %span{ title: "SHA-256: #{domain_block.domain_digest}" }= domain_block.public_domain - %td - = domain_block.public_comment if display_blocks_rationale? diff --git a/app/views/about/_logged_in.html.haml b/app/views/about/_logged_in.html.haml deleted file mode 100644 index e1bcfffb3..000000000 --- a/app/views/about/_logged_in.html.haml +++ /dev/null @@ -1,10 +0,0 @@ -.simple_form - %p.lead= t('about.logged_in_as_html', username: content_tag(:strong, current_account.username)) - - .actions - = link_to t('about.continue_to_web'), root_url, class: 'button button-primary' - -.form-footer - %ul.no-list - %li= link_to t('about.get_apps'), 'https://joinmastodon.org/apps', target: '_blank', rel: 'noopener noreferrer' - %li= link_to t('auth.logout'), destroy_user_session_path, data: { method: :delete } diff --git a/app/views/about/_login.html.haml b/app/views/about/_login.html.haml deleted file mode 100644 index 0f19e8164..000000000 --- a/app/views/about/_login.html.haml +++ /dev/null @@ -1,22 +0,0 @@ -- unless omniauth_only? - = simple_form_for(new_user, url: user_session_path, namespace: 'login') do |f| - .fields-group - - if use_seamless_external_login? - = f.input :email, placeholder: t('simple_form.labels.defaults.username_or_email'), input_html: { 'aria-label' => t('simple_form.labels.defaults.username_or_email') }, hint: false - - else - = f.input :email, placeholder: t('simple_form.labels.defaults.email'), input_html: { 'aria-label' => t('simple_form.labels.defaults.email') }, hint: false - - = f.input :password, placeholder: t('simple_form.labels.defaults.password'), input_html: { 'aria-label' => t('simple_form.labels.defaults.password') }, hint: false - - .actions - = f.button :button, t('auth.login'), type: :submit, class: 'button button-primary' - - %p.hint.subtle-hint= link_to t('auth.trouble_logging_in'), new_user_password_path - -- if Devise.mappings[:user].omniauthable? and User.omniauth_providers.any? - .simple_form.alternative-login - %h4= omniauth_only? ? t('auth.log_in_with') : t('auth.or_log_in_with') - - .actions - - User.omniauth_providers.each do |provider| - = provider_sign_in_link(provider) diff --git a/app/views/about/_registration.html.haml b/app/views/about/_registration.html.haml deleted file mode 100644 index 5db620b2d..000000000 --- a/app/views/about/_registration.html.haml +++ /dev/null @@ -1,37 +0,0 @@ -- disabled = closed_registrations? || omniauth_only? || current_account.present? -- show_message = disabled && (current_user.present? || @instance_presenter.closed_registrations_message.present?) - -.simple_form__overlay-area{ class: show_message ? 'simple_form__overlay-area__blurred' : '' } - = simple_form_for(new_user, url: user_registration_path, namespace: 'registration', html: { novalidate: false }) do |f| - %p.lead= t('about.federation_hint_html', instance: content_tag(:strong, site_hostname)) - - .fields-group - = f.simple_fields_for :account do |account_fields| - = account_fields.input :username, wrapper: :with_label, label: false, required: true, input_html: { 'aria-label' => t('simple_form.labels.defaults.username'), :autocomplete => 'off', placeholder: t('simple_form.labels.defaults.username'), pattern: '[a-zA-Z0-9_]+', maxlength: 30 }, append: "@#{site_hostname}", hint: false, disabled: disabled - - = f.input :email, placeholder: t('simple_form.labels.defaults.email'), required: true, input_html: { 'aria-label' => t('simple_form.labels.defaults.email'), :autocomplete => 'off' }, hint: false, disabled: disabled - = f.input :password, placeholder: t('simple_form.labels.defaults.password'), required: true, input_html: { 'aria-label' => t('simple_form.labels.defaults.password'), :autocomplete => 'new-password', :minlength => User.password_length.first, :maxlength => User.password_length.last }, hint: false, disabled: disabled - = f.input :password_confirmation, placeholder: t('simple_form.labels.defaults.confirm_password'), required: true, input_html: { 'aria-label' => t('simple_form.labels.defaults.confirm_password'), :autocomplete => 'new-password' }, hint: false, disabled: disabled - - = f.input :confirm_password, as: :string, placeholder: t('simple_form.labels.defaults.honeypot', label: t('simple_form.labels.defaults.password')), required: false, input_html: { 'aria-label' => t('simple_form.labels.defaults.honeypot', label: t('simple_form.labels.defaults.password')), :autocomplete => 'off' }, hint: false, disabled: disabled - = f.input :website, as: :url, placeholder: t('simple_form.labels.defaults.honeypot', label: 'Website'), required: false, input_html: { 'aria-label' => t('simple_form.labels.defaults.honeypot', label: 'Website'), :autocomplete => 'off' }, hint: false, disabled: disabled - - - if approved_registrations? - .fields-group - = f.simple_fields_for :invite_request do |invite_request_fields| - = invite_request_fields.input :text, as: :text, wrapper: :with_block_label, required: Setting.require_invite_text - - .fields-group - = f.input :agreement, as: :boolean, wrapper: :with_label, label: t('auth.checkbox_agreement_html', rules_path: about_more_path, terms_path: terms_path), required: true, disabled: disabled - - .actions - = f.button :button, sign_up_message, type: :submit, class: 'button button-primary', disabled: disabled - - - if show_message - .simple_form__overlay-area__overlay - .simple_form__overlay-area__overlay__content.rich-formatting - .block-icon= fa_icon 'warning' - - if current_account.present? - = t('about.logout_before_registering') - - else - = @instance_presenter.closed_registrations_message.html_safe diff --git a/app/views/about/more.html.haml b/app/views/about/more.html.haml deleted file mode 100644 index a75549120..000000000 --- a/app/views/about/more.html.haml +++ /dev/null @@ -1,95 +0,0 @@ -- content_for :page_title do - = site_hostname - -- content_for :header_tags do - = render partial: 'shared/og' - -.grid-4 - .column-0 - .public-account-header.public-account-header--no-bar - .public-account-header__image - = image_tag @instance_presenter.hero&.file&.url || @instance_presenter.thumbnail&.file&.url || asset_pack_path('media/images/preview.png'), alt: @instance_presenter.title, class: 'parallax' - - .column-1 - .landing-page__call-to-action{ dir: 'ltr' } - .row - .row__information-board - .information-board__section - %span= t 'about.user_count_before' - %strong= friendly_number_to_human @instance_presenter.user_count - %span= t 'about.user_count_after', count: @instance_presenter.user_count - .information-board__section - %span= t 'about.status_count_before' - %strong= friendly_number_to_human @instance_presenter.status_count - %span= t 'about.status_count_after', count: @instance_presenter.status_count - .row__mascot - .landing-page__mascot - = image_tag @instance_presenter.mascot&.file&.url || asset_pack_path('media/images/elephant_ui_plane.svg'), alt: '' - - .column-2 - .contact-widget - %h4= t 'about.administered_by' - - = account_link_to(@instance_presenter.contact.account) - - - if @instance_presenter.contact.email.present? - %h4 - = succeed ':' do - = t 'about.contact' - - = mail_to @instance_presenter.contact.email, nil, title: @instance_presenter.contact.email - - .column-3 - = render 'application/flashes' - - - if @contents.blank? && @rules.empty? && (!display_blocks? || @blocks&.empty?) - = nothing_here - - else - .box-widget - .rich-formatting - - unless @rules.empty? - %h2#rules= t('about.rules') - - %p= t('about.rules_html') - - %ol.rules-list - - @rules.each do |rule| - %li - .rules-list__text= rule.text - - = @contents.html_safe - - - if display_blocks? && !@blocks.empty? - %h2#unavailable-content= t('about.unavailable_content') - - %p= t('about.unavailable_content_html') - - - if (blocks = @blocks.select(&:reject_media?)) && !blocks.empty? - %h3= t('about.unavailable_content_description.rejecting_media_title') - %p= t('about.unavailable_content_description.rejecting_media') - = render partial: 'domain_blocks', locals: { domain_blocks: blocks } - - if (blocks = @blocks.select(&:silence?)) && !blocks.empty? - %h3= t('about.unavailable_content_description.silenced_title') - %p= t('about.unavailable_content_description.silenced') - = render partial: 'domain_blocks', locals: { domain_blocks: blocks } - - if (blocks = @blocks.select(&:suspend?)) && !blocks.empty? - %h3= t('about.unavailable_content_description.suspended_title') - %p= t('about.unavailable_content_description.suspended') - = render partial: 'domain_blocks', locals: { domain_blocks: blocks } - - .column-4 - %ul.table-of-contents - - unless @rules.empty? - %li= link_to t('about.rules'), '#rules' - - - @table_of_contents.each do |item| - %li - = link_to item.title, "##{item.anchor}" - - - unless item.children.empty? - %ul - - item.children.each do |sub_item| - %li= link_to sub_item.title, "##{sub_item.anchor}" - - - if display_blocks? && !@blocks.empty? - %li= link_to t('about.unavailable_content'), '#unavailable-content' diff --git a/app/views/about/show.html.haml b/app/views/about/show.html.haml index 8d09a2938..05d8989ad 100644 --- a/app/views/about/show.html.haml +++ b/app/views/about/show.html.haml @@ -1,82 +1,7 @@ - content_for :page_title do - = site_hostname + = t('about.title') - content_for :header_tags do - %link{ rel: 'canonical', href: about_url }/ = render partial: 'shared/og' -.landing - .landing__brand - = link_to root_url, class: 'brand' do - = logo_as_symbol(:wordmark) - %span.brand__tagline=t 'about.tagline' - - .landing__grid - .landing__grid__column.landing__grid__column-registration - .box-widget - = render 'registration' - - .directory - - if Setting.profile_directory - .directory__tag - = optional_link_to Setting.profile_directory, explore_path do - %h4 - = fa_icon 'address-book fw' - = t('about.discover_users') - %small= t('about.browse_directory') - - .avatar-stack - - @instance_presenter.sample_accounts.each do |account| - = image_tag current_account&.user&.setting_auto_play_gif ? account.avatar_original_url : account.avatar_static_url, alt: '', class: 'account__avatar' - - - if Setting.timeline_preview - .directory__tag - = optional_link_to Setting.timeline_preview, public_timeline_path do - %h4 - = fa_icon 'globe fw' - = t('about.see_whats_happening') - %small= t('about.browse_public_posts') - - .directory__tag - = link_to 'https://joinmastodon.org/apps', target: '_blank', rel: 'noopener noreferrer' do - %h4 - = fa_icon 'tablet fw' - = t('about.get_apps') - %small= t('about.apps_platforms') - - .landing__grid__column.landing__grid__column-login - .box-widget - - if current_user.present? - = render 'logged_in' - - else - = render 'login' - - .hero-widget - .hero-widget__img - = image_tag @instance_presenter.hero&.file&.url || @instance_presenter.thumbnail&.file&.url || asset_pack_path('media/images/preview.png'), alt: @instance_presenter.title - - .hero-widget__text - %p - = @instance_presenter.description.html_safe.presence || t('about.about_mastodon_html') - = link_to about_more_path do - = t('about.learn_more') - = fa_icon 'angle-double-right' - - .hero-widget__footer - .hero-widget__footer__column - %h4= t 'about.administered_by' - - = account_link_to @instance_presenter.contact.account - - .hero-widget__footer__column - %h4= t 'about.server_stats' - - .hero-widget__counters__wrapper - .hero-widget__counter - %strong= friendly_number_to_human @instance_presenter.user_count - %span= t 'about.user_count_after', count: @instance_presenter.user_count - .hero-widget__counter - %strong= friendly_number_to_human @instance_presenter.active_user_count - %span - = t 'about.active_count_after' - %abbr{ title: t('about.active_footnote') } * += render partial: 'shared/web_app' diff --git a/app/views/accounts/_bio.html.haml b/app/views/accounts/_bio.html.haml deleted file mode 100644 index e2539b1d4..000000000 --- a/app/views/accounts/_bio.html.haml +++ /dev/null @@ -1,21 +0,0 @@ -- fields = account.fields - -.public-account-bio - - unless fields.empty? - .account__header__fields - - fields.each do |field| - %dl - %dt.emojify{ title: field.name }= prerender_custom_emojis(h(field.name), account.emojis) - %dd{ title: field.value, class: custom_field_classes(field) } - - if field.verified? - %span.verified__mark{ title: t('accounts.link_verified_on', date: l(field.verified_at)) } - = fa_icon 'check' - = prerender_custom_emojis(account_field_value_format(field), account.emojis) - - = account_badge(account) - - - if account.note.present? - .account__header__content.emojify= prerender_custom_emojis(account_bio_format(account), account.emojis) - - .public-account-bio__extra - = t 'accounts.joined', date: l(account.created_at, format: :month) diff --git a/app/views/accounts/_header.html.haml b/app/views/accounts/_header.html.haml deleted file mode 100644 index d583edbd2..000000000 --- a/app/views/accounts/_header.html.haml +++ /dev/null @@ -1,43 +0,0 @@ -.public-account-header{:class => ("inactive" if account.moved?)} - .public-account-header__image - = image_tag (prefers_autoplay? ? account.header_original_url : account.header_static_url), class: 'parallax' - .public-account-header__bar - = link_to short_account_url(account), class: 'avatar' do - = image_tag (prefers_autoplay? ? account.avatar_original_url : account.avatar_static_url), id: 'profile_page_avatar', data: { original: full_asset_url(account.avatar_original_url), static: full_asset_url(account.avatar_static_url), autoplay: prefers_autoplay? } - .public-account-header__tabs - .public-account-header__tabs__name - %h1 - = display_name(account, custom_emojify: true) - %small - = acct(account) - = fa_icon('lock') if account.locked? - .public-account-header__tabs__tabs - .details-counters - .counter{ class: active_nav_class(short_account_url(account), short_account_with_replies_url(account), short_account_media_url(account)) } - = link_to short_account_url(account), class: 'u-url u-uid', title: number_with_delimiter(account.statuses_count) do - %span.counter-number= friendly_number_to_human account.statuses_count - %span.counter-label= t('accounts.posts', count: account.statuses_count) - - .counter{ class: active_nav_class(account_following_index_url(account)) } - = link_to account_following_index_url(account), title: number_with_delimiter(account.following_count) do - %span.counter-number= friendly_number_to_human account.following_count - %span.counter-label= t('accounts.following', count: account.following_count) - - .counter{ class: active_nav_class(account_followers_url(account)) } - = link_to account_followers_url(account), title: hide_followers_count?(account) ? nil : number_with_delimiter(account.followers_count) do - %span.counter-number= hide_followers_count?(account) ? '-' : (friendly_number_to_human account.followers_count) - %span.counter-label= t('accounts.followers', count: account.followers_count) - .spacer - .public-account-header__tabs__tabs__buttons - = account_action_button(account) - - .public-account-header__extra - = render 'accounts/bio', account: account - - .public-account-header__extra__links - = link_to account_following_index_url(account) do - %strong= friendly_number_to_human account.following_count - = t('accounts.following', count: account.following_count) - = link_to account_followers_url(account) do - %strong= hide_followers_count?(account) ? '-' : (friendly_number_to_human account.followers_count) - = t('accounts.followers', count: account.followers_count) diff --git a/app/views/accounts/_moved.html.haml b/app/views/accounts/_moved.html.haml deleted file mode 100644 index 2f46e0dd0..000000000 --- a/app/views/accounts/_moved.html.haml +++ /dev/null @@ -1,20 +0,0 @@ -- moved_to_account = account.moved_to_account - -.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.pretty_acct)])), ActivityPub::TagManager.instance.url_for(moved_to_account), class: 'mention')) - - .moved-account-widget__card - = link_to ActivityPub::TagManager.instance.url_for(moved_to_account), class: 'detailed-status__display-name p-author h-card', target: '_blank', rel: 'me noopener noreferrer' do - .detailed-status__display-avatar - .account__avatar-overlay - .account__avatar-overlay-base - = image_tag moved_to_account.avatar_static_url - .account__avatar-overlay-overlay - = image_tag account.avatar_static_url - - %span.display-name - %bdi - %strong.emojify= display_name(moved_to_account, custom_emojify: true) - %span @#{moved_to_account.pretty_acct} diff --git a/app/views/accounts/show.html.haml b/app/views/accounts/show.html.haml index 7fa688bd3..a51dcd7be 100644 --- a/app/views/accounts/show.html.haml +++ b/app/views/accounts/show.html.haml @@ -2,85 +2,13 @@ = "#{display_name(@account)} (#{acct(@account)})" - content_for :header_tags do - - if @account.user&.setting_noindex + - if @account.user_prefers_noindex? %meta{ name: 'robots', content: 'noindex, noarchive' }/ %link{ rel: 'alternate', type: 'application/rss+xml', href: @rss_url }/ %link{ rel: 'alternate', type: 'application/activity+json', href: ActivityPub::TagManager.instance.uri_for(@account) }/ - - if @older_url - %link{ rel: 'next', href: @older_url }/ - - if @newer_url - %link{ rel: 'prev', href: @newer_url }/ - = opengraph 'og:type', 'profile' = render 'og', account: @account, url: short_account_url(@account, only_path: false) - -= render 'header', account: @account, with_bio: true - -.grid - .column-0 - .h-feed - %data.p-name{ value: "#{@account.username} on #{site_hostname}" }/ - - .account__section-headline - = active_link_to t('accounts.posts_tab_heading'), short_account_url(@account) - = active_link_to t('accounts.posts_with_replies'), short_account_with_replies_url(@account) - = active_link_to t('accounts.media'), short_account_media_url(@account) - - - if user_signed_in? && @account.blocking?(current_account) - .nothing-here.nothing-here--under-tabs= t('accounts.unavailable') - - elsif @statuses.empty? - = nothing_here 'nothing-here--under-tabs' - - else - .activity-stream.activity-stream--under-tabs - - if params[:page].to_i.zero? - = render partial: 'statuses/status', collection: @pinned_statuses, as: :status, locals: { pinned: true } - - - if @newer_url - .entry= link_to_newer @newer_url - - = render partial: 'statuses/status', collection: @statuses, as: :status - - - if @older_url - .entry= link_to_older @older_url - - .column-1 - - if @account.memorial? - .memoriam-widget= t('in_memoriam_html') - - elsif @account.moved? - = render 'moved', account: @account - - = render 'bio', account: @account - - - if @endorsed_accounts.empty? && @account.id == current_account&.id - .placeholder-widget= t('accounts.endorsements_hint') - - elsif !@endorsed_accounts.empty? - .endorsements-widget - %h4= t 'accounts.choices_html', name: content_tag(:bdi, display_name(@account, custom_emojify: true)) - - - @endorsed_accounts.each do |account| - = account_link_to account - - - if @featured_hashtags.empty? && @account.id == current_account&.id - .placeholder-widget - = t('accounts.featured_tags_hint') - = link_to settings_featured_tags_path do - = t('featured_tags.add_new') - = fa_icon 'chevron-right fw' - - else - - @featured_hashtags.each do |featured_tag| - .directory__tag{ class: params[:tag] == featured_tag.name ? 'active' : nil } - = link_to short_account_tag_path(@account, featured_tag.tag) do - %h4 - = fa_icon 'hashtag' - = featured_tag.display_name - %small - - if featured_tag.last_status_at.nil? - = t('accounts.nothing_here') - - else - %time.formatted{ datetime: featured_tag.last_status_at.iso8601, title: l(featured_tag.last_status_at) }= l featured_tag.last_status_at - .trends__item__current= friendly_number_to_human featured_tag.statuses_count - - = render 'application/sidebar' += render partial: 'shared/web_app' diff --git a/app/views/admin/announcements/edit.html.haml b/app/views/admin/announcements/edit.html.haml index 5f56db5e7..0f9727014 100644 --- a/app/views/admin/announcements/edit.html.haml +++ b/app/views/admin/announcements/edit.html.haml @@ -5,8 +5,8 @@ = render 'shared/error_messages', object: @announcement .fields-group - = f.input :starts_at, include_blank: true, wrapper: :with_block_label - = f.input :ends_at, include_blank: true, wrapper: :with_block_label + = f.input :starts_at, include_blank: true, wrapper: :with_block_label, html5: true, input_html: { pattern: '[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}(:[0-9]{2}){1,2}', placeholder: Time.now.strftime('%FT%R') } + = f.input :ends_at, include_blank: true, wrapper: :with_block_label, html5: true, input_html: { pattern: '[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}(:[0-9]{2}){1,2}', placeholder: Time.now.strftime('%FT%R') } .fields-group = f.input :all_day, as: :boolean, wrapper: :with_label diff --git a/app/views/admin/announcements/new.html.haml b/app/views/admin/announcements/new.html.haml index a5298c5f6..b2f0c01ec 100644 --- a/app/views/admin/announcements/new.html.haml +++ b/app/views/admin/announcements/new.html.haml @@ -5,8 +5,8 @@ = render 'shared/error_messages', object: @announcement .fields-group - = f.input :starts_at, include_blank: true, wrapper: :with_block_label - = f.input :ends_at, include_blank: true, wrapper: :with_block_label + = f.input :starts_at, include_blank: true, wrapper: :with_block_label, html5: true, input_html: { pattern: '[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}(:[0-9]{2}){1,2}', placeholder: Time.now.strftime('%FT%R') } + = f.input :ends_at, include_blank: true, wrapper: :with_block_label, html5: true, input_html: { pattern: '[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}(:[0-9]{2}){1,2}', placeholder: Time.now.strftime('%FT%R') } .fields-group = f.input :all_day, as: :boolean, wrapper: :with_label @@ -15,7 +15,7 @@ = f.input :text, wrapper: :with_block_label .fields-group - = f.input :scheduled_at, include_blank: true, wrapper: :with_block_label + = f.input :scheduled_at, include_blank: true, wrapper: :with_block_label, html5: true, input_html: { pattern: '[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}(:[0-9]{2}){1,2}', placeholder: Time.now.strftime('%FT%R') } .actions = f.button :button, t('.create'), type: :submit diff --git a/app/views/admin/reports/_media_attachments.html.haml b/app/views/admin/reports/_media_attachments.html.haml new file mode 100644 index 000000000..d0b7d52c3 --- /dev/null +++ b/app/views/admin/reports/_media_attachments.html.haml @@ -0,0 +1,8 @@ +- if status.ordered_media_attachments.first.video? + - video = status.ordered_media_attachments.first + = react_component :video, src: video.file.url(:original), preview: video.file.url(:small), frameRate: video.file.meta.dig('original', 'frame_rate'), blurhash: video.blurhash, sensitive: status.sensitive?, visible: false, width: 610, height: 343, inline: true, alt: video.description, media: [ActiveModelSerializers::SerializableResource.new(video, serializer: REST::MediaAttachmentSerializer)].as_json +- elsif status.ordered_media_attachments.first.audio? + - audio = status.ordered_media_attachments.first + = react_component :audio, src: audio.file.url(:original), height: 110, alt: audio.description, duration: audio.file.meta.dig(:original, :duration) +- else + = react_component :media_gallery, height: 343, sensitive: status.sensitive?, visible: false, media: status.ordered_media_attachments.map { |a| ActiveModelSerializers::SerializableResource.new(a, serializer: REST::MediaAttachmentSerializer).as_json } diff --git a/app/views/admin/reports/_status.html.haml b/app/views/admin/reports/_status.html.haml index 392fc8f81..b2982a42b 100644 --- a/app/views/admin/reports/_status.html.haml +++ b/app/views/admin/reports/_status.html.haml @@ -12,14 +12,7 @@ = prerender_custom_emojis(status_content_format(status.proper), status.proper.emojis) - unless status.proper.ordered_media_attachments.empty? - - if status.proper.ordered_media_attachments.first.video? - - video = status.proper.ordered_media_attachments.first - = react_component :video, src: video.file.url(:original), preview: video.file.url(:small), frameRate: video.file.meta.dig('original', 'frame_rate'), blurhash: video.blurhash, sensitive: status.proper.sensitive?, visible: false, width: 610, height: 343, inline: true, alt: video.description, media: [ActiveModelSerializers::SerializableResource.new(video, serializer: REST::MediaAttachmentSerializer)].as_json - - elsif status.proper.ordered_media_attachments.first.audio? - - audio = status.proper.ordered_media_attachments.first - = react_component :audio, src: audio.file.url(:original), height: 110, alt: audio.description, duration: audio.file.meta.dig(:original, :duration) - - else - = react_component :media_gallery, height: 343, sensitive: status.proper.sensitive?, visible: false, media: status.proper.ordered_media_attachments.map { |a| ActiveModelSerializers::SerializableResource.new(a, serializer: REST::MediaAttachmentSerializer).as_json } + = render partial: 'admin/reports/media_attachments', locals: { status: status.proper } .detailed-status__meta - if status.application @@ -29,7 +22,7 @@ %time.formatted{ datetime: status.created_at.iso8601, title: l(status.created_at) }= l(status.created_at) - if status.edited? · - = t('statuses.edited_at_html', date: content_tag(:time, l(status.edited_at), datetime: status.edited_at.iso8601, title: l(status.edited_at), class: 'formatted')) + = link_to t('statuses.edited_at_html', date: content_tag(:time, l(status.edited_at), datetime: status.edited_at.iso8601, title: l(status.edited_at), class: 'formatted')), admin_account_status_path(status.account_id, status), class: 'detailed-status__datetime' - if status.discarded? · %span.negative-hint= t('admin.statuses.deleted') diff --git a/app/views/admin/settings/about/show.html.haml b/app/views/admin/settings/about/show.html.haml new file mode 100644 index 000000000..6ee719e36 --- /dev/null +++ b/app/views/admin/settings/about/show.html.haml @@ -0,0 +1,30 @@ +- content_for :page_title do + = t('admin.settings.about.title') + +- content_for :heading do + %h2= t('admin.settings.title') + = render partial: 'admin/settings/shared/links' + += simple_form_for @admin_settings, url: admin_settings_about_path, html: { method: :patch } do |f| + = render 'shared/error_messages', object: @admin_settings + + %p.lead= t('admin.settings.about.preamble') + + .fields-group + = f.input :site_extended_description, wrapper: :with_block_label, as: :text, input_html: { rows: 8 } + + %p.hint + = t 'admin.settings.about.rules_hint' + = link_to t('admin.settings.about.manage_rules'), admin_rules_path + + .fields-row + .fields-row__column.fields-row__column-6.fields-group + = f.input :show_domain_blocks, wrapper: :with_label, collection: %i(disabled users all), label_method: lambda { |value| t("admin.settings.domain_blocks.#{value}") }, include_blank: false, collection_wrapper_tag: 'ul', item_wrapper_tag: 'li' + .fields-row__column.fields-row__column-6.fields-group + = f.input :show_domain_blocks_rationale, wrapper: :with_label, collection: %i(disabled users all), label_method: lambda { |value| t("admin.settings.domain_blocks.#{value}") }, include_blank: false, collection_wrapper_tag: 'ul', item_wrapper_tag: 'li' + + .fields-group + = f.input :site_terms, wrapper: :with_block_label, as: :text, input_html: { rows: 8 } + + .actions + = f.button :button, t('generic.save_changes'), type: :submit diff --git a/app/views/admin/settings/appearance/show.html.haml b/app/views/admin/settings/appearance/show.html.haml new file mode 100644 index 000000000..f02ecc105 --- /dev/null +++ b/app/views/admin/settings/appearance/show.html.haml @@ -0,0 +1,31 @@ +- content_for :page_title do + = t('admin.settings.appearance.title') + +- content_for :heading do + %h2= t('admin.settings.title') + = render partial: 'admin/settings/shared/links' + += simple_form_for @admin_settings, url: admin_settings_appearance_path, html: { method: :patch } do |f| + = render 'shared/error_messages', object: @admin_settings + + %p.lead= t('admin.settings.appearance.preamble') + + .fields-group + = f.input :flavour_and_skin, collection: Themes.instance.flavours_and_skins, group_label_method: lambda { |(flavour, _)| I18n.t("flavours.#{flavour}.name", default: flavour) }, wrapper: :with_label, label: t('admin.settings.flavour_and_skin.title'), include_blank: false, as: :grouped_select, label_method: :last, value_method: lambda { |value| value.join('/') }, group_method: :last + + .fields-group + = f.input :custom_css, wrapper: :with_block_label, as: :text, input_html: { rows: 8 } + + .fields-row + .fields-row__column.fields-row__column-6.fields-group + = f.input :mascot, as: :file, wrapper: :with_block_label + + .fields-row__column.fields-row__column-6.fields-group + - if @admin_settings.mascot.persisted? + = image_tag @admin_settings.mascot.file.url, class: 'fields-group__thumbnail' + = link_to admin_site_upload_path(@admin_settings.mascot), data: { method: :delete }, class: 'link-button link-button--destructive' do + = fa_icon 'trash fw' + = t('admin.site_uploads.delete') + + .actions + = f.button :button, t('generic.save_changes'), type: :submit diff --git a/app/views/admin/settings/branding/show.html.haml b/app/views/admin/settings/branding/show.html.haml new file mode 100644 index 000000000..aee730689 --- /dev/null +++ b/app/views/admin/settings/branding/show.html.haml @@ -0,0 +1,36 @@ +- content_for :page_title do + = t('admin.settings.branding.title') + +- content_for :heading do + %h2= t('admin.settings.title') + = render partial: 'admin/settings/shared/links' + += simple_form_for @admin_settings, url: admin_settings_branding_path, html: { method: :patch } do |f| + = render 'shared/error_messages', object: @admin_settings + + %p.lead= t('admin.settings.branding.preamble') + + .fields-group + = f.input :site_title, wrapper: :with_label + + .fields-row + .fields-row__column.fields-row__column-6.fields-group + = f.input :site_contact_username, wrapper: :with_label + .fields-row__column.fields-row__column-6.fields-group + = f.input :site_contact_email, wrapper: :with_label + + .fields-group + = f.input :site_short_description, wrapper: :with_block_label, as: :text, input_html: { rows: 2, maxlength: 200 } + + .fields-row + .fields-row__column.fields-row__column-6.fields-group + = f.input :thumbnail, as: :file, wrapper: :with_block_label + .fields-row__column.fields-row__column-6.fields-group + - if @admin_settings.thumbnail.persisted? + = image_tag @admin_settings.thumbnail.file.url(:'@1x'), class: 'fields-group__thumbnail' + = link_to admin_site_upload_path(@admin_settings.thumbnail), data: { method: :delete }, class: 'link-button link-button--destructive' do + = fa_icon 'trash fw' + = t('admin.site_uploads.delete') + + .actions + = f.button :button, t('generic.save_changes'), type: :submit diff --git a/app/views/admin/settings/content_retention/show.html.haml b/app/views/admin/settings/content_retention/show.html.haml new file mode 100644 index 000000000..b9467572a --- /dev/null +++ b/app/views/admin/settings/content_retention/show.html.haml @@ -0,0 +1,19 @@ +- content_for :page_title do + = t('admin.settings.content_retention.title') + +- content_for :heading do + %h2= t('admin.settings.title') + = render partial: 'admin/settings/shared/links' + += simple_form_for @admin_settings, url: admin_settings_content_retention_path, html: { method: :patch } do |f| + = render 'shared/error_messages', object: @admin_settings + + %p.lead= t('admin.settings.content_retention.preamble') + + .fields-group + = f.input :media_cache_retention_period, wrapper: :with_block_label, input_html: { pattern: '[0-9]+' } + = f.input :content_cache_retention_period, wrapper: :with_block_label, input_html: { pattern: '[0-9]+' } + = f.input :backups_retention_period, wrapper: :with_block_label, input_html: { pattern: '[0-9]+' } + + .actions + = f.button :button, t('generic.save_changes'), type: :submit diff --git a/app/views/admin/settings/discovery/show.html.haml b/app/views/admin/settings/discovery/show.html.haml new file mode 100644 index 000000000..9b6424c79 --- /dev/null +++ b/app/views/admin/settings/discovery/show.html.haml @@ -0,0 +1,40 @@ +- content_for :page_title do + = t('admin.settings.discovery.title') + +- content_for :heading do + %h2= t('admin.settings.title') + = render partial: 'admin/settings/shared/links' + += simple_form_for @admin_settings, url: admin_settings_discovery_path, html: { method: :patch } do |f| + = render 'shared/error_messages', object: @admin_settings + + %p.lead= t('admin.settings.discovery.preamble') + + %h4= t('admin.settings.discovery.trends') + + .fields-group + = f.input :trends, as: :boolean, wrapper: :with_label + + .fields-group + = f.input :trendable_by_default, as: :boolean, wrapper: :with_label, recommended: :not_recommended + + .fields-group + = f.input :trending_status_cw, as: :boolean, wrapper: :with_label, label: t('admin.settings.trending_status_cw.title'), hint: t('admin.settings.trending_status_cw.desc_html') + + %h4= t('admin.settings.discovery.public_timelines') + + .fields-group + = f.input :timeline_preview, as: :boolean, wrapper: :with_label + + %h4= t('admin.settings.discovery.follow_recommendations') + + .fields-group + = f.input :bootstrap_timeline_accounts, wrapper: :with_block_label + + %h4= t('admin.settings.discovery.profile_directory') + + .fields-group + = f.input :profile_directory, as: :boolean, wrapper: :with_label + + .actions + = f.button :button, t('generic.save_changes'), type: :submit diff --git a/app/views/admin/settings/edit.html.haml b/app/views/admin/settings/edit.html.haml deleted file mode 100644 index f2fdab90d..000000000 --- a/app/views/admin/settings/edit.html.haml +++ /dev/null @@ -1,126 +0,0 @@ -- content_for :page_title do - = t('admin.settings.title') - - - content_for :heading_actions do - = button_tag t('generic.save_changes'), class: 'button', form: 'edit_admin' - -= simple_form_for @admin_settings, url: admin_settings_path, html: { method: :patch, id: 'edit_admin' } do |f| - = render 'shared/error_messages', object: @admin_settings - - .fields-group - = f.input :site_title, wrapper: :with_label, label: t('admin.settings.site_title') - - .fields-row - .fields-row__column.fields-row__column-6.fields-group - = f.input :flavour_and_skin, collection: Themes.instance.flavours_and_skins, group_label_method: lambda { |(flavour, _)| I18n.t("flavours.#{flavour}.name", default: flavour) }, wrapper: :with_label, label: t('admin.settings.flavour_and_skin.title'), include_blank: false, as: :grouped_select, label_method: :last, value_method: lambda { |value| value.join('/') }, group_method: :last - .fields-row__column.fields-row__column-6.fields-group - = f.input :registrations_mode, collection: %w(open approved none), wrapper: :with_label, label: t('admin.settings.registrations_mode.title'), include_blank: false, label_method: lambda { |mode| I18n.t("admin.settings.registrations_mode.modes.#{mode}") } - - .fields-row - .fields-row__column.fields-row__column-6.fields-group - = f.input :site_contact_username, wrapper: :with_label, label: t('admin.settings.contact_information.username') - .fields-row__column.fields-row__column-6.fields-group - = f.input :site_contact_email, wrapper: :with_label, label: t('admin.settings.contact_information.email') - - .fields-group - = f.input :site_short_description, wrapper: :with_block_label, as: :text, label: t('admin.settings.site_short_description.title'), hint: t('admin.settings.site_short_description.desc_html'), input_html: { rows: 2 } - - .fields-group - = f.input :site_description, wrapper: :with_block_label, as: :text, label: t('admin.settings.site_description.title'), hint: t('admin.settings.site_description.desc_html'), input_html: { rows: 2 } - - .fields-row - .fields-row__column.fields-row__column-6.fields-group - = f.input :thumbnail, as: :file, wrapper: :with_block_label, label: t('admin.settings.thumbnail.title'), hint: site_upload_delete_hint(t('admin.settings.thumbnail.desc_html'), :thumbnail) - .fields-row__column.fields-row__column-6.fields-group - = f.input :hero, as: :file, wrapper: :with_block_label, label: t('admin.settings.hero.title'), hint: site_upload_delete_hint(t('admin.settings.hero.desc_html'), :hero) - - .fields-row - .fields-row__column.fields-row__column-6.fields-group - = f.input :mascot, as: :file, wrapper: :with_block_label, label: t('admin.settings.mascot.title'), hint: site_upload_delete_hint(t('admin.settings.mascot.desc_html'), :mascot) - - %hr.spacer/ - - .fields-group - = f.input :require_invite_text, as: :boolean, wrapper: :with_label, label: t('admin.settings.registrations.require_invite_text.title'), hint: t('admin.settings.registrations.require_invite_text.desc_html'), disabled: !approved_registrations? - - - if captcha_available? - .fields-group - = f.input :captcha_enabled, as: :boolean, wrapper: :with_label, label: t('admin.settings.captcha_enabled.title'), hint: t('admin.settings.captcha_enabled.desc_html') - - %hr.spacer/ - - .fields-group - = f.input :bootstrap_timeline_accounts, wrapper: :with_block_label, label: t('admin.settings.bootstrap_timeline_accounts.title'), hint: t('admin.settings.bootstrap_timeline_accounts.desc_html') - - %hr.spacer/ - - - unless whitelist_mode? - .fields-group - = f.input :timeline_preview, as: :boolean, wrapper: :with_label, label: t('admin.settings.timeline_preview.title'), hint: t('admin.settings.timeline_preview.desc_html') - - .fields-group - = f.input :show_known_fediverse_at_about_page, as: :boolean, wrapper: :with_label, label: t('admin.settings.show_known_fediverse_at_about_page.title'), hint: t('admin.settings.show_known_fediverse_at_about_page.desc_html') - - .fields-group - = f.input :open_deletion, as: :boolean, wrapper: :with_label, label: t('admin.settings.registrations.deletion.title'), hint: t('admin.settings.registrations.deletion.desc_html') - - - unless whitelist_mode? - .fields-group - = f.input :activity_api_enabled, as: :boolean, wrapper: :with_label, label: t('admin.settings.activity_api_enabled.title'), hint: t('admin.settings.activity_api_enabled.desc_html'), recommended: true - - .fields-group - = f.input :peers_api_enabled, as: :boolean, wrapper: :with_label, label: t('admin.settings.peers_api_enabled.title'), hint: t('admin.settings.peers_api_enabled.desc_html'), recommended: true - - .fields-group - = f.input :preview_sensitive_media, as: :boolean, wrapper: :with_label, label: t('admin.settings.preview_sensitive_media.title'), hint: t('admin.settings.preview_sensitive_media.desc_html') - - .fields-group - = f.input :profile_directory, as: :boolean, wrapper: :with_label, label: t('admin.settings.profile_directory.title'), hint: t('admin.settings.profile_directory.desc_html') - - .fields-group - = f.input :trends, as: :boolean, wrapper: :with_label, label: t('admin.settings.trends.title'), hint: t('admin.settings.trends.desc_html') - - .fields-group - = f.input :trendable_by_default, as: :boolean, wrapper: :with_label, label: t('admin.settings.trendable_by_default.title'), hint: t('admin.settings.trendable_by_default.desc_html') - - .fields-group - = f.input :trending_status_cw, as: :boolean, wrapper: :with_label, label: t('admin.settings.trending_status_cw.title'), hint: t('admin.settings.trending_status_cw.desc_html') - - .fields-group - = f.input :noindex, as: :boolean, wrapper: :with_label, label: t('admin.settings.default_noindex.title'), hint: t('admin.settings.default_noindex.desc_html') - - .fields-group - = f.input :hide_followers_count, as: :boolean, wrapper: :with_label, label: t('admin.settings.hide_followers_count.title'), hint: t('admin.settings.hide_followers_count.desc_html') - - .fields-group - = f.input :show_reblogs_in_public_timelines, as: :boolean, wrapper: :with_label, label: t('admin.settings.show_reblogs_in_public_timelines.title'), hint: t('admin.settings.show_reblogs_in_public_timelines.desc_html') - - .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') - - %hr.spacer/ - - .fields-row - .fields-row__column.fields-row__column-6.fields-group - = f.input :show_domain_blocks, wrapper: :with_label, collection: %i(disabled users all), label: t('admin.settings.domain_blocks.title'), label_method: lambda { |value| t("admin.settings.domain_blocks.#{value}") }, include_blank: false, collection_wrapper_tag: 'ul', item_wrapper_tag: 'li' - .fields-row__column.fields-row__column-6.fields-group - = f.input :show_domain_blocks_rationale, wrapper: :with_label, collection: %i(disabled users all), label: t('admin.settings.domain_blocks_rationale.title'), label_method: lambda { |value| t("admin.settings.domain_blocks.#{value}") }, include_blank: false, collection_wrapper_tag: 'ul', item_wrapper_tag: 'li' - - .fields-group - = f.input :outgoing_spoilers, wrapper: :with_label, label: t('admin.settings.outgoing_spoilers.title'), hint: t('admin.settings.outgoing_spoilers.desc_html') - - .fields-group - = f.input :site_extended_description, wrapper: :with_block_label, as: :text, label: t('admin.settings.site_description_extended.title'), hint: t('admin.settings.site_description_extended.desc_html'), input_html: { rows: 8 } unless whitelist_mode? - = f.input :closed_registrations_message, as: :text, wrapper: :with_block_label, label: t('admin.settings.registrations.closed_message.title'), hint: t('admin.settings.registrations.closed_message.desc_html'), input_html: { rows: 8 } - = f.input :site_terms, wrapper: :with_block_label, as: :text, label: t('admin.settings.site_terms.title'), hint: t('admin.settings.site_terms.desc_html'), input_html: { rows: 8 } - = f.input :custom_css, wrapper: :with_block_label, as: :text, input_html: { rows: 8 }, label: t('admin.settings.custom_css.title'), hint: t('admin.settings.custom_css.desc_html') - - %hr.spacer/ - - .fields-group - = f.input :media_cache_retention_period, wrapper: :with_block_label, input_html: { pattern: '[0-9]+' } - = f.input :content_cache_retention_period, wrapper: :with_block_label, input_html: { pattern: '[0-9]+' } - = f.input :backups_retention_period, wrapper: :with_block_label, input_html: { pattern: '[0-9]+' } - - .actions - = f.button :button, t('generic.save_changes'), type: :submit diff --git a/app/views/admin/settings/registrations/show.html.haml b/app/views/admin/settings/registrations/show.html.haml new file mode 100644 index 000000000..f5e448125 --- /dev/null +++ b/app/views/admin/settings/registrations/show.html.haml @@ -0,0 +1,28 @@ +- content_for :page_title do + = t('admin.settings.registrations.title') + +- content_for :heading do + %h2= t('admin.settings.title') + = render partial: 'admin/settings/shared/links' + += simple_form_for @admin_settings, url: admin_settings_branding_path, html: { method: :patch } do |f| + = render 'shared/error_messages', object: @admin_settings + + %p.lead= t('admin.settings.registrations.preamble') + + .fields-row + .fields-row__column.fields-row__column-6.fields-group + = f.input :registrations_mode, collection: %w(open approved none), wrapper: :with_label, include_blank: false, label_method: lambda { |mode| I18n.t("admin.settings.registrations_mode.modes.#{mode}") } + + .fields-row__column.fields-row__column-6.fields-group + = f.input :require_invite_text, as: :boolean, wrapper: :with_label, disabled: !approved_registrations? + + - if captcha_available? + .fields-group + = f.input :captcha_enabled, as: :boolean, wrapper: :with_label, label: t('admin.settings.captcha_enabled.title'), hint: t('admin.settings.captcha_enabled.desc_html') + + .fields-group + = f.input :closed_registrations_message, as: :text, wrapper: :with_block_label, input_html: { rows: 2 } + + .actions + = f.button :button, t('generic.save_changes'), type: :submit diff --git a/app/views/admin/settings/shared/_links.html.haml b/app/views/admin/settings/shared/_links.html.haml new file mode 100644 index 000000000..1294c26ce --- /dev/null +++ b/app/views/admin/settings/shared/_links.html.haml @@ -0,0 +1,8 @@ +.content__heading__tabs + = render_navigation renderer: :links do |primary| + - primary.item :branding, safe_join([fa_icon('pencil fw'), t('admin.settings.branding.title')]), admin_settings_branding_path + - primary.item :about, safe_join([fa_icon('file-text fw'), t('admin.settings.about.title')]), admin_settings_about_path + - primary.item :registrations, safe_join([fa_icon('users fw'), t('admin.settings.registrations.title')]), admin_settings_registrations_path + - primary.item :discovery, safe_join([fa_icon('search fw'), t('admin.settings.discovery.title')]), admin_settings_discovery_path + - primary.item :content_retention, safe_join([fa_icon('history fw'), t('admin.settings.content_retention.title')]), admin_settings_content_retention_path + - primary.item :appearance, safe_join([fa_icon('desktop fw'), t('admin.settings.appearance.title')]), admin_settings_appearance_path diff --git a/app/views/admin/status_edits/_status_edit.html.haml b/app/views/admin/status_edits/_status_edit.html.haml new file mode 100644 index 000000000..19a0e063d --- /dev/null +++ b/app/views/admin/status_edits/_status_edit.html.haml @@ -0,0 +1,20 @@ +.status + .status__content>< + - if status_edit.spoiler_text.blank? + = prerender_custom_emojis(status_content_format(status_edit), status_edit.emojis) + - else + %details< + %summary>< + %strong> Content warning: #{prerender_custom_emojis(h(status_edit.spoiler_text), status_edit.emojis)} + = prerender_custom_emojis(status_content_format(status_edit), status_edit.emojis) + + - unless status_edit.ordered_media_attachments.empty? + = render partial: 'admin/reports/media_attachments', locals: { status: status_edit } + + .detailed-status__meta + %time.formatted{ datetime: status_edit.created_at.iso8601, title: l(status_edit.created_at) }= l(status_edit.created_at) + + - if status_edit.sensitive? + · + = fa_icon('eye-slash fw') + = t('stream_entries.sensitive_content') diff --git a/app/views/admin/statuses/show.html.haml b/app/views/admin/statuses/show.html.haml new file mode 100644 index 000000000..1e1e63f37 --- /dev/null +++ b/app/views/admin/statuses/show.html.haml @@ -0,0 +1,61 @@ +- 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 :heading_actions do + = link_to t('admin.statuses.open'), ActivityPub::TagManager.instance.url_for(@status), class: 'button', target: '_blank' + +%h3= t('admin.statuses.metadata') + +.table-wrapper + %table.table.horizontal-table + %tbody + %tr + %th= t('admin.statuses.account') + %td= admin_account_link_to @status.account + - if @status.reply? + %tr + %th= t('admin.statuses.in_reply_to') + %td= admin_account_link_to @status.in_reply_to_account, path: admin_account_status_path(@status.thread.account_id, @status.in_reply_to_id) + %tr + %th= t('admin.statuses.application') + %td= @status.application&.name + %tr + %th= t('admin.statuses.language') + %td= standard_locale_name(@status.language) + %tr + %th= t('admin.statuses.visibility') + %td= t("statuses.visibilities.#{@status.visibility}") + - if @status.trend + %tr + %th= t('admin.statuses.trending') + %td + - if @status.trend.allowed? + %abbr{ title: t('admin.trends.tags.current_score', score: @status.trend.score) }= t('admin.trends.tags.trending_rank', rank: @status.trend.rank) + - elsif @status.trend.requires_review? + = t('admin.trends.pending_review') + - else + = t('admin.trends.not_allowed_to_trend') + %tr + %th= t('admin.statuses.reblogs') + %td= friendly_number_to_human @status.reblogs_count + %tr + %th= t('admin.statuses.favourites') + %td= friendly_number_to_human @status.favourites_count + +%hr.spacer/ + +%h3= t('admin.statuses.history') + +%ol.history + - @status.edits.includes(:account, status: [:account]).each.with_index do |status_edit, i| + %li + .history__entry + %h5 + - if i.zero? + = t('admin.statuses.original_status') + - else + = t('admin.statuses.status_changed') + · + %time.formatted{ datetime: status_edit.created_at.iso8601, title: l(status_edit.created_at) }= l(status_edit.created_at) + + = render status_edit diff --git a/app/views/admin/trends/links/_preview_card.html.haml b/app/views/admin/trends/links/_preview_card.html.haml index 7d4897c7e..8812feb31 100644 --- a/app/views/admin/trends/links/_preview_card.html.haml +++ b/app/views/admin/trends/links/_preview_card.html.haml @@ -18,9 +18,9 @@ = t('admin.trends.links.shared_by_over_week', count: preview_card.history.reduce(0) { |sum, day| sum + day.accounts }) - - if preview_card.trendable? && (rank = Trends.links.rank(preview_card.id, locale: params[:locale].presence)) + - if preview_card.trend.allowed? • - %abbr{ title: t('admin.trends.tags.current_score', score: Trends.links.score(preview_card.id, locale: params[:locale].presence)) }= t('admin.trends.tags.trending_rank', rank: rank + 1) + %abbr{ title: t('admin.trends.tags.current_score', score: preview_card.trend.score) }= t('admin.trends.tags.trending_rank', rank: preview_card.trend.rank) - if preview_card.decaying? • diff --git a/app/views/admin/trends/links/index.html.haml b/app/views/admin/trends/links/index.html.haml index 6f090df7b..e6ed9d95f 100644 --- a/app/views/admin/trends/links/index.html.haml +++ b/app/views/admin/trends/links/index.html.haml @@ -13,7 +13,7 @@ .filter-subset.filter-subset--with-select %strong= t('admin.follow_recommendations.language') .input.select.optional - = select_tag :locale, options_for_select(Trends.available_locales.map { |key| [standard_locale_name(key), key] }, params[:locale]), include_blank: true + = select_tag :locale, options_for_select(@locales.map { |key| [standard_locale_name(key), key] }, params[:locale]), include_blank: true .filter-subset %strong= t('admin.trends.trending') %ul diff --git a/app/views/admin/trends/statuses/_status.html.haml b/app/views/admin/trends/statuses/_status.html.haml index e4d75bbb9..f35e13d12 100644 --- a/app/views/admin/trends/statuses/_status.html.haml +++ b/app/views/admin/trends/statuses/_status.html.haml @@ -25,9 +25,9 @@ - if status.trendable? && !status.account.discoverable? • = t('admin.trends.statuses.not_discoverable') - - if status.trendable? && (rank = Trends.statuses.rank(status.id, locale: params[:locale].presence)) + - if status.trend.allowed? • - %abbr{ title: t('admin.trends.tags.current_score', score: Trends.statuses.score(status.id, locale: params[:locale].presence)) }= t('admin.trends.tags.trending_rank', rank: rank + 1) + %abbr{ title: t('admin.trends.tags.current_score', score: status.trend.score) }= t('admin.trends.tags.trending_rank', rank: status.trend.rank) - elsif status.requires_review? • = t('admin.trends.pending_review') diff --git a/app/views/admin/trends/statuses/index.html.haml b/app/views/admin/trends/statuses/index.html.haml index c96f4323a..bf04772f2 100644 --- a/app/views/admin/trends/statuses/index.html.haml +++ b/app/views/admin/trends/statuses/index.html.haml @@ -13,7 +13,7 @@ .filter-subset.filter-subset--with-select %strong= t('admin.follow_recommendations.language') .input.select.optional - = select_tag :locale, options_for_select(Trends.available_locales.map { |key| [standard_locale_name(key), key]}, params[:locale]), include_blank: true + = select_tag :locale, options_for_select(@locales.map { |key| [standard_locale_name(key), key] }, params[:locale]), include_blank: true .filter-subset %strong= t('admin.trends.trending') %ul diff --git a/app/views/admin_mailer/_new_trending_links.text.erb b/app/views/admin_mailer/_new_trending_links.text.erb index 405926fdd..602e12793 100644 --- a/app/views/admin_mailer/_new_trending_links.text.erb +++ b/app/views/admin_mailer/_new_trending_links.text.erb @@ -2,13 +2,7 @@ <% @links.each do |link| %> - <%= link.title %> • <%= link.url %> - <%= raw t('admin.trends.links.usage_comparison', today: link.history.get(Time.now.utc).accounts, yesterday: link.history.get(Time.now.utc - 1.day).accounts) %> • <%= t('admin.trends.tags.current_score', score: Trends.links.score(link.id).round(2)) %> -<% end %> - -<% if @lowest_trending_link %> -<%= raw t('admin_mailer.new_trends.new_trending_links.requirements', lowest_link_title: @lowest_trending_link.title, lowest_link_score: Trends.links.score(@lowest_trending_link.id).round(2), rank: Trends.links.options[:review_threshold]) %> -<% else %> -<%= raw t('admin_mailer.new_trends.new_trending_links.no_approved_links') %> + <%= standard_locale_name(link.language) %> • <%= raw t('admin.trends.links.usage_comparison', today: link.history.get(Time.now.utc).accounts, yesterday: link.history.get(Time.now.utc - 1.day).accounts) %> • <%= t('admin.trends.tags.current_score', score: link.trend.score.round(2)) %> <% end %> <%= raw t('application_mailer.view')%> <%= admin_trends_links_url %> diff --git a/app/views/admin_mailer/_new_trending_statuses.text.erb b/app/views/admin_mailer/_new_trending_statuses.text.erb index 8d11a80c2..1ed3ae857 100644 --- a/app/views/admin_mailer/_new_trending_statuses.text.erb +++ b/app/views/admin_mailer/_new_trending_statuses.text.erb @@ -2,13 +2,7 @@ <% @statuses.each do |status| %> - <%= ActivityPub::TagManager.instance.url_for(status) %> - <%= raw t('admin.trends.tags.current_score', score: Trends.statuses.score(status.id).round(2)) %> -<% end %> - -<% if @lowest_trending_status %> -<%= raw t('admin_mailer.new_trends.new_trending_statuses.requirements', lowest_status_url: ActivityPub::TagManager.instance.url_for(@lowest_trending_status), lowest_status_score: Trends.statuses.score(@lowest_trending_status.id).round(2), rank: Trends.statuses.options[:review_threshold]) %> -<% else %> -<%= raw t('admin_mailer.new_trends.new_trending_statuses.no_approved_statuses') %> + <%= standard_locale_name(status.language) %> • <%= raw t('admin.trends.tags.current_score', score: status.trend.score.round(2)) %> <% end %> <%= raw t('application_mailer.view')%> <%= admin_trends_statuses_url %> diff --git a/app/views/application/_sidebar.html.haml b/app/views/application/_sidebar.html.haml index eb2813dd0..6d18668b0 100644 --- a/app/views/application/_sidebar.html.haml +++ b/app/views/application/_sidebar.html.haml @@ -1,6 +1,6 @@ .hero-widget .hero-widget__img - = image_tag @instance_presenter.hero&.file&.url || @instance_presenter.thumbnail&.file&.url || asset_pack_path('media/images/preview.png'), alt: @instance_presenter.title + = image_tag @instance_presenter.thumbnail&.file&.url(:'@1x') || asset_pack_path('media/images/preview.png'), alt: @instance_presenter.title .hero-widget__text %p= @instance_presenter.description.html_safe.presence || t('about.about_mastodon_html') diff --git a/app/views/auth/registrations/edit.html.haml b/app/views/auth/registrations/edit.html.haml index a3445b421..df929e3e8 100644 --- a/app/views/auth/registrations/edit.html.haml +++ b/app/views/auth/registrations/edit.html.haml @@ -41,8 +41,7 @@ %h3= t('migrations.incoming_migrations') %p.muted-hint= t('migrations.incoming_migrations_html', path: settings_aliases_path) - - if open_deletion? - %hr.spacer/ + %hr.spacer/ - %h3= t('auth.delete_account') - %p.muted-hint= t('auth.delete_account_html', path: settings_delete_path) + %h3= t('auth.delete_account') + %p.muted-hint= t('auth.delete_account_html', path: settings_delete_path) diff --git a/app/views/auth/registrations/new.html.haml b/app/views/auth/registrations/new.html.haml index 6981195ed..5eb3f937c 100644 --- a/app/views/auth/registrations/new.html.haml +++ b/app/views/auth/registrations/new.html.haml @@ -5,6 +5,9 @@ = render partial: 'shared/og', locals: { description: description_for_sign_up } = simple_form_for(resource, as: resource_name, url: registration_path(resource_name), html: { novalidate: false }) do |f| + %h1.title= t('auth.sign_up.title', domain: site_hostname) + %p.lead= t('auth.sign_up.preamble') + = render 'shared/error_messages', object: resource - if @invite.present? && @invite.autofollow? @@ -12,31 +15,27 @@ %p.hint= t('invites.invited_by') = render 'application/card', account: @invite.user.account - = f.simple_fields_for :account do |ff| - .fields-group - = ff.input :username, wrapper: :with_label, autofocus: true, label: t('simple_form.labels.defaults.username'), required: true, input_html: { 'aria-label' => t('simple_form.labels.defaults.username'), :autocomplete => 'off', pattern: '[a-zA-Z0-9_]+', maxlength: 30 }, append: "@#{site_hostname}", hint: t('simple_form.hints.defaults.username', domain: site_hostname) - - .fields-group - = f.input :email, wrapper: :with_label, label: t('simple_form.labels.defaults.email'), required: true, input_html: { 'aria-label' => t('simple_form.labels.defaults.email'), :autocomplete => 'off' } - .fields-group - = f.input :password, wrapper: :with_label, label: t('simple_form.labels.defaults.password'), required: true, input_html: { 'aria-label' => t('simple_form.labels.defaults.password'), :autocomplete => 'off', :minlength => User.password_length.first, :maxlength => User.password_length.last } - - .fields-group - = f.input :password_confirmation, wrapper: :with_label, label: t('simple_form.labels.defaults.confirm_password'), required: true, input_html: { 'aria-label' => t('simple_form.labels.defaults.confirm_password'), :autocomplete => 'off' } - = f.input :confirm_password, as: :string, wrapper: :with_label, label: t('simple_form.labels.defaults.honeypot', label: t('simple_form.labels.defaults.password')), required: false, input_html: { 'aria-label' => t('simple_form.labels.defaults.honeypot', label: t('simple_form.labels.defaults.password')), :autocomplete => 'off' } - - = f.input :website, as: :url, wrapper: :with_label, label: t('simple_form.labels.defaults.honeypot', label: 'Website'), required: false, input_html: { 'aria-label' => t('simple_form.labels.defaults.honeypot', label: 'Website'), :autocomplete => 'off' } + = f.simple_fields_for :account do |ff| + = ff.input :display_name, wrapper: :with_label, label: false, required: false, input_html: { 'aria-label' => t('simple_form.labels.defaults.display_name'), :autocomplete => 'off', placeholder: t('simple_form.labels.defaults.display_name') } + = ff.input :username, wrapper: :with_label, label: false, required: true, input_html: { 'aria-label' => t('simple_form.labels.defaults.username'), :autocomplete => 'off', placeholder: t('simple_form.labels.defaults.username'), pattern: '[a-zA-Z0-9_]+', maxlength: 30 }, append: "@#{site_hostname}", hint: false + = f.input :email, placeholder: t('simple_form.labels.defaults.email'), required: true, input_html: { 'aria-label' => t('simple_form.labels.defaults.email'), :autocomplete => 'off' }, hint: false + = f.input :password, placeholder: t('simple_form.labels.defaults.password'), required: true, input_html: { 'aria-label' => t('simple_form.labels.defaults.password'), :autocomplete => 'new-password', :minlength => User.password_length.first, :maxlength => User.password_length.last }, hint: false + = f.input :password_confirmation, placeholder: t('simple_form.labels.defaults.confirm_password'), required: true, input_html: { 'aria-label' => t('simple_form.labels.defaults.confirm_password'), :autocomplete => 'new-password' }, hint: false + = f.input :confirm_password, as: :string, placeholder: t('simple_form.labels.defaults.honeypot', label: t('simple_form.labels.defaults.password')), required: false, input_html: { 'aria-label' => t('simple_form.labels.defaults.honeypot', label: t('simple_form.labels.defaults.password')), :autocomplete => 'off' }, hint: false + = f.input :website, as: :url, wrapper: :with_label, label: t('simple_form.labels.defaults.honeypot', label: 'Website'), required: false, input_html: { 'aria-label' => t('simple_form.labels.defaults.honeypot', label: 'Website'), :autocomplete => 'off' } - if approved_registrations? && !@invite.present? .fields-group = f.simple_fields_for :invite_request, resource.invite_request || resource.build_invite_request do |invite_request_fields| = invite_request_fields.input :text, as: :text, wrapper: :with_block_label, required: Setting.require_invite_text + + = hidden_field_tag :accept, params[:accept] = f.input :invite_code, as: :hidden .fields-group - = f.input :agreement, as: :boolean, wrapper: :with_label, label: whitelist_mode? ? t('auth.checkbox_agreement_without_rules_html', terms_path: terms_path) : t('auth.checkbox_agreement_html', rules_path: about_more_path, terms_path: terms_path), required: true + = f.input :agreement, as: :boolean, wrapper: :with_label, label: t('auth.privacy_policy_agreement_html', rules_path: about_more_path, privacy_policy_path: privacy_policy_path), required: true .actions = f.button :button, @invite.present? ? t('auth.register') : sign_up_message, type: :submit diff --git a/app/views/auth/registrations/rules.html.haml b/app/views/auth/registrations/rules.html.haml new file mode 100644 index 000000000..8e7a90cbe --- /dev/null +++ b/app/views/auth/registrations/rules.html.haml @@ -0,0 +1,21 @@ +- content_for :page_title do + = t('auth.register') + +- content_for :header_tags do + = render partial: 'shared/og', locals: { description: description_for_sign_up } + +.simple_form + %h1.title= t('auth.rules.title') + %p.lead= t('auth.rules.preamble', domain: site_hostname) + + %ol.rules-list + - @rules.each do |rule| + %li + .rules-list__text= rule.text + + .stacked-actions + - accept_path = @invite_code.present? ? public_invite_url(invite_code: @invite_code, accept: @accept_token) : new_user_registration_path(accept: @accept_token) + = link_to t('auth.rules.accept'), accept_path, class: 'button' + = link_to t('auth.rules.back'), root_path, class: 'button button-tertiary' + +.form-footer= render 'auth/shared/links' diff --git a/app/views/directories/index.html.haml b/app/views/directories/index.html.haml deleted file mode 100644 index 4872432d4..000000000 --- a/app/views/directories/index.html.haml +++ /dev/null @@ -1,54 +0,0 @@ -- content_for :page_title do - = t('directories.explore_mastodon', title: site_title) - -- content_for :header_tags do - %meta{ name: 'description', content: t('directories.explanation') } - - = opengraph 'og:site_name', t('about.hosted_on', domain: site_hostname) - = opengraph 'og:type', 'website' - = opengraph 'og:title', t('directories.explore_mastodon', title: site_title) - = opengraph 'og:description', t('directories.explanation') - = opengraph 'og:image', File.join(root_url, 'android-chrome-192x192.png') - -.page-header - %h1= t('directories.explore_mastodon', title: site_title) - %p= t('directories.explanation') - -- if @accounts.empty? - = nothing_here -- else - .directory__list - - @accounts.each do |account| - .account-card - = link_to TagManager.instance.url_for(account), class: 'account-card__permalink' do - .account-card__header - = image_tag account.header.url, alt: '' - .account-card__title - .account-card__title__avatar - = image_tag account.avatar.url, alt: '' - .display-name - %bdi - %strong.emojify.p-name= display_name(account, custom_emojify: true) - %span - = acct(account) - = fa_icon('lock') if account.locked? - - if account.note.present? - .account-card__bio.emojify - = prerender_custom_emojis(account_bio_format(account), account.emojis) - - else - .flex-spacer - .account-card__actions - .account-card__counters - .account-card__counters__item - = friendly_number_to_human account.statuses_count - %small= t('accounts.posts', count: account.statuses_count).downcase - .account-card__counters__item - = hide_followers_count?(account) ? '-' : (friendly_number_to_human account.followers_count) - %small= t('accounts.followers', count: account.followers_count).downcase - .account-card__counters__item - = friendly_number_to_human account.following_count - %small= t('accounts.following', count: account.following_count).downcase - .account-card__actions__button - = account_action_button(account) - - = paginate @accounts diff --git a/app/views/follower_accounts/index.html.haml b/app/views/follower_accounts/index.html.haml index 92de35a9f..d93540c02 100644 --- a/app/views/follower_accounts/index.html.haml +++ b/app/views/follower_accounts/index.html.haml @@ -1,20 +1,6 @@ -- content_for :page_title do - = t('accounts.people_who_follow', name: display_name(@account)) - - content_for :header_tags do %meta{ name: 'robots', content: 'noindex' }/ - = render 'accounts/og', account: @account, url: account_followers_url(@account, only_path: false) -= render 'accounts/header', account: @account - -- if @account.hide_collections? - .nothing-here= t('accounts.network_hidden') -- elsif user_signed_in? && @account.blocking?(current_account) - .nothing-here= t('accounts.unavailable') -- elsif @follows.empty? - = nothing_here -- else - .card-grid - = render partial: 'application/card', collection: @follows.map(&:account), as: :account + = render 'accounts/og', account: @account, url: account_followers_url(@account, only_path: false) - = paginate @follows += render 'shared/web_app' diff --git a/app/views/following_accounts/index.html.haml b/app/views/following_accounts/index.html.haml index 9bb1a9edd..d93540c02 100644 --- a/app/views/following_accounts/index.html.haml +++ b/app/views/following_accounts/index.html.haml @@ -1,20 +1,6 @@ -- content_for :page_title do - = t('accounts.people_followed_by', name: display_name(@account)) - - content_for :header_tags do %meta{ name: 'robots', content: 'noindex' }/ - = render 'accounts/og', account: @account, url: account_followers_url(@account, only_path: false) -= render 'accounts/header', account: @account - -- if @account.hide_collections? - .nothing-here= t('accounts.network_hidden') -- elsif user_signed_in? && @account.blocking?(current_account) - .nothing-here= t('accounts.unavailable') -- elsif @follows.empty? - = nothing_here -- else - .card-grid - = render partial: 'application/card', collection: @follows.map(&:target_account), as: :account + = render 'accounts/og', account: @account, url: account_followers_url(@account, only_path: false) - = paginate @follows += render 'shared/web_app' diff --git a/app/views/home/index.html.haml b/app/views/home/index.html.haml index 437c33715..45990cd10 100644 --- a/app/views/home/index.html.haml +++ b/app/views/home/index.html.haml @@ -1,19 +1,7 @@ - content_for :header_tags do - - if user_signed_in? - = preload_pack_asset 'features/getting_started.js', crossorigin: 'anonymous' - = preload_pack_asset 'features/compose.js', crossorigin: 'anonymous' - = preload_pack_asset 'features/home_timeline.js', crossorigin: 'anonymous' - = preload_pack_asset 'features/notifications.js', crossorigin: 'anonymous' + - unless request.path == '/' + %meta{ name: 'robots', content: 'noindex' }/ = render partial: 'shared/og' - %meta{name: 'applicationServerKey', content: Rails.configuration.x.vapid_public_key} - - = render_initial_state - -.notranslate.app-holder#mastodon{ data: { props: Oj.dump(default_props) } } - %noscript - = image_pack_tag 'logo.svg', alt: 'Mastodon' - - %div - = t('errors.noscript_html', apps_path: 'https://joinmastodon.org/apps') += render 'shared/web_app' diff --git a/app/views/layouts/admin.html.haml b/app/views/layouts/admin.html.haml index aa66815cc..3048e0e6a 100644 --- a/app/views/layouts/admin.html.haml +++ b/app/views/layouts/admin.html.haml @@ -14,22 +14,24 @@ = link_to root_path do = logo_as_symbol(:wordmark) - = link_to '#', class: 'sidebar__toggle__icon' do + = link_to '#', class: 'sidebar__toggle__icon', 'aria-label': t('navigation.toggle_menu'), 'aria-expanded': 'false' do = fa_icon 'bars' + = fa_icon 'times' = render_navigation .content-wrapper .content - .content-heading + .content__heading - if content_for?(:heading) = yield :heading - else - %h2= yield :page_title + .content__heading__row + %h2= yield :page_title - - if :heading_actions - .content-heading-actions - = yield :heading_actions + - if content_for?(:heading_actions) + .content__heading__actions + = yield :heading_actions = render 'application/flashes' diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index 5cbab8fc5..d3f1294c6 100755 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -21,7 +21,7 @@ %link{ rel: 'mask-icon', href: asset_pack_path('media/images/logo-symbol-icon.svg'), color: '#6364FF' }/ %link{ rel: 'manifest', href: manifest_path(format: :json) }/ - %meta{ name: 'theme-color', content: '#6364FF' }/ + %meta{ name: 'theme-color', content: '#191b22' }/ %meta{ name: 'apple-mobile-web-app-capable', content: 'yes' }/ %meta{ name: 'apple-itunes-app', content: 'app-id=1571998974' }/ @@ -44,7 +44,7 @@ = render partial: 'layouts/theme', object: @core = render partial: 'layouts/theme', object: @theme - = stylesheet_link_tag custom_css_path, host: request.host, media: 'all' + = stylesheet_link_tag custom_css_path, skip_pipeline: true, host: root_url, media: 'all' %body{ class: body_classes } = content_for?(:content) ? yield(:content) : yield diff --git a/app/views/layouts/public.html.haml b/app/views/layouts/public.html.haml deleted file mode 100644 index 10bc681ce..000000000 --- a/app/views/layouts/public.html.haml +++ /dev/null @@ -1,60 +0,0 @@ -- content_for :header_tags do - = render_initial_state - -- content_for :content do - .public-layout - - unless @hide_navbar - .container - %nav.header - .nav-left - = link_to root_url, class: 'brand' do - = logo_as_symbol(:wordmark) - - - unless whitelist_mode? - = link_to t('directories.directory'), explore_path, class: 'nav-link optional' if Setting.profile_directory - = link_to t('about.about_this'), about_more_path, class: 'nav-link optional' - = link_to t('about.apps'), 'https://joinmastodon.org/apps', class: 'nav-link optional' - - .nav-center - - .nav-right - - if user_signed_in? - = link_to t('settings.back'), root_url, class: 'nav-link nav-button webapp-btn' - - else - = link_to_login t('auth.login'), class: 'webapp-btn nav-link nav-button' - = link_to t('auth.register'), available_sign_up_path, class: 'webapp-btn nav-link nav-button' - - .container= yield - - .container - .footer - .grid - .column-0 - %h4= t 'footer.resources' - %ul - %li= link_to t('about.privacy_policy'), privacy_policy_path - .column-1 - %h4= t 'footer.developers' - %ul - %li= link_to t('about.documentation'), 'https://docs.joinmastodon.org/' - %li= link_to t('about.api'), 'https://docs.joinmastodon.org/client/intro/' - .column-2 - %h4= link_to t('about.what_is_mastodon'), 'https://joinmastodon.org/' - = link_to logo_as_symbol, root_url, class: 'brand' - .column-3 - %h4= site_hostname - %ul - - unless whitelist_mode? - %li= link_to t('about.about_this'), about_more_path - %li= "v#{Mastodon::Version.to_s}" - .column-4 - %h4= t 'footer.more' - %ul - %li= link_to t('about.source_code'), Mastodon::Version.source_url - %li= link_to t('about.apps'), 'https://joinmastodon.org/apps' - .legal-xs - = link_to "v#{Mastodon::Version.to_s}", Mastodon::Version.source_url - · - = link_to t('about.privacy_policy'), privacy_policy_path - -= render template: 'layouts/application' diff --git a/app/views/privacy/show.html.haml b/app/views/privacy/show.html.haml index cdd38a595..95e506641 100644 --- a/app/views/privacy/show.html.haml +++ b/app/views/privacy/show.html.haml @@ -1,9 +1,7 @@ - content_for :page_title do - = t('terms.title', instance: site_hostname) + = t('privacy_policy.title') -.grid - .column-0 - .box-widget - .rich-formatting= @instance_presenter.privacy_policy.html_safe.presence || t('terms.body_html') - .column-1 - = render 'application/sidebar' +- content_for :header_tags do + = render partial: 'shared/og' + += render 'shared/web_app' diff --git a/app/views/public_timelines/show.html.haml b/app/views/public_timelines/show.html.haml deleted file mode 100644 index 71a3d289b..000000000 --- a/app/views/public_timelines/show.html.haml +++ /dev/null @@ -1,16 +0,0 @@ -- content_for :page_title do - = t('about.see_whats_happening') - -- content_for :header_tags do - %meta{ name: 'robots', content: 'noindex' }/ - -.page-header - %h1= t('about.see_whats_happening') - - - if Setting.show_known_fediverse_at_about_page - %p= t('about.browse_public_posts') - - else - %p= t('about.browse_local_posts') - -#mastodon-timeline{ data: { props: Oj.dump(default_props.merge(local: !Setting.show_known_fediverse_at_about_page)) }} -.notranslate#modal-container diff --git a/app/views/remote_follow/new.html.haml b/app/views/remote_follow/new.html.haml deleted file mode 100644 index 4e9601f6a..000000000 --- a/app/views/remote_follow/new.html.haml +++ /dev/null @@ -1,20 +0,0 @@ -- content_for :header_tags do - %meta{ name: 'robots', content: 'noindex' }/ - -.form-container - .follow-prompt - %h2= t('remote_follow.prompt') - - = render partial: 'application/card', locals: { account: @account } - - = simple_form_for @remote_follow, as: :remote_follow, url: account_remote_follow_path(@account) do |f| - = render 'shared/error_messages', object: @remote_follow - - = f.input :acct, placeholder: t('remote_follow.acct'), input_html: { autocapitalize: 'none', autocorrect: 'off' } - - .actions - = f.button :button, t('remote_follow.proceed'), type: :submit - - %p.hint.subtle-hint - = t('remote_follow.reason_html', instance: site_hostname) - = t('remote_follow.no_account_html', sign_up_path: available_sign_up_path) diff --git a/app/views/remote_interaction/new.html.haml b/app/views/remote_interaction/new.html.haml deleted file mode 100644 index 2cc0fcb93..000000000 --- a/app/views/remote_interaction/new.html.haml +++ /dev/null @@ -1,24 +0,0 @@ -- content_for :header_tags do - %meta{ name: 'robots', content: 'noindex' }/ - -.form-container - .follow-prompt - %h2= t("remote_interaction.#{@interaction_type}.prompt") - - .public-layout - .activity-stream.activity-stream--highlighted - = 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 - - = hidden_field_tag :type, @interaction_type - - = f.input :acct, placeholder: t('remote_follow.acct'), input_html: { autocapitalize: 'none', autocorrect: 'off' } - - .actions - = f.button :button, t("remote_interaction.#{@interaction_type}.proceed"), type: :submit - - %p.hint.subtle-hint - = t('remote_follow.reason_html', instance: site_hostname) - = t('remote_follow.no_account_html', sign_up_path: available_sign_up_path) diff --git a/app/views/settings/featured_tags/index.html.haml b/app/views/settings/featured_tags/index.html.haml index 5d87e2862..595094fc7 100644 --- a/app/views/settings/featured_tags/index.html.haml +++ b/app/views/settings/featured_tags/index.html.haml @@ -21,7 +21,7 @@ %div %h4 = fa_icon 'hashtag' - = featured_tag.name + = featured_tag.display_name %small - if featured_tag.last_status_at.nil? = t('accounts.nothing_here') diff --git a/app/views/settings/migrations/show.html.haml b/app/views/settings/migrations/show.html.haml index 492f6fe12..14bebb19b 100644 --- a/app/views/settings/migrations/show.html.haml +++ b/app/views/settings/migrations/show.html.haml @@ -76,7 +76,7 @@ - if migration.target_account.present? = compact_account_link_to migration.target_account - else - = migration.pretty_acct + = migration.acct %td= number_with_delimiter migration.followers_count diff --git a/app/views/settings/profiles/show.html.haml b/app/views/settings/profiles/show.html.haml index 39a508218..430d1f339 100644 --- a/app/views/settings/profiles/show.html.haml +++ b/app/views/settings/profiles/show.html.haml @@ -70,8 +70,7 @@ %h6= t 'migrations.incoming_migrations' %p.muted-hint= t('migrations.incoming_migrations_html', path: settings_aliases_path) -- if open_deletion? - %hr.spacer/ +%hr.spacer/ - %h6= t('auth.delete_account') - %p.muted-hint= t('auth.delete_account_html', path: settings_delete_path) +%h6= t('auth.delete_account') +%p.muted-hint= t('auth.delete_account_html', path: settings_delete_path) diff --git a/app/views/shared/_og.html.haml b/app/views/shared/_og.html.haml index b54ab2429..2941b566e 100644 --- a/app/views/shared/_og.html.haml +++ b/app/views/shared/_og.html.haml @@ -8,7 +8,7 @@ = opengraph 'og:type', 'website' = opengraph 'og:title', @instance_presenter.title = opengraph 'og:description', description -= opengraph 'og:image', full_asset_url(thumbnail&.file&.url || asset_pack_path('media/images/preview.png', protocol: :request)) += opengraph 'og:image', full_asset_url(thumbnail&.file&.url(:'@1x') || asset_pack_path('media/images/preview.png', protocol: :request)) = opengraph 'og:image:width', thumbnail ? thumbnail.meta['width'] : '1200' = opengraph 'og:image:height', thumbnail ? thumbnail.meta['height'] : '630' = opengraph 'twitter:card', 'summary_large_image' diff --git a/app/views/shared/_web_app.html.haml b/app/views/shared/_web_app.html.haml new file mode 100644 index 000000000..b9a0ce1fc --- /dev/null +++ b/app/views/shared/_web_app.html.haml @@ -0,0 +1,16 @@ +- content_for :header_tags do + - if user_signed_in? + = preload_pack_asset 'features/compose.js', crossorigin: 'anonymous' + = preload_pack_asset 'features/home_timeline.js', crossorigin: 'anonymous' + = preload_pack_asset 'features/notifications.js', crossorigin: 'anonymous' + + %meta{ name: 'applicationServerKey', content: Rails.configuration.x.vapid_public_key } + + = render_initial_state + +.notranslate.app-holder#mastodon{ data: { props: Oj.dump(default_props) } } + %noscript + = image_pack_tag 'logo.svg', alt: 'Mastodon' + + %div + = t('errors.noscript_html', apps_path: 'https://joinmastodon.org/apps') diff --git a/app/views/statuses/_detailed_status.html.haml b/app/views/statuses/_detailed_status.html.haml index c67f0e4d9..37001b022 100644 --- a/app/views/statuses/_detailed_status.html.haml +++ b/app/views/statuses/_detailed_status.html.haml @@ -56,7 +56,7 @@ - else = link_to status.application.name, status.application.website, class: 'detailed-status__application', target: '_blank', rel: 'noopener noreferrer' · - = link_to remote_interaction_path(status, type: :reply), class: 'modal-button detailed-status__link' do + %span.detailed-status__link - if status.in_reply_to_id.nil? = fa_icon('reply') - else @@ -65,12 +65,12 @@ = " " · - if status.public_visibility? || status.unlisted_visibility? - = link_to remote_interaction_path(status, type: :reblog), class: 'modal-button detailed-status__link' do + %span.detailed-status__link = fa_icon('retweet') %span.detailed-status__reblogs>= friendly_number_to_human status.reblogs_count = " " · - = link_to remote_interaction_path(status, type: :favourite), class: 'modal-button detailed-status__link' do + %span.detailed-status__link = fa_icon('star') %span.detailed-status__favorites>= friendly_number_to_human status.favourites_count = " " diff --git a/app/views/statuses/_simple_status.html.haml b/app/views/statuses/_simple_status.html.haml index 936ecd27e..1e37b6cf3 100644 --- a/app/views/statuses/_simple_status.html.haml +++ b/app/views/statuses/_simple_status.html.haml @@ -53,18 +53,18 @@ = t 'statuses.show_thread' .status__action-bar - = link_to remote_interaction_path(status, type: :reply), class: 'status__action-bar-button icon-button icon-button--with-counter modal-button' do + %span.status__action-bar-button.icon-button.icon-button--with-counter - if status.in_reply_to_id.nil? = fa_icon 'reply fw' - else = fa_icon 'reply-all fw' %span.icon-button__counter= obscured_counter status.replies_count - = link_to remote_interaction_path(status, type: :reblog), class: 'status__action-bar-button icon-button modal-button' do + %span.status__action-bar-button.icon-button - if status.distributable? = fa_icon 'retweet fw' - elsif status.private_visibility? || status.limited_visibility? = fa_icon 'lock fw' - else = fa_icon 'at fw' - = link_to remote_interaction_path(status, type: :favourite), class: 'status__action-bar-button icon-button modal-button' do + %span.status__action-bar-button.icon-button = fa_icon 'star fw' diff --git a/app/views/statuses/show.html.haml b/app/views/statuses/show.html.haml index 7ef7b09a2..106c41725 100644 --- a/app/views/statuses/show.html.haml +++ b/app/views/statuses/show.html.haml @@ -2,7 +2,7 @@ = 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 + - if @account.user_prefers_noindex? %meta{ name: 'robots', content: 'noindex, noarchive' }/ %link{ rel: 'alternate', type: 'application/json+oembed', href: api_oembed_url(url: short_account_status_url(@account, @status), format: 'json') }/ @@ -17,9 +17,4 @@ = 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' += render 'shared/web_app' diff --git a/app/views/tags/_og.html.haml b/app/views/tags/_og.html.haml deleted file mode 100644 index 37f644cf2..000000000 --- a/app/views/tags/_og.html.haml +++ /dev/null @@ -1,6 +0,0 @@ -= opengraph 'og:site_name', t('about.hosted_on', domain: site_hostname) -= opengraph 'og:url', tag_url(@tag) -= opengraph 'og:type', 'website' -= opengraph 'og:title', "##{@tag.display_name}" -= opengraph 'og:description', strip_tags(t('about.about_hashtag_html', hashtag: @tag.display_name)) -= opengraph 'twitter:card', 'summary' diff --git a/app/views/tags/show.html.haml b/app/views/tags/show.html.haml index 608989a2b..4b4967a8f 100644 --- a/app/views/tags/show.html.haml +++ b/app/views/tags/show.html.haml @@ -1,15 +1,5 @@ -- content_for :page_title do - = "##{@tag.display_name}" - - content_for :header_tags do %meta{ name: 'robots', content: 'noindex' }/ - %link{ rel: 'alternate', type: 'application/rss+xml', href: tag_url(@tag, format: 'rss') }/ - - = render 'og' - -.page-header - %h1= "##{@tag.display_name}" - %p= t('about.about_hashtag_html', hashtag: @tag.display_name) + = render partial: 'shared/og' -#mastodon-timeline{ data: { props: Oj.dump(default_props.merge(hashtag: @tag.name, local: @local)) }} -.notranslate#modal-container += render partial: 'shared/web_app' diff --git a/app/views/user_mailer/welcome.html.haml b/app/views/user_mailer/welcome.html.haml index 1f75ff48a..3ab994ad3 100644 --- a/app/views/user_mailer/welcome.html.haml +++ b/app/views/user_mailer/welcome.html.haml @@ -76,26 +76,7 @@ %td.button-primary = link_to settings_profile_url do %span= t 'user_mailer.welcome.edit_profile_action' - %tr - %td.content-cell - .email-row - .col-4 - %table.column{ cellspacing: 0, cellpadding: 0 } - %tbody - %tr - %td.column-cell.padded - = t 'user_mailer.welcome.review_preferences_step' - .col-2 - %table.column{ cellspacing: 0, cellpadding: 0 } - %tbody - %tr - %td.column-cell.padded - %table.button.button-small{ align: 'left', cellspacing: 0, cellpadding: 0 } - %tbody - %tr - %td.button-primary - = link_to settings_preferences_url do - %span= t 'user_mailer.welcome.review_preferences_action' + %tr %td.content-cell.padded-bottom .email-row @@ -116,29 +97,3 @@ %td.button-primary = link_to web_url do %span= t 'user_mailer.welcome.final_action' - -%table.email-table{ cellspacing: 0, cellpadding: 0 } - %tbody - %tr - %td.email-body - .email-container - %table.content-section{ cellspacing: 0, cellpadding: 0 } - %tbody - %tr - %td.content-cell.border-top - .email-row - .col-6 - %table.column{ cellspacing: 0, cellpadding: 0 } - %tbody - %tr - %td.column-cell.padded - %h5= t 'user_mailer.welcome.tips' - %ul - %li - %span= t 'user_mailer.welcome.tip_mobile_webapp' - %li - %span= t 'user_mailer.welcome.tip_following' - %li - %span= t 'user_mailer.welcome.tip_local_timeline', instance: @instance - %li - %span= t 'user_mailer.welcome.tip_federated_timeline' diff --git a/app/views/user_mailer/welcome.text.erb b/app/views/user_mailer/welcome.text.erb index e310d7ca6..d78cdb938 100644 --- a/app/views/user_mailer/welcome.text.erb +++ b/app/views/user_mailer/welcome.text.erb @@ -11,19 +11,6 @@ => <%= settings_profile_url %> -<%= t 'user_mailer.welcome.review_preferences_step' %> - -=> <%= settings_preferences_url %> - <%= t 'user_mailer.welcome.final_step' %> => <%= web_url %> - ---- - -<%= t 'user_mailer.welcome.tips' %> - -* <%= t 'user_mailer.welcome.tip_mobile_webapp' %> -* <%= t 'user_mailer.welcome.tip_following' %> -* <%= t 'user_mailer.welcome.tip_local_timeline', instance: @instance %> -* <%= t 'user_mailer.welcome.tip_federated_timeline' %> diff --git a/app/workers/activitypub/account_raw_distribution_worker.rb b/app/workers/activitypub/account_raw_distribution_worker.rb new file mode 100644 index 000000000..a84c7d214 --- /dev/null +++ b/app/workers/activitypub/account_raw_distribution_worker.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +class ActivityPub::AccountRawDistributionWorker < ActivityPub::RawDistributionWorker + protected + + def inboxes + @inboxes ||= AccountReachFinder.new(@account).inboxes + end +end diff --git a/app/workers/activitypub/synchronize_featured_collection_worker.rb b/app/workers/activitypub/synchronize_featured_collection_worker.rb index 7a0898e89..f67d693cb 100644 --- a/app/workers/activitypub/synchronize_featured_collection_worker.rb +++ b/app/workers/activitypub/synchronize_featured_collection_worker.rb @@ -5,8 +5,10 @@ class ActivityPub::SynchronizeFeaturedCollectionWorker sidekiq_options queue: 'pull', lock: :until_executed - def perform(account_id) - ActivityPub::FetchFeaturedCollectionService.new.call(Account.find(account_id)) + def perform(account_id, options = {}) + options = { note: true, hashtag: false }.deep_merge(options.deep_symbolize_keys) + + ActivityPub::FetchFeaturedCollectionService.new.call(Account.find(account_id), **options) rescue ActiveRecord::RecordNotFound true end diff --git a/app/workers/activitypub/synchronize_featured_tags_collection_worker.rb b/app/workers/activitypub/synchronize_featured_tags_collection_worker.rb new file mode 100644 index 000000000..14af4f725 --- /dev/null +++ b/app/workers/activitypub/synchronize_featured_tags_collection_worker.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +class ActivityPub::SynchronizeFeaturedTagsCollectionWorker + include Sidekiq::Worker + + sidekiq_options queue: 'pull', lock: :until_executed + + def perform(account_id, url) + ActivityPub::FetchFeaturedTagsCollectionService.new.call(Account.find(account_id), url) + rescue ActiveRecord::RecordNotFound + true + end +end diff --git a/app/workers/activitypub/update_distribution_worker.rb b/app/workers/activitypub/update_distribution_worker.rb index 81fde63b8..d0391bb6f 100644 --- a/app/workers/activitypub/update_distribution_worker.rb +++ b/app/workers/activitypub/update_distribution_worker.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true class ActivityPub::UpdateDistributionWorker < ActivityPub::RawDistributionWorker + sidekiq_options queue: 'push', lock: :until_executed + # Distribute an profile update to servers that might have a copy # of the account in question def perform(account_id, options = {}) diff --git a/app/workers/remove_featured_tag_worker.rb b/app/workers/remove_featured_tag_worker.rb new file mode 100644 index 000000000..065ec79d8 --- /dev/null +++ b/app/workers/remove_featured_tag_worker.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +class RemoveFeaturedTagWorker + include Sidekiq::Worker + + def perform(account_id, featured_tag_id) + RemoveFeaturedTagService.new.call(Account.find(account_id), FeaturedTag.find(featured_tag_id)) + rescue ActiveRecord::RecordNotFound + true + end +end diff --git a/app/workers/scheduler/vacuum_scheduler.rb b/app/workers/scheduler/vacuum_scheduler.rb index ce88ff204..9544f808b 100644 --- a/app/workers/scheduler/vacuum_scheduler.rb +++ b/app/workers/scheduler/vacuum_scheduler.rb @@ -3,7 +3,7 @@ class Scheduler::VacuumScheduler include Sidekiq::Worker - sidekiq_options retry: 0 + sidekiq_options retry: 0, lock: :until_executed def perform vacuum_operations.each do |operation| |