Merge tag 'v2.1.2' into kosmos

This commit is contained in:
Basti 2018-01-09 19:54:13 +00:00
commit 42cea8a076
203 changed files with 4964 additions and 572 deletions

View File

@ -11,10 +11,11 @@ DB_PASS=
DB_PORT=5432 DB_PORT=5432
# Federation # Federation
# Note: Changing LOCAL_DOMAIN or LOCAL_HTTPS at a later time will cause unwanted side effects. # Note: Changing LOCAL_DOMAIN at a later time will cause unwanted side effects, including breaking all existing federation.
# LOCAL_DOMAIN should *NOT* contain the protocol part of the domain e.g https://example.com. # LOCAL_DOMAIN should *NOT* contain the protocol part of the domain e.g https://example.com.
LOCAL_DOMAIN=example.com LOCAL_DOMAIN=example.com
LOCAL_HTTPS=true
# Changing LOCAL_HTTPS in production is no longer supported. (Mastodon will always serve https:// links)
# Use this only if you need to run mastodon on a different domain than the one used for federation. # Use this only if you need to run mastodon on a different domain than the one used for federation.
# You can read more about this option on https://github.com/tootsuite/documentation/blob/master/Running-Mastodon/Serving_a_different_domain.md # You can read more about this option on https://github.com/tootsuite/documentation/blob/master/Running-Mastodon/Serving_a_different_domain.md

View File

@ -28,7 +28,7 @@ gem 'browser'
gem 'charlock_holmes', '~> 0.7.5' gem 'charlock_holmes', '~> 0.7.5'
gem 'iso-639' gem 'iso-639'
gem 'cld3', '~> 3.2.0' gem 'cld3', '~> 3.2.0'
gem 'devise', '~> 4.2' gem 'devise', '~> 4.3'
gem 'devise-two-factor', '~> 3.0' gem 'devise-two-factor', '~> 3.0'
gem 'doorkeeper', '~> 4.2' gem 'doorkeeper', '~> 4.2'
gem 'fast_blank', '~> 1.0' gem 'fast_blank', '~> 1.0'
@ -58,6 +58,7 @@ gem 'redis', '~> 3.3', require: ['redis', 'redis/connection/hiredis']
gem 'mario-redis-lock', '~> 1.2', require: 'redis_lock' gem 'mario-redis-lock', '~> 1.2', require: 'redis_lock'
gem 'rqrcode', '~> 0.10' gem 'rqrcode', '~> 0.10'
gem 'ruby-oembed', '~> 0.12', require: 'oembed' gem 'ruby-oembed', '~> 0.12', require: 'oembed'
gem 'ruby-progressbar', '~> 1.4'
gem 'sanitize', '~> 4.4' gem 'sanitize', '~> 4.4'
gem 'sidekiq', '~> 5.0' gem 'sidekiq', '~> 5.0'
gem 'sidekiq-scheduler', '~> 2.1' gem 'sidekiq-scheduler', '~> 2.1'

View File

@ -299,13 +299,11 @@ GEM
sidekiq (>= 3.5.0) sidekiq (>= 3.5.0)
statsd-ruby (~> 1.2.0) statsd-ruby (~> 1.2.0)
oj (3.3.9) oj (3.3.9)
openssl (2.0.6)
orm_adapter (0.5.0) orm_adapter (0.5.0)
ostatus2 (2.0.1) ostatus2 (2.0.2)
addressable (~> 2.4) addressable (~> 2.4)
http (~> 2.0) http (~> 2.0)
nokogiri (~> 1.6) nokogiri (~> 1.6)
openssl (~> 2.0)
ox (2.8.2) ox (2.8.2)
paperclip (5.1.0) paperclip (5.1.0)
activemodel (>= 4.2.0) activemodel (>= 4.2.0)
@ -561,7 +559,7 @@ DEPENDENCIES
charlock_holmes (~> 0.7.5) charlock_holmes (~> 0.7.5)
cld3 (~> 3.2.0) cld3 (~> 3.2.0)
climate_control (~> 0.2) climate_control (~> 0.2)
devise (~> 4.2) devise (~> 4.3)
devise-two-factor (~> 3.0) devise-two-factor (~> 3.0)
doorkeeper (~> 4.2) doorkeeper (~> 4.2)
dotenv-rails (~> 2.2) dotenv-rails (~> 2.2)
@ -621,6 +619,7 @@ DEPENDENCIES
rspec-sidekiq (~> 3.0) rspec-sidekiq (~> 3.0)
rubocop rubocop
ruby-oembed (~> 0.12) ruby-oembed (~> 0.12)
ruby-progressbar (~> 1.4)
sanitize (~> 4.4) sanitize (~> 4.4)
scss_lint (~> 0.55) scss_lint (~> 0.55)
sidekiq (~> 5.0) sidekiq (~> 5.0)
@ -643,4 +642,4 @@ RUBY VERSION
ruby 2.4.2p198 ruby 2.4.2p198
BUNDLED WITH BUNDLED WITH
1.16.0 1.16.1

View File

@ -2,7 +2,8 @@
class AccountsController < ApplicationController class AccountsController < ApplicationController
include AccountControllerConcern include AccountControllerConcern
include SignatureVerification
before_action :set_cache_headers
def show def show
respond_to do |format| respond_to do |format|
@ -26,10 +27,11 @@ class AccountsController < ApplicationController
end end
format.json do format.json do
render json: @account, skip_session!
serializer: ActivityPub::ActorSerializer,
adapter: ActivityPub::Adapter, render_cached_json(['activitypub', 'actor', @account.cache_key], content_type: 'application/activity+json') do
content_type: 'application/activity+json' ActiveModelSerializers::SerializableResource.new(@account, serializer: ActivityPub::ActorSerializer, adapter: ActivityPub::Adapter)
end
end end
end end
end end

View File

@ -0,0 +1,22 @@
# frozen_string_literal: true
class ActivityPub::FollowsController < Api::BaseController
include SignatureVerification
def show
render json: follow_request,
serializer: ActivityPub::FollowSerializer,
adapter: ActivityPub::Adapter,
content_type: 'application/activity+json'
end
private
def follow_request
FollowRequest.includes(:account).references(:account).find_by!(
id: params.require(:id),
accounts: { domain: nil, username: params.require(:account_username) },
target_account: signed_request_account
)
end
end

View File

@ -3,6 +3,7 @@
module Admin module Admin
class CustomEmojisController < BaseController class CustomEmojisController < BaseController
before_action :set_custom_emoji, except: [:index, :new, :create] before_action :set_custom_emoji, except: [:index, :new, :create]
before_action :set_filter_params
def index def index
authorize :custom_emoji, :index? authorize :custom_emoji, :index?
@ -32,23 +33,26 @@ module Admin
if @custom_emoji.update(resource_params) if @custom_emoji.update(resource_params)
log_action :update, @custom_emoji log_action :update, @custom_emoji
redirect_to admin_custom_emojis_path, notice: I18n.t('admin.custom_emojis.updated_msg') flash[:notice] = I18n.t('admin.custom_emojis.updated_msg')
else else
redirect_to admin_custom_emojis_path, notice: I18n.t('admin.custom_emojis.update_failed_msg') flash[:alert] = I18n.t('admin.custom_emojis.update_failed_msg')
end end
redirect_to admin_custom_emojis_path(page: params[:page], **@filter_params)
end end
def destroy def destroy
authorize @custom_emoji, :destroy? authorize @custom_emoji, :destroy?
@custom_emoji.destroy! @custom_emoji.destroy!
log_action :destroy, @custom_emoji log_action :destroy, @custom_emoji
redirect_to admin_custom_emojis_path, notice: I18n.t('admin.custom_emojis.destroyed_msg') flash[:notice] = I18n.t('admin.custom_emojis.destroyed_msg')
redirect_to admin_custom_emojis_path(page: params[:page], **@filter_params)
end end
def copy def copy
authorize @custom_emoji, :copy? authorize @custom_emoji, :copy?
emoji = CustomEmoji.find_or_initialize_by(domain: nil, shortcode: @custom_emoji.shortcode) emoji = CustomEmoji.find_or_initialize_by(domain: nil,
shortcode: @custom_emoji.shortcode)
emoji.image = @custom_emoji.image emoji.image = @custom_emoji.image
if emoji.save if emoji.save
@ -58,21 +62,23 @@ module Admin
flash[:alert] = I18n.t('admin.custom_emojis.copy_failed_msg') flash[:alert] = I18n.t('admin.custom_emojis.copy_failed_msg')
end end
redirect_to admin_custom_emojis_path(page: params[:page]) redirect_to admin_custom_emojis_path(page: params[:page], **@filter_params)
end end
def enable def enable
authorize @custom_emoji, :enable? authorize @custom_emoji, :enable?
@custom_emoji.update!(disabled: false) @custom_emoji.update!(disabled: false)
log_action :enable, @custom_emoji log_action :enable, @custom_emoji
redirect_to admin_custom_emojis_path, notice: I18n.t('admin.custom_emojis.enabled_msg') flash[:notice] = I18n.t('admin.custom_emojis.enabled_msg')
redirect_to admin_custom_emojis_path(page: params[:page], **@filter_params)
end end
def disable def disable
authorize @custom_emoji, :disable? authorize @custom_emoji, :disable?
@custom_emoji.update!(disabled: true) @custom_emoji.update!(disabled: true)
log_action :disable, @custom_emoji log_action :disable, @custom_emoji
redirect_to admin_custom_emojis_path, notice: I18n.t('admin.custom_emojis.disabled_msg') flash[:notice] = I18n.t('admin.custom_emojis.disabled_msg')
redirect_to admin_custom_emojis_path(page: params[:page], **@filter_params)
end end
private private
@ -81,6 +87,10 @@ module Admin
@custom_emoji = CustomEmoji.find(params[:id]) @custom_emoji = CustomEmoji.find(params[:id])
end end
def set_filter_params
@filter_params = filter_params.to_hash.symbolize_keys
end
def resource_params def resource_params
params.require(:custom_emoji).permit(:shortcode, :image, :visible_in_picker) params.require(:custom_emoji).permit(:shortcode, :image, :visible_in_picker)
end end

View File

@ -17,6 +17,8 @@ module Admin
bootstrap_timeline_accounts bootstrap_timeline_accounts
thumbnail thumbnail
min_invite_role min_invite_role
activity_api_enabled
peers_api_enabled
).freeze ).freeze
BOOLEAN_SETTINGS = %w( BOOLEAN_SETTINGS = %w(
@ -24,6 +26,8 @@ module Admin
open_deletion open_deletion
timeline_preview timeline_preview
show_staff_badge show_staff_badge
activity_api_enabled
peers_api_enabled
).freeze ).freeze
UPLOAD_SETTINGS = %w( UPLOAD_SETTINGS = %w(

View File

@ -0,0 +1,36 @@
# frozen_string_literal: true
class Api::V1::Instances::ActivityController < Api::BaseController
before_action :require_enabled_api!
respond_to :json
def show
render_cached_json('api:v1:instances:activity:show', expires_in: 1.day) { activity }
end
private
def activity
weeks = []
12.times do |i|
day = i.weeks.ago.to_date
week_id = day.cweek
week = Date.commercial(day.cwyear, week_id)
weeks << {
week: week.to_time.to_i.to_s,
statuses: Redis.current.get("activity:statuses:local:#{week_id}") || '0',
logins: Redis.current.pfcount("activity:logins:#{week_id}").to_s,
registrations: Redis.current.get("activity:accounts:local:#{week_id}") || '0',
}
end
weeks
end
def require_enabled_api!
head 404 unless Setting.activity_api_enabled
end
end

View File

@ -0,0 +1,17 @@
# frozen_string_literal: true
class Api::V1::Instances::PeersController < Api::BaseController
before_action :require_enabled_api!
respond_to :json
def index
render_cached_json('api:v1:instances:peers:index', expires_in: 1.day) { Account.remote.domains }
end
private
def require_enabled_api!
head 404 unless Setting.peers_api_enabled
end
end

View File

@ -121,4 +121,26 @@ class ApplicationController < ActionController::Base
end end
end end
end end
def render_cached_json(cache_key, **options)
options[:expires_in] ||= 3.minutes
options[:public] ||= true
cache_key = cache_key.join(':') if cache_key.is_a?(Enumerable)
content_type = options.delete(:content_type) || 'application/json'
data = Rails.cache.fetch(cache_key, { raw: true }.merge(options)) do
yield.to_json
end
expires_in options[:expires_in], public: options[:public]
render json: data, content_type: content_type
end
def set_cache_headers
response.headers['Vary'] = 'Accept'
end
def skip_session!
request.session_options[:skip] = true
end
end end

View File

@ -2,10 +2,4 @@
class Auth::ConfirmationsController < Devise::ConfirmationsController class Auth::ConfirmationsController < Devise::ConfirmationsController
layout 'auth' layout 'auth'
def show
super do |user|
BootstrapTimelineWorker.perform_async(user.account_id) if user.errors.empty?
end
end
end end

View File

@ -37,6 +37,10 @@ class Auth::RegistrationsController < Devise::RegistrationsController
new_user_session_path new_user_session_path
end end
def after_update_path_for(_resource)
edit_user_registration_path
end
def check_enabled_registrations def check_enabled_registrations
redirect_to root_path if single_user_mode? || !allowed_registrations? redirect_to root_path if single_user_mode? || !allowed_registrations?
end end

View File

@ -4,6 +4,7 @@ class AuthorizeFollowsController < ApplicationController
layout 'modal' layout 'modal'
before_action :authenticate_user! before_action :authenticate_user!
before_action :set_body_classes
def show def show
@account = located_account || render(:error) @account = located_account || render(:error)
@ -58,4 +59,8 @@ class AuthorizeFollowsController < ApplicationController
def acct_params def acct_params
params.fetch(:acct, '') params.fetch(:acct, '')
end end
def set_body_classes
@body_classes = 'modal-layout'
end
end end

View File

@ -17,6 +17,7 @@ module UserTrackingConcern
# Mark as signed-in today # Mark as signed-in today
current_user.update_tracked_fields!(request) current_user.update_tracked_fields!(request)
ActivityTracker.record('activity:logins', current_user.id)
# Regenerate feed if needed # Regenerate feed if needed
regenerate_feed! if user_needs_feed_update? regenerate_feed! if user_needs_feed_update?

View File

@ -2,14 +2,16 @@
class EmojisController < ApplicationController class EmojisController < ApplicationController
before_action :set_emoji before_action :set_emoji
before_action :set_cache_headers
def show def show
respond_to do |format| respond_to do |format|
format.json do format.json do
render json: @emoji, skip_session!
serializer: ActivityPub::EmojiSerializer,
adapter: ActivityPub::Adapter, render_cached_json(['activitypub', 'emoji', @emoji.cache_key], content_type: 'application/activity+json') do
content_type: 'application/activity+json' ActiveModelSerializers::SerializableResource.new(@emoji, serializer: ActivityPub::EmojiSerializer, adapter: ActivityPub::Adapter)
end
end end
end end
end end

View File

@ -38,4 +38,8 @@ class RemoteFollowController < ApplicationController
def suspended_account? def suspended_account?
@account.suspended? @account.suspended?
end end
def set_body_classes
@body_classes = 'modal-layout'
end
end end

View File

@ -25,6 +25,6 @@ class SharesController < ApplicationController
end end
def set_body_classes def set_body_classes
@body_classes = 'compose-standalone' @body_classes = 'modal-layout compose-standalone'
end end
end end

View File

@ -10,6 +10,7 @@ class StatusesController < ApplicationController
before_action :set_link_headers before_action :set_link_headers
before_action :check_account_suspension before_action :check_account_suspension
before_action :redirect_to_original, only: [:show] before_action :redirect_to_original, only: [:show]
before_action :set_cache_headers
def show def show
respond_to do |format| respond_to do |format|
@ -21,19 +22,21 @@ class StatusesController < ApplicationController
end end
format.json do format.json do
render json: @status, skip_session! unless @stream_entry.hidden?
serializer: ActivityPub::NoteSerializer,
adapter: ActivityPub::Adapter, render_cached_json(['activitypub', 'note', @status.cache_key], content_type: 'application/activity+json', public: !@stream_entry.hidden?) do
content_type: 'application/activity+json' ActiveModelSerializers::SerializableResource.new(@status, serializer: ActivityPub::NoteSerializer, adapter: ActivityPub::Adapter)
end
end end
end end
end end
def activity def activity
render json: @status, skip_session!
serializer: ActivityPub::ActivitySerializer,
adapter: ActivityPub::Adapter, render_cached_json(['activitypub', 'activity', @status.cache_key], content_type: 'application/activity+json', public: !@stream_entry.hidden?) do
content_type: 'application/activity+json' ActiveModelSerializers::SerializableResource.new(@status, serializer: ActivityPub::ActivitySerializer, adapter: ActivityPub::Adapter)
end
end end
def embed def embed

View File

@ -1,15 +1,19 @@
# frozen_string_literal: true # frozen_string_literal: true
module WellKnown module WellKnown
class HostMetaController < ApplicationController class HostMetaController < ActionController::Base
include RoutingHelper include RoutingHelper
before_action { response.headers['Vary'] = 'Accept' }
def show def show
@webfinger_template = "#{webfinger_url}?resource={uri}" @webfinger_template = "#{webfinger_url}?resource={uri}"
respond_to do |format| respond_to do |format|
format.xml { render content_type: 'application/xrd+xml' } format.xml { render content_type: 'application/xrd+xml' }
end end
expires_in(3.days, public: true)
end end
end end
end end

View File

@ -1,9 +1,11 @@
# frozen_string_literal: true # frozen_string_literal: true
module WellKnown module WellKnown
class WebfingerController < ApplicationController class WebfingerController < ActionController::Base
include RoutingHelper include RoutingHelper
before_action { response.headers['Vary'] = 'Accept' }
def show def show
@account = Account.find_local!(username_from_resource) @account = Account.find_local!(username_from_resource)
@ -16,6 +18,8 @@ module WellKnown
render content_type: 'application/xrd+xml' render content_type: 'application/xrd+xml'
end end
end end
expires_in(3.days, public: true)
rescue ActiveRecord::RecordNotFound rescue ActiveRecord::RecordNotFound
head 404 head 404
end end

View File

@ -34,7 +34,7 @@ module Admin::ActionLogsHelper
link_to attributes['domain'], "https://#{attributes['domain']}" link_to attributes['domain'], "https://#{attributes['domain']}"
when 'Status' when 'Status'
tmp_status = Status.new(attributes) tmp_status = Status.new(attributes)
link_to tmp_status.account.acct, TagManager.instance.url_for(tmp_status) link_to tmp_status.account&.acct || "##{tmp_status.account_id}", TagManager.instance.url_for(tmp_status)
end end
end end

View File

@ -4,6 +4,7 @@ module RoutingHelper
extend ActiveSupport::Concern extend ActiveSupport::Concern
include Rails.application.routes.url_helpers include Rails.application.routes.url_helpers
include ActionView::Helpers::AssetTagHelper include ActionView::Helpers::AssetTagHelper
include Webpacker::Helper
included do included do
def default_url_options def default_url_options
@ -17,6 +18,10 @@ module RoutingHelper
URI.join(root_url, source).to_s URI.join(root_url, source).to_s
end end
def full_pack_url(source, **options)
full_asset_url(asset_pack_path(source, options))
end
private private
def use_storage? def use_storage?

View File

@ -28,6 +28,9 @@ module SettingsHelper
pt: 'Português', pt: 'Português',
'pt-BR': 'Português do Brasil', 'pt-BR': 'Português do Brasil',
ru: 'Русский', ru: 'Русский',
sk: 'Slovensky',
sr: 'Српски',
'sr-Latn': 'Srpski (latinica)',
sv: 'Svenska', sv: 'Svenska',
th: 'ภาษาไทย', th: 'ภาษาไทย',
tr: 'Türkçe', tr: 'Türkçe',

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

View File

@ -31,7 +31,7 @@ const fetchRelatedRelationships = (dispatch, notifications) => {
const unescapeHTML = (html) => { const unescapeHTML = (html) => {
const wrapper = document.createElement('div'); const wrapper = document.createElement('div');
html = html.replace(/<br \/>|<br>|\n/, ' '); html = html.replace(/<br \/>|<br>|\n/g, ' ');
wrapper.innerHTML = html; wrapper.innerHTML = html;
return wrapper.textContent; return wrapper.textContent;
}; };

View File

@ -1,57 +0,0 @@
import axios from 'axios';
import { pushNotificationsSetting } from '../settings';
export const SET_BROWSER_SUPPORT = 'PUSH_NOTIFICATIONS_SET_BROWSER_SUPPORT';
export const SET_SUBSCRIPTION = 'PUSH_NOTIFICATIONS_SET_SUBSCRIPTION';
export const CLEAR_SUBSCRIPTION = 'PUSH_NOTIFICATIONS_CLEAR_SUBSCRIPTION';
export const ALERTS_CHANGE = 'PUSH_NOTIFICATIONS_ALERTS_CHANGE';
export function setBrowserSupport (value) {
return {
type: SET_BROWSER_SUPPORT,
value,
};
}
export function setSubscription (subscription) {
return {
type: SET_SUBSCRIPTION,
subscription,
};
}
export function clearSubscription () {
return {
type: CLEAR_SUBSCRIPTION,
};
}
export function changeAlerts(key, value) {
return dispatch => {
dispatch({
type: ALERTS_CHANGE,
key,
value,
});
dispatch(saveSettings());
};
}
export function saveSettings() {
return (_, getState) => {
const state = getState().get('push_notifications');
const subscription = state.get('subscription');
const alerts = state.get('alerts');
const data = { alerts };
axios.put(`/api/web/push_subscriptions/${subscription.get('id')}`, {
data,
}).then(() => {
const me = getState().getIn(['meta', 'me']);
if (me) {
pushNotificationsSetting.set(me, data);
}
});
};
}

View File

@ -0,0 +1,23 @@
import {
SET_BROWSER_SUPPORT,
SET_SUBSCRIPTION,
CLEAR_SUBSCRIPTION,
SET_ALERTS,
setAlerts,
} from './setter';
import { register, saveSettings } from './registerer';
export {
SET_BROWSER_SUPPORT,
SET_SUBSCRIPTION,
CLEAR_SUBSCRIPTION,
SET_ALERTS,
register,
};
export function changeAlerts(path, value) {
return dispatch => {
dispatch(setAlerts(path, value));
dispatch(saveSettings());
};
}

View File

@ -0,0 +1,149 @@
import axios from 'axios';
import { pushNotificationsSetting } from '../../settings';
import { setBrowserSupport, setSubscription, clearSubscription } from './setter';
// Taken from https://www.npmjs.com/package/web-push
const urlBase64ToUint8Array = (base64String) => {
const padding = '='.repeat((4 - base64String.length % 4) % 4);
const base64 = (base64String + padding)
.replace(/\-/g, '+')
.replace(/_/g, '/');
const rawData = window.atob(base64);
const outputArray = new Uint8Array(rawData.length);
for (let i = 0; i < rawData.length; ++i) {
outputArray[i] = rawData.charCodeAt(i);
}
return outputArray;
};
const getApplicationServerKey = () => document.querySelector('[name="applicationServerKey"]').getAttribute('content');
const getRegistration = () => navigator.serviceWorker.ready;
const getPushSubscription = (registration) =>
registration.pushManager.getSubscription()
.then(subscription => ({ registration, subscription }));
const subscribe = (registration) =>
registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: urlBase64ToUint8Array(getApplicationServerKey()),
});
const unsubscribe = ({ registration, subscription }) =>
subscription ? subscription.unsubscribe().then(() => registration) : registration;
const sendSubscriptionToBackend = (subscription, me) => {
const params = { subscription };
if (me) {
const data = pushNotificationsSetting.get(me);
if (data) {
params.data = data;
}
}
return axios.post('/api/web/push_subscriptions', params).then(response => response.data);
};
// Last one checks for payload support: https://web-push-book.gauntface.com/chapter-06/01-non-standards-browsers/#no-payload
const supportsPushNotifications = ('serviceWorker' in navigator && 'PushManager' in window && 'getKey' in PushSubscription.prototype);
export function register () {
return (dispatch, getState) => {
dispatch(setBrowserSupport(supportsPushNotifications));
const me = getState().getIn(['meta', 'me']);
if (me && !pushNotificationsSetting.get(me)) {
const alerts = getState().getIn(['push_notifications', 'alerts']);
if (alerts) {
pushNotificationsSetting.set(me, { alerts: alerts });
}
}
if (supportsPushNotifications) {
if (!getApplicationServerKey()) {
console.error('The VAPID public key is not set. You will not be able to receive Web Push Notifications.');
return;
}
getRegistration()
.then(getPushSubscription)
.then(({ registration, subscription }) => {
if (subscription !== null) {
// We have a subscription, check if it is still valid
const currentServerKey = (new Uint8Array(subscription.options.applicationServerKey)).toString();
const subscriptionServerKey = urlBase64ToUint8Array(getApplicationServerKey()).toString();
const serverEndpoint = getState().getIn(['push_notifications', 'subscription', 'endpoint']);
// If the VAPID public key did not change and the endpoint corresponds
// to the endpoint saved in the backend, the subscription is valid
if (subscriptionServerKey === currentServerKey && subscription.endpoint === serverEndpoint) {
return subscription;
} else {
// Something went wrong, try to subscribe again
return unsubscribe({ registration, subscription }).then(subscribe).then(
subscription => sendSubscriptionToBackend(subscription, me));
}
}
// No subscription, try to subscribe
return subscribe(registration).then(
subscription => sendSubscriptionToBackend(subscription, me));
})
.then(subscription => {
// If we got a PushSubscription (and not a subscription object from the backend)
// it means that the backend subscription is valid (and was set during hydration)
if (!(subscription instanceof PushSubscription)) {
dispatch(setSubscription(subscription));
if (me) {
pushNotificationsSetting.set(me, { alerts: subscription.alerts });
}
}
})
.catch(error => {
if (error.code === 20 && error.name === 'AbortError') {
console.warn('Your browser supports Web Push Notifications, but does not seem to implement the VAPID protocol.');
} else if (error.code === 5 && error.name === 'InvalidCharacterError') {
console.error('The VAPID public key seems to be invalid:', getApplicationServerKey());
}
// Clear alerts and hide UI settings
dispatch(clearSubscription());
if (me) {
pushNotificationsSetting.remove(me);
}
try {
getRegistration()
.then(getPushSubscription)
.then(unsubscribe);
} catch (e) {
}
});
} else {
console.warn('Your browser does not support Web Push Notifications.');
}
};
}
export function saveSettings() {
return (_, getState) => {
const state = getState().get('push_notifications');
const subscription = state.get('subscription');
const alerts = state.get('alerts');
const data = { alerts };
axios.put(`/api/web/push_subscriptions/${subscription.get('id')}`, {
data,
}).then(() => {
const me = getState().getIn(['meta', 'me']);
if (me) {
pushNotificationsSetting.set(me, data);
}
});
};
}

View File

@ -0,0 +1,34 @@
export const SET_BROWSER_SUPPORT = 'PUSH_NOTIFICATIONS_SET_BROWSER_SUPPORT';
export const SET_SUBSCRIPTION = 'PUSH_NOTIFICATIONS_SET_SUBSCRIPTION';
export const CLEAR_SUBSCRIPTION = 'PUSH_NOTIFICATIONS_CLEAR_SUBSCRIPTION';
export const SET_ALERTS = 'PUSH_NOTIFICATIONS_SET_ALERTS';
export function setBrowserSupport (value) {
return {
type: SET_BROWSER_SUPPORT,
value,
};
}
export function setSubscription (subscription) {
return {
type: SET_SUBSCRIPTION,
subscription,
};
}
export function clearSubscription () {
return {
type: CLEAR_SUBSCRIPTION,
};
}
export function setAlerts (path, value) {
return dispatch => {
dispatch({
type: SET_ALERTS,
path,
value,
});
};
}

View File

@ -4,11 +4,11 @@ import { debounce } from 'lodash';
export const SETTING_CHANGE = 'SETTING_CHANGE'; export const SETTING_CHANGE = 'SETTING_CHANGE';
export const SETTING_SAVE = 'SETTING_SAVE'; export const SETTING_SAVE = 'SETTING_SAVE';
export function changeSetting(key, value) { export function changeSetting(path, value) {
return dispatch => { return dispatch => {
dispatch({ dispatch({
type: SETTING_CHANGE, type: SETTING_CHANGE,
key, path,
value, value,
}); });
@ -21,7 +21,7 @@ const debouncedSave = debounce((dispatch, getState) => {
return; return;
} }
const data = getState().get('settings').filter((_, key) => key !== 'saved').toJS(); const data = getState().get('settings').filter((_, path) => path !== 'saved').toJS();
axios.put('/api/web/settings', { data }).then(() => dispatch({ type: SETTING_SAVE })); axios.put('/api/web/settings', { data }).then(() => dispatch({ type: SETTING_SAVE }));
}, 5000, { trailing: true }); }, 5000, { trailing: true });

View File

@ -27,6 +27,7 @@ export default class Account extends ImmutablePureComponent {
onFollow: PropTypes.func.isRequired, onFollow: PropTypes.func.isRequired,
onBlock: PropTypes.func.isRequired, onBlock: PropTypes.func.isRequired,
onMute: PropTypes.func.isRequired, onMute: PropTypes.func.isRequired,
onMuteNotifications: PropTypes.func.isRequired,
intl: PropTypes.object.isRequired, intl: PropTypes.object.isRequired,
hidden: PropTypes.bool, hidden: PropTypes.bool,
}; };

View File

@ -5,20 +5,27 @@ import PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl'; import { FormattedMessage } from 'react-intl';
import { me } from '../../../initial_state'; import { me } from '../../../initial_state';
const APPROX_HASHTAG_RE = /(?:^|[^\/\)\w])#(\S+)/i;
const mapStateToProps = state => ({ const mapStateToProps = state => ({
needsLockWarning: state.getIn(['compose', 'privacy']) === 'private' && !state.getIn(['accounts', me, 'locked']), needsLockWarning: state.getIn(['compose', 'privacy']) === 'private' && !state.getIn(['accounts', me, 'locked']),
hashtagWarning: state.getIn(['compose', 'privacy']) !== 'public' && APPROX_HASHTAG_RE.test(state.getIn(['compose', 'text'])),
}); });
const WarningWrapper = ({ needsLockWarning }) => { const WarningWrapper = ({ needsLockWarning, hashtagWarning }) => {
if (needsLockWarning) { if (needsLockWarning) {
return <Warning message={<FormattedMessage id='compose_form.lock_disclaimer' defaultMessage='Your account is not {locked}. Anyone can follow you to view your follower-only posts.' values={{ locked: <a href='/settings/profile'><FormattedMessage id='compose_form.lock_disclaimer.lock' defaultMessage='locked' /></a> }} />} />; return <Warning message={<FormattedMessage id='compose_form.lock_disclaimer' defaultMessage='Your account is not {locked}. Anyone can follow you to view your follower-only posts.' values={{ locked: <a href='/settings/profile'><FormattedMessage id='compose_form.lock_disclaimer.lock' defaultMessage='locked' /></a> }} />} />;
} }
if (hashtagWarning) {
return <Warning message={<FormattedMessage id='compose_form.hashtag_warning' defaultMessage="This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag." />} />;
}
return null; return null;
}; };
WarningWrapper.propTypes = { WarningWrapper.propTypes = {
needsLockWarning: PropTypes.bool, needsLockWarning: PropTypes.bool,
hashtagWarning: PropTypes.bool,
}; };
export default connect(mapStateToProps)(WarningWrapper); export default connect(mapStateToProps)(WarningWrapper);

View File

@ -94,6 +94,7 @@ export default class Compose extends React.PureComponent {
<div className='drawer__inner' onFocus={this.onFocus}> <div className='drawer__inner' onFocus={this.onFocus}>
<NavigationContainer onClose={this.onBlur} /> <NavigationContainer onClose={this.onBlur} />
<ComposeFormContainer /> <ComposeFormContainer />
<div className='mastodon' />
</div> </div>
<Motion defaultStyle={{ x: -100 }} style={{ x: spring(showSearch ? 0 : -100, { stiffness: 210, damping: 20 }) }}> <Motion defaultStyle={{ x: -100 }} style={{ x: spring(showSearch ? 0 : -100, { stiffness: 210, damping: 20 }) }}>

View File

@ -48,7 +48,7 @@ export default class GettingStarted extends ImmutablePureComponent {
render () { render () {
const { intl, myAccount, columns, multiColumn } = this.props; const { intl, myAccount, columns, multiColumn } = this.props;
let navItems = []; const navItems = [];
if (multiColumn) { if (multiColumn) {
if (!columns.find(item => item.get('id') === 'HOME')) { if (!columns.find(item => item.get('id') === 'HOME')) {
@ -68,21 +68,20 @@ export default class GettingStarted extends ImmutablePureComponent {
} }
} }
navItems = navItems.concat([ navItems.push(
<ColumnLink key='4' icon='star' text={intl.formatMessage(messages.favourites)} to='/favourites' />, <ColumnLink key='4' icon='star' text={intl.formatMessage(messages.favourites)} to='/favourites' />,
<ColumnLink key='5' icon='thumb-tack' text={intl.formatMessage(messages.pins)} to='/pinned' />, <ColumnLink key='5' icon='bars' text={intl.formatMessage(messages.lists)} to='/lists' />
<ColumnLink key='9' icon='bars' text={intl.formatMessage(messages.lists)} to='/lists' />, );
]);
if (myAccount.get('locked')) { if (myAccount.get('locked')) {
navItems.push(<ColumnLink key='6' icon='users' text={intl.formatMessage(messages.follow_requests)} to='/follow_requests' />); navItems.push(<ColumnLink key='6' icon='users' text={intl.formatMessage(messages.follow_requests)} to='/follow_requests' />);
} }
navItems = navItems.concat([ if (multiColumn) {
<ColumnLink key='7' icon='volume-off' text={intl.formatMessage(messages.mutes)} to='/mutes' />, navItems.push(<ColumnLink key='7' icon='question' text={intl.formatMessage(messages.keyboard_shortcuts)} to='/keyboard-shortcuts' />);
<ColumnLink key='8' icon='ban' text={intl.formatMessage(messages.blocks)} to='/blocks' />, }
<ColumnLink key='10' icon='question' text={intl.formatMessage(messages.keyboard_shortcuts)} to='/keyboard-shortcuts' hideOnMobile />,
]); navItems.push(<ColumnLink key='8' icon='book' text={intl.formatMessage(messages.info)} href='/about/more' />);
return ( return (
<Column icon='asterisk' heading={intl.formatMessage(messages.heading)} hideHeadingOnMobile> <Column icon='asterisk' heading={intl.formatMessage(messages.heading)} hideHeadingOnMobile>
@ -90,24 +89,24 @@ export default class GettingStarted extends ImmutablePureComponent {
<ColumnSubheading text={intl.formatMessage(messages.navigation_subheading)} /> <ColumnSubheading text={intl.formatMessage(messages.navigation_subheading)} />
{navItems} {navItems}
<ColumnSubheading text={intl.formatMessage(messages.settings_subheading)} /> <ColumnSubheading text={intl.formatMessage(messages.settings_subheading)} />
<ColumnLink icon='book' text={intl.formatMessage(messages.info)} href='/about/more' /> <ColumnLink icon='thumb-tack' text={intl.formatMessage(messages.pins)} to='/pinned' />
<ColumnLink icon='volume-off' text={intl.formatMessage(messages.mutes)} to='/mutes' />
<ColumnLink icon='ban' text={intl.formatMessage(messages.blocks)} to='/blocks' />
<ColumnLink icon='cog' text={intl.formatMessage(messages.preferences)} href='/settings/preferences' /> <ColumnLink icon='cog' text={intl.formatMessage(messages.preferences)} href='/settings/preferences' />
<ColumnLink icon='sign-out' text={intl.formatMessage(messages.sign_out)} href='/auth/sign_out' method='delete' /> <ColumnLink icon='sign-out' text={intl.formatMessage(messages.sign_out)} href='/auth/sign_out' method='delete' />
</div> </div>
<div className='getting-started__footer scrollable optionally-scrollable'> <div className='static-content getting-started'>
<div className='static-content getting-started'> <p>
<p> <a href='https://github.com/tootsuite/documentation/blob/master/Using-Mastodon/FAQ.md' rel='noopener' target='_blank'><FormattedMessage id='getting_started.faq' defaultMessage='FAQ' /></a> • <a href='https://github.com/tootsuite/documentation/blob/master/Using-Mastodon/User-guide.md' rel='noopener' target='_blank'><FormattedMessage id='getting_started.userguide' defaultMessage='User Guide' /></a> • <a href='https://github.com/tootsuite/documentation/blob/master/Using-Mastodon/Apps.md' rel='noopener' target='_blank'><FormattedMessage id='getting_started.appsshort' defaultMessage='Apps' /></a>
<a href='https://github.com/tootsuite/documentation/blob/master/Using-Mastodon/FAQ.md' rel='noopener' target='_blank'><FormattedMessage id='getting_started.faq' defaultMessage='FAQ' /></a> • <a href='https://github.com/tootsuite/documentation/blob/master/Using-Mastodon/User-guide.md' rel='noopener' target='_blank'><FormattedMessage id='getting_started.userguide' defaultMessage='User Guide' /></a> • <a href='https://github.com/tootsuite/documentation/blob/master/Using-Mastodon/Apps.md' rel='noopener' target='_blank'><FormattedMessage id='getting_started.appsshort' defaultMessage='Apps' /></a> </p>
</p> <p>
<p> <FormattedMessage
<FormattedMessage id='getting_started.open_source_notice'
id='getting_started.open_source_notice' defaultMessage='Mastodon is open source software. You can contribute or report issues on GitHub at {github}.'
defaultMessage='Mastodon is open source software. You can contribute or report issues on GitHub at {github}.' values={{ github: <a href='https://github.com/tootsuite/mastodon' rel='noopener' target='_blank'>tootsuite/mastodon</a> }}
values={{ github: <a href='https://github.com/tootsuite/mastodon' rel='noopener' target='_blank'>tootsuite/mastodon</a> }} />
/> </p>
</p>
</div>
</div> </div>
</Column> </Column>
); );

View File

@ -27,11 +27,11 @@ export default class ColumnSettings extends React.PureComponent {
<span className='column-settings__section'><FormattedMessage id='home.column_settings.basic' defaultMessage='Basic' /></span> <span className='column-settings__section'><FormattedMessage id='home.column_settings.basic' defaultMessage='Basic' /></span>
<div className='column-settings__row'> <div className='column-settings__row'>
<SettingToggle prefix='home_timeline' settings={settings} settingKey={['shows', 'reblog']} onChange={onChange} label={<FormattedMessage id='home.column_settings.show_reblogs' defaultMessage='Show boosts' />} /> <SettingToggle prefix='home_timeline' settings={settings} settingPath={['shows', 'reblog']} onChange={onChange} label={<FormattedMessage id='home.column_settings.show_reblogs' defaultMessage='Show boosts' />} />
</div> </div>
<div className='column-settings__row'> <div className='column-settings__row'>
<SettingToggle prefix='home_timeline' settings={settings} settingKey={['shows', 'reply']} onChange={onChange} label={<FormattedMessage id='home.column_settings.show_replies' defaultMessage='Show replies' />} /> <SettingToggle prefix='home_timeline' settings={settings} settingPath={['shows', 'reply']} onChange={onChange} label={<FormattedMessage id='home.column_settings.show_replies' defaultMessage='Show replies' />} />
</div> </div>
<span className='column-settings__section'><FormattedMessage id='home.column_settings.advanced' defaultMessage='Advanced' /></span> <span className='column-settings__section'><FormattedMessage id='home.column_settings.advanced' defaultMessage='Advanced' /></span>

View File

@ -33,59 +33,59 @@ export default class KeyboardShortcuts extends ImmutablePureComponent {
</thead> </thead>
<tbody> <tbody>
<tr> <tr>
<td><code>r</code></td> <td><kbd>r</kbd></td>
<td><FormattedMessage id='keyboard_shortcuts.reply' defaultMessage='to reply' /></td> <td><FormattedMessage id='keyboard_shortcuts.reply' defaultMessage='to reply' /></td>
</tr> </tr>
<tr> <tr>
<td><code>m</code></td> <td><kbd>m</kbd></td>
<td><FormattedMessage id='keyboard_shortcuts.mention' defaultMessage='to mention author' /></td> <td><FormattedMessage id='keyboard_shortcuts.mention' defaultMessage='to mention author' /></td>
</tr> </tr>
<tr> <tr>
<td><code>f</code></td> <td><kbd>f</kbd></td>
<td><FormattedMessage id='keyboard_shortcuts.favourite' defaultMessage='to favourite' /></td> <td><FormattedMessage id='keyboard_shortcuts.favourite' defaultMessage='to favourite' /></td>
</tr> </tr>
<tr> <tr>
<td><code>b</code></td> <td><kbd>b</kbd></td>
<td><FormattedMessage id='keyboard_shortcuts.boost' defaultMessage='to boost' /></td> <td><FormattedMessage id='keyboard_shortcuts.boost' defaultMessage='to boost' /></td>
</tr> </tr>
<tr> <tr>
<td><code>enter</code></td> <td><kbd>enter</kbd></td>
<td><FormattedMessage id='keyboard_shortcuts.enter' defaultMessage='to open status' /></td> <td><FormattedMessage id='keyboard_shortcuts.enter' defaultMessage='to open status' /></td>
</tr> </tr>
<tr> <tr>
<td><code>up</code></td> <td><kbd>up</kbd></td>
<td><FormattedMessage id='keyboard_shortcuts.up' defaultMessage='to move up in the list' /></td> <td><FormattedMessage id='keyboard_shortcuts.up' defaultMessage='to move up in the list' /></td>
</tr> </tr>
<tr> <tr>
<td><code>down</code></td> <td><kbd>down</kbd></td>
<td><FormattedMessage id='keyboard_shortcuts.down' defaultMessage='to move down in the list' /></td> <td><FormattedMessage id='keyboard_shortcuts.down' defaultMessage='to move down in the list' /></td>
</tr> </tr>
<tr> <tr>
<td><code>1</code>-<code>9</code></td> <td><kbd>1</kbd>-<kbd>9</kbd></td>
<td><FormattedMessage id='keyboard_shortcuts.column' defaultMessage='to focus a status in one of the columns' /></td> <td><FormattedMessage id='keyboard_shortcuts.column' defaultMessage='to focus a status in one of the columns' /></td>
</tr> </tr>
<tr> <tr>
<td><code>n</code></td> <td><kbd>n</kbd></td>
<td><FormattedMessage id='keyboard_shortcuts.compose' defaultMessage='to focus the compose textarea' /></td> <td><FormattedMessage id='keyboard_shortcuts.compose' defaultMessage='to focus the compose textarea' /></td>
</tr> </tr>
<tr> <tr>
<td><code>alt</code>+<code>n</code></td> <td><kbd>alt</kbd>+<kbd>n</kbd></td>
<td><FormattedMessage id='keyboard_shortcuts.toot' defaultMessage='to start a brand new toot' /></td> <td><FormattedMessage id='keyboard_shortcuts.toot' defaultMessage='to start a brand new toot' /></td>
</tr> </tr>
<tr> <tr>
<td><code>backspace</code></td> <td><kbd>backspace</kbd></td>
<td><FormattedMessage id='keyboard_shortcuts.back' defaultMessage='to navigate back' /></td> <td><FormattedMessage id='keyboard_shortcuts.back' defaultMessage='to navigate back' /></td>
</tr> </tr>
<tr> <tr>
<td><code>s</code></td> <td><kbd>s</kbd></td>
<td><FormattedMessage id='keyboard_shortcuts.search' defaultMessage='to focus search' /></td> <td><FormattedMessage id='keyboard_shortcuts.search' defaultMessage='to focus search' /></td>
</tr> </tr>
<tr> <tr>
<td><code>esc</code></td> <td><kbd>esc</kbd></td>
<td><FormattedMessage id='keyboard_shortcuts.unfocus' defaultMessage='to un-focus compose textarea/search' /></td> <td><FormattedMessage id='keyboard_shortcuts.unfocus' defaultMessage='to un-focus compose textarea/search' /></td>
</tr> </tr>
<tr> <tr>
<td><code>?</code></td> <td><kbd>?</kbd></td>
<td><FormattedMessage id='keyboard_shortcuts.legend' defaultMessage='to display this legend' /></td> <td><FormattedMessage id='keyboard_shortcuts.legend' defaultMessage='to display this legend' /></td>
</tr> </tr>
</tbody> </tbody>

View File

@ -11,12 +11,11 @@ export default class ColumnSettings extends React.PureComponent {
settings: ImmutablePropTypes.map.isRequired, settings: ImmutablePropTypes.map.isRequired,
pushSettings: ImmutablePropTypes.map.isRequired, pushSettings: ImmutablePropTypes.map.isRequired,
onChange: PropTypes.func.isRequired, onChange: PropTypes.func.isRequired,
onSave: PropTypes.func.isRequired,
onClear: PropTypes.func.isRequired, onClear: PropTypes.func.isRequired,
}; };
onPushChange = (key, checked) => { onPushChange = (path, checked) => {
this.props.onChange(['push', ...key], checked); this.props.onChange(['push', ...path], checked);
} }
render () { render () {
@ -40,10 +39,10 @@ export default class ColumnSettings extends React.PureComponent {
<span id='notifications-follow' className='column-settings__section'><FormattedMessage id='notifications.column_settings.follow' defaultMessage='New followers:' /></span> <span id='notifications-follow' className='column-settings__section'><FormattedMessage id='notifications.column_settings.follow' defaultMessage='New followers:' /></span>
<div className='column-settings__row'> <div className='column-settings__row'>
<SettingToggle prefix='notifications_desktop' settings={settings} settingKey={['alerts', 'follow']} onChange={onChange} label={alertStr} /> <SettingToggle prefix='notifications_desktop' settings={settings} settingPath={['alerts', 'follow']} onChange={onChange} label={alertStr} />
{showPushSettings && <SettingToggle prefix='notifications_push' settings={pushSettings} settingKey={['alerts', 'follow']} meta={pushMeta} onChange={this.onPushChange} label={pushStr} />} {showPushSettings && <SettingToggle prefix='notifications_push' settings={pushSettings} settingPath={['alerts', 'follow']} meta={pushMeta} onChange={this.onPushChange} label={pushStr} />}
<SettingToggle prefix='notifications' settings={settings} settingKey={['shows', 'follow']} onChange={onChange} label={showStr} /> <SettingToggle prefix='notifications' settings={settings} settingPath={['shows', 'follow']} onChange={onChange} label={showStr} />
<SettingToggle prefix='notifications' settings={settings} settingKey={['sounds', 'follow']} onChange={onChange} label={soundStr} /> <SettingToggle prefix='notifications' settings={settings} settingPath={['sounds', 'follow']} onChange={onChange} label={soundStr} />
</div> </div>
</div> </div>
@ -51,10 +50,10 @@ export default class ColumnSettings extends React.PureComponent {
<span id='notifications-favourite' className='column-settings__section'><FormattedMessage id='notifications.column_settings.favourite' defaultMessage='Favourites:' /></span> <span id='notifications-favourite' className='column-settings__section'><FormattedMessage id='notifications.column_settings.favourite' defaultMessage='Favourites:' /></span>
<div className='column-settings__row'> <div className='column-settings__row'>
<SettingToggle prefix='notifications_desktop' settings={settings} settingKey={['alerts', 'favourite']} onChange={onChange} label={alertStr} /> <SettingToggle prefix='notifications_desktop' settings={settings} settingPath={['alerts', 'favourite']} onChange={onChange} label={alertStr} />
{showPushSettings && <SettingToggle prefix='notifications_push' settings={pushSettings} settingKey={['alerts', 'favourite']} meta={pushMeta} onChange={this.onPushChange} label={pushStr} />} {showPushSettings && <SettingToggle prefix='notifications_push' settings={pushSettings} settingPath={['alerts', 'favourite']} meta={pushMeta} onChange={this.onPushChange} label={pushStr} />}
<SettingToggle prefix='notifications' settings={settings} settingKey={['shows', 'favourite']} onChange={onChange} label={showStr} /> <SettingToggle prefix='notifications' settings={settings} settingPath={['shows', 'favourite']} onChange={onChange} label={showStr} />
<SettingToggle prefix='notifications' settings={settings} settingKey={['sounds', 'favourite']} onChange={onChange} label={soundStr} /> <SettingToggle prefix='notifications' settings={settings} settingPath={['sounds', 'favourite']} onChange={onChange} label={soundStr} />
</div> </div>
</div> </div>
@ -62,10 +61,10 @@ export default class ColumnSettings extends React.PureComponent {
<span id='notifications-mention' className='column-settings__section'><FormattedMessage id='notifications.column_settings.mention' defaultMessage='Mentions:' /></span> <span id='notifications-mention' className='column-settings__section'><FormattedMessage id='notifications.column_settings.mention' defaultMessage='Mentions:' /></span>
<div className='column-settings__row'> <div className='column-settings__row'>
<SettingToggle prefix='notifications_desktop' settings={settings} settingKey={['alerts', 'mention']} onChange={onChange} label={alertStr} /> <SettingToggle prefix='notifications_desktop' settings={settings} settingPath={['alerts', 'mention']} onChange={onChange} label={alertStr} />
{showPushSettings && <SettingToggle prefix='notifications_push' settings={pushSettings} settingKey={['alerts', 'mention']} meta={pushMeta} onChange={this.onPushChange} label={pushStr} />} {showPushSettings && <SettingToggle prefix='notifications_push' settings={pushSettings} settingPath={['alerts', 'mention']} meta={pushMeta} onChange={this.onPushChange} label={pushStr} />}
<SettingToggle prefix='notifications' settings={settings} settingKey={['shows', 'mention']} onChange={onChange} label={showStr} /> <SettingToggle prefix='notifications' settings={settings} settingPath={['shows', 'mention']} onChange={onChange} label={showStr} />
<SettingToggle prefix='notifications' settings={settings} settingKey={['sounds', 'mention']} onChange={onChange} label={soundStr} /> <SettingToggle prefix='notifications' settings={settings} settingPath={['sounds', 'mention']} onChange={onChange} label={soundStr} />
</div> </div>
</div> </div>
@ -73,10 +72,10 @@ export default class ColumnSettings extends React.PureComponent {
<span id='notifications-reblog' className='column-settings__section'><FormattedMessage id='notifications.column_settings.reblog' defaultMessage='Boosts:' /></span> <span id='notifications-reblog' className='column-settings__section'><FormattedMessage id='notifications.column_settings.reblog' defaultMessage='Boosts:' /></span>
<div className='column-settings__row'> <div className='column-settings__row'>
<SettingToggle prefix='notifications_desktop' settings={settings} settingKey={['alerts', 'reblog']} onChange={onChange} label={alertStr} /> <SettingToggle prefix='notifications_desktop' settings={settings} settingPath={['alerts', 'reblog']} onChange={onChange} label={alertStr} />
{showPushSettings && <SettingToggle prefix='notifications_push' settings={pushSettings} settingKey={['alerts', 'reblog']} meta={pushMeta} onChange={this.onPushChange} label={pushStr} />} {showPushSettings && <SettingToggle prefix='notifications_push' settings={pushSettings} settingPath={['alerts', 'reblog']} meta={pushMeta} onChange={this.onPushChange} label={pushStr} />}
<SettingToggle prefix='notifications' settings={settings} settingKey={['shows', 'reblog']} onChange={onChange} label={showStr} /> <SettingToggle prefix='notifications' settings={settings} settingPath={['shows', 'reblog']} onChange={onChange} label={showStr} />
<SettingToggle prefix='notifications' settings={settings} settingKey={['sounds', 'reblog']} onChange={onChange} label={soundStr} /> <SettingToggle prefix='notifications' settings={settings} settingPath={['sounds', 'reblog']} onChange={onChange} label={soundStr} />
</div> </div>
</div> </div>
</div> </div>

View File

@ -8,23 +8,23 @@ export default class SettingToggle extends React.PureComponent {
static propTypes = { static propTypes = {
prefix: PropTypes.string, prefix: PropTypes.string,
settings: ImmutablePropTypes.map.isRequired, settings: ImmutablePropTypes.map.isRequired,
settingKey: PropTypes.array.isRequired, settingPath: PropTypes.array.isRequired,
label: PropTypes.node.isRequired, label: PropTypes.node.isRequired,
meta: PropTypes.node, meta: PropTypes.node,
onChange: PropTypes.func.isRequired, onChange: PropTypes.func.isRequired,
} }
onChange = ({ target }) => { onChange = ({ target }) => {
this.props.onChange(this.props.settingKey, target.checked); this.props.onChange(this.props.settingPath, target.checked);
} }
render () { render () {
const { prefix, settings, settingKey, label, meta } = this.props; const { prefix, settings, settingPath, label, meta } = this.props;
const id = ['setting-toggle', prefix, ...settingKey].filter(Boolean).join('-'); const id = ['setting-toggle', prefix, ...settingPath].filter(Boolean).join('-');
return ( return (
<div className='setting-toggle'> <div className='setting-toggle'>
<Toggle id={id} checked={settings.getIn(settingKey)} onChange={this.onChange} onKeyDown={this.onKeyDown} /> <Toggle id={id} checked={settings.getIn(settingPath)} onChange={this.onChange} onKeyDown={this.onKeyDown} />
<label htmlFor={id} className='setting-toggle__label'>{label}</label> <label htmlFor={id} className='setting-toggle__label'>{label}</label>
{meta && <span className='setting-meta__label'>{meta}</span>} {meta && <span className='setting-meta__label'>{meta}</span>}
</div> </div>

View File

@ -1,9 +1,9 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { defineMessages, injectIntl } from 'react-intl'; import { defineMessages, injectIntl } from 'react-intl';
import ColumnSettings from '../components/column_settings'; import ColumnSettings from '../components/column_settings';
import { changeSetting, saveSettings } from '../../../actions/settings'; import { changeSetting } from '../../../actions/settings';
import { clearNotifications } from '../../../actions/notifications'; import { clearNotifications } from '../../../actions/notifications';
import { changeAlerts as changePushNotifications, saveSettings as savePushNotificationSettings } from '../../../actions/push_notifications'; import { changeAlerts as changePushNotifications } from '../../../actions/push_notifications';
import { openModal } from '../../../actions/modal'; import { openModal } from '../../../actions/modal';
const messages = defineMessages({ const messages = defineMessages({
@ -18,19 +18,14 @@ const mapStateToProps = state => ({
const mapDispatchToProps = (dispatch, { intl }) => ({ const mapDispatchToProps = (dispatch, { intl }) => ({
onChange (key, checked) { onChange (path, checked) {
if (key[0] === 'push') { if (path[0] === 'push') {
dispatch(changePushNotifications(key.slice(1), checked)); dispatch(changePushNotifications(path.slice(1), checked));
} else { } else {
dispatch(changeSetting(['notifications', ...key], checked)); dispatch(changeSetting(['notifications', ...path], checked));
} }
}, },
onSave () {
dispatch(saveSettings());
dispatch(savePushNotificationSettings());
},
onClear () { onClear () {
dispatch(openModal('CONFIRM', { dispatch(openModal('CONFIRM', {
message: intl.formatMessage(messages.clearMessage), message: intl.formatMessage(messages.clearMessage),

View File

@ -13,6 +13,10 @@ const messages = defineMessages({
reblog: { id: 'status.reblog', defaultMessage: 'Boost' }, reblog: { id: 'status.reblog', defaultMessage: 'Boost' },
cannot_reblog: { id: 'status.cannot_reblog', defaultMessage: 'This post cannot be boosted' }, cannot_reblog: { id: 'status.cannot_reblog', defaultMessage: 'This post cannot be boosted' },
favourite: { id: 'status.favourite', defaultMessage: 'Favourite' }, favourite: { id: 'status.favourite', defaultMessage: 'Favourite' },
mute: { id: 'status.mute', defaultMessage: 'Mute @{name}' },
muteConversation: { id: 'status.mute_conversation', defaultMessage: 'Mute conversation' },
unmuteConversation: { id: 'status.unmute_conversation', defaultMessage: 'Unmute conversation' },
block: { id: 'status.block', defaultMessage: 'Block @{name}' },
report: { id: 'status.report', defaultMessage: 'Report @{name}' }, report: { id: 'status.report', defaultMessage: 'Report @{name}' },
share: { id: 'status.share', defaultMessage: 'Share' }, share: { id: 'status.share', defaultMessage: 'Share' },
pin: { id: 'status.pin', defaultMessage: 'Pin on profile' }, pin: { id: 'status.pin', defaultMessage: 'Pin on profile' },
@ -34,6 +38,9 @@ export default class ActionBar extends React.PureComponent {
onFavourite: PropTypes.func.isRequired, onFavourite: PropTypes.func.isRequired,
onDelete: PropTypes.func.isRequired, onDelete: PropTypes.func.isRequired,
onMention: PropTypes.func.isRequired, onMention: PropTypes.func.isRequired,
onMute: PropTypes.func,
onMuteConversation: PropTypes.func,
onBlock: PropTypes.func,
onReport: PropTypes.func, onReport: PropTypes.func,
onPin: PropTypes.func, onPin: PropTypes.func,
onEmbed: PropTypes.func, onEmbed: PropTypes.func,
@ -60,6 +67,18 @@ export default class ActionBar extends React.PureComponent {
this.props.onMention(this.props.status.get('account'), this.context.router.history); this.props.onMention(this.props.status.get('account'), this.context.router.history);
} }
handleMuteClick = () => {
this.props.onMute(this.props.status.get('account'));
}
handleConversationMuteClick = () => {
this.props.onMuteConversation(this.props.status);
}
handleBlockClick = () => {
this.props.onBlock(this.props.status.get('account'));
}
handleReport = () => { handleReport = () => {
this.props.onReport(this.props.status); this.props.onReport(this.props.status);
} }
@ -83,6 +102,7 @@ export default class ActionBar extends React.PureComponent {
const { status, intl } = this.props; const { status, intl } = this.props;
const publicStatus = ['public', 'unlisted'].includes(status.get('visibility')); const publicStatus = ['public', 'unlisted'].includes(status.get('visibility'));
const mutingConversation = status.get('muted');
let menu = []; let menu = [];
@ -95,10 +115,15 @@ export default class ActionBar extends React.PureComponent {
menu.push({ text: intl.formatMessage(status.get('pinned') ? messages.unpin : messages.pin), action: this.handlePinClick }); menu.push({ text: intl.formatMessage(status.get('pinned') ? messages.unpin : messages.pin), action: this.handlePinClick });
} }
menu.push(null);
menu.push({ text: intl.formatMessage(mutingConversation ? messages.unmuteConversation : messages.muteConversation), action: this.handleConversationMuteClick });
menu.push(null);
menu.push({ text: intl.formatMessage(messages.delete), action: this.handleDeleteClick }); menu.push({ text: intl.formatMessage(messages.delete), action: this.handleDeleteClick });
} else { } else {
menu.push({ text: intl.formatMessage(messages.mention, { name: status.getIn(['account', 'username']) }), action: this.handleMentionClick }); menu.push({ text: intl.formatMessage(messages.mention, { name: status.getIn(['account', 'username']) }), action: this.handleMentionClick });
menu.push(null); menu.push(null);
menu.push({ text: intl.formatMessage(messages.mute, { name: status.getIn(['account', 'username']) }), action: this.handleMuteClick });
menu.push({ text: intl.formatMessage(messages.block, { name: status.getIn(['account', 'username']) }), action: this.handleBlockClick });
menu.push({ text: intl.formatMessage(messages.report, { name: status.getIn(['account', 'username']) }), action: this.handleReport }); menu.push({ text: intl.formatMessage(messages.report, { name: status.getIn(['account', 'username']) }), action: this.handleReport });
} }

View File

@ -20,14 +20,16 @@ import {
replyCompose, replyCompose,
mentionCompose, mentionCompose,
} from '../../actions/compose'; } from '../../actions/compose';
import { deleteStatus } from '../../actions/statuses'; import { blockAccount } from '../../actions/accounts';
import { muteStatus, unmuteStatus, deleteStatus } from '../../actions/statuses';
import { initMuteModal } from '../../actions/mutes';
import { initReport } from '../../actions/reports'; import { initReport } from '../../actions/reports';
import { makeGetStatus } from '../../selectors'; import { makeGetStatus } from '../../selectors';
import { ScrollContainer } from 'react-router-scroll-4'; import { ScrollContainer } from 'react-router-scroll-4';
import ColumnBackButton from '../../components/column_back_button'; import ColumnBackButton from '../../components/column_back_button';
import StatusContainer from '../../containers/status_container'; import StatusContainer from '../../containers/status_container';
import { openModal } from '../../actions/modal'; import { openModal } from '../../actions/modal';
import { defineMessages, injectIntl } from 'react-intl'; import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import ImmutablePureComponent from 'react-immutable-pure-component'; import ImmutablePureComponent from 'react-immutable-pure-component';
import { HotKeys } from 'react-hotkeys'; import { HotKeys } from 'react-hotkeys';
import { boostModal, deleteModal } from '../../initial_state'; import { boostModal, deleteModal } from '../../initial_state';
@ -36,6 +38,7 @@ import { attachFullscreenListener, detachFullscreenListener, isFullscreen } from
const messages = defineMessages({ const messages = defineMessages({
deleteConfirm: { id: 'confirmations.delete.confirm', defaultMessage: 'Delete' }, deleteConfirm: { id: 'confirmations.delete.confirm', defaultMessage: 'Delete' },
deleteMessage: { id: 'confirmations.delete.message', defaultMessage: 'Are you sure you want to delete this status?' }, deleteMessage: { id: 'confirmations.delete.message', defaultMessage: 'Are you sure you want to delete this status?' },
blockConfirm: { id: 'confirmations.block.confirm', defaultMessage: 'Block' },
}); });
const makeMapStateToProps = () => { const makeMapStateToProps = () => {
@ -148,6 +151,28 @@ export default class Status extends ImmutablePureComponent {
this.props.dispatch(openModal('VIDEO', { media, time })); this.props.dispatch(openModal('VIDEO', { media, time }));
} }
handleMuteClick = (account) => {
this.props.dispatch(initMuteModal(account));
}
handleConversationMuteClick = (status) => {
if (status.get('muted')) {
this.props.dispatch(unmuteStatus(status.get('id')));
} else {
this.props.dispatch(muteStatus(status.get('id')));
}
}
handleBlockClick = (account) => {
const { dispatch, intl } = this.props;
dispatch(openModal('CONFIRM', {
message: <FormattedMessage id='confirmations.block.message' defaultMessage='Are you sure you want to block {name}?' values={{ name: <strong>@{account.get('acct')}</strong> }} />,
confirm: intl.formatMessage(messages.blockConfirm),
onConfirm: () => dispatch(blockAccount(account.get('id'))),
}));
}
handleReport = (status) => { handleReport = (status) => {
this.props.dispatch(initReport(status.get('account'), status)); this.props.dispatch(initReport(status.get('account'), status));
} }
@ -321,6 +346,9 @@ export default class Status extends ImmutablePureComponent {
onReblog={this.handleReblogClick} onReblog={this.handleReblogClick}
onDelete={this.handleDeleteClick} onDelete={this.handleDeleteClick}
onMention={this.handleMentionClick} onMention={this.handleMentionClick}
onMute={this.handleMuteClick}
onMuteConversation={this.handleConversationMuteClick}
onBlock={this.handleBlockClick}
onReport={this.handleReport} onReport={this.handleReport}
onPin={this.handlePin} onPin={this.handlePin}
onEmbed={this.handleEmbed} onEmbed={this.handleEmbed}

View File

@ -26,7 +26,6 @@ ColumnLink.propTypes = {
to: PropTypes.string, to: PropTypes.string,
href: PropTypes.string, href: PropTypes.string,
method: PropTypes.string, method: PropTypes.string,
hideOnMobile: PropTypes.bool,
}; };
export default ColumnLink; export default ColumnLink;

View File

@ -50,6 +50,7 @@
"column_header.unpin": "فك التدبيس", "column_header.unpin": "فك التدبيس",
"column_subheading.navigation": "التصفح", "column_subheading.navigation": "التصفح",
"column_subheading.settings": "الإعدادات", "column_subheading.settings": "الإعدادات",
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
"compose_form.lock_disclaimer": "حسابك ليس {locked}. يمكن لأي شخص متابعتك و عرض المنشورات.", "compose_form.lock_disclaimer": "حسابك ليس {locked}. يمكن لأي شخص متابعتك و عرض المنشورات.",
"compose_form.lock_disclaimer.lock": "مقفل", "compose_form.lock_disclaimer.lock": "مقفل",
"compose_form.placeholder": "فيمَ تفكّر؟", "compose_form.placeholder": "فيمَ تفكّر؟",
@ -213,6 +214,7 @@
"search_popout.tips.user": "مستخدِم", "search_popout.tips.user": "مستخدِم",
"search_results.total": "{count, number} {count, plural, one {result} و {results}}", "search_results.total": "{count, number} {count, plural, one {result} و {results}}",
"standalone.public_title": "نظرة على ...", "standalone.public_title": "نظرة على ...",
"status.block": "Block @{name}",
"status.cannot_reblog": "تعذرت ترقية هذا المنشور", "status.cannot_reblog": "تعذرت ترقية هذا المنشور",
"status.delete": "إحذف", "status.delete": "إحذف",
"status.embed": "إدماج", "status.embed": "إدماج",
@ -221,6 +223,7 @@
"status.media_hidden": "الصورة مستترة", "status.media_hidden": "الصورة مستترة",
"status.mention": "أذكُر @{name}", "status.mention": "أذكُر @{name}",
"status.more": "المزيد", "status.more": "المزيد",
"status.mute": "Mute @{name}",
"status.mute_conversation": "كتم المحادثة", "status.mute_conversation": "كتم المحادثة",
"status.open": "وسع هذه المشاركة", "status.open": "وسع هذه المشاركة",
"status.pin": "تدبيس على الملف الشخصي", "status.pin": "تدبيس على الملف الشخصي",

View File

@ -50,6 +50,7 @@
"column_header.unpin": "Unpin", "column_header.unpin": "Unpin",
"column_subheading.navigation": "Navigation", "column_subheading.navigation": "Navigation",
"column_subheading.settings": "Settings", "column_subheading.settings": "Settings",
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
"compose_form.lock_disclaimer": "Your account is not {locked}. Anyone can follow you to view your follower-only posts.", "compose_form.lock_disclaimer": "Your account is not {locked}. Anyone can follow you to view your follower-only posts.",
"compose_form.lock_disclaimer.lock": "locked", "compose_form.lock_disclaimer.lock": "locked",
"compose_form.placeholder": "Какво си мислиш?", "compose_form.placeholder": "Какво си мислиш?",
@ -213,6 +214,7 @@
"search_popout.tips.user": "user", "search_popout.tips.user": "user",
"search_results.total": "{count, number} {count, plural, one {result} other {results}}", "search_results.total": "{count, number} {count, plural, one {result} other {results}}",
"standalone.public_title": "A look inside...", "standalone.public_title": "A look inside...",
"status.block": "Block @{name}",
"status.cannot_reblog": "This post cannot be boosted", "status.cannot_reblog": "This post cannot be boosted",
"status.delete": "Изтриване", "status.delete": "Изтриване",
"status.embed": "Embed", "status.embed": "Embed",
@ -221,6 +223,7 @@
"status.media_hidden": "Media hidden", "status.media_hidden": "Media hidden",
"status.mention": "Споменаване", "status.mention": "Споменаване",
"status.more": "More", "status.more": "More",
"status.mute": "Mute @{name}",
"status.mute_conversation": "Mute conversation", "status.mute_conversation": "Mute conversation",
"status.open": "Expand this status", "status.open": "Expand this status",
"status.pin": "Pin on profile", "status.pin": "Pin on profile",

View File

@ -50,6 +50,7 @@
"column_header.unpin": "Deslligar", "column_header.unpin": "Deslligar",
"column_subheading.navigation": "Navegació", "column_subheading.navigation": "Navegació",
"column_subheading.settings": "Configuració", "column_subheading.settings": "Configuració",
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
"compose_form.lock_disclaimer": "El teu compte no està bloquejat {locked}. Tothom pot seguir-te i veure els teus missatges a seguidors.", "compose_form.lock_disclaimer": "El teu compte no està bloquejat {locked}. Tothom pot seguir-te i veure els teus missatges a seguidors.",
"compose_form.lock_disclaimer.lock": "bloquejat", "compose_form.lock_disclaimer.lock": "bloquejat",
"compose_form.placeholder": "En què estàs pensant?", "compose_form.placeholder": "En què estàs pensant?",
@ -213,6 +214,7 @@
"search_popout.tips.user": "usuari", "search_popout.tips.user": "usuari",
"search_results.total": "{count, number} {count, plural, un {result} altres {results}}", "search_results.total": "{count, number} {count, plural, un {result} altres {results}}",
"standalone.public_title": "Una mirada a l'interior ...", "standalone.public_title": "Una mirada a l'interior ...",
"status.block": "Block @{name}",
"status.cannot_reblog": "Aquesta publicació no pot ser retootejada", "status.cannot_reblog": "Aquesta publicació no pot ser retootejada",
"status.delete": "Esborrar", "status.delete": "Esborrar",
"status.embed": "Incrustar", "status.embed": "Incrustar",
@ -221,6 +223,7 @@
"status.media_hidden": "Multimèdia amagat", "status.media_hidden": "Multimèdia amagat",
"status.mention": "Esmentar @{name}", "status.mention": "Esmentar @{name}",
"status.more": "Més", "status.more": "Més",
"status.mute": "Mute @{name}",
"status.mute_conversation": "Silenciar conversació", "status.mute_conversation": "Silenciar conversació",
"status.open": "Ampliar aquest estat", "status.open": "Ampliar aquest estat",
"status.pin": "Fixat en el perfil", "status.pin": "Fixat en el perfil",

View File

@ -50,6 +50,7 @@
"column_header.unpin": "Lösen", "column_header.unpin": "Lösen",
"column_subheading.navigation": "Navigation", "column_subheading.navigation": "Navigation",
"column_subheading.settings": "Einstellungen", "column_subheading.settings": "Einstellungen",
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
"compose_form.lock_disclaimer": "Dein Profil ist nicht {locked}. Wer dir folgen will, kann das jederzeit tun und dann auch deine privaten Beiträge sehen.", "compose_form.lock_disclaimer": "Dein Profil ist nicht {locked}. Wer dir folgen will, kann das jederzeit tun und dann auch deine privaten Beiträge sehen.",
"compose_form.lock_disclaimer.lock": "gesperrt", "compose_form.lock_disclaimer.lock": "gesperrt",
"compose_form.placeholder": "Worüber möchtest du schreiben?", "compose_form.placeholder": "Worüber möchtest du schreiben?",
@ -213,6 +214,7 @@
"search_popout.tips.user": "user", "search_popout.tips.user": "user",
"search_results.total": "{count, number} {count, plural, one {Ergebnis} other {Ergebnisse}}", "search_results.total": "{count, number} {count, plural, one {Ergebnis} other {Ergebnisse}}",
"standalone.public_title": "Ein kleiner Einblick …", "standalone.public_title": "Ein kleiner Einblick …",
"status.block": "Block @{name}",
"status.cannot_reblog": "Dieser Beitrag kann nicht geteilt werden", "status.cannot_reblog": "Dieser Beitrag kann nicht geteilt werden",
"status.delete": "Löschen", "status.delete": "Löschen",
"status.embed": "Einbetten", "status.embed": "Einbetten",
@ -221,6 +223,7 @@
"status.media_hidden": "Medien versteckt", "status.media_hidden": "Medien versteckt",
"status.mention": "@{name} erwähnen", "status.mention": "@{name} erwähnen",
"status.more": "Mehr", "status.more": "Mehr",
"status.mute": "Mute @{name}",
"status.mute_conversation": "Thread stummschalten", "status.mute_conversation": "Thread stummschalten",
"status.open": "Diesen Beitrag öffnen", "status.open": "Diesen Beitrag öffnen",
"status.pin": "Im Profil anheften", "status.pin": "Im Profil anheften",

View File

@ -727,6 +727,10 @@
{ {
"defaultMessage": "locked", "defaultMessage": "locked",
"id": "compose_form.lock_disclaimer.lock" "id": "compose_form.lock_disclaimer.lock"
},
{
"defaultMessage": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
"id": "compose_form.hashtag_warning"
} }
], ],
"path": "app/javascript/mastodon/features/compose/containers/warning_container.json" "path": "app/javascript/mastodon/features/compose/containers/warning_container.json"
@ -1053,7 +1057,7 @@
"id": "lists.delete" "id": "lists.delete"
}, },
{ {
"defaultMessage": "There is nothing in this list yet.", "defaultMessage": "There is nothing in this list yet. When members of this list post new statuses, they will appear here.",
"id": "empty_column.list" "id": "empty_column.list"
} }
], ],
@ -1244,6 +1248,22 @@
"defaultMessage": "Favourite", "defaultMessage": "Favourite",
"id": "status.favourite" "id": "status.favourite"
}, },
{
"defaultMessage": "Mute @{name}",
"id": "status.mute"
},
{
"defaultMessage": "Mute conversation",
"id": "status.mute_conversation"
},
{
"defaultMessage": "Unmute conversation",
"id": "status.unmute_conversation"
},
{
"defaultMessage": "Block @{name}",
"id": "status.block"
},
{ {
"defaultMessage": "Report @{name}", "defaultMessage": "Report @{name}",
"id": "status.report" "id": "status.report"
@ -1276,6 +1296,14 @@
{ {
"defaultMessage": "Are you sure you want to delete this status?", "defaultMessage": "Are you sure you want to delete this status?",
"id": "confirmations.delete.message" "id": "confirmations.delete.message"
},
{
"defaultMessage": "Block",
"id": "confirmations.block.confirm"
},
{
"defaultMessage": "Are you sure you want to block {name}?",
"id": "confirmations.block.message"
} }
], ],
"path": "app/javascript/mastodon/features/status/index.json" "path": "app/javascript/mastodon/features/status/index.json"

View File

@ -50,6 +50,7 @@
"column_header.unpin": "Unpin", "column_header.unpin": "Unpin",
"column_subheading.navigation": "Navigation", "column_subheading.navigation": "Navigation",
"column_subheading.settings": "Settings", "column_subheading.settings": "Settings",
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
"compose_form.lock_disclaimer": "Your account is not {locked}. Anyone can follow you to view your follower-only posts.", "compose_form.lock_disclaimer": "Your account is not {locked}. Anyone can follow you to view your follower-only posts.",
"compose_form.lock_disclaimer.lock": "locked", "compose_form.lock_disclaimer.lock": "locked",
"compose_form.placeholder": "What is on your mind?", "compose_form.placeholder": "What is on your mind?",
@ -213,6 +214,7 @@
"search_popout.tips.user": "user", "search_popout.tips.user": "user",
"search_results.total": "{count, number} {count, plural, one {result} other {results}}", "search_results.total": "{count, number} {count, plural, one {result} other {results}}",
"standalone.public_title": "A look inside...", "standalone.public_title": "A look inside...",
"status.block": "Block @{name}",
"status.cannot_reblog": "This post cannot be boosted", "status.cannot_reblog": "This post cannot be boosted",
"status.delete": "Delete", "status.delete": "Delete",
"status.embed": "Embed", "status.embed": "Embed",
@ -221,6 +223,7 @@
"status.media_hidden": "Media hidden", "status.media_hidden": "Media hidden",
"status.mention": "Mention @{name}", "status.mention": "Mention @{name}",
"status.more": "More", "status.more": "More",
"status.mute": "Mute @{name}",
"status.mute_conversation": "Mute conversation", "status.mute_conversation": "Mute conversation",
"status.open": "Expand this status", "status.open": "Expand this status",
"status.pin": "Pin on profile", "status.pin": "Pin on profile",

View File

@ -50,6 +50,7 @@
"column_header.unpin": "Depingli", "column_header.unpin": "Depingli",
"column_subheading.navigation": "Navigado", "column_subheading.navigation": "Navigado",
"column_subheading.settings": "Agordoj", "column_subheading.settings": "Agordoj",
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
"compose_form.lock_disclaimer": "Via konta ne estas ŝlosita. Iu ajn povas sekvi vin por vidi viajn privatajn pepojn.", "compose_form.lock_disclaimer": "Via konta ne estas ŝlosita. Iu ajn povas sekvi vin por vidi viajn privatajn pepojn.",
"compose_form.lock_disclaimer.lock": "ŝlosita", "compose_form.lock_disclaimer.lock": "ŝlosita",
"compose_form.placeholder": "Pri kio vi pensas?", "compose_form.placeholder": "Pri kio vi pensas?",
@ -213,6 +214,7 @@
"search_popout.tips.user": "uzanto", "search_popout.tips.user": "uzanto",
"search_results.total": "{count, number} {count, plural, one {rezultato} other {rezultatoj}}", "search_results.total": "{count, number} {count, plural, one {rezultato} other {rezultatoj}}",
"standalone.public_title": "Rigardeti…", "standalone.public_title": "Rigardeti…",
"status.block": "Block @{name}",
"status.cannot_reblog": "Tiun publikaĵon oni ne povas diskonigi", "status.cannot_reblog": "Tiun publikaĵon oni ne povas diskonigi",
"status.delete": "Forigi", "status.delete": "Forigi",
"status.embed": "Enmeti", "status.embed": "Enmeti",
@ -221,6 +223,7 @@
"status.media_hidden": "Sonbildaĵo kaŝita", "status.media_hidden": "Sonbildaĵo kaŝita",
"status.mention": "Mencii @{name}", "status.mention": "Mencii @{name}",
"status.more": "Pli", "status.more": "Pli",
"status.mute": "Mute @{name}",
"status.mute_conversation": "Silentigi konversacion", "status.mute_conversation": "Silentigi konversacion",
"status.open": "Disfaldi statkonigon", "status.open": "Disfaldi statkonigon",
"status.pin": "Pingli al la profilo", "status.pin": "Pingli al la profilo",

View File

@ -50,6 +50,7 @@
"column_header.unpin": "Dejar de fijar", "column_header.unpin": "Dejar de fijar",
"column_subheading.navigation": "Navegación", "column_subheading.navigation": "Navegación",
"column_subheading.settings": "Ajustes", "column_subheading.settings": "Ajustes",
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
"compose_form.lock_disclaimer": "Tu cuenta no está bloqueada. Todos pueden seguirte para ver tus toots solo para seguidores.", "compose_form.lock_disclaimer": "Tu cuenta no está bloqueada. Todos pueden seguirte para ver tus toots solo para seguidores.",
"compose_form.lock_disclaimer.lock": "bloqueado", "compose_form.lock_disclaimer.lock": "bloqueado",
"compose_form.placeholder": "¿En qué estás pensando?", "compose_form.placeholder": "¿En qué estás pensando?",
@ -213,6 +214,7 @@
"search_popout.tips.user": "usuario", "search_popout.tips.user": "usuario",
"search_results.total": "{count, number} {count, plural, one {resultado} other {resultados}}", "search_results.total": "{count, number} {count, plural, one {resultado} other {resultados}}",
"standalone.public_title": "Un pequeño vistazo...", "standalone.public_title": "Un pequeño vistazo...",
"status.block": "Block @{name}",
"status.cannot_reblog": "Este toot no puede retootearse", "status.cannot_reblog": "Este toot no puede retootearse",
"status.delete": "Borrar", "status.delete": "Borrar",
"status.embed": "Incrustado", "status.embed": "Incrustado",
@ -221,6 +223,7 @@
"status.media_hidden": "Contenido multimedia oculto", "status.media_hidden": "Contenido multimedia oculto",
"status.mention": "Mencionar", "status.mention": "Mencionar",
"status.more": "Más", "status.more": "Más",
"status.mute": "Mute @{name}",
"status.mute_conversation": "Silenciar conversación", "status.mute_conversation": "Silenciar conversación",
"status.open": "Expandir estado", "status.open": "Expandir estado",
"status.pin": "Fijar", "status.pin": "Fijar",

View File

@ -50,6 +50,7 @@
"column_header.unpin": "رهاکردن", "column_header.unpin": "رهاکردن",
"column_subheading.navigation": "گشت و گذار", "column_subheading.navigation": "گشت و گذار",
"column_subheading.settings": "تنظیمات", "column_subheading.settings": "تنظیمات",
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
"compose_form.lock_disclaimer": "حساب شما {locked} نیست. هر کسی می‌تواند پیگیر شما شود و نوشته‌های ویژهٔ پیگیران شما را ببیند.", "compose_form.lock_disclaimer": "حساب شما {locked} نیست. هر کسی می‌تواند پیگیر شما شود و نوشته‌های ویژهٔ پیگیران شما را ببیند.",
"compose_form.lock_disclaimer.lock": "قفل", "compose_form.lock_disclaimer.lock": "قفل",
"compose_form.placeholder": "تازه چه خبر؟", "compose_form.placeholder": "تازه چه خبر؟",
@ -213,6 +214,7 @@
"search_popout.tips.user": "کاربر", "search_popout.tips.user": "کاربر",
"search_results.total": "{count, number} {count, plural, one {نتیجه} other {نتیجه}}", "search_results.total": "{count, number} {count, plural, one {نتیجه} other {نتیجه}}",
"standalone.public_title": "نگاهی به کاربران این سرور...", "standalone.public_title": "نگاهی به کاربران این سرور...",
"status.block": "Block @{name}",
"status.cannot_reblog": "این نوشته را نمی‌شود بازبوقید", "status.cannot_reblog": "این نوشته را نمی‌شود بازبوقید",
"status.delete": "پاک‌کردن", "status.delete": "پاک‌کردن",
"status.embed": "جاگذاری", "status.embed": "جاگذاری",
@ -221,6 +223,7 @@
"status.media_hidden": "تصویر پنهان شده", "status.media_hidden": "تصویر پنهان شده",
"status.mention": "نام‌بردن از @{name}", "status.mention": "نام‌بردن از @{name}",
"status.more": "More", "status.more": "More",
"status.mute": "Mute @{name}",
"status.mute_conversation": "بی‌صداکردن گفتگو", "status.mute_conversation": "بی‌صداکردن گفتگو",
"status.open": "این نوشته را باز کن", "status.open": "این نوشته را باز کن",
"status.pin": "نوشتهٔ ثابت نمایه", "status.pin": "نوشتهٔ ثابت نمایه",

View File

@ -50,6 +50,7 @@
"column_header.unpin": "Unpin", "column_header.unpin": "Unpin",
"column_subheading.navigation": "Navigation", "column_subheading.navigation": "Navigation",
"column_subheading.settings": "Settings", "column_subheading.settings": "Settings",
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
"compose_form.lock_disclaimer": "Your account is not {locked}. Anyone can follow you to view your follower-only posts.", "compose_form.lock_disclaimer": "Your account is not {locked}. Anyone can follow you to view your follower-only posts.",
"compose_form.lock_disclaimer.lock": "locked", "compose_form.lock_disclaimer.lock": "locked",
"compose_form.placeholder": "Mitä sinulla on mielessä?", "compose_form.placeholder": "Mitä sinulla on mielessä?",
@ -213,6 +214,7 @@
"search_popout.tips.user": "user", "search_popout.tips.user": "user",
"search_results.total": "{count, number} {count, plural, one {result} other {results}}", "search_results.total": "{count, number} {count, plural, one {result} other {results}}",
"standalone.public_title": "A look inside...", "standalone.public_title": "A look inside...",
"status.block": "Block @{name}",
"status.cannot_reblog": "This post cannot be boosted", "status.cannot_reblog": "This post cannot be boosted",
"status.delete": "Poista", "status.delete": "Poista",
"status.embed": "Embed", "status.embed": "Embed",
@ -221,6 +223,7 @@
"status.media_hidden": "Media hidden", "status.media_hidden": "Media hidden",
"status.mention": "Mainitse @{name}", "status.mention": "Mainitse @{name}",
"status.more": "More", "status.more": "More",
"status.mute": "Mute @{name}",
"status.mute_conversation": "Mute conversation", "status.mute_conversation": "Mute conversation",
"status.open": "Expand this status", "status.open": "Expand this status",
"status.pin": "Pin on profile", "status.pin": "Pin on profile",

View File

@ -50,6 +50,7 @@
"column_header.unpin": "Retirer", "column_header.unpin": "Retirer",
"column_subheading.navigation": "Navigation", "column_subheading.navigation": "Navigation",
"column_subheading.settings": "Paramètres", "column_subheading.settings": "Paramètres",
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
"compose_form.lock_disclaimer": "Votre compte nest pas {locked}. Tout le monde peut vous suivre et voir vos pouets privés.", "compose_form.lock_disclaimer": "Votre compte nest pas {locked}. Tout le monde peut vous suivre et voir vos pouets privés.",
"compose_form.lock_disclaimer.lock": "verrouillé", "compose_form.lock_disclaimer.lock": "verrouillé",
"compose_form.placeholder": "Quavez-vous en tête?", "compose_form.placeholder": "Quavez-vous en tête?",
@ -213,6 +214,7 @@
"search_popout.tips.user": "utilisateur⋅ice", "search_popout.tips.user": "utilisateur⋅ice",
"search_results.total": "{count, number} {count, plural, one {résultat} other {résultats}}", "search_results.total": "{count, number} {count, plural, one {résultat} other {résultats}}",
"standalone.public_title": "Jeter un coup dœil…", "standalone.public_title": "Jeter un coup dœil…",
"status.block": "Block @{name}",
"status.cannot_reblog": "Cette publication ne peut être boostée", "status.cannot_reblog": "Cette publication ne peut être boostée",
"status.delete": "Effacer", "status.delete": "Effacer",
"status.embed": "Intégrer", "status.embed": "Intégrer",
@ -221,6 +223,7 @@
"status.media_hidden": "Média caché", "status.media_hidden": "Média caché",
"status.mention": "Mentionner", "status.mention": "Mentionner",
"status.more": "Plus", "status.more": "Plus",
"status.mute": "Mute @{name}",
"status.mute_conversation": "Masquer la conversation", "status.mute_conversation": "Masquer la conversation",
"status.open": "Déplier ce statut", "status.open": "Déplier ce statut",
"status.pin": "Épingler sur le profil", "status.pin": "Épingler sur le profil",

View File

@ -50,6 +50,7 @@
"column_header.unpin": "Soltar", "column_header.unpin": "Soltar",
"column_subheading.navigation": "Navegación", "column_subheading.navigation": "Navegación",
"column_subheading.settings": "Axustes", "column_subheading.settings": "Axustes",
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
"compose_form.lock_disclaimer": "A súa conta non está {locked}. Calquera pode seguila para ver as súas mensaxes só-para-seguidoras.", "compose_form.lock_disclaimer": "A súa conta non está {locked}. Calquera pode seguila para ver as súas mensaxes só-para-seguidoras.",
"compose_form.lock_disclaimer.lock": "bloqueado", "compose_form.lock_disclaimer.lock": "bloqueado",
"compose_form.placeholder": "A qué andas?", "compose_form.placeholder": "A qué andas?",
@ -213,6 +214,7 @@
"search_popout.tips.user": "usuaria", "search_popout.tips.user": "usuaria",
"search_results.total": "{count, number} {count,plural,one {result} outros {results}}", "search_results.total": "{count, number} {count,plural,one {result} outros {results}}",
"standalone.public_title": "Ollada dentro...", "standalone.public_title": "Ollada dentro...",
"status.block": "Block @{name}",
"status.cannot_reblog": "Esta mensaxe non pode ser promocionada", "status.cannot_reblog": "Esta mensaxe non pode ser promocionada",
"status.delete": "Eliminar", "status.delete": "Eliminar",
"status.embed": "Incrustar", "status.embed": "Incrustar",
@ -221,6 +223,7 @@
"status.media_hidden": "Medios ocultos", "status.media_hidden": "Medios ocultos",
"status.mention": "Mencionar @{name}", "status.mention": "Mencionar @{name}",
"status.more": "Máis", "status.more": "Máis",
"status.mute": "Mute @{name}",
"status.mute_conversation": "Acalar conversa", "status.mute_conversation": "Acalar conversa",
"status.open": "Expandir este estado", "status.open": "Expandir este estado",
"status.pin": "Fixar no perfil", "status.pin": "Fixar no perfil",

View File

@ -50,6 +50,7 @@
"column_header.unpin": "שחרור קיבוע", "column_header.unpin": "שחרור קיבוע",
"column_subheading.navigation": "ניווט", "column_subheading.navigation": "ניווט",
"column_subheading.settings": "אפשרויות", "column_subheading.settings": "אפשרויות",
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
"compose_form.lock_disclaimer": "חשבונך אינו {locked}. כל אחד יוכל לעקוב אחריך כדי לקרוא את הודעותיך המיועדות לעוקבים בלבד.", "compose_form.lock_disclaimer": "חשבונך אינו {locked}. כל אחד יוכל לעקוב אחריך כדי לקרוא את הודעותיך המיועדות לעוקבים בלבד.",
"compose_form.lock_disclaimer.lock": "נעול", "compose_form.lock_disclaimer.lock": "נעול",
"compose_form.placeholder": "מה עובר לך בראש?", "compose_form.placeholder": "מה עובר לך בראש?",
@ -213,6 +214,7 @@
"search_popout.tips.user": "משתמש(ת)", "search_popout.tips.user": "משתמש(ת)",
"search_results.total": "{count, number} {count, plural, one {תוצאה} other {תוצאות}}", "search_results.total": "{count, number} {count, plural, one {תוצאה} other {תוצאות}}",
"standalone.public_title": "הצצה פנימה...", "standalone.public_title": "הצצה פנימה...",
"status.block": "Block @{name}",
"status.cannot_reblog": "לא ניתן להדהד הודעה זו", "status.cannot_reblog": "לא ניתן להדהד הודעה זו",
"status.delete": "מחיקה", "status.delete": "מחיקה",
"status.embed": "הטמעה", "status.embed": "הטמעה",
@ -221,6 +223,7 @@
"status.media_hidden": "מדיה מוסתרת", "status.media_hidden": "מדיה מוסתרת",
"status.mention": "פניה אל @{name}", "status.mention": "פניה אל @{name}",
"status.more": "עוד", "status.more": "עוד",
"status.mute": "Mute @{name}",
"status.mute_conversation": "השתקת שיחה", "status.mute_conversation": "השתקת שיחה",
"status.open": "הרחבת הודעה", "status.open": "הרחבת הודעה",
"status.pin": "לקבע באודות", "status.pin": "לקבע באודות",

View File

@ -50,6 +50,7 @@
"column_header.unpin": "Unpin", "column_header.unpin": "Unpin",
"column_subheading.navigation": "Navigacija", "column_subheading.navigation": "Navigacija",
"column_subheading.settings": "Postavke", "column_subheading.settings": "Postavke",
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
"compose_form.lock_disclaimer": "Tvoj račun nije {locked}. Svatko te može slijediti kako bi vidio postove namijenjene samo tvojim sljedbenicima.", "compose_form.lock_disclaimer": "Tvoj račun nije {locked}. Svatko te može slijediti kako bi vidio postove namijenjene samo tvojim sljedbenicima.",
"compose_form.lock_disclaimer.lock": "zaključan", "compose_form.lock_disclaimer.lock": "zaključan",
"compose_form.placeholder": "Što ti je na umu?", "compose_form.placeholder": "Što ti je na umu?",
@ -213,6 +214,7 @@
"search_popout.tips.user": "user", "search_popout.tips.user": "user",
"search_results.total": "{count, number} {count, plural, one {result} other {results}}", "search_results.total": "{count, number} {count, plural, one {result} other {results}}",
"standalone.public_title": "A look inside...", "standalone.public_title": "A look inside...",
"status.block": "Block @{name}",
"status.cannot_reblog": "Ovaj post ne može biti boostan", "status.cannot_reblog": "Ovaj post ne može biti boostan",
"status.delete": "Obriši", "status.delete": "Obriši",
"status.embed": "Embed", "status.embed": "Embed",
@ -221,6 +223,7 @@
"status.media_hidden": "Sakriven media sadržaj", "status.media_hidden": "Sakriven media sadržaj",
"status.mention": "Spomeni @{name}", "status.mention": "Spomeni @{name}",
"status.more": "More", "status.more": "More",
"status.mute": "Mute @{name}",
"status.mute_conversation": "Utišaj razgovor", "status.mute_conversation": "Utišaj razgovor",
"status.open": "Proširi ovaj status", "status.open": "Proširi ovaj status",
"status.pin": "Pin on profile", "status.pin": "Pin on profile",

View File

@ -50,6 +50,7 @@
"column_header.unpin": "Unpin", "column_header.unpin": "Unpin",
"column_subheading.navigation": "Navigation", "column_subheading.navigation": "Navigation",
"column_subheading.settings": "Settings", "column_subheading.settings": "Settings",
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
"compose_form.lock_disclaimer": "Your account is not {locked}. Anyone can follow you to view your follower-only posts.", "compose_form.lock_disclaimer": "Your account is not {locked}. Anyone can follow you to view your follower-only posts.",
"compose_form.lock_disclaimer.lock": "locked", "compose_form.lock_disclaimer.lock": "locked",
"compose_form.placeholder": "Mire gondolsz?", "compose_form.placeholder": "Mire gondolsz?",
@ -213,6 +214,7 @@
"search_popout.tips.user": "user", "search_popout.tips.user": "user",
"search_results.total": "{count, number} {count, plural, one {result} other {results}}", "search_results.total": "{count, number} {count, plural, one {result} other {results}}",
"standalone.public_title": "A look inside...", "standalone.public_title": "A look inside...",
"status.block": "Block @{name}",
"status.cannot_reblog": "This post cannot be boosted", "status.cannot_reblog": "This post cannot be boosted",
"status.delete": "Törlés", "status.delete": "Törlés",
"status.embed": "Embed", "status.embed": "Embed",
@ -221,6 +223,7 @@
"status.media_hidden": "Media hidden", "status.media_hidden": "Media hidden",
"status.mention": "Említés", "status.mention": "Említés",
"status.more": "More", "status.more": "More",
"status.mute": "Mute @{name}",
"status.mute_conversation": "Mute conversation", "status.mute_conversation": "Mute conversation",
"status.open": "Expand this status", "status.open": "Expand this status",
"status.pin": "Pin on profile", "status.pin": "Pin on profile",

View File

@ -50,6 +50,7 @@
"column_header.unpin": "Unpin", "column_header.unpin": "Unpin",
"column_subheading.navigation": "Navigasi", "column_subheading.navigation": "Navigasi",
"column_subheading.settings": "Pengaturan", "column_subheading.settings": "Pengaturan",
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
"compose_form.lock_disclaimer": "Akun anda tidak {locked}. Semua orang dapat mengikuti anda untuk melihat postingan khusus untuk pengikut anda.", "compose_form.lock_disclaimer": "Akun anda tidak {locked}. Semua orang dapat mengikuti anda untuk melihat postingan khusus untuk pengikut anda.",
"compose_form.lock_disclaimer.lock": "dikunci", "compose_form.lock_disclaimer.lock": "dikunci",
"compose_form.placeholder": "Apa yang ada di pikiran anda?", "compose_form.placeholder": "Apa yang ada di pikiran anda?",
@ -213,6 +214,7 @@
"search_popout.tips.user": "user", "search_popout.tips.user": "user",
"search_results.total": "{count} {count, plural, one {hasil} other {hasil}}", "search_results.total": "{count} {count, plural, one {hasil} other {hasil}}",
"standalone.public_title": "A look inside...", "standalone.public_title": "A look inside...",
"status.block": "Block @{name}",
"status.cannot_reblog": "This post cannot be boosted", "status.cannot_reblog": "This post cannot be boosted",
"status.delete": "Hapus", "status.delete": "Hapus",
"status.embed": "Embed", "status.embed": "Embed",
@ -221,6 +223,7 @@
"status.media_hidden": "Media disembunyikan", "status.media_hidden": "Media disembunyikan",
"status.mention": "Balasan @{name}", "status.mention": "Balasan @{name}",
"status.more": "More", "status.more": "More",
"status.mute": "Mute @{name}",
"status.mute_conversation": "Mute conversation", "status.mute_conversation": "Mute conversation",
"status.open": "Tampilkan status ini", "status.open": "Tampilkan status ini",
"status.pin": "Pin on profile", "status.pin": "Pin on profile",

View File

@ -50,6 +50,7 @@
"column_header.unpin": "Unpin", "column_header.unpin": "Unpin",
"column_subheading.navigation": "Navigation", "column_subheading.navigation": "Navigation",
"column_subheading.settings": "Settings", "column_subheading.settings": "Settings",
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
"compose_form.lock_disclaimer": "Your account is not {locked}. Anyone can follow you to view your follower-only posts.", "compose_form.lock_disclaimer": "Your account is not {locked}. Anyone can follow you to view your follower-only posts.",
"compose_form.lock_disclaimer.lock": "locked", "compose_form.lock_disclaimer.lock": "locked",
"compose_form.placeholder": "Quo esas en tua spirito?", "compose_form.placeholder": "Quo esas en tua spirito?",
@ -213,6 +214,7 @@
"search_popout.tips.user": "user", "search_popout.tips.user": "user",
"search_results.total": "{count, number} {count, plural, one {rezulto} other {rezulti}}", "search_results.total": "{count, number} {count, plural, one {rezulto} other {rezulti}}",
"standalone.public_title": "A look inside...", "standalone.public_title": "A look inside...",
"status.block": "Block @{name}",
"status.cannot_reblog": "This post cannot be boosted", "status.cannot_reblog": "This post cannot be boosted",
"status.delete": "Efacar", "status.delete": "Efacar",
"status.embed": "Embed", "status.embed": "Embed",
@ -221,6 +223,7 @@
"status.media_hidden": "Kontenajo celita", "status.media_hidden": "Kontenajo celita",
"status.mention": "Mencionar @{name}", "status.mention": "Mencionar @{name}",
"status.more": "More", "status.more": "More",
"status.mute": "Mute @{name}",
"status.mute_conversation": "Mute conversation", "status.mute_conversation": "Mute conversation",
"status.open": "Detaligar ca mesajo", "status.open": "Detaligar ca mesajo",
"status.pin": "Pin on profile", "status.pin": "Pin on profile",

View File

@ -50,6 +50,7 @@
"column_header.unpin": "Unpin", "column_header.unpin": "Unpin",
"column_subheading.navigation": "Navigation", "column_subheading.navigation": "Navigation",
"column_subheading.settings": "Settings", "column_subheading.settings": "Settings",
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
"compose_form.lock_disclaimer": "Your account is not {locked}. Anyone can follow you to view your follower-only posts.", "compose_form.lock_disclaimer": "Your account is not {locked}. Anyone can follow you to view your follower-only posts.",
"compose_form.lock_disclaimer.lock": "locked", "compose_form.lock_disclaimer.lock": "locked",
"compose_form.placeholder": "A cosa stai pensando?", "compose_form.placeholder": "A cosa stai pensando?",
@ -213,6 +214,7 @@
"search_popout.tips.user": "user", "search_popout.tips.user": "user",
"search_results.total": "{count} {count, plural, one {risultato} other {risultati}}", "search_results.total": "{count} {count, plural, one {risultato} other {risultati}}",
"standalone.public_title": "A look inside...", "standalone.public_title": "A look inside...",
"status.block": "Block @{name}",
"status.cannot_reblog": "This post cannot be boosted", "status.cannot_reblog": "This post cannot be boosted",
"status.delete": "Elimina", "status.delete": "Elimina",
"status.embed": "Embed", "status.embed": "Embed",
@ -221,6 +223,7 @@
"status.media_hidden": "Allegato nascosto", "status.media_hidden": "Allegato nascosto",
"status.mention": "Nomina @{name}", "status.mention": "Nomina @{name}",
"status.more": "More", "status.more": "More",
"status.mute": "Mute @{name}",
"status.mute_conversation": "Mute conversation", "status.mute_conversation": "Mute conversation",
"status.open": "Espandi questo post", "status.open": "Espandi questo post",
"status.pin": "Pin on profile", "status.pin": "Pin on profile",

View File

@ -50,6 +50,7 @@
"column_header.unpin": "ピン留めを外す", "column_header.unpin": "ピン留めを外す",
"column_subheading.navigation": "ナビゲーション", "column_subheading.navigation": "ナビゲーション",
"column_subheading.settings": "設定", "column_subheading.settings": "設定",
"compose_form.hashtag_warning": "このトゥートは未収載なのでハッシュタグの一覧に表示されません。公開トゥートだけがハッシュタグで検索できます。",
"compose_form.lock_disclaimer": "あなたのアカウントは{locked}になっていません。誰でもあなたをフォローすることができ、フォロワー限定の投稿を見ることができます。", "compose_form.lock_disclaimer": "あなたのアカウントは{locked}になっていません。誰でもあなたをフォローすることができ、フォロワー限定の投稿を見ることができます。",
"compose_form.lock_disclaimer.lock": "非公開", "compose_form.lock_disclaimer.lock": "非公開",
"compose_form.placeholder": "今なにしてる?", "compose_form.placeholder": "今なにしてる?",
@ -91,7 +92,7 @@
"empty_column.hashtag": "このハッシュタグはまだ使われていません。", "empty_column.hashtag": "このハッシュタグはまだ使われていません。",
"empty_column.home": "まだ誰もフォローしていません。{public}を見に行くか、検索を使って他のユーザーを見つけましょう。", "empty_column.home": "まだ誰もフォローしていません。{public}を見に行くか、検索を使って他のユーザーを見つけましょう。",
"empty_column.home.public_timeline": "連合タイムライン", "empty_column.home.public_timeline": "連合タイムライン",
"empty_column.list": "このリストにはまだなにもありません。", "empty_column.list": "このリストにはまだなにもありません。このリストのメンバーが新しいトゥートをするとここに表示されます。",
"empty_column.notifications": "まだ通知がありません。他の人とふれ合って会話を始めましょう。", "empty_column.notifications": "まだ通知がありません。他の人とふれ合って会話を始めましょう。",
"empty_column.public": "ここにはまだ何もありません! 公開で何かを投稿したり、他のインスタンスのユーザーをフォローしたりしていっぱいにしましょう", "empty_column.public": "ここにはまだ何もありません! 公開で何かを投稿したり、他のインスタンスのユーザーをフォローしたりしていっぱいにしましょう",
"follow_request.authorize": "許可", "follow_request.authorize": "許可",
@ -213,6 +214,7 @@
"search_popout.tips.user": "ユーザー", "search_popout.tips.user": "ユーザー",
"search_results.total": "{count, number}件の結果", "search_results.total": "{count, number}件の結果",
"standalone.public_title": "今こんな話をしています...", "standalone.public_title": "今こんな話をしています...",
"status.block": "@{name}をブロック",
"status.cannot_reblog": "この投稿はブーストできません", "status.cannot_reblog": "この投稿はブーストできません",
"status.delete": "削除", "status.delete": "削除",
"status.embed": "埋め込み", "status.embed": "埋め込み",
@ -221,6 +223,7 @@
"status.media_hidden": "非表示のメディア", "status.media_hidden": "非表示のメディア",
"status.mention": "返信", "status.mention": "返信",
"status.more": "もっと見る", "status.more": "もっと見る",
"status.mute": "@{name}をミュート",
"status.mute_conversation": "会話をミュート", "status.mute_conversation": "会話をミュート",
"status.open": "詳細を表示", "status.open": "詳細を表示",
"status.pin": "プロフィールに固定表示", "status.pin": "プロフィールに固定表示",

View File

@ -1,55 +1,56 @@
{ {
"account.block": "차단", "account.block": "차단",
"account.block_domain": "{domain} 전체를 숨김", "account.block_domain": "{domain} 전체를 숨김",
"account.disclaimer_full": "Information below may reflect the user's profile incompletely.", "account.disclaimer_full": "여기 있는 정보는 유저의 프로파일을 정확히 반영하지 못 할 수도 있습니다.",
"account.edit_profile": "프로필 편집", "account.edit_profile": "프로필 편집",
"account.follow": "팔로우", "account.follow": "팔로우",
"account.followers": "팔로워", "account.followers": "팔로워",
"account.follows": "팔로우", "account.follows": "팔로우",
"account.follows_you": "날 팔로우합니다", "account.follows_you": "날 팔로우합니다",
"account.hide_reblogs": "Hide boosts from @{name}", "account.hide_reblogs": "@{name}의 부스트를 숨기기",
"account.media": "미디어", "account.media": "미디어",
"account.mention": "답장", "account.mention": "답장",
"account.moved_to": "{name} has moved to:", "account.moved_to": "{name}는 계정을 이동했습니다:",
"account.mute": "뮤트", "account.mute": "뮤트",
"account.mute_notifications": "Mute notifications from @{name}", "account.mute_notifications": "@{name}의 알림을 뮤트",
"account.posts": "포스트", "account.posts": "포스트",
"account.report": "신고", "account.report": "신고",
"account.requested": "승인 대기 중", "account.requested": "승인 대기 중",
"account.share": "Share @{name}'s profile", "account.share": "@{name}의 프로파일 공유",
"account.show_reblogs": "Show boosts from @{name}", "account.show_reblogs": "@{name}의 부스트 보기",
"account.unblock": "차단 해제", "account.unblock": "차단 해제",
"account.unblock_domain": "{domain} 숨김 해제", "account.unblock_domain": "{domain} 숨김 해제",
"account.unfollow": "팔로우 해제", "account.unfollow": "팔로우 해제",
"account.unmute": "뮤트 해제", "account.unmute": "뮤트 해제",
"account.unmute_notifications": "Unmute notifications from @{name}", "account.unmute_notifications": "@{name}의 알림 뮤트 해제",
"account.view_full_profile": "전체 프로필 보기", "account.view_full_profile": "전체 프로필 보기",
"boost_modal.combo": "다음부터 {combo}를 누르면 이 과정을 건너뛸 수 있습니다.", "boost_modal.combo": "다음부터 {combo}를 누르면 이 과정을 건너뛸 수 있습니다.",
"bundle_column_error.body": "Something went wrong while loading this component.", "bundle_column_error.body": "Something went wrong while loading this component.",
"bundle_column_error.retry": "Try again", "bundle_column_error.retry": "다시 시도",
"bundle_column_error.title": "Network error", "bundle_column_error.title": "네트워크 에러",
"bundle_modal_error.close": "Close", "bundle_modal_error.close": "닫기",
"bundle_modal_error.message": "Something went wrong while loading this component.", "bundle_modal_error.message": "Something went wrong while loading this component.",
"bundle_modal_error.retry": "Try again", "bundle_modal_error.retry": "다시 시도",
"column.blocks": "차단 중인 사용자", "column.blocks": "차단 중인 사용자",
"column.community": "로컬 타임라인", "column.community": "로컬 타임라인",
"column.favourites": "즐겨찾기", "column.favourites": "즐겨찾기",
"column.follow_requests": "팔로우 요청", "column.follow_requests": "팔로우 요청",
"column.home": "홈", "column.home": "홈",
"column.lists": "Lists", "column.lists": "리스트",
"column.mutes": "뮤트 중인 사용자", "column.mutes": "뮤트 중인 사용자",
"column.notifications": "알림", "column.notifications": "알림",
"column.pins": "고정된 툿", "column.pins": "고정된 툿",
"column.public": "연합 타임라인", "column.public": "연합 타임라인",
"column_back_button.label": "돌아가기", "column_back_button.label": "돌아가기",
"column_header.hide_settings": "Hide settings", "column_header.hide_settings": "설정 숨기기",
"column_header.moveLeft_settings": "Move column to the left", "column_header.moveLeft_settings": "왼쪽으로 이동",
"column_header.moveRight_settings": "Move column to the right", "column_header.moveRight_settings": "오른쪽으로 이동",
"column_header.pin": "고정하기", "column_header.pin": "고정하기",
"column_header.show_settings": "Show settings", "column_header.show_settings": "설정 보이기",
"column_header.unpin": "고정 해제", "column_header.unpin": "고정 해제",
"column_subheading.navigation": "내비게이션", "column_subheading.navigation": "내비게이션",
"column_subheading.settings": "설정", "column_subheading.settings": "설정",
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
"compose_form.lock_disclaimer": "이 계정은 {locked}로 설정 되어 있지 않습니다. 누구나 이 계정을 팔로우 할 수 있으며, 팔로워 공개의 포스팅을 볼 수 있습니다.", "compose_form.lock_disclaimer": "이 계정은 {locked}로 설정 되어 있지 않습니다. 누구나 이 계정을 팔로우 할 수 있으며, 팔로워 공개의 포스팅을 볼 수 있습니다.",
"compose_form.lock_disclaimer.lock": "비공개", "compose_form.lock_disclaimer.lock": "비공개",
"compose_form.placeholder": "지금 무엇을 하고 있나요?", "compose_form.placeholder": "지금 무엇을 하고 있나요?",
@ -63,35 +64,35 @@
"confirmations.block.message": "정말로 {name}를 차단하시겠습니까?", "confirmations.block.message": "정말로 {name}를 차단하시겠습니까?",
"confirmations.delete.confirm": "삭제", "confirmations.delete.confirm": "삭제",
"confirmations.delete.message": "정말로 삭제하시겠습니까?", "confirmations.delete.message": "정말로 삭제하시겠습니까?",
"confirmations.delete_list.confirm": "Delete", "confirmations.delete_list.confirm": "삭제",
"confirmations.delete_list.message": "Are you sure you want to permanently delete this list?", "confirmations.delete_list.message": "정말로 이 리스트를 삭제하시겠습니까?",
"confirmations.domain_block.confirm": "도메인 전체를 숨김", "confirmations.domain_block.confirm": "도메인 전체를 숨김",
"confirmations.domain_block.message": "정말로 {domain} 전체를 숨기시겠습니까? 대부분의 경우 개별 차단이나 뮤트로 충분합니다.", "confirmations.domain_block.message": "정말로 {domain} 전체를 숨기시겠습니까? 대부분의 경우 개별 차단이나 뮤트로 충분합니다.",
"confirmations.mute.confirm": "뮤트", "confirmations.mute.confirm": "뮤트",
"confirmations.mute.message": "정말로 {name}를 뮤트하시겠습니까?", "confirmations.mute.message": "정말로 {name}를 뮤트하시겠습니까?",
"confirmations.unfollow.confirm": "Unfollow", "confirmations.unfollow.confirm": "언팔로우",
"confirmations.unfollow.message": "Are you sure you want to unfollow {name}?", "confirmations.unfollow.message": "정말로 {name}를 언팔로우하시겠습니까?",
"embed.instructions": "아래의 코드를 복사하여 대화를 원하는 곳으로 공유하세요.", "embed.instructions": "아래의 코드를 복사하여 대화를 원하는 곳으로 공유하세요.",
"embed.preview": "다음과 같이 표시됩니다:", "embed.preview": "다음과 같이 표시됩니다:",
"emoji_button.activity": "활동", "emoji_button.activity": "활동",
"emoji_button.custom": "Custom", "emoji_button.custom": "커스텀",
"emoji_button.flags": "국기", "emoji_button.flags": "국기",
"emoji_button.food": "음식", "emoji_button.food": "음식",
"emoji_button.label": "emoji를 추가", "emoji_button.label": "emoji를 추가",
"emoji_button.nature": "자연", "emoji_button.nature": "자연",
"emoji_button.not_found": "No emojos!! (╯°□°)╯︵ ┻━┻", "emoji_button.not_found": "없어!! (╯°□°)╯︵ ┻━┻",
"emoji_button.objects": "물건", "emoji_button.objects": "물건",
"emoji_button.people": "사람들", "emoji_button.people": "사람들",
"emoji_button.recent": "Frequently used", "emoji_button.recent": "자주 사용 됨",
"emoji_button.search": "검색...", "emoji_button.search": "검색...",
"emoji_button.search_results": "Search results", "emoji_button.search_results": "검색 결과",
"emoji_button.symbols": "기호", "emoji_button.symbols": "기호",
"emoji_button.travel": "여행과 장소", "emoji_button.travel": "여행과 장소",
"empty_column.community": "로컬 타임라인에 아무 것도 없습니다. 아무거나 적어 보세요!", "empty_column.community": "로컬 타임라인에 아무 것도 없습니다. 아무거나 적어 보세요!",
"empty_column.hashtag": "이 해시태그는 아직 사용되지 않았습니다.", "empty_column.hashtag": "이 해시태그는 아직 사용되지 않았습니다.",
"empty_column.home": "아직 아무도 팔로우 하고 있지 않습니다. {public}를 보러 가거나, 검색하여 다른 사용자를 찾아 보세요.", "empty_column.home": "아직 아무도 팔로우 하고 있지 않습니다. {public}를 보러 가거나, 검색하여 다른 사용자를 찾아 보세요.",
"empty_column.home.public_timeline": "연합 타임라인", "empty_column.home.public_timeline": "연합 타임라인",
"empty_column.list": "There is nothing in this list yet.", "empty_column.list": "리스트에 아직 아무 것도 없습니다.",
"empty_column.notifications": "아직 알림이 없습니다. 다른 사람과 대화를 시작해 보세요!", "empty_column.notifications": "아직 알림이 없습니다. 다른 사람과 대화를 시작해 보세요!",
"empty_column.public": "여기엔 아직 아무 것도 없습니다! 공개적으로 무언가 포스팅하거나, 다른 인스턴스 유저를 팔로우 해서 가득 채워보세요!", "empty_column.public": "여기엔 아직 아무 것도 없습니다! 공개적으로 무언가 포스팅하거나, 다른 인스턴스 유저를 팔로우 해서 가득 채워보세요!",
"follow_request.authorize": "허가", "follow_request.authorize": "허가",
@ -107,46 +108,46 @@
"home.column_settings.show_reblogs": "부스트 표시", "home.column_settings.show_reblogs": "부스트 표시",
"home.column_settings.show_replies": "답글 표시", "home.column_settings.show_replies": "답글 표시",
"home.settings": "컬럼 설정", "home.settings": "컬럼 설정",
"keyboard_shortcuts.back": "to navigate back", "keyboard_shortcuts.back": "뒤로가기",
"keyboard_shortcuts.boost": "to boost", "keyboard_shortcuts.boost": "부스트",
"keyboard_shortcuts.column": "to focus a status in one of the columns", "keyboard_shortcuts.column": "해당 열에 포커스",
"keyboard_shortcuts.compose": "to focus the compose textarea", "keyboard_shortcuts.compose": "작성창으로 포커스",
"keyboard_shortcuts.description": "Description", "keyboard_shortcuts.description": "설명",
"keyboard_shortcuts.down": "to move down in the list", "keyboard_shortcuts.down": "리스트에서 아래로 이동",
"keyboard_shortcuts.enter": "to open status", "keyboard_shortcuts.enter": "열기",
"keyboard_shortcuts.favourite": "to favourite", "keyboard_shortcuts.favourite": "관심글 지정",
"keyboard_shortcuts.heading": "Keyboard Shortcuts", "keyboard_shortcuts.heading": "키보드 단축키",
"keyboard_shortcuts.hotkey": "Hotkey", "keyboard_shortcuts.hotkey": "핫키",
"keyboard_shortcuts.legend": "to display this legend", "keyboard_shortcuts.legend": "이 도움말 표시",
"keyboard_shortcuts.mention": "to mention author", "keyboard_shortcuts.mention": "멘션",
"keyboard_shortcuts.reply": "to reply", "keyboard_shortcuts.reply": "답장",
"keyboard_shortcuts.search": "to focus search", "keyboard_shortcuts.search": "검색창에 포커스",
"keyboard_shortcuts.toot": "to start a brand new toot", "keyboard_shortcuts.toot": "새 툿 작성",
"keyboard_shortcuts.unfocus": "to un-focus compose textarea/search", "keyboard_shortcuts.unfocus": "작성창에서 포커스 해제",
"keyboard_shortcuts.up": "to move up in the list", "keyboard_shortcuts.up": "리스트에서 위로 이동",
"lightbox.close": "닫기", "lightbox.close": "닫기",
"lightbox.next": "Next", "lightbox.next": "다음",
"lightbox.previous": "Previous", "lightbox.previous": "이전",
"lists.account.add": "Add to list", "lists.account.add": "리스트에 추가",
"lists.account.remove": "Remove from list", "lists.account.remove": "리스트에서 제거",
"lists.delete": "Delete list", "lists.delete": "리스트 삭제",
"lists.edit": "Edit list", "lists.edit": "리스트 편집",
"lists.new.create": "Add list", "lists.new.create": "리스트 추가",
"lists.new.title_placeholder": "New list title", "lists.new.title_placeholder": "새 리스트의 이름",
"lists.search": "Search among people you follow", "lists.search": "팔로우 중인 사람들 중에서 찾기",
"lists.subheading": "Your lists", "lists.subheading": "Your lists",
"loading_indicator.label": "불러오는 중...", "loading_indicator.label": "불러오는 중...",
"media_gallery.toggle_visible": "표시 전환", "media_gallery.toggle_visible": "표시 전환",
"missing_indicator.label": "찾을 수 없습니다", "missing_indicator.label": "찾을 수 없습니다",
"mute_modal.hide_notifications": "Hide notifications from this user?", "mute_modal.hide_notifications": "이 사용자로부터의 알림을 뮤트하시겠습니까?",
"navigation_bar.blocks": "차단한 사용자", "navigation_bar.blocks": "차단한 사용자",
"navigation_bar.community_timeline": "로컬 타임라인", "navigation_bar.community_timeline": "로컬 타임라인",
"navigation_bar.edit_profile": "프로필 편집", "navigation_bar.edit_profile": "프로필 편집",
"navigation_bar.favourites": "즐겨찾기", "navigation_bar.favourites": "즐겨찾기",
"navigation_bar.follow_requests": "팔로우 요청", "navigation_bar.follow_requests": "팔로우 요청",
"navigation_bar.info": "이 인스턴스에 대해서", "navigation_bar.info": "이 인스턴스에 대해서",
"navigation_bar.keyboard_shortcuts": "Keyboard shortcuts", "navigation_bar.keyboard_shortcuts": "키보드 단축키",
"navigation_bar.lists": "Lists", "navigation_bar.lists": "리스트",
"navigation_bar.logout": "로그아웃", "navigation_bar.logout": "로그아웃",
"navigation_bar.mutes": "뮤트 중인 사용자", "navigation_bar.mutes": "뮤트 중인 사용자",
"navigation_bar.pins": "고정된 툿", "navigation_bar.pins": "고정된 툿",
@ -162,8 +163,8 @@
"notifications.column_settings.favourite": "즐겨찾기", "notifications.column_settings.favourite": "즐겨찾기",
"notifications.column_settings.follow": "새 팔로워", "notifications.column_settings.follow": "새 팔로워",
"notifications.column_settings.mention": "답글", "notifications.column_settings.mention": "답글",
"notifications.column_settings.push": "Push notifications", "notifications.column_settings.push": "푸시 알림",
"notifications.column_settings.push_meta": "This device", "notifications.column_settings.push_meta": "이 장치",
"notifications.column_settings.reblog": "부스트", "notifications.column_settings.reblog": "부스트",
"notifications.column_settings.show": "컬럼에 표시", "notifications.column_settings.show": "컬럼에 표시",
"notifications.column_settings.sound": "효과음 재생", "notifications.column_settings.sound": "효과음 재생",
@ -213,6 +214,7 @@
"search_popout.tips.user": "유저", "search_popout.tips.user": "유저",
"search_results.total": "{count, number}건의 결과", "search_results.total": "{count, number}건의 결과",
"standalone.public_title": "A look inside...", "standalone.public_title": "A look inside...",
"status.block": "@{name} 차단",
"status.cannot_reblog": "이 포스트는 부스트 할 수 없습니다", "status.cannot_reblog": "이 포스트는 부스트 할 수 없습니다",
"status.delete": "삭제", "status.delete": "삭제",
"status.embed": "공유하기", "status.embed": "공유하기",
@ -220,7 +222,8 @@
"status.load_more": "더 보기", "status.load_more": "더 보기",
"status.media_hidden": "미디어 숨겨짐", "status.media_hidden": "미디어 숨겨짐",
"status.mention": "답장", "status.mention": "답장",
"status.more": "More", "status.more": "자세히",
"status.mute": "@{name} 뮤트",
"status.mute_conversation": "이 대화를 뮤트", "status.mute_conversation": "이 대화를 뮤트",
"status.open": "상세 정보 표시", "status.open": "상세 정보 표시",
"status.pin": "고정", "status.pin": "고정",
@ -231,7 +234,7 @@
"status.report": "신고", "status.report": "신고",
"status.sensitive_toggle": "클릭해서 표시하기", "status.sensitive_toggle": "클릭해서 표시하기",
"status.sensitive_warning": "민감한 미디어", "status.sensitive_warning": "민감한 미디어",
"status.share": "Share", "status.share": "공유",
"status.show_less": "숨기기", "status.show_less": "숨기기",
"status.show_more": "더 보기", "status.show_more": "더 보기",
"status.unmute_conversation": "이 대화의 뮤트 해제하기", "status.unmute_conversation": "이 대화의 뮤트 해제하기",
@ -241,19 +244,19 @@
"tabs_bar.home": "홈", "tabs_bar.home": "홈",
"tabs_bar.local_timeline": "로컬", "tabs_bar.local_timeline": "로컬",
"tabs_bar.notifications": "알림", "tabs_bar.notifications": "알림",
"ui.beforeunload": "Your draft will be lost if you leave Mastodon.", "ui.beforeunload": "지금 나가면 저장되지 않은 항목을 잃게 됩니다.",
"upload_area.title": "드래그 & 드롭으로 업로드", "upload_area.title": "드래그 & 드롭으로 업로드",
"upload_button.label": "미디어 추가", "upload_button.label": "미디어 추가",
"upload_form.description": "Describe for the visually impaired", "upload_form.description": "Describe for the visually impaired",
"upload_form.undo": "재시도", "upload_form.undo": "재시도",
"upload_progress.label": "업로드 중...", "upload_progress.label": "업로드 중...",
"video.close": "Close video", "video.close": "동영상 닫기",
"video.exit_fullscreen": "Exit full screen", "video.exit_fullscreen": "전체화면 나가기",
"video.expand": "Expand video", "video.expand": "동영상 확장",
"video.fullscreen": "Full screen", "video.fullscreen": "전체화면",
"video.hide": "Hide video", "video.hide": "동영상 숨기기",
"video.mute": "Mute sound", "video.mute": "음소거",
"video.pause": "Pause", "video.pause": "일시정지",
"video.play": "Play", "video.play": "재생",
"video.unmute": "Unmute sound" "video.unmute": "음소거 해제"
} }

View File

@ -50,6 +50,7 @@
"column_header.unpin": "Losmaken", "column_header.unpin": "Losmaken",
"column_subheading.navigation": "Navigatie", "column_subheading.navigation": "Navigatie",
"column_subheading.settings": "Instellingen", "column_subheading.settings": "Instellingen",
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
"compose_form.lock_disclaimer": "Jouw account is niet {locked}. Iedereen kan jou volgen en toots zien die je alleen aan volgers hebt gericht.", "compose_form.lock_disclaimer": "Jouw account is niet {locked}. Iedereen kan jou volgen en toots zien die je alleen aan volgers hebt gericht.",
"compose_form.lock_disclaimer.lock": "besloten", "compose_form.lock_disclaimer.lock": "besloten",
"compose_form.placeholder": "Wat wil je kwijt?", "compose_form.placeholder": "Wat wil je kwijt?",
@ -213,6 +214,7 @@
"search_popout.tips.user": "gebruiker", "search_popout.tips.user": "gebruiker",
"search_results.total": "{count, number} {count, plural, one {resultaat} other {resultaten}}", "search_results.total": "{count, number} {count, plural, one {resultaat} other {resultaten}}",
"standalone.public_title": "Een kijkje binnenin...", "standalone.public_title": "Een kijkje binnenin...",
"status.block": "Block @{name}",
"status.cannot_reblog": "Deze toot kan niet geboost worden", "status.cannot_reblog": "Deze toot kan niet geboost worden",
"status.delete": "Verwijderen", "status.delete": "Verwijderen",
"status.embed": "Embed", "status.embed": "Embed",
@ -221,6 +223,7 @@
"status.media_hidden": "Media verborgen", "status.media_hidden": "Media verborgen",
"status.mention": "Vermeld @{name}", "status.mention": "Vermeld @{name}",
"status.more": "Meer", "status.more": "Meer",
"status.mute": "Mute @{name}",
"status.mute_conversation": "Negeer conversatie", "status.mute_conversation": "Negeer conversatie",
"status.open": "Toot volledig tonen", "status.open": "Toot volledig tonen",
"status.pin": "Aan profielpagina vastmaken", "status.pin": "Aan profielpagina vastmaken",

View File

@ -50,6 +50,7 @@
"column_header.unpin": "Løsne", "column_header.unpin": "Løsne",
"column_subheading.navigation": "Navigasjon", "column_subheading.navigation": "Navigasjon",
"column_subheading.settings": "Innstillinger", "column_subheading.settings": "Innstillinger",
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
"compose_form.lock_disclaimer": "Din konto er ikke {locked}. Hvem som helst kan følge deg og se dine private poster.", "compose_form.lock_disclaimer": "Din konto er ikke {locked}. Hvem som helst kan følge deg og se dine private poster.",
"compose_form.lock_disclaimer.lock": "låst", "compose_form.lock_disclaimer.lock": "låst",
"compose_form.placeholder": "Hva har du på hjertet?", "compose_form.placeholder": "Hva har du på hjertet?",
@ -213,6 +214,7 @@
"search_popout.tips.user": "user", "search_popout.tips.user": "user",
"search_results.total": "{count, number} {count, plural, one {resultat} other {resultater}}", "search_results.total": "{count, number} {count, plural, one {resultat} other {resultater}}",
"standalone.public_title": "A look inside...", "standalone.public_title": "A look inside...",
"status.block": "Block @{name}",
"status.cannot_reblog": "Denne posten kan ikke fremheves", "status.cannot_reblog": "Denne posten kan ikke fremheves",
"status.delete": "Slett", "status.delete": "Slett",
"status.embed": "Embed", "status.embed": "Embed",
@ -221,6 +223,7 @@
"status.media_hidden": "Media skjult", "status.media_hidden": "Media skjult",
"status.mention": "Nevn @{name}", "status.mention": "Nevn @{name}",
"status.more": "More", "status.more": "More",
"status.mute": "Mute @{name}",
"status.mute_conversation": "Demp samtale", "status.mute_conversation": "Demp samtale",
"status.open": "Utvid denne statusen", "status.open": "Utvid denne statusen",
"status.pin": "Pin on profile", "status.pin": "Pin on profile",

View File

@ -50,6 +50,7 @@
"column_header.unpin": "Despenjar", "column_header.unpin": "Despenjar",
"column_subheading.navigation": "Navigacion", "column_subheading.navigation": "Navigacion",
"column_subheading.settings": "Paramètres", "column_subheading.settings": "Paramètres",
"compose_form.hashtag_warning": "Aqueste tut serà pas ligat a cap etiqueta estant ques pas listat. Òm pas cercar que los tuts publics per etiqueta.",
"compose_form.lock_disclaimer": "Vòstre compte es pas {locked}. Tot lo mond pòt vos sègre e veire los estatuts reservats als seguidors.", "compose_form.lock_disclaimer": "Vòstre compte es pas {locked}. Tot lo mond pòt vos sègre e veire los estatuts reservats als seguidors.",
"compose_form.lock_disclaimer.lock": "clavat", "compose_form.lock_disclaimer.lock": "clavat",
"compose_form.placeholder": "A de qué pensatz?", "compose_form.placeholder": "A de qué pensatz?",
@ -213,6 +214,7 @@
"search_popout.tips.user": "utilizaire", "search_popout.tips.user": "utilizaire",
"search_results.total": "{count, number} {count, plural, one {resultat} other {resultats}}", "search_results.total": "{count, number} {count, plural, one {resultat} other {resultats}}",
"standalone.public_title": "Una ulhada dedins…", "standalone.public_title": "Una ulhada dedins…",
"status.block": "Blocar @{name}",
"status.cannot_reblog": "Aqueste estatut pòt pas èsser partejat", "status.cannot_reblog": "Aqueste estatut pòt pas èsser partejat",
"status.delete": "Escafar", "status.delete": "Escafar",
"status.embed": "Embarcar", "status.embed": "Embarcar",
@ -221,6 +223,7 @@
"status.media_hidden": "Mèdia rescondut", "status.media_hidden": "Mèdia rescondut",
"status.mention": "Mencionar", "status.mention": "Mencionar",
"status.more": "Mai", "status.more": "Mai",
"status.mute": "Rescondre @{name}",
"status.mute_conversation": "Rescondre la conversacion", "status.mute_conversation": "Rescondre la conversacion",
"status.open": "Desplegar aqueste estatut", "status.open": "Desplegar aqueste estatut",
"status.pin": "Penjar al perfil", "status.pin": "Penjar al perfil",

View File

@ -50,6 +50,7 @@
"column_header.unpin": "Cofnij przypięcie", "column_header.unpin": "Cofnij przypięcie",
"column_subheading.navigation": "Nawigacja", "column_subheading.navigation": "Nawigacja",
"column_subheading.settings": "Ustawienia", "column_subheading.settings": "Ustawienia",
"compose_form.hashtag_warning": "Ten wpis nie będzie widoczny pod podanymi hashtagami, ponieważ jest oznaczony jako niewidoczny. Tylko publiczne wpisy mogą zostać znalezione z użyciem hashtagów.",
"compose_form.lock_disclaimer": "Twoje konto nie jest {locked}. Każdy, kto Cię śledzi, może wyświetlać Twoje wpisy przeznaczone tylko dla śledzących.", "compose_form.lock_disclaimer": "Twoje konto nie jest {locked}. Każdy, kto Cię śledzi, może wyświetlać Twoje wpisy przeznaczone tylko dla śledzących.",
"compose_form.lock_disclaimer.lock": "zablokowane", "compose_form.lock_disclaimer.lock": "zablokowane",
"compose_form.placeholder": "Co Ci chodzi po głowie?", "compose_form.placeholder": "Co Ci chodzi po głowie?",
@ -213,6 +214,7 @@
"search_popout.tips.user": "użytkownik", "search_popout.tips.user": "użytkownik",
"search_results.total": "{count, number} {count, plural, one {wynik} few {wyniki} many {wyników} more {wyników}}", "search_results.total": "{count, number} {count, plural, one {wynik} few {wyniki} many {wyników} more {wyników}}",
"standalone.public_title": "Spojrzenie w głąb…", "standalone.public_title": "Spojrzenie w głąb…",
"status.block": "Zablokuj @{name}",
"status.cannot_reblog": "Ten wpis nie może zostać podbity", "status.cannot_reblog": "Ten wpis nie może zostać podbity",
"status.delete": "Usuń", "status.delete": "Usuń",
"status.embed": "Osadź", "status.embed": "Osadź",
@ -221,6 +223,7 @@
"status.media_hidden": "Zawartość multimedialna ukryta", "status.media_hidden": "Zawartość multimedialna ukryta",
"status.mention": "Wspomnij o @{name}", "status.mention": "Wspomnij o @{name}",
"status.more": "Więcej", "status.more": "Więcej",
"status.mute": "Wycisz @{name}",
"status.mute_conversation": "Wycisz konwersację", "status.mute_conversation": "Wycisz konwersację",
"status.open": "Rozszerz ten wpis", "status.open": "Rozszerz ten wpis",
"status.pin": "Przypnij do profilu", "status.pin": "Przypnij do profilu",

View File

@ -50,6 +50,7 @@
"column_header.unpin": "Desafixar", "column_header.unpin": "Desafixar",
"column_subheading.navigation": "Navegação", "column_subheading.navigation": "Navegação",
"column_subheading.settings": "Configurações", "column_subheading.settings": "Configurações",
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
"compose_form.lock_disclaimer": "A sua conta não está {locked}. Qualquer pessoa pode te seguir e visualizar postagens direcionadas a apenas seguidores.", "compose_form.lock_disclaimer": "A sua conta não está {locked}. Qualquer pessoa pode te seguir e visualizar postagens direcionadas a apenas seguidores.",
"compose_form.lock_disclaimer.lock": "trancada", "compose_form.lock_disclaimer.lock": "trancada",
"compose_form.placeholder": "No que você está pensando?", "compose_form.placeholder": "No que você está pensando?",
@ -213,6 +214,7 @@
"search_popout.tips.user": "usuário", "search_popout.tips.user": "usuário",
"search_results.total": "{count, number} {count, plural, one {resultado} other {resultados}}", "search_results.total": "{count, number} {count, plural, one {resultado} other {resultados}}",
"standalone.public_title": "Dê uma espiada...", "standalone.public_title": "Dê uma espiada...",
"status.block": "Block @{name}",
"status.cannot_reblog": "Esta postagem não pode ser compartilhada", "status.cannot_reblog": "Esta postagem não pode ser compartilhada",
"status.delete": "Excluir", "status.delete": "Excluir",
"status.embed": "Incorporar", "status.embed": "Incorporar",
@ -221,6 +223,7 @@
"status.media_hidden": "Mídia escondida", "status.media_hidden": "Mídia escondida",
"status.mention": "Mencionar @{name}", "status.mention": "Mencionar @{name}",
"status.more": "Mais", "status.more": "Mais",
"status.mute": "Mute @{name}",
"status.mute_conversation": "Silenciar conversa", "status.mute_conversation": "Silenciar conversa",
"status.open": "Expandir", "status.open": "Expandir",
"status.pin": "Fixar no perfil", "status.pin": "Fixar no perfil",

View File

@ -50,6 +50,7 @@
"column_header.unpin": "Remover fixar", "column_header.unpin": "Remover fixar",
"column_subheading.navigation": "Navegação", "column_subheading.navigation": "Navegação",
"column_subheading.settings": "Preferências", "column_subheading.settings": "Preferências",
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
"compose_form.lock_disclaimer": "A tua conta não está {locked}. Qualquer pessoa pode seguir-te e ver as publicações direcionadas apenas a seguidores.", "compose_form.lock_disclaimer": "A tua conta não está {locked}. Qualquer pessoa pode seguir-te e ver as publicações direcionadas apenas a seguidores.",
"compose_form.lock_disclaimer.lock": "bloqueada", "compose_form.lock_disclaimer.lock": "bloqueada",
"compose_form.placeholder": "Em que estás a pensar?", "compose_form.placeholder": "Em que estás a pensar?",
@ -213,6 +214,7 @@
"search_popout.tips.user": "utilizador", "search_popout.tips.user": "utilizador",
"search_results.total": "{count, number} {count, plural, one {resultado} other {resultados}}", "search_results.total": "{count, number} {count, plural, one {resultado} other {resultados}}",
"standalone.public_title": "Espreitar lá dentro...", "standalone.public_title": "Espreitar lá dentro...",
"status.block": "Block @{name}",
"status.cannot_reblog": "Este post não pode ser partilhado", "status.cannot_reblog": "Este post não pode ser partilhado",
"status.delete": "Eliminar", "status.delete": "Eliminar",
"status.embed": "Incorporar", "status.embed": "Incorporar",
@ -221,6 +223,7 @@
"status.media_hidden": "Media escondida", "status.media_hidden": "Media escondida",
"status.mention": "Mencionar @{name}", "status.mention": "Mencionar @{name}",
"status.more": "Mais", "status.more": "Mais",
"status.mute": "Mute @{name}",
"status.mute_conversation": "Silenciar conversa", "status.mute_conversation": "Silenciar conversa",
"status.open": "Expandir", "status.open": "Expandir",
"status.pin": "Pin on profile", "status.pin": "Pin on profile",

View File

@ -50,6 +50,7 @@
"column_header.unpin": "Открепить", "column_header.unpin": "Открепить",
"column_subheading.navigation": "Навигация", "column_subheading.navigation": "Навигация",
"column_subheading.settings": "Настройки", "column_subheading.settings": "Настройки",
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
"compose_form.lock_disclaimer": "Ваш аккаунт не {locked}. Любой человек может подписаться на Вас и просматривать посты для подписчиков.", "compose_form.lock_disclaimer": "Ваш аккаунт не {locked}. Любой человек может подписаться на Вас и просматривать посты для подписчиков.",
"compose_form.lock_disclaimer.lock": "закрыт", "compose_form.lock_disclaimer.lock": "закрыт",
"compose_form.placeholder": "О чем Вы думаете?", "compose_form.placeholder": "О чем Вы думаете?",
@ -213,6 +214,7 @@
"search_popout.tips.user": "пользователь", "search_popout.tips.user": "пользователь",
"search_results.total": "{count, number} {count, plural, one {результат} few {результата} many {результатов} other {результатов}}", "search_results.total": "{count, number} {count, plural, one {результат} few {результата} many {результатов} other {результатов}}",
"standalone.public_title": "Прямо сейчас", "standalone.public_title": "Прямо сейчас",
"status.block": "Block @{name}",
"status.cannot_reblog": "Этот статус не может быть продвинут", "status.cannot_reblog": "Этот статус не может быть продвинут",
"status.delete": "Удалить", "status.delete": "Удалить",
"status.embed": "Встроить", "status.embed": "Встроить",
@ -221,6 +223,7 @@
"status.media_hidden": "Медиаконтент скрыт", "status.media_hidden": "Медиаконтент скрыт",
"status.mention": "Упомянуть @{name}", "status.mention": "Упомянуть @{name}",
"status.more": "Больше", "status.more": "Больше",
"status.mute": "Mute @{name}",
"status.mute_conversation": "Заглушить тред", "status.mute_conversation": "Заглушить тред",
"status.open": "Развернуть статус", "status.open": "Развернуть статус",
"status.pin": "Закрепить в профиле", "status.pin": "Закрепить в профиле",

View File

@ -0,0 +1,262 @@
{
"account.block": "Blokovať @{name}",
"account.block_domain": "Blokovať všetko z {domain}",
"account.disclaimer_full": "Inofrmácie nižšie nemusia reflektovať použivateľský účet kompletne.",
"account.edit_profile": "Upraviť profil",
"account.follow": "Sledovať",
"account.followers": "Sledujúci",
"account.follows": "Sledovaní",
"account.follows_you": "Sleduje teba",
"account.hide_reblogs": "Hide boosts from @{name}",
"account.media": "Média",
"account.mention": "Napísať @{name}",
"account.moved_to": "{name} has moved to:",
"account.mute": "Ignorovať @{name}",
"account.mute_notifications": "Mute notifications from @{name}",
"account.posts": "Správ",
"account.report": "Nahlásiť @{name}",
"account.requested": "Čaká na schválenie. Klikni na zrušenie žiadosti",
"account.share": "Zdieľať @{name} profil",
"account.show_reblogs": "Show boosts from @{name}",
"account.unblock": "Odblokovať @{name}",
"account.unblock_domain": "Prestať blokovať {domain}",
"account.unfollow": "Prestať nasledovať",
"account.unmute": "Prestať ignorovať @{name}",
"account.unmute_notifications": "Unmute notifications from @{name}",
"account.view_full_profile": "Pozri celý profil",
"boost_modal.combo": "Nabudúce môžeš kliknúť {combo} a preskočiť",
"bundle_column_error.body": "Nastala chyba pri načítaní tohto komponentu.",
"bundle_column_error.retry": "Skús znova",
"bundle_column_error.title": "Chyba siete",
"bundle_modal_error.close": "Zatvoriť",
"bundle_modal_error.message": "Nastala chyba pri načítaní tohto komponentu.",
"bundle_modal_error.retry": "Skúsiť znova",
"column.blocks": "Blokovaní používatelia",
"column.community": "Lokálna časová os",
"column.favourites": "Obľúbené",
"column.follow_requests": "Žiadosti",
"column.home": "Moja časová os",
"column.lists": "Lists",
"column.mutes": "Ignorovaní používatelia",
"column.notifications": "Notifikácie",
"column.pins": "Pripnuté toots",
"column.public": "Federovaná časová os",
"column_back_button.label": "Späť",
"column_header.hide_settings": "Skryť nastavenia",
"column_header.moveLeft_settings": "Presunúť stĺpec doľava",
"column_header.moveRight_settings": "Presunúť stĺpec doprava",
"column_header.pin": "Pripnúť",
"column_header.show_settings": "Ukázať nastavenia",
"column_header.unpin": "Odopnúť",
"column_subheading.navigation": "Navigácia",
"column_subheading.settings": "Nastavenia",
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
"compose_form.lock_disclaimer": "Tvoj účet nie je zamknutý. Ktokoľvek ťa môže nasledovať a vidieť tvoje správy pre sledujúcich.",
"compose_form.lock_disclaimer.lock": "zamknutý",
"compose_form.placeholder": "Čo máš na mysli?",
"compose_form.publish": "Toot",
"compose_form.publish_loud": "{publish}!",
"compose_form.sensitive": "Označ súbor ako chúlostivý",
"compose_form.spoiler": "Skryť text za varovanie",
"compose_form.spoiler_placeholder": "Napíš sem tvoje varovanie",
"confirmation_modal.cancel": "Zrušiť",
"confirmations.block.confirm": "Blokovať",
"confirmations.block.message": "Naozaj chceš blokovať {name}?",
"confirmations.delete.confirm": "Zmazať",
"confirmations.delete.message": "Naozaj chceš zmazať túto správu?",
"confirmations.delete_list.confirm": "Delete",
"confirmations.delete_list.message": "Are you sure you want to permanently delete this list?",
"confirmations.domain_block.confirm": "Skryť celú doménu",
"confirmations.domain_block.message": "Si si naozaj istý, že chceš blokovať celú {domain}? Vo väčšine prípadov stačí blokovať alebo ignorovať daných používateľov.",
"confirmations.mute.confirm": "Ignoruj",
"confirmations.mute.message": "Naozaj chceš ignorovať {name}?",
"confirmations.unfollow.confirm": "Nesledovať",
"confirmations.unfollow.message": "Naozaj chceš prestať sledovať {name}?",
"embed.instructions": "Skopíruj kód nižšie a ridaj tento status na tvoju web stránku.",
"embed.preview": "Tu je ukážka ako to bude vyzerať:",
"emoji_button.activity": "Aktivity",
"emoji_button.custom": "Vlastné",
"emoji_button.flags": "Vlajky",
"emoji_button.food": "Jedlá a nápoje",
"emoji_button.label": "Vlož emoji",
"emoji_button.nature": "Zvieratká",
"emoji_button.not_found": "Nenájdené",
"emoji_button.objects": "Predmety",
"emoji_button.people": "Ľudia",
"emoji_button.recent": "Často používané",
"emoji_button.search": "Hľadaj...",
"emoji_button.search_results": "Nájdené",
"emoji_button.symbols": "Symboly",
"emoji_button.travel": "Cestovanie a miesta",
"empty_column.community": "Lokálna časová os je prázdna. Napíš niečo aby sa to začalo hýbať!",
"empty_column.hashtag": "Ešte nič nie je v tomto hashtag-u.",
"empty_column.home": "Ešte nesleduješ nikoho. Pre začiatok pozri {public} alebo použi vyhľadávanie aby si našiel ostatných používateľov.",
"empty_column.home.public_timeline": "verejnú časovú os",
"empty_column.list": "There is nothing in this list yet. When members of this list post new statuses, they will appear here.",
"empty_column.notifications": "Nemáš žiadne notifikácie. Napíš niekomu, nasleduj niekoho alebo komunikuj s ostatnými.",
"empty_column.public": "Ešte tu nič nie je. Napíš niečo verejne alebo začni sledovať používateľov z iných Mastodon serverov aby tu niečo bolo",
"follow_request.authorize": "Potvrdiť",
"follow_request.reject": "Odmietnúť",
"getting_started.appsshort": "Aplikácie",
"getting_started.faq": "FAQ",
"getting_started.heading": "Začíname",
"getting_started.open_source_notice": "Mastodon má otvorený kód. Reportovať chyby alebo prispievať vlastným kódom môžeš na GitHube v {github}.",
"getting_started.userguide": "Používateľská príručka",
"home.column_settings.advanced": "Rozšírené",
"home.column_settings.basic": "Základné",
"home.column_settings.filter_regex": "Filtrovať použitím regulárnych výrazov",
"home.column_settings.show_reblogs": "Zobraziť boosts",
"home.column_settings.show_replies": "Zobraziť odpovede",
"home.settings": "Nastavenia stĺpcov",
"keyboard_shortcuts.back": "to navigate back",
"keyboard_shortcuts.boost": "to boost",
"keyboard_shortcuts.column": "to focus a status in one of the columns",
"keyboard_shortcuts.compose": "to focus the compose textarea",
"keyboard_shortcuts.description": "Description",
"keyboard_shortcuts.down": "to move down in the list",
"keyboard_shortcuts.enter": "to open status",
"keyboard_shortcuts.favourite": "to favourite",
"keyboard_shortcuts.heading": "Keyboard Shortcuts",
"keyboard_shortcuts.hotkey": "Hotkey",
"keyboard_shortcuts.legend": "to display this legend",
"keyboard_shortcuts.mention": "to mention author",
"keyboard_shortcuts.reply": "to reply",
"keyboard_shortcuts.search": "to focus search",
"keyboard_shortcuts.toot": "to start a brand new toot",
"keyboard_shortcuts.unfocus": "to un-focus compose textarea/search",
"keyboard_shortcuts.up": "to move up in the list",
"lightbox.close": "Zavrieť",
"lightbox.next": "Ďalší",
"lightbox.previous": "Predchádzajúci",
"lists.account.add": "Add to list",
"lists.account.remove": "Remove from list",
"lists.delete": "Delete list",
"lists.edit": "Edit list",
"lists.new.create": "Add list",
"lists.new.title_placeholder": "New list title",
"lists.search": "Search among people you follow",
"lists.subheading": "Your lists",
"loading_indicator.label": "Nahrávam...",
"media_gallery.toggle_visible": "Zapnúť/Vypnúť viditeľnosť",
"missing_indicator.label": "Nenájdené",
"mute_modal.hide_notifications": "Hide notifications from this user?",
"navigation_bar.blocks": "Blokovaní používatelia",
"navigation_bar.community_timeline": "Lokálna časová os",
"navigation_bar.edit_profile": "Upraviť profil",
"navigation_bar.favourites": "Obľúbené",
"navigation_bar.follow_requests": "Žiadosti",
"navigation_bar.info": "O tomto Mastodon serveri",
"navigation_bar.keyboard_shortcuts": "Keyboard shortcuts",
"navigation_bar.lists": "Lists",
"navigation_bar.logout": "Odhlásiť",
"navigation_bar.mutes": "Ignorovaní používatelia",
"navigation_bar.pins": "Pripnuté toots",
"navigation_bar.preferences": "Možnosti",
"navigation_bar.public_timeline": "Federovaná časová os",
"notification.favourite": "{name} sa páči tvoj status",
"notification.follow": "{name} ťa začal(a) sledovať",
"notification.mention": "{name} ťa zmienil",
"notification.reblog": "{name} re-tootol tvoj status",
"notifications.clear": "Vymazať notifikácie",
"notifications.clear_confirmation": "Naozaj chceš vymazať všetky tvoje notifikácie?",
"notifications.column_settings.alert": "Bublinové notifikácie",
"notifications.column_settings.favourite": "Obľúbené:",
"notifications.column_settings.follow": "Nový nasledujúci:",
"notifications.column_settings.mention": "Zmienenia:",
"notifications.column_settings.push": "Push notifikácie",
"notifications.column_settings.push_meta": "Toto zariadenie",
"notifications.column_settings.reblog": "Re-toots:",
"notifications.column_settings.show": "Zobraziť v stĺpci",
"notifications.column_settings.sound": "Prehrať zvuk",
"onboarding.done": "Koniec",
"onboarding.next": "Ďalej",
"onboarding.page_five.public_timelines": "Lokálna časová os zobrazuje verejné správy od všetkých na {domain}. Federovaná časová os zobrazuje verejné správy od všetkých ľudí ktoré {domain} nasleduje. Tieto sú takzvané Verejné Časové Osi, výborná možnosť ako nájsť a spoznať nových ľudí.",
"onboarding.page_four.home": "Domovská časová os zobrazí správy od ľudí ktorých sleduješ.",
"onboarding.page_four.notifications": "Stĺpec s notifikáciami zobrazí keď budeš s niekým komunikovať.",
"onboarding.page_one.federation": "Mastodon je sieť nezávislých serverov spojením ktorých vzniká jedna veľká federovaná sociálna sieť.",
"onboarding.page_one.handle": "Ty si na {domain}, takže tvoje celý nickname je {handle}",
"onboarding.page_one.welcome": "Vitajte v Mastodon!",
"onboarding.page_six.admin": "Správca tohto servera je {admin}.",
"onboarding.page_six.almost_done": "Takmer hotovo...",
"onboarding.page_six.appetoot": "Bon Appetoot!",
"onboarding.page_six.apps_available": "Aplikácie {apps} sú dostupné na pre iOS, Android and ďalšie platformy.",
"onboarding.page_six.github": "Mastodon je free open-source software. Chyby, nové funkcie alebo prispievať svojím kódom mǒžeš na {github}.",
"onboarding.page_six.guidelines": "pravidlá komunity",
"onboarding.page_six.read_guidelines": "Prosím prečítajte si {domain} pravidlá {guidelines}!",
"onboarding.page_six.various_app": "mobilné applikácie",
"onboarding.page_three.profile": "Uprav svoj profile a zmeň svoj avatar, bio a meno ktoré bude zobrazené. V nastaveniach nájdeš ďalšie možnosti.",
"onboarding.page_three.search": "Použi vyhľadávacie políčko na nájdenie ľudí a hashtagov, ako napríklad {slovensko}, {slovakia} alebo {pivo}. Na nájdenie človeka ktorý je registrovaný na inom Mastodon serveri použi jeho celý nickname.",
"onboarding.page_two.compose": "Správy píš zo stĺpca na komponovanie. Môžeš nahrávať obrázky, meniť nastavenia súkromia správ a pridávať varovania ikonkami nižšie.",
"onboarding.skip": "Preskočiť",
"privacy.change": "Zmeň viditeľnosť statusu",
"privacy.direct.long": "Pošli priamo iba spomenutým používateľom",
"privacy.direct.short": "Súkromne",
"privacy.private.long": "Pošli iba sledujúcim",
"privacy.private.short": "Iba sledujúci",
"privacy.public.long": "Pošli všetkým",
"privacy.public.short": "Verejne",
"privacy.unlisted.long": "Neposielať verejne",
"privacy.unlisted.short": "Nie je v zozname",
"relative_time.days": "{number}d",
"relative_time.hours": "{number}h",
"relative_time.just_now": "now",
"relative_time.minutes": "{number}m",
"relative_time.seconds": "{number}s",
"reply_indicator.cancel": "Zrušiť",
"report.placeholder": "Ďalšie komentáre",
"report.submit": "Poslať",
"report.target": "Reportovať {target}",
"search.placeholder": "Hľadaj",
"search_popout.search_format": "Advanced search format",
"search_popout.tips.hashtag": "hashtag",
"search_popout.tips.status": "status",
"search_popout.tips.text": "Simple text returns matching display names, usernames and hashtags",
"search_popout.tips.user": "user",
"search_results.total": "{count, number} nájdených",
"standalone.public_title": "Čo tam nájdeš...",
"status.block": "Block @{name}",
"status.cannot_reblog": "Tento príspevok nemôže byť re-tootnutý",
"status.delete": "Zmazať",
"status.embed": "Embed",
"status.favourite": "Páči sa mi",
"status.load_more": "Zobraziť viac",
"status.media_hidden": "Skryté médiá",
"status.mention": "Napísať @{name}",
"status.more": "More",
"status.mute": "Mute @{name}",
"status.mute_conversation": "Ignorovať konverzáciu",
"status.open": "Otvoriť",
"status.pin": "Pripnúť na profil",
"status.reblog": "Re-toot",
"status.reblogged_by": "{name} re-tootol",
"status.reply": "Odpovedať",
"status.replyAll": "Odpovedať všetkým",
"status.report": "Nahlásiť @{name}",
"status.sensitive_toggle": "Klikni pre zobrazenie",
"status.sensitive_warning": "Chúlostivý obsah",
"status.share": "Zdieľať",
"status.show_less": "Zobraziť menej",
"status.show_more": "Zobraziť viac",
"status.unmute_conversation": "Prestať ignorovať konverzáciu",
"status.unpin": "Odopnúť z profilu",
"tabs_bar.compose": "Napísať",
"tabs_bar.federated_timeline": "Federovaná",
"tabs_bar.home": "Domov",
"tabs_bar.local_timeline": "Local",
"tabs_bar.notifications": "Notifikácie",
"ui.beforeunload": "Your draft will be lost if you leave Mastodon.",
"upload_area.title": "Ťahaj a pusti pre nahratie",
"upload_button.label": "Pridať",
"upload_form.description": "Describe for the visually impaired",
"upload_form.undo": "Späť",
"upload_progress.label": "Nahrávam...",
"video.close": "Zavrieť video",
"video.exit_fullscreen": "Vpnúť zobrazenie na celú obrazovku",
"video.expand": "Zväčšiť video",
"video.fullscreen": "Zapnúť zobrazenie na celú obrazovku",
"video.hide": "Skryť video",
"video.mute": "Vypnúť zvuk",
"video.pause": "Pauza",
"video.play": "Prehrať",
"video.unmute": "Zapnúť zvuk"
}

View File

@ -0,0 +1,262 @@
{
"account.block": "Blokiraj korisnika @{name}",
"account.block_domain": "Sakrij sve sa domena {domain}",
"account.disclaimer_full": "Navedene informacije možda ne odslikavaju korisnički profil u potpunosti.",
"account.edit_profile": "Izmeni profil",
"account.follow": "Zaprati",
"account.followers": "Pratioca",
"account.follows": "Prati",
"account.follows_you": "Prati Vas",
"account.hide_reblogs": "Sakrij podrške koje daje korisnika @{name}",
"account.media": "Mediji",
"account.mention": "Pomeni korisnika @{name}",
"account.moved_to": "{name} se pomerio na:",
"account.mute": "Ućutkaj korisnika @{name}",
"account.mute_notifications": "Isključi obaveštenja od korisnika @{name}",
"account.posts": "Statusa",
"account.report": "Prijavi @{name}",
"account.requested": "Čekam odobrenje. Kliknite da poništite zahtev za praćenje",
"account.share": "Podeli profil korisnika @{name}",
"account.show_reblogs": "Prikaži podrške od korisnika @{name}",
"account.unblock": "Odblokiraj korisnika @{name}",
"account.unblock_domain": "Odblokiraj domen {domain}",
"account.unfollow": "Otprati",
"account.unmute": "Ukloni ućutkavanje korisniku @{name}",
"account.unmute_notifications": "Uključi nazad obaveštenja od korisnika @{name}",
"account.view_full_profile": "Vidi ceo profil",
"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.retry": "Pokušajte ponovo",
"bundle_column_error.title": "Mrežna greška",
"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",
"column.blocks": "Blokirani korisnici",
"column.community": "Lokalna lajna",
"column.favourites": "Omiljeni",
"column.follow_requests": "Zahtevi za praćenje",
"column.home": "Početna",
"column.lists": "Liste",
"column.mutes": "Ućutkani korisnici",
"column.notifications": "Obaveštenja",
"column.pins": "Prikačeni tutovi",
"column.public": "Federisana lajna",
"column_back_button.label": "Nazad",
"column_header.hide_settings": "Sakrij postavke",
"column_header.moveLeft_settings": "Pomeri kolonu ulevo",
"column_header.moveRight_settings": "Pomeri kolonu udesno",
"column_header.pin": "Prikači",
"column_header.show_settings": "Prikaži postavke",
"column_header.unpin": "Otkači",
"column_subheading.navigation": "Navigacija",
"column_subheading.settings": "Postavke",
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
"compose_form.lock_disclaimer": "Vaš nalog nije {locked}. Svako može da Vas zaprati i da vidi objave namenjene samo Vašim pratiocima.",
"compose_form.lock_disclaimer.lock": "zaključan",
"compose_form.placeholder": "Šta Vam je na umu?",
"compose_form.publish": "Tutni",
"compose_form.publish_loud": "{publish}!",
"compose_form.sensitive": "Obeleži multimediju kao osetljivu",
"compose_form.spoiler": "Sakrij tekst ispod upozorenja",
"compose_form.spoiler_placeholder": "Ovde upišite upozorenje",
"confirmation_modal.cancel": "Poništi",
"confirmations.block.confirm": "Blokiraj",
"confirmations.block.message": "Da li ste sigurni da želite da blokirate korisnika {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",
"confirmations.delete_list.message": "Da li ste sigurni da želite da bespovratno obrišete ovu listu?",
"confirmations.domain_block.confirm": "Sakrij ceo domen",
"confirmations.domain_block.message": "Da li ste stvarno, stvarno sigurno da želite da blokirate ceo domen {domain}? U većini slučajeva, par dobrih blokiranja ili ućutkavanja su dovoljna i preporučljiva.",
"confirmations.mute.confirm": "Ućutkaj",
"confirmations.mute.message": "Da li stvarno želite da ućutkate korisnika {name}?",
"confirmations.unfollow.confirm": "Otprati",
"confirmations.unfollow.message": "Da li ste sigurni da želite da otpratite korisnika {name}?",
"embed.instructions": "Ugradi ovaj status na Vaš veb sajt kopiranjem koda ispod.",
"embed.preview": "Ovako će da izgleda:",
"emoji_button.activity": "Aktivnost",
"emoji_button.custom": "Proizvoljno",
"emoji_button.flags": "Zastave",
"emoji_button.food": "Hrana & piće",
"emoji_button.label": "Ubaci smajli",
"emoji_button.nature": "Priroda",
"emoji_button.not_found": "Nema smajlija!! (╯°□°)╯︵ ┻━┻",
"emoji_button.objects": "Objekti",
"emoji_button.people": "Ljudi",
"emoji_button.recent": "Najčešće korišćeni",
"emoji_button.search": "Pretraga...",
"emoji_button.search_results": "Rezultati pretrage",
"emoji_button.symbols": "Simboli",
"emoji_button.travel": "Putovanja & mesta",
"empty_column.community": "Lokalna lajna je prazna. Napišite nešto javno da lajna produva!",
"empty_column.hashtag": "Trenutno nema ništa na ovom heštegu.",
"empty_column.home": "Vaša lajna je prazna! Posetite {public} ili koristite pretragu da počnete i upoznajete nove ljude.",
"empty_column.home.public_timeline": "javna lajna",
"empty_column.list": "U ovoj listi još nema ničega. Kada članovi liste objave nove statuse, oni će se pojavljivati ovde.",
"empty_column.notifications": "Trenutno nemate obaveštenja. Družite se malo da započnete razgovore.",
"empty_column.public": "Ovde nema ničega! Napišite nešto javno, ili nađite korisnike sa drugih instanci koje ćete zapratiti da popunite ovu prazninu",
"follow_request.authorize": "Odobri",
"follow_request.reject": "Odbij",
"getting_started.appsshort": "Aplikacije",
"getting_started.faq": "ČPP",
"getting_started.heading": "Da počnete",
"getting_started.open_source_notice": "Mastodont je softver otvorenog koda. Možete mu doprineti ili prijaviti probleme preko GitHub-a na {github}.",
"getting_started.userguide": "Korisničko uputstvo",
"home.column_settings.advanced": "Napredno",
"home.column_settings.basic": "Osnovno",
"home.column_settings.filter_regex": "Filtriraj regularnim izrazima",
"home.column_settings.show_reblogs": "Prikaži i podržavanja",
"home.column_settings.show_replies": "Prikaži odgovore",
"home.settings": "Postavke kolone",
"keyboard_shortcuts.back": "da odete nazad",
"keyboard_shortcuts.boost": "da podržite",
"keyboard_shortcuts.column": "da se prebacite na status u jednoj od kolona",
"keyboard_shortcuts.compose": "da se prebacite na pisanje novog tuta",
"keyboard_shortcuts.description": "Opis",
"keyboard_shortcuts.down": "da se pomerite na dole u listi",
"keyboard_shortcuts.enter": "da otvorite status",
"keyboard_shortcuts.favourite": "da označite kao omiljeno",
"keyboard_shortcuts.heading": "Prečice na tastaturi",
"keyboard_shortcuts.hotkey": "Prečica",
"keyboard_shortcuts.legend": "da prikažete ovaj podsetnik",
"keyboard_shortcuts.mention": "da pomenete autora",
"keyboard_shortcuts.reply": "da odgovorite",
"keyboard_shortcuts.search": "da se prebacite na pretragu",
"keyboard_shortcuts.toot": "da započnete skroz novi tut",
"keyboard_shortcuts.unfocus": "da ne budete više na pretrazi/pravljenju novog tuta",
"keyboard_shortcuts.up": "da se pomerite na gore u listi",
"lightbox.close": "Zatvori",
"lightbox.next": "Sledeći",
"lightbox.previous": "Prethodni",
"lists.account.add": "Dodaj na listu",
"lists.account.remove": "Ukloni sa liste",
"lists.delete": "Obriši listu",
"lists.edit": "Izmeni listu",
"lists.new.create": "Dodaj listu",
"lists.new.title_placeholder": "Naslov nove liste",
"lists.search": "Pretraži među ljudima koje pratite",
"lists.subheading": "Vaše liste",
"loading_indicator.label": "Učitavam...",
"media_gallery.toggle_visible": "Uključi/isključi vidljivost",
"missing_indicator.label": "Nije pronađeno",
"mute_modal.hide_notifications": "Sakrij obaveštenja od ovog korisnika?",
"navigation_bar.blocks": "Blokirani korisnici",
"navigation_bar.community_timeline": "Lokalna lajna",
"navigation_bar.edit_profile": "Izmeni profil",
"navigation_bar.favourites": "Omiljeni",
"navigation_bar.follow_requests": "Zahtevi za praćenje",
"navigation_bar.info": "O ovoj instanci",
"navigation_bar.keyboard_shortcuts": "Prečice na tastaturi",
"navigation_bar.lists": "Liste",
"navigation_bar.logout": "Odjava",
"navigation_bar.mutes": "Ućutkani korisnici",
"navigation_bar.pins": "Prikačeni tutovi",
"navigation_bar.preferences": "Podešavanja",
"navigation_bar.public_timeline": "Federisana lajna",
"notification.favourite": "{name} je stavio Vaš status kao omiljeni",
"notification.follow": "{name} Vas je zapratio",
"notification.mention": "{name} Vas je pomenuo",
"notification.reblog": "{name} je podržao(la) Vaš status",
"notifications.clear": "Očisti obaveštenja",
"notifications.clear_confirmation": "Da li ste sigurno da trajno želite da očistite Vaša obaveštenja?",
"notifications.column_settings.alert": "Obaveštenja na radnoj površini",
"notifications.column_settings.favourite": "Omiljeni:",
"notifications.column_settings.follow": "Novi pratioci:",
"notifications.column_settings.mention": "Pominjanja:",
"notifications.column_settings.push": "Guraj obaveštenja",
"notifications.column_settings.push_meta": "Ovaj uređaj",
"notifications.column_settings.reblog": "Podrški:",
"notifications.column_settings.show": "Prikaži u koloni",
"notifications.column_settings.sound": "Puštaj zvuk",
"onboarding.done": "Gotovo",
"onboarding.next": "Sledeće",
"onboarding.page_five.public_timelines": "Lokalna lajna prikazuje sve javne statuse od svih na domenu {domain}. Federisana lajna prikazuje javne statuse od svih ljudi koje prate korisnici sa domena {domain}. Ovo su javne lajne, sjajan način da otkrijete nove ljude.",
"onboarding.page_four.home": "Početna lajna prikazuje statuse ljudi koje Vi pratite.",
"onboarding.page_four.notifications": "Kolona sa obaveštenjima Vam prikazuje kada neko priča sa Vama.",
"onboarding.page_one.federation": "Mastodont je mreža nezavisnih servera koji se uvezuju da naprave jednu veću društvenu mrežu. Ove servere zovemo instancama.",
"onboarding.page_one.handle": "Vi ste na domenu {domain}, pa je Vaša puna identifikacija {handle}",
"onboarding.page_one.welcome": "Dobrodošli na Mastodont!",
"onboarding.page_six.admin": "Administrator Vaše instance je {admin}.",
"onboarding.page_six.almost_done": "Još malo, pa gotovo...",
"onboarding.page_six.appetoot": "Prijatutno!",
"onboarding.page_six.apps_available": "Postoje {apps} dostupne za iOS, Android i druge platforme.",
"onboarding.page_six.github": "Mastodont je slobodan softver otvorenog koda. Možete prijavljivati greške, potraživati nove funckionalnosti, ili učestvujući u programiranju. Naš izvorni kod je ovde: {github}.",
"onboarding.page_six.guidelines": "smernice zajednice",
"onboarding.page_six.read_guidelines": "Pročitejte {guidelines} domena {domain}!",
"onboarding.page_six.various_app": "mobilne aplikacije",
"onboarding.page_three.profile": "Izmenite profil da promenite avatar, biografiju i ime za prikaz. Tamo ćete naći i ostala podešavanja.",
"onboarding.page_three.search": "Korisite pretragu da nađete ljude i gledate heštegove, kao što su {illustration} i {introductions}. Da nađete osobu koja nije na ovoj instanci, koristite njenu punu identifikaciju.",
"onboarding.page_two.compose": "Pišite statuse iz prve kolone. Možete otpremati slike, menjati podešavanja privatnosti, i dodavati upozorenja za osetljiv sadržaj preko ikonica ispod.",
"onboarding.skip": "Preskoči",
"privacy.change": "Podesi status privatnosti",
"privacy.direct.long": "Objavi samo korisnicima koji su pomenuti",
"privacy.direct.short": "Direktno",
"privacy.private.long": "Objavi samo pratiocima",
"privacy.private.short": "Samo za pratioce",
"privacy.public.long": "Objavi na javnoj lajni",
"privacy.public.short": "Javno",
"privacy.unlisted.long": "Ne objavljuj na javnim lajnama",
"privacy.unlisted.short": "Neizlistano",
"relative_time.days": "{number}d",
"relative_time.hours": "{number}h",
"relative_time.just_now": "sada",
"relative_time.minutes": "{number}m",
"relative_time.seconds": "{number}s",
"reply_indicator.cancel": "Poništi",
"report.placeholder": "Dodatni komentari",
"report.submit": "Pošalji",
"report.target": "Prijavljujem {target}",
"search.placeholder": "Pretraga",
"search_popout.search_format": "Napredni format pretrage",
"search_popout.tips.hashtag": "hešteg",
"search_popout.tips.status": "status",
"search_popout.tips.text": "Traženjem običnog teksta ćete dobiti sva pronađena imena, sva korisnička imena i sve nađene heštegove",
"search_popout.tips.user": "korisnik",
"search_results.total": "{count, number} {count, plural, one {rezultat} few {rezultata} other {rezultata}}",
"standalone.public_title": "Pogled iznutra...",
"status.block": "Block @{name}",
"status.cannot_reblog": "Ovaj status ne može da se podrži",
"status.delete": "Obriši",
"status.embed": "Ugradi na sajt",
"status.favourite": "Omiljeno",
"status.load_more": "Učitaj još",
"status.media_hidden": "Multimedija sakrivena",
"status.mention": "Pomeni korisnika @{name}",
"status.more": "Još",
"status.mute": "Mute @{name}",
"status.mute_conversation": "Ućutkaj prepisku",
"status.open": "Proširi ovaj status",
"status.pin": "Prikači na profil",
"status.reblog": "Podrži",
"status.reblogged_by": "{name} podržao(la)",
"status.reply": "Odgovori",
"status.replyAll": "Odgovori na diskusiju",
"status.report": "Prijavi korisnika @{name}",
"status.sensitive_toggle": "Kliknite da vidite",
"status.sensitive_warning": "Osetljiv sadržaj",
"status.share": "Podeli",
"status.show_less": "Prikaži manje",
"status.show_more": "Prikaži više",
"status.unmute_conversation": "Uključi prepisku",
"status.unpin": "Otkači sa profila",
"tabs_bar.compose": "Napiši",
"tabs_bar.federated_timeline": "Federisano",
"tabs_bar.home": "Početna",
"tabs_bar.local_timeline": "Lokalno",
"tabs_bar.notifications": "Obaveštenja",
"ui.beforeunload": "Ako napustite Mastodont, izgubićete napisani nacrt.",
"upload_area.title": "Prevucite ovde da otpremite",
"upload_button.label": "Dodaj multimediju",
"upload_form.description": "Opiši za slabovide osobe",
"upload_form.undo": "Opozovi",
"upload_progress.label": "Otpremam...",
"video.close": "Zatvori video",
"video.exit_fullscreen": "Napusti ceo ekran",
"video.expand": "Proširi video",
"video.fullscreen": "Ceo ekran",
"video.hide": "Sakrij video",
"video.mute": "Ugasi zvuk",
"video.pause": "Pauziraj",
"video.play": "Pusti",
"video.unmute": "Vrati zvuk"
}

View File

@ -0,0 +1,262 @@
{
"account.block": "Блокирај корисника @{name}",
"account.block_domain": "Сакриј све са домена {domain}",
"account.disclaimer_full": "Наведене информације можда не одсликавају кориснички профил у потпуности.",
"account.edit_profile": "Измени профил",
"account.follow": "Запрати",
"account.followers": "Пратиоца",
"account.follows": "Прати",
"account.follows_you": "Прати Вас",
"account.hide_reblogs": "Сакриј подршке које даје корисника @{name}",
"account.media": "Медији",
"account.mention": "Помени корисника @{name}",
"account.moved_to": "{name} се померио на:",
"account.mute": "Ућуткај корисника @{name}",
"account.mute_notifications": "Искључи обавештења од корисника @{name}",
"account.posts": "Статуса",
"account.report": "Пријави @{name}",
"account.requested": "Чекам одобрење. Кликните да поништите захтев за праћење",
"account.share": "Подели профил корисника @{name}",
"account.show_reblogs": "Прикажи подршке од корисника @{name}",
"account.unblock": "Одблокирај корисника @{name}",
"account.unblock_domain": "Одблокирај домен {domain}",
"account.unfollow": "Отпрати",
"account.unmute": "Уклони ућуткавање кориснику @{name}",
"account.unmute_notifications": "Укључи назад обавештења од корисника @{name}",
"account.view_full_profile": "Види цео профил",
"boost_modal.combo": "Можете притиснути {combo} да прескочите ово следећи пут",
"bundle_column_error.body": "Нешто је пошло по злу приликом учитавања ове компоненте.",
"bundle_column_error.retry": "Покушајте поново",
"bundle_column_error.title": "Мрежна грешка",
"bundle_modal_error.close": "Затвори",
"bundle_modal_error.message": "Нешто није било у реду при учитавању ове компоненте.",
"bundle_modal_error.retry": "Покушајте поново",
"column.blocks": "Блокирани корисници",
"column.community": "Локална лајна",
"column.favourites": "Омиљени",
"column.follow_requests": "Захтеви за праћење",
"column.home": "Почетна",
"column.lists": "Листе",
"column.mutes": "Ућуткани корисници",
"column.notifications": "Обавештења",
"column.pins": "Прикачени тутови",
"column.public": "Федерисана лајна",
"column_back_button.label": "Назад",
"column_header.hide_settings": "Сакриј поставке",
"column_header.moveLeft_settings": "Помери колону улево",
"column_header.moveRight_settings": "Помери колону удесно",
"column_header.pin": "Прикачи",
"column_header.show_settings": "Прикажи поставке",
"column_header.unpin": "Откачи",
"column_subheading.navigation": "Навигација",
"column_subheading.settings": "Поставке",
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
"compose_form.lock_disclaimer": "Ваш налог није {locked}. Свако може да Вас запрати и да види објаве намењене само Вашим пратиоцима.",
"compose_form.lock_disclaimer.lock": "закључан",
"compose_form.placeholder": "Шта Вам је на уму?",
"compose_form.publish": "Тутни",
"compose_form.publish_loud": "{publish}!",
"compose_form.sensitive": "Обележи мултимедију као осетљиву",
"compose_form.spoiler": "Сакриј текст испод упозорења",
"compose_form.spoiler_placeholder": "Овде упишите упозорење",
"confirmation_modal.cancel": "Поништи",
"confirmations.block.confirm": "Блокирај",
"confirmations.block.message": "Да ли сте сигурни да желите да блокирате корисника {name}?",
"confirmations.delete.confirm": "Обриши",
"confirmations.delete.message": "Да ли сте сигурни да желите обришете овај статус?",
"confirmations.delete_list.confirm": "Обриши",
"confirmations.delete_list.message": "Да ли сте сигурни да желите да бесповратно обришете ову листу?",
"confirmations.domain_block.confirm": "Сакриј цео домен",
"confirmations.domain_block.message": "Да ли сте стварно, стварно сигурно да желите да блокирате цео домен {domain}? У већини случајева, пар добрих блокирања или ућуткавања су довољна и препоручљива.",
"confirmations.mute.confirm": "Ућуткај",
"confirmations.mute.message": "Да ли стварно желите да ућуткате корисника {name}?",
"confirmations.unfollow.confirm": "Отпрати",
"confirmations.unfollow.message": "Да ли сте сигурни да желите да отпратите корисника {name}?",
"embed.instructions": "Угради овај статус на Ваш веб сајт копирањем кода испод.",
"embed.preview": "Овако ће да изгледа:",
"emoji_button.activity": "Активност",
"emoji_button.custom": "Произвољно",
"emoji_button.flags": "Заставе",
"emoji_button.food": "Храна & пиће",
"emoji_button.label": "Убаци смајли",
"emoji_button.nature": "Природа",
"emoji_button.not_found": "Нема смајлија!! (╯°□°)╯︵ ┻━┻",
"emoji_button.objects": "Објекти",
"emoji_button.people": "Људи",
"emoji_button.recent": "Најчешће коришћени",
"emoji_button.search": "Претрага...",
"emoji_button.search_results": "Резултати претраге",
"emoji_button.symbols": "Симболи",
"emoji_button.travel": "Путовања & места",
"empty_column.community": "Локална лајна је празна. Напишите нешто јавно да лајна продува!",
"empty_column.hashtag": "Тренутно нема ништа на овом хештегу.",
"empty_column.home": "Ваша лајна је празна! Посетите {public} или користите претрагу да почнете и упознајете нове људе.",
"empty_column.home.public_timeline": "јавна лајна",
"empty_column.list": "У овој листи још нема ничега. Када чланови листе објаве нове статусе, они ће се појављивати овде.",
"empty_column.notifications": "Тренутно немате обавештења. Дружите се мало да започнете разговоре.",
"empty_column.public": "Овде нема ничега! Напишите нешто јавно, или нађите кориснике са других инстанци које ћете запратити да попуните ову празнину",
"follow_request.authorize": "Одобри",
"follow_request.reject": "Одбиј",
"getting_started.appsshort": "Апликације",
"getting_started.faq": "ЧПП",
"getting_started.heading": "Да почнете",
"getting_started.open_source_notice": "Мастoдонт је софтвер отвореног кода. Можете му допринети или пријавити проблеме преко GitHub-а на {github}.",
"getting_started.userguide": "Корисничко упутство",
"home.column_settings.advanced": "Напредно",
"home.column_settings.basic": "Основно",
"home.column_settings.filter_regex": "Филтрирај регуларним изразима",
"home.column_settings.show_reblogs": "Прикажи и подржавања",
"home.column_settings.show_replies": "Прикажи одговоре",
"home.settings": "Поставке колоне",
"keyboard_shortcuts.back": "да одете назад",
"keyboard_shortcuts.boost": "да подржите",
"keyboard_shortcuts.column": "да се пребаците на статус у једној од колона",
"keyboard_shortcuts.compose": "да се пребаците на писање новог тута",
"keyboard_shortcuts.description": "Опис",
"keyboard_shortcuts.down": "да се померите на доле у листи",
"keyboard_shortcuts.enter": "да отворите статус",
"keyboard_shortcuts.favourite": "да означите као омиљено",
"keyboard_shortcuts.heading": "Пречице на тастатури",
"keyboard_shortcuts.hotkey": "Пречица",
"keyboard_shortcuts.legend": "да прикажете овај подсетник",
"keyboard_shortcuts.mention": "да поменете аутора",
"keyboard_shortcuts.reply": "да одговорите",
"keyboard_shortcuts.search": "да се пребаците на претрагу",
"keyboard_shortcuts.toot": "да започнете скроз нови тут",
"keyboard_shortcuts.unfocus": "да не будете више на претрази/прављењу новог тута",
"keyboard_shortcuts.up": "да се померите на горе у листи",
"lightbox.close": "Затвори",
"lightbox.next": "Следећи",
"lightbox.previous": "Претходни",
"lists.account.add": "Додај на листу",
"lists.account.remove": "Уклони са листе",
"lists.delete": "Обриши листу",
"lists.edit": "Измени листу",
"lists.new.create": "Додај листу",
"lists.new.title_placeholder": "Наслов нове листе",
"lists.search": "Претражи међу људима које пратите",
"lists.subheading": "Ваше листе",
"loading_indicator.label": "Учитавам...",
"media_gallery.toggle_visible": "Укључи/искључи видљивост",
"missing_indicator.label": "Није пронађено",
"mute_modal.hide_notifications": "Сакриј обавештења од овог корисника?",
"navigation_bar.blocks": "Блокирани корисници",
"navigation_bar.community_timeline": "Локална лајна",
"navigation_bar.edit_profile": "Измени профил",
"navigation_bar.favourites": "Омиљени",
"navigation_bar.follow_requests": "Захтеви за праћење",
"navigation_bar.info": "О овој инстанци",
"navigation_bar.keyboard_shortcuts": "Пречице на тастатури",
"navigation_bar.lists": "Листе",
"navigation_bar.logout": "Одјава",
"navigation_bar.mutes": "Ућуткани корисници",
"navigation_bar.pins": "Прикачени тутови",
"navigation_bar.preferences": "Подешавања",
"navigation_bar.public_timeline": "Федерисана лајна",
"notification.favourite": "{name} је ставио Ваш статус као омиљени",
"notification.follow": "{name} Вас је запратио",
"notification.mention": "{name} Вас је поменуо",
"notification.reblog": "{name} је подржао(ла) Ваш статус",
"notifications.clear": "Очисти обавештења",
"notifications.clear_confirmation": "Да ли сте сигурно да трајно желите да очистите Ваша обавештења?",
"notifications.column_settings.alert": "Обавештења на радној површини",
"notifications.column_settings.favourite": "Омиљени:",
"notifications.column_settings.follow": "Нови пратиоци:",
"notifications.column_settings.mention": "Помињања:",
"notifications.column_settings.push": "Гурај обавештења",
"notifications.column_settings.push_meta": "Овај уређај",
"notifications.column_settings.reblog": "Подршки:",
"notifications.column_settings.show": "Прикажи у колони",
"notifications.column_settings.sound": "Пуштај звук",
"onboarding.done": "Готово",
"onboarding.next": "Следеће",
"onboarding.page_five.public_timelines": "Локална лајна приказује све јавне статусе од свих на домену {domain}. Федерисана лајна приказује јавне статусе од свих људи које прате корисници са домена {domain}. Ово су јавне лајне, сјајан начин да откријете нове људе.",
"onboarding.page_four.home": "Почетна лајна приказује статусе људи које Ви пратите.",
"onboarding.page_four.notifications": "Колона са обавештењима Вам приказује када неко прича са Вама.",
"onboarding.page_one.federation": "Мастодонт је мрежа независних сервера који се увезују да направе једну већу друштвену мрежу. Ове сервере зовемо инстанцама.",
"onboarding.page_one.handle": "Ви сте на домену {domain}, па је Ваша пуна идентификација {handle}",
"onboarding.page_one.welcome": "Добродошли на Мастодонт!",
"onboarding.page_six.admin": "Администратор Ваше инстанце је {admin}.",
"onboarding.page_six.almost_done": "Још мало, па готово...",
"onboarding.page_six.appetoot": "Пријатутно!",
"onboarding.page_six.apps_available": "Постоје {apps} доступне за iOS, Андроид и друге платформе.",
"onboarding.page_six.github": "Мастодонт је слободан софтвер отвореног кода. Можете пријављивати грешке, потраживати нове фунцкионалности, или учествујући у програмирању. Наш изворни код је овде: {github}.",
"onboarding.page_six.guidelines": "смернице заједнице",
"onboarding.page_six.read_guidelines": "Прочитејте {guidelines} домена {domain}!",
"onboarding.page_six.various_app": "мобилне апликације",
"onboarding.page_three.profile": "Измените профил да промените аватар, биографију и име за приказ. Тамо ћете наћи и остала подешавања.",
"onboarding.page_three.search": "Корисите претрагу да нађете људе и гледате хештегове, као што су {illustration} и {introductions}. Да нађете особу која није на овој инстанци, користите њену пуну идентификацију.",
"onboarding.page_two.compose": "Пишите статусе из прве колоне. Можете отпремати слике, мењати подешавања приватности, и додавати упозорења за осетљив садржај преко иконица испод.",
"onboarding.skip": "Прескочи",
"privacy.change": "Подеси статус приватности",
"privacy.direct.long": "Објави само корисницима који су поменути",
"privacy.direct.short": "Директно",
"privacy.private.long": "Објави само пратиоцима",
"privacy.private.short": "Само за пратиоце",
"privacy.public.long": "Објави на јавној лајни",
"privacy.public.short": "Јавно",
"privacy.unlisted.long": "Не објављуј на јавним лајнама",
"privacy.unlisted.short": "Неизлистано",
"relative_time.days": "{number}d",
"relative_time.hours": "{number}h",
"relative_time.just_now": "сада",
"relative_time.minutes": "{number}m",
"relative_time.seconds": "{number}s",
"reply_indicator.cancel": "Поништи",
"report.placeholder": "Додатни коментари",
"report.submit": "Пошаљи",
"report.target": "Пријављујем {target}",
"search.placeholder": "Претрага",
"search_popout.search_format": "Напредни формат претраге",
"search_popout.tips.hashtag": "хештег",
"search_popout.tips.status": "статус",
"search_popout.tips.text": "Тражењем обичног текста ћете добити сва пронађена имена, сва корисничка имена и све нађене хештегове",
"search_popout.tips.user": "корисник",
"search_results.total": "{count, number} {count, plural, one {резултат} few {резултата} other {резултата}}",
"standalone.public_title": "Поглед изнутра...",
"status.block": "Block @{name}",
"status.cannot_reblog": "Овај статус не може да се подржи",
"status.delete": "Обриши",
"status.embed": "Угради на сајт",
"status.favourite": "Омиљено",
"status.load_more": "Учитај још",
"status.media_hidden": "Мултимедија сакривена",
"status.mention": "Помени корисника @{name}",
"status.more": "Још",
"status.mute": "Mute @{name}",
"status.mute_conversation": "Ућуткај преписку",
"status.open": "Прошири овај статус",
"status.pin": "Прикачи на профил",
"status.reblog": "Подржи",
"status.reblogged_by": "{name} подржао(ла)",
"status.reply": "Одговори",
"status.replyAll": "Одговори на дискусију",
"status.report": "Пријави корисника @{name}",
"status.sensitive_toggle": "Кликните да видите",
"status.sensitive_warning": "Осетљив садржај",
"status.share": "Подели",
"status.show_less": "Прикажи мање",
"status.show_more": "Прикажи више",
"status.unmute_conversation": "Укључи преписку",
"status.unpin": "Откачи са профила",
"tabs_bar.compose": "Напиши",
"tabs_bar.federated_timeline": "Федерисано",
"tabs_bar.home": "Почетна",
"tabs_bar.local_timeline": "Локално",
"tabs_bar.notifications": "Обавештења",
"ui.beforeunload": "Ако напустите Мастодонт, изгубићете написани нацрт.",
"upload_area.title": "Превуците овде да отпремите",
"upload_button.label": "Додај мултимедију",
"upload_form.description": "Опиши за слабовиде особе",
"upload_form.undo": "Опозови",
"upload_progress.label": "Отпремам...",
"video.close": "Затвори видео",
"video.exit_fullscreen": "Напусти цео екран",
"video.expand": "Прошири видео",
"video.fullscreen": "Цео екран",
"video.hide": "Сакриј видео",
"video.mute": "Угаси звук",
"video.pause": "Паузирај",
"video.play": "Пусти",
"video.unmute": "Врати звук"
}

View File

@ -50,6 +50,7 @@
"column_header.unpin": "Ångra fäst", "column_header.unpin": "Ångra fäst",
"column_subheading.navigation": "Navigation", "column_subheading.navigation": "Navigation",
"column_subheading.settings": "Inställningar", "column_subheading.settings": "Inställningar",
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
"compose_form.lock_disclaimer": "Ditt konto är inte {locked}. Vemsomhelst kan följa dig och även se dina inlägg skrivna för endast dina följare.", "compose_form.lock_disclaimer": "Ditt konto är inte {locked}. Vemsomhelst kan följa dig och även se dina inlägg skrivna för endast dina följare.",
"compose_form.lock_disclaimer.lock": "låst", "compose_form.lock_disclaimer.lock": "låst",
"compose_form.placeholder": "Vad funderar du på?", "compose_form.placeholder": "Vad funderar du på?",
@ -213,6 +214,7 @@
"search_popout.tips.user": "användare", "search_popout.tips.user": "användare",
"search_results.total": "{count, number} {count, plural, ett {result} andra {results}}", "search_results.total": "{count, number} {count, plural, ett {result} andra {results}}",
"standalone.public_title": "En titt inuti...", "standalone.public_title": "En titt inuti...",
"status.block": "Block @{name}",
"status.cannot_reblog": "Detta inlägg kan inte knuffas", "status.cannot_reblog": "Detta inlägg kan inte knuffas",
"status.delete": "Ta bort", "status.delete": "Ta bort",
"status.embed": "Bädda in", "status.embed": "Bädda in",
@ -221,6 +223,7 @@
"status.media_hidden": "Media dold", "status.media_hidden": "Media dold",
"status.mention": "Omnämn @{name}", "status.mention": "Omnämn @{name}",
"status.more": "More", "status.more": "More",
"status.mute": "Mute @{name}",
"status.mute_conversation": "Tysta konversation", "status.mute_conversation": "Tysta konversation",
"status.open": "Utvidga denna status", "status.open": "Utvidga denna status",
"status.pin": "Fäst i profil", "status.pin": "Fäst i profil",

View File

@ -50,6 +50,7 @@
"column_header.unpin": "Unpin", "column_header.unpin": "Unpin",
"column_subheading.navigation": "Navigation", "column_subheading.navigation": "Navigation",
"column_subheading.settings": "Settings", "column_subheading.settings": "Settings",
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
"compose_form.lock_disclaimer": "Your account is not {locked}. Anyone can follow you to view your follower-only posts.", "compose_form.lock_disclaimer": "Your account is not {locked}. Anyone can follow you to view your follower-only posts.",
"compose_form.lock_disclaimer.lock": "locked", "compose_form.lock_disclaimer.lock": "locked",
"compose_form.placeholder": "What is on your mind?", "compose_form.placeholder": "What is on your mind?",
@ -213,6 +214,7 @@
"search_popout.tips.user": "user", "search_popout.tips.user": "user",
"search_results.total": "{count, number} {count, plural, one {result} other {results}}", "search_results.total": "{count, number} {count, plural, one {result} other {results}}",
"standalone.public_title": "A look inside...", "standalone.public_title": "A look inside...",
"status.block": "Block @{name}",
"status.cannot_reblog": "This post cannot be boosted", "status.cannot_reblog": "This post cannot be boosted",
"status.delete": "Delete", "status.delete": "Delete",
"status.embed": "Embed", "status.embed": "Embed",
@ -221,6 +223,7 @@
"status.media_hidden": "Media hidden", "status.media_hidden": "Media hidden",
"status.mention": "Mention @{name}", "status.mention": "Mention @{name}",
"status.more": "More", "status.more": "More",
"status.mute": "Mute @{name}",
"status.mute_conversation": "Mute conversation", "status.mute_conversation": "Mute conversation",
"status.open": "Expand this status", "status.open": "Expand this status",
"status.pin": "Pin on profile", "status.pin": "Pin on profile",

View File

@ -50,6 +50,7 @@
"column_header.unpin": "Unpin", "column_header.unpin": "Unpin",
"column_subheading.navigation": "Navigasyon", "column_subheading.navigation": "Navigasyon",
"column_subheading.settings": "Ayarlar", "column_subheading.settings": "Ayarlar",
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
"compose_form.lock_disclaimer": "Hesabınız {locked} değil. Sadece takipçilerle paylaştığınız gönderileri görebilmek için sizi herhangi bir kullanıcı takip edebilir.", "compose_form.lock_disclaimer": "Hesabınız {locked} değil. Sadece takipçilerle paylaştığınız gönderileri görebilmek için sizi herhangi bir kullanıcı takip edebilir.",
"compose_form.lock_disclaimer.lock": "kilitli", "compose_form.lock_disclaimer.lock": "kilitli",
"compose_form.placeholder": "Ne düşünüyorsun?", "compose_form.placeholder": "Ne düşünüyorsun?",
@ -213,6 +214,7 @@
"search_popout.tips.user": "user", "search_popout.tips.user": "user",
"search_results.total": "{count, number} {count, plural, one {sonuç} other {sonuçlar}}", "search_results.total": "{count, number} {count, plural, one {sonuç} other {sonuçlar}}",
"standalone.public_title": "A look inside...", "standalone.public_title": "A look inside...",
"status.block": "Block @{name}",
"status.cannot_reblog": "Bu gönderi boost edilemez", "status.cannot_reblog": "Bu gönderi boost edilemez",
"status.delete": "Sil", "status.delete": "Sil",
"status.embed": "Embed", "status.embed": "Embed",
@ -221,6 +223,7 @@
"status.media_hidden": "Gizli görsel", "status.media_hidden": "Gizli görsel",
"status.mention": "Bahset @{name}", "status.mention": "Bahset @{name}",
"status.more": "More", "status.more": "More",
"status.mute": "Mute @{name}",
"status.mute_conversation": "Mute conversation", "status.mute_conversation": "Mute conversation",
"status.open": "Bu gönderiyi genişlet", "status.open": "Bu gönderiyi genişlet",
"status.pin": "Pin on profile", "status.pin": "Pin on profile",

View File

@ -50,6 +50,7 @@
"column_header.unpin": "Unpin", "column_header.unpin": "Unpin",
"column_subheading.navigation": "Навігація", "column_subheading.navigation": "Навігація",
"column_subheading.settings": "Налаштування", "column_subheading.settings": "Налаштування",
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
"compose_form.lock_disclaimer": "Ваш акаунт не {locked}. Кожен може підписатися на Вас та бачити Ваші приватні пости.", "compose_form.lock_disclaimer": "Ваш акаунт не {locked}. Кожен може підписатися на Вас та бачити Ваші приватні пости.",
"compose_form.lock_disclaimer.lock": "приватний", "compose_form.lock_disclaimer.lock": "приватний",
"compose_form.placeholder": "Що у Вас на думці?", "compose_form.placeholder": "Що у Вас на думці?",
@ -213,6 +214,7 @@
"search_popout.tips.user": "user", "search_popout.tips.user": "user",
"search_results.total": "{count, number} {count, plural, one {результат} few {результати} many {результатів} other {результатів}}", "search_results.total": "{count, number} {count, plural, one {результат} few {результати} many {результатів} other {результатів}}",
"standalone.public_title": "A look inside...", "standalone.public_title": "A look inside...",
"status.block": "Block @{name}",
"status.cannot_reblog": "Цей допис не може бути передмухнутий", "status.cannot_reblog": "Цей допис не може бути передмухнутий",
"status.delete": "Видалити", "status.delete": "Видалити",
"status.embed": "Embed", "status.embed": "Embed",
@ -221,6 +223,7 @@
"status.media_hidden": "Медіаконтент приховано", "status.media_hidden": "Медіаконтент приховано",
"status.mention": "Згадати", "status.mention": "Згадати",
"status.more": "More", "status.more": "More",
"status.mute": "Mute @{name}",
"status.mute_conversation": "Заглушити діалог", "status.mute_conversation": "Заглушити діалог",
"status.open": "Розгорнути допис", "status.open": "Розгорнути допис",
"status.pin": "Pin on profile", "status.pin": "Pin on profile",

View File

@ -0,0 +1,2 @@
[
]

View File

@ -0,0 +1,2 @@
[
]

View File

@ -0,0 +1,2 @@
[
]

View File

@ -50,6 +50,7 @@
"column_header.unpin": "取消固定", "column_header.unpin": "取消固定",
"column_subheading.navigation": "导航", "column_subheading.navigation": "导航",
"column_subheading.settings": "设置", "column_subheading.settings": "设置",
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
"compose_form.lock_disclaimer": "你的帐户没有{locked}。任何人都可以在关注你后立即查看仅关注者可见的嘟文。", "compose_form.lock_disclaimer": "你的帐户没有{locked}。任何人都可以在关注你后立即查看仅关注者可见的嘟文。",
"compose_form.lock_disclaimer.lock": "开启保护", "compose_form.lock_disclaimer.lock": "开启保护",
"compose_form.placeholder": "在想啥?", "compose_form.placeholder": "在想啥?",
@ -213,6 +214,7 @@
"search_popout.tips.user": "用户", "search_popout.tips.user": "用户",
"search_results.total": "共 {count, number} 个结果", "search_results.total": "共 {count, number} 个结果",
"standalone.public_title": "大家都在干啥?", "standalone.public_title": "大家都在干啥?",
"status.block": "Block @{name}",
"status.cannot_reblog": "无法转嘟这条嘟文", "status.cannot_reblog": "无法转嘟这条嘟文",
"status.delete": "删除", "status.delete": "删除",
"status.embed": "嵌入", "status.embed": "嵌入",
@ -221,6 +223,7 @@
"status.media_hidden": "隐藏媒体内容", "status.media_hidden": "隐藏媒体内容",
"status.mention": "提及 @{name}", "status.mention": "提及 @{name}",
"status.more": "更多", "status.more": "更多",
"status.mute": "Mute @{name}",
"status.mute_conversation": "隐藏此对话", "status.mute_conversation": "隐藏此对话",
"status.open": "展开嘟文", "status.open": "展开嘟文",
"status.pin": "在个人资料页面置顶", "status.pin": "在个人资料页面置顶",

View File

@ -50,6 +50,7 @@
"column_header.unpin": "取下", "column_header.unpin": "取下",
"column_subheading.navigation": "瀏覽", "column_subheading.navigation": "瀏覽",
"column_subheading.settings": "設定", "column_subheading.settings": "設定",
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
"compose_form.lock_disclaimer": "你的用戶狀態為「{locked}」,任何人都能立即關注你,然後看到「只有關注者能看」的文章。", "compose_form.lock_disclaimer": "你的用戶狀態為「{locked}」,任何人都能立即關注你,然後看到「只有關注者能看」的文章。",
"compose_form.lock_disclaimer.lock": "公共", "compose_form.lock_disclaimer.lock": "公共",
"compose_form.placeholder": "你在想甚麼?", "compose_form.placeholder": "你在想甚麼?",
@ -213,6 +214,7 @@
"search_popout.tips.user": "user", "search_popout.tips.user": "user",
"search_results.total": "{count, number} 項結果", "search_results.total": "{count, number} 項結果",
"standalone.public_title": "站點一瞥…", "standalone.public_title": "站點一瞥…",
"status.block": "Block @{name}",
"status.cannot_reblog": "這篇文章無法被轉推", "status.cannot_reblog": "這篇文章無法被轉推",
"status.delete": "刪除", "status.delete": "刪除",
"status.embed": "鑲嵌", "status.embed": "鑲嵌",
@ -221,6 +223,7 @@
"status.media_hidden": "隱藏媒體內容", "status.media_hidden": "隱藏媒體內容",
"status.mention": "提及 @{name}", "status.mention": "提及 @{name}",
"status.more": "More", "status.more": "More",
"status.mute": "Mute @{name}",
"status.mute_conversation": "靜音對話", "status.mute_conversation": "靜音對話",
"status.open": "展開文章", "status.open": "展開文章",
"status.pin": "置頂到資料頁", "status.pin": "置頂到資料頁",

View File

@ -50,6 +50,7 @@
"column_header.unpin": "取下", "column_header.unpin": "取下",
"column_subheading.navigation": "瀏覽", "column_subheading.navigation": "瀏覽",
"column_subheading.settings": "設定", "column_subheading.settings": "設定",
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
"compose_form.lock_disclaimer": "你的帳號沒有{locked}。任何人都可以關注你,看到發給關注者的貼文。", "compose_form.lock_disclaimer": "你的帳號沒有{locked}。任何人都可以關注你,看到發給關注者的貼文。",
"compose_form.lock_disclaimer.lock": "上鎖", "compose_form.lock_disclaimer.lock": "上鎖",
"compose_form.placeholder": "在想些什麼?", "compose_form.placeholder": "在想些什麼?",
@ -63,8 +64,8 @@
"confirmations.block.message": "你確定要封鎖 {name} ", "confirmations.block.message": "你確定要封鎖 {name} ",
"confirmations.delete.confirm": "刪除", "confirmations.delete.confirm": "刪除",
"confirmations.delete.message": "你確定要刪除這個狀態?", "confirmations.delete.message": "你確定要刪除這個狀態?",
"confirmations.delete_list.confirm": "Delete", "confirmations.delete_list.confirm": "刪除",
"confirmations.delete_list.message": "Are you sure you want to permanently delete this list?", "confirmations.delete_list.message": "確定要永久性地刪除這個名單嗎?",
"confirmations.domain_block.confirm": "隱藏整個網域", "confirmations.domain_block.confirm": "隱藏整個網域",
"confirmations.domain_block.message": "你真的真的確定要隱藏整個 {domain} ?多數情況下,比較推薦封鎖或消音幾個特定目標就好。", "confirmations.domain_block.message": "你真的真的確定要隱藏整個 {domain} ?多數情況下,比較推薦封鎖或消音幾個特定目標就好。",
"confirmations.mute.confirm": "消音", "confirmations.mute.confirm": "消音",
@ -127,14 +128,14 @@
"lightbox.close": "關閉", "lightbox.close": "關閉",
"lightbox.next": "繼續", "lightbox.next": "繼續",
"lightbox.previous": "回退", "lightbox.previous": "回退",
"lists.account.add": "Add to list", "lists.account.add": "加到名單裡",
"lists.account.remove": "Remove from list", "lists.account.remove": "從名單中移除",
"lists.delete": "Delete list", "lists.delete": "刪除名單",
"lists.edit": "Edit list", "lists.edit": "修改名單",
"lists.new.create": "Add list", "lists.new.create": "新增名單",
"lists.new.title_placeholder": "New list title", "lists.new.title_placeholder": "名單名稱",
"lists.search": "Search among people you follow", "lists.search": "搜尋您關注的使用者",
"lists.subheading": "Your lists", "lists.subheading": "您的名單",
"loading_indicator.label": "讀取中...", "loading_indicator.label": "讀取中...",
"media_gallery.toggle_visible": "切換可見性", "media_gallery.toggle_visible": "切換可見性",
"missing_indicator.label": "找不到", "missing_indicator.label": "找不到",
@ -145,8 +146,8 @@
"navigation_bar.favourites": "最愛", "navigation_bar.favourites": "最愛",
"navigation_bar.follow_requests": "關注請求", "navigation_bar.follow_requests": "關注請求",
"navigation_bar.info": "關於本站", "navigation_bar.info": "關於本站",
"navigation_bar.keyboard_shortcuts": "Keyboard shortcuts", "navigation_bar.keyboard_shortcuts": "快速鍵",
"navigation_bar.lists": "Lists", "navigation_bar.lists": "名單",
"navigation_bar.logout": "登出", "navigation_bar.logout": "登出",
"navigation_bar.mutes": "消音的使用者", "navigation_bar.mutes": "消音的使用者",
"navigation_bar.pins": "置頂貼文", "navigation_bar.pins": "置頂貼文",
@ -213,6 +214,7 @@
"search_popout.tips.user": "user", "search_popout.tips.user": "user",
"search_results.total": "{count, number} 項結果", "search_results.total": "{count, number} 項結果",
"standalone.public_title": "站點一瞥…", "standalone.public_title": "站點一瞥…",
"status.block": "Block @{name}",
"status.cannot_reblog": "此貼文無法轉推", "status.cannot_reblog": "此貼文無法轉推",
"status.delete": "刪除", "status.delete": "刪除",
"status.embed": "Embed", "status.embed": "Embed",
@ -221,6 +223,7 @@
"status.media_hidden": "媒體已隱藏", "status.media_hidden": "媒體已隱藏",
"status.mention": "提到 @{name}", "status.mention": "提到 @{name}",
"status.more": "More", "status.more": "More",
"status.mute": "Mute @{name}",
"status.mute_conversation": "消音對話", "status.mute_conversation": "消音對話",
"status.open": "展開這個狀態", "status.open": "展開這個狀態",
"status.pin": "置頂到個人資訊頁", "status.pin": "置頂到個人資訊頁",

View File

@ -1,5 +1,5 @@
import * as WebPushSubscription from './web_push_subscription'; import * as registerPushNotifications from './actions/push_notifications';
import Mastodon from './containers/mastodon'; import { default as Mastodon, store } from './containers/mastodon';
import React from 'react'; import React from 'react';
import ReactDOM from 'react-dom'; import ReactDOM from 'react-dom';
import ready from './ready'; import ready from './ready';
@ -25,7 +25,7 @@ function main() {
if (process.env.NODE_ENV === 'production') { if (process.env.NODE_ENV === 'production') {
// avoid offline in dev mode because it's harder to debug // avoid offline in dev mode because it's harder to debug
require('offline-plugin/runtime').install(); require('offline-plugin/runtime').install();
WebPushSubscription.register(); store.dispatch(registerPushNotifications.register());
} }
perf.stop('main()'); perf.stop('main()');
}); });

View File

@ -1,5 +1,5 @@
import { STORE_HYDRATE } from '../actions/store'; import { STORE_HYDRATE } from '../actions/store';
import { SET_BROWSER_SUPPORT, SET_SUBSCRIPTION, CLEAR_SUBSCRIPTION, ALERTS_CHANGE } from '../actions/push_notifications'; import { SET_BROWSER_SUPPORT, SET_SUBSCRIPTION, CLEAR_SUBSCRIPTION, SET_ALERTS } from '../actions/push_notifications';
import Immutable from 'immutable'; import Immutable from 'immutable';
const initialState = Immutable.Map({ const initialState = Immutable.Map({
@ -43,8 +43,8 @@ export default function push_subscriptions(state = initialState, action) {
return state.set('browserSupport', action.value); return state.set('browserSupport', action.value);
case CLEAR_SUBSCRIPTION: case CLEAR_SUBSCRIPTION:
return initialState; return initialState;
case ALERTS_CHANGE: case SET_ALERTS:
return state.setIn(action.key, action.value); return state.setIn(action.path, action.value);
default: default:
return state; return state;
} }

View File

@ -93,7 +93,7 @@ export default function settings(state = initialState, action) {
return hydrate(state, action.state.get('settings')); return hydrate(state, action.state.get('settings'));
case SETTING_CHANGE: case SETTING_CHANGE:
return state return state
.setIn(action.key, action.value) .setIn(action.path, action.value)
.set('saved', false); .set('saved', false);
case COLUMN_ADD: case COLUMN_ADD:
return state return state

View File

@ -1,129 +0,0 @@
import axios from 'axios';
import { store } from './containers/mastodon';
import { setBrowserSupport, setSubscription, clearSubscription } from './actions/push_notifications';
import { pushNotificationsSetting } from './settings';
// Taken from https://www.npmjs.com/package/web-push
const urlBase64ToUint8Array = (base64String) => {
const padding = '='.repeat((4 - base64String.length % 4) % 4);
const base64 = (base64String + padding)
.replace(/\-/g, '+')
.replace(/_/g, '/');
const rawData = window.atob(base64);
const outputArray = new Uint8Array(rawData.length);
for (let i = 0; i < rawData.length; ++i) {
outputArray[i] = rawData.charCodeAt(i);
}
return outputArray;
};
const getApplicationServerKey = () => document.querySelector('[name="applicationServerKey"]').getAttribute('content');
const getRegistration = () => navigator.serviceWorker.ready;
const getPushSubscription = (registration) =>
registration.pushManager.getSubscription()
.then(subscription => ({ registration, subscription }));
const subscribe = (registration) =>
registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: urlBase64ToUint8Array(getApplicationServerKey()),
});
const unsubscribe = ({ registration, subscription }) =>
subscription ? subscription.unsubscribe().then(() => registration) : registration;
const sendSubscriptionToBackend = (subscription) => {
const params = { subscription };
const me = store.getState().getIn(['meta', 'me']);
if (me) {
const data = pushNotificationsSetting.get(me);
if (data) {
params.data = data;
}
}
return axios.post('/api/web/push_subscriptions', params).then(response => response.data);
};
// Last one checks for payload support: https://web-push-book.gauntface.com/chapter-06/01-non-standards-browsers/#no-payload
const supportsPushNotifications = ('serviceWorker' in navigator && 'PushManager' in window && 'getKey' in PushSubscription.prototype);
export function register () {
store.dispatch(setBrowserSupport(supportsPushNotifications));
const me = store.getState().getIn(['meta', 'me']);
if (me && !pushNotificationsSetting.get(me)) {
const alerts = store.getState().getIn(['push_notifications', 'alerts']);
if (alerts) {
pushNotificationsSetting.set(me, { alerts: alerts });
}
}
if (supportsPushNotifications) {
if (!getApplicationServerKey()) {
console.error('The VAPID public key is not set. You will not be able to receive Web Push Notifications.');
return;
}
getRegistration()
.then(getPushSubscription)
.then(({ registration, subscription }) => {
if (subscription !== null) {
// We have a subscription, check if it is still valid
const currentServerKey = (new Uint8Array(subscription.options.applicationServerKey)).toString();
const subscriptionServerKey = urlBase64ToUint8Array(getApplicationServerKey()).toString();
const serverEndpoint = store.getState().getIn(['push_notifications', 'subscription', 'endpoint']);
// If the VAPID public key did not change and the endpoint corresponds
// to the endpoint saved in the backend, the subscription is valid
if (subscriptionServerKey === currentServerKey && subscription.endpoint === serverEndpoint) {
return subscription;
} else {
// Something went wrong, try to subscribe again
return unsubscribe({ registration, subscription }).then(subscribe).then(sendSubscriptionToBackend);
}
}
// No subscription, try to subscribe
return subscribe(registration).then(sendSubscriptionToBackend);
})
.then(subscription => {
// If we got a PushSubscription (and not a subscription object from the backend)
// it means that the backend subscription is valid (and was set during hydration)
if (!(subscription instanceof PushSubscription)) {
store.dispatch(setSubscription(subscription));
if (me) {
pushNotificationsSetting.set(me, { alerts: subscription.alerts });
}
}
})
.catch(error => {
if (error.code === 20 && error.name === 'AbortError') {
console.warn('Your browser supports Web Push Notifications, but does not seem to implement the VAPID protocol.');
} else if (error.code === 5 && error.name === 'InvalidCharacterError') {
console.error('The VAPID public key seems to be invalid:', getApplicationServerKey());
}
// Clear alerts and hide UI settings
store.dispatch(clearSubscription());
if (me) {
pushNotificationsSetting.remove(me);
}
try {
getRegistration()
.then(getPushSubscription)
.then(unsubscribe);
} catch (e) {
}
});
} else {
console.warn('Your browser does not support Web Push Notifications.');
}
}

View File

@ -6,6 +6,7 @@
@import 'mastodon/reset'; @import 'mastodon/reset';
@import 'mastodon/basics'; @import 'mastodon/basics';
@import 'mastodon/modal';
@import 'mastodon/containers'; @import 'mastodon/containers';
@import 'mastodon/lists'; @import 'mastodon/lists';
@import 'mastodon/footer'; @import 'mastodon/footer';

View File

@ -398,10 +398,12 @@
} }
} }
&__content {
max-width: calc(100% - 90px);
}
&__title { &__title {
overflow: hidden; word-wrap: break-word;
text-overflow: ellipsis;
white-space: nowrap;
} }
&__timestamp { &__timestamp {
@ -415,7 +417,7 @@
color: $ui-primary-color; color: $ui-primary-color;
font-family: 'mastodon-font-monospace', monospace; font-family: 'mastodon-font-monospace', monospace;
font-size: 12px; font-size: 12px;
white-space: nowrap; word-wrap: break-word;
min-height: 20px; min-height: 20px;
} }

View File

@ -214,6 +214,7 @@
.dropdown-menu { .dropdown-menu {
position: absolute; position: absolute;
transform-origin: 50% 0;
} }
.dropdown--active .icon-button { .dropdown--active .icon-button {
@ -1757,7 +1758,7 @@
position: absolute; position: absolute;
top: 0; top: 0;
left: 0; left: 0;
background: lighten($ui-base-color, 13%); background: lighten($ui-base-color, 13%) url('../images/wave-drawer.png') no-repeat bottom / 100% auto;
box-sizing: border-box; box-sizing: border-box;
padding: 0; padding: 0;
display: flex; display: flex;
@ -1770,6 +1771,11 @@
&.darker { &.darker {
background: $ui-base-color; background: $ui-base-color;
} }
> .mastodon {
background: url('../images/mastodon-ui.png') no-repeat left bottom / contain;
flex: 1;
}
} }
.pseudo-drawer { .pseudo-drawer {
@ -2066,20 +2072,18 @@
cursor: default; cursor: default;
} }
.getting-started__wrapper,
.getting_started {
background: $ui-base-color;
}
.getting-started__wrapper { .getting-started__wrapper {
position: relative; position: relative;
overflow-y: auto; overflow-y: auto;
} }
.getting-started__footer {
display: flex;
flex-direction: column;
}
.getting-started { .getting-started {
box-sizing: border-box; background: $ui-base-color;
padding-bottom: 235px;
background: url('../images/mastodon-getting-started.png') no-repeat 0 100%;
flex: 1 0 auto; flex: 1 0 auto;
p { p {
@ -2104,7 +2108,7 @@
padding: 0 10px 8px; padding: 0 10px 8px;
} }
code { kbd {
display: inline-block; display: inline-block;
padding: 3px 5px; padding: 3px 5px;
background-color: lighten($ui-base-color, 8%); background-color: lighten($ui-base-color, 8%);
@ -2148,7 +2152,8 @@
@import 'boost'; @import 'boost';
button.icon-button i.fa-retweet { .no-reduce-motion button.icon-button i.fa-retweet {
background-position: 0 0; background-position: 0 0;
height: 19px; height: 19px;
transition: background-position 0.9s steps(10); transition: background-position 0.9s steps(10);
@ -2159,13 +2164,23 @@ button.icon-button i.fa-retweet {
&::before { &::before {
display: none !important; display: none !important;
} }
} }
button.icon-button.active i.fa-retweet { .no-reduce-motion button.icon-button.active i.fa-retweet {
transition-duration: 0.9s; transition-duration: 0.9s;
background-position: 0 100%; background-position: 0 100%;
} }
.reduce-motion button.icon-button i.fa-retweet {
color: $ui-base-lighter-color;
transition: color 100ms ease-in;
}
.reduce-motion button.icon-button.active i.fa-retweet {
color: $ui-highlight-color;
}
.status-card { .status-card {
display: flex; display: flex;
cursor: pointer; cursor: pointer;
@ -2943,6 +2958,7 @@ button.icon-button.active i.fa-retweet {
border-radius: 4px; border-radius: 4px;
margin-left: 40px; margin-left: 40px;
overflow: hidden; overflow: hidden;
transform-origin: 50% 0;
} }
.privacy-dropdown__option { .privacy-dropdown__option {

View File

@ -0,0 +1,20 @@
.modal-layout {
background: $ui-base-color url('../images/wave-modal.png') repeat-x bottom fixed;
display: flex;
flex-direction: column;
height: 100vh;
padding: 0;
}
.modal-layout__mastodon {
display: flex;
flex: 1;
flex-direction: column;
justify-content: flex-end;
> * {
flex: 1;
max-height: 235px;
background: url('../images/mastodon-ui.png') no-repeat left bottom / contain;
}
}

View File

@ -0,0 +1,31 @@
# frozen_string_literal: true
class ActivityTracker
EXPIRE_AFTER = 90.days.seconds
class << self
def increment(prefix)
key = [prefix, current_week].join(':')
redis.incrby(key, 1)
redis.expire(key, EXPIRE_AFTER)
end
def record(prefix, value)
key = [prefix, current_week].join(':')
redis.pfadd(key, value)
redis.expire(key, EXPIRE_AFTER)
end
private
def redis
Redis.current
end
def current_week
Time.zone.today.cweek
end
end
end

View File

@ -2,16 +2,18 @@
class ActivityPub::Activity::Accept < ActivityPub::Activity class ActivityPub::Activity::Accept < ActivityPub::Activity
def perform def perform
case @object['type'] if @object.respond_to?(:[]) &&
when 'Follow' @object['type'] == 'Follow' && @object['actor'].present?
accept_follow accept_follow_from @object['actor']
else
accept_follow_object @object
end end
end end
private private
def accept_follow def accept_follow_from(actor)
target_account = account_from_uri(target_uri) target_account = account_from_uri(value_or_id(actor))
return if target_account.nil? || !target_account.local? return if target_account.nil? || !target_account.local?
@ -19,7 +21,8 @@ class ActivityPub::Activity::Accept < ActivityPub::Activity
follow_request&.authorize! follow_request&.authorize!
end end
def target_uri def accept_follow_object(object)
@target_uri ||= value_or_id(@object['actor']) follow_request = ActivityPub::TagManager.instance.uri_to_resource(value_or_id(object), FollowRequest)
follow_request&.authorize!
end end
end end

View File

@ -13,6 +13,7 @@ class ActivityPub::Activity::Delete < ActivityPub::Activity
def delete_person def delete_person
SuspendAccountService.new.call(@account) SuspendAccountService.new.call(@account)
@account.destroy!
end end
def delete_note def delete_note

View File

@ -28,6 +28,8 @@ class ActivityPub::TagManager
return target.uri if target.respond_to?(:local?) && !target.local? return target.uri if target.respond_to?(:local?) && !target.local?
case target.object_type case target.object_type
when :follow
account_follow_url(target.account.username, target)
when :person when :person
account_url(target) account_url(target)
when :note, :comment, :activity when :note, :comment, :activity
@ -97,6 +99,12 @@ class ActivityPub::TagManager
case klass.name case klass.name
when 'Account' when 'Account'
klass.find_local(uri_to_local_id(uri, :username)) klass.find_local(uri_to_local_id(uri, :username))
when 'FollowRequest'
params = Rails.application.routes.recognize_path(uri)
klass.joins(:account).find_by!(
accounts: { domain: nil, username: params[:account_username] },
id: params[:id]
)
else else
StatusFinder.new(uri).status StatusFinder.new(uri).status
end end

View File

@ -171,10 +171,10 @@ class Formatter
end end
def link_to_url(entity) def link_to_url(entity)
normalized_url = Addressable::URI.parse(entity[:url]).normalize url = Addressable::URI.parse(entity[:url])
html_attrs = { target: '_blank', rel: 'nofollow noopener' } html_attrs = { target: '_blank', rel: 'nofollow noopener' }
Twitter::Autolink.send(:link_to_text, entity, link_html(entity[:url]), normalized_url, html_attrs) Twitter::Autolink.send(:link_to_text, entity, link_html(entity[:url]), url, html_attrs)
rescue Addressable::URI::InvalidURIError, IDN::Idna::IdnaError rescue Addressable::URI::InvalidURIError, IDN::Idna::IdnaError
encode(entity[:url]) encode(entity[:url])
end end

View File

@ -29,7 +29,7 @@ class ProviderDiscovery < OEmbed::ProviderDiscovery
end end
if format.nil? || format == :xml if format.nil? || format == :xml
provider_endpoint ||= html.at_xpath('//link[@type="application/xml+oembed"]')&.attribute('href')&.value provider_endpoint ||= html.at_xpath('//link[@type="text/xml+oembed"]')&.attribute('href')&.value
format ||= :xml if provider_endpoint format ||= :xml if provider_endpoint
end end

View File

@ -6,14 +6,14 @@ class Sanitize
CLASS_WHITELIST_TRANSFORMER = lambda do |env| CLASS_WHITELIST_TRANSFORMER = lambda do |env|
node = env[:node] node = env[:node]
class_list = node['class']&.split(' ') class_list = node['class']&.split(/[\t\n\f\r ]/)
return unless class_list return unless class_list
class_list.keep_if do |e| class_list.keep_if do |e|
return true if e =~ /^(h|p|u|dt|e)-/ # microformats classes next true if e =~ /^(h|p|u|dt|e)-/ # microformats classes
return true if e =~ /^(mention|hashtag)$/ # semantic classes next true if e =~ /^(mention|hashtag)$/ # semantic classes
return true if e =~ /^(ellipsis|invisible)$/ # link formatting classes next true if e =~ /^(ellipsis|invisible)$/ # link formatting classes
end end
node['class'] = class_list.join(' ') node['class'] = class_list.join(' ')

Some files were not shown because too many files have changed in this diff Show More