diff options
Diffstat (limited to 'app')
121 files changed, 1819 insertions, 461 deletions
diff --git a/app/controllers/admin/accounts_controller.rb b/app/controllers/admin/accounts_controller.rb index 5d57fe361..f155543ce 100644 --- a/app/controllers/admin/accounts_controller.rb +++ b/app/controllers/admin/accounts_controller.rb @@ -94,8 +94,8 @@ module Admin :local, :remote, :by_domain, + :active, :silenced, - :alphabetic, :suspended, :username, :display_name, diff --git a/app/controllers/admin/instances_controller.rb b/app/controllers/admin/instances_controller.rb index 8ed0ea421..6f8eaf65c 100644 --- a/app/controllers/admin/instances_controller.rb +++ b/app/controllers/admin/instances_controller.rb @@ -31,7 +31,7 @@ module Admin end def subscribeable_accounts - Account.with_followers.remote.where(domain: params[:by_domain]) + Account.remote.where(protocol: :ostatus).where(domain: params[:by_domain]) end def filter_params diff --git a/app/controllers/api/v1/accounts/follower_accounts_controller.rb b/app/controllers/api/v1/accounts/follower_accounts_controller.rb index daa35769e..ec15debb0 100644 --- a/app/controllers/api/v1/accounts/follower_accounts_controller.rb +++ b/app/controllers/api/v1/accounts/follower_accounts_controller.rb @@ -25,7 +25,7 @@ class Api::V1::Accounts::FollowerAccountsController < Api::BaseController end def default_accounts - Account.includes(:active_relationships).references(:active_relationships) + Account.includes(:active_relationships, :account_stat).references(:active_relationships) end def paginated_follows diff --git a/app/controllers/api/v1/accounts/following_accounts_controller.rb b/app/controllers/api/v1/accounts/following_accounts_controller.rb index 6be97b87e..f3e112f2c 100644 --- a/app/controllers/api/v1/accounts/following_accounts_controller.rb +++ b/app/controllers/api/v1/accounts/following_accounts_controller.rb @@ -25,7 +25,7 @@ class Api::V1::Accounts::FollowingAccountsController < Api::BaseController end def default_accounts - Account.includes(:passive_relationships).references(:passive_relationships) + Account.includes(:passive_relationships, :account_stat).references(:passive_relationships) end def paginated_follows diff --git a/app/controllers/api/v1/blocks_controller.rb b/app/controllers/api/v1/blocks_controller.rb index 99c53d59a..4cff04cad 100644 --- a/app/controllers/api/v1/blocks_controller.rb +++ b/app/controllers/api/v1/blocks_controller.rb @@ -19,7 +19,7 @@ class Api::V1::BlocksController < Api::BaseController end def paginated_blocks - @paginated_blocks ||= Block.eager_load(:target_account) + @paginated_blocks ||= Block.eager_load(target_account: :account_stat) .where(account: current_account) .paginate_by_max_id( limit_param(DEFAULT_ACCOUNTS_LIMIT), diff --git a/app/controllers/api/v1/endorsements_controller.rb b/app/controllers/api/v1/endorsements_controller.rb index 0f04b488f..2770c7aef 100644 --- a/app/controllers/api/v1/endorsements_controller.rb +++ b/app/controllers/api/v1/endorsements_controller.rb @@ -27,7 +27,7 @@ class Api::V1::EndorsementsController < Api::BaseController end def endorsed_accounts - current_account.endorsed_accounts + current_account.endorsed_accounts.includes(:account_stat) end def insert_pagination_headers diff --git a/app/controllers/api/v1/follow_requests_controller.rb b/app/controllers/api/v1/follow_requests_controller.rb index e9aca5f8a..e6888154e 100644 --- a/app/controllers/api/v1/follow_requests_controller.rb +++ b/app/controllers/api/v1/follow_requests_controller.rb @@ -33,7 +33,7 @@ class Api::V1::FollowRequestsController < Api::BaseController end def default_accounts - Account.includes(:follow_requests).references(:follow_requests) + Account.includes(:follow_requests, :account_stat).references(:follow_requests) end def paginated_follow_requests diff --git a/app/controllers/api/v1/lists/accounts_controller.rb b/app/controllers/api/v1/lists/accounts_controller.rb index ec4477034..23078263e 100644 --- a/app/controllers/api/v1/lists/accounts_controller.rb +++ b/app/controllers/api/v1/lists/accounts_controller.rb @@ -37,9 +37,9 @@ class Api::V1::Lists::AccountsController < Api::BaseController def load_accounts if unlimited? - @list.accounts.all + @list.accounts.includes(:account_stat).all else - @list.accounts.paginate_by_max_id(limit_param(DEFAULT_ACCOUNTS_LIMIT), params[:max_id], params[:since_id]) + @list.accounts.includes(:account_stat).paginate_by_max_id(limit_param(DEFAULT_ACCOUNTS_LIMIT), params[:max_id], params[:since_id]) end end diff --git a/app/controllers/api/v1/lists_controller.rb b/app/controllers/api/v1/lists_controller.rb index 054172bee..e5ac45fef 100644 --- a/app/controllers/api/v1/lists_controller.rb +++ b/app/controllers/api/v1/lists_controller.rb @@ -38,6 +38,6 @@ class Api::V1::ListsController < Api::BaseController end def list_params - params.permit(:title) + params.permit(:title, :replies_policy) end end diff --git a/app/controllers/api/v1/statuses/favourited_by_accounts_controller.rb b/app/controllers/api/v1/statuses/favourited_by_accounts_controller.rb index 8f4070bc7..657e57831 100644 --- a/app/controllers/api/v1/statuses/favourited_by_accounts_controller.rb +++ b/app/controllers/api/v1/statuses/favourited_by_accounts_controller.rb @@ -22,7 +22,7 @@ class Api::V1::Statuses::FavouritedByAccountsController < Api::BaseController def default_accounts Account - .includes(:favourites) + .includes(:favourites, :account_stat) .references(:favourites) .where(favourites: { status_id: @status.id }) end diff --git a/app/controllers/api/v1/statuses/reblogged_by_accounts_controller.rb b/app/controllers/api/v1/statuses/reblogged_by_accounts_controller.rb index 93b83ce48..4315b0283 100644 --- a/app/controllers/api/v1/statuses/reblogged_by_accounts_controller.rb +++ b/app/controllers/api/v1/statuses/reblogged_by_accounts_controller.rb @@ -21,7 +21,7 @@ class Api::V1::Statuses::RebloggedByAccountsController < Api::BaseController end def default_accounts - Account.includes(:statuses).references(:statuses) + Account.includes(:statuses, :account_stat).references(:statuses) end def paginated_statuses diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 983b116c9..0209805d0 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -188,7 +188,7 @@ class ApplicationController < ActionController::Base klass.reload_stale_associations!(cached_keys_with_value.values) if klass.respond_to?(:reload_stale_associations!) unless uncached_ids.empty? - uncached = klass.where(id: uncached_ids).with_includes.map { |item| [item.id, item] }.to_h + uncached = klass.where(id: uncached_ids).with_includes.each_with_object({}) { |item, h| h[item.id] = item } uncached.each_value do |item| Rails.cache.write(item, item) diff --git a/app/helpers/admin/account_moderation_notes_helper.rb b/app/helpers/admin/account_moderation_notes_helper.rb index 4d8f0352e..40b2a5289 100644 --- a/app/helpers/admin/account_moderation_notes_helper.rb +++ b/app/helpers/admin/account_moderation_notes_helper.rb @@ -24,7 +24,7 @@ module Admin::AccountModerationNotesHelper def name_tag_classes(account, inline = false) classes = [inline ? 'inline-name-tag' : 'name-tag'] - classes << 'suspended' if account.suspended? + classes << 'suspended' if account.suspended? || (account.local? && account.user.nil?) classes.join(' ') end end diff --git a/app/helpers/admin/filter_helper.rb b/app/helpers/admin/filter_helper.rb index 60e5142e3..9a663051c 100644 --- a/app/helpers/admin/filter_helper.rb +++ b/app/helpers/admin/filter_helper.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module Admin::FilterHelper - ACCOUNT_FILTERS = %i(local remote by_domain silenced suspended alphabetic username display_name email ip staff).freeze + ACCOUNT_FILTERS = %i(local remote by_domain active silenced suspended username display_name email ip staff).freeze REPORT_FILTERS = %i(resolved account_id target_account_id).freeze INVITE_FILTER = %i(available expired).freeze CUSTOM_EMOJI_FILTERS = %i(local remote by_domain shortcode).freeze diff --git a/app/helpers/stream_entries_helper.rb b/app/helpers/stream_entries_helper.rb index ac655f622..033d435c4 100644 --- a/app/helpers/stream_entries_helper.rb +++ b/app/helpers/stream_entries_helper.rb @@ -34,12 +34,14 @@ module StreamEntriesHelper end end - def account_badge(account) + def account_badge(account, all: false) if account.bot? content_tag(:div, content_tag(:div, t('accounts.roles.bot'), class: 'account-role bot'), class: 'roles') - elsif Setting.show_staff_badge && account.user_staff? + elsif (Setting.show_staff_badge && account.user_staff?) || all content_tag(:div, class: 'roles') do - if account.user_admin? + if all && !account.user_staff? + content_tag(:div, t('admin.accounts.roles.user'), class: 'account-role') + elsif account.user_admin? content_tag(:div, t('accounts.roles.admin'), class: 'account-role admin') elsif account.user_moderator? content_tag(:div, t('accounts.roles.moderator'), class: 'account-role moderator') diff --git a/app/javascript/flavours/glitch/actions/lists.js b/app/javascript/flavours/glitch/actions/lists.js index 3021fa5b5..7d94ee950 100644 --- a/app/javascript/flavours/glitch/actions/lists.js +++ b/app/javascript/flavours/glitch/actions/lists.js @@ -148,10 +148,10 @@ export const createListFail = error => ({ error, }); -export const updateList = (id, title, shouldReset) => (dispatch, getState) => { +export const updateList = (id, title, shouldReset, replies_policy) => (dispatch, getState) => { dispatch(updateListRequest(id)); - api(getState).put(`/api/v1/lists/${id}`, { title }).then(({ data }) => { + api(getState).put(`/api/v1/lists/${id}`, { title, replies_policy }).then(({ data }) => { dispatch(updateListSuccess(data)); if (shouldReset) { diff --git a/app/javascript/flavours/glitch/actions/notifications.js b/app/javascript/flavours/glitch/actions/notifications.js index ddf14f78f..0184d9c80 100644 --- a/app/javascript/flavours/glitch/actions/notifications.js +++ b/app/javascript/flavours/glitch/actions/notifications.js @@ -102,7 +102,7 @@ export function expandNotifications({ maxId } = {}, done = noOp) { }; if (!maxId && notifications.get('items').size > 0) { - params.since_id = notifications.getIn(['items', 0]); + params.since_id = notifications.getIn(['items', 0, 'id']); } dispatch(expandNotificationsRequest(isLoadingMore)); diff --git a/app/javascript/flavours/glitch/actions/timelines.js b/app/javascript/flavours/glitch/actions/timelines.js index 27ca66e51..ffd259d5f 100644 --- a/app/javascript/flavours/glitch/actions/timelines.js +++ b/app/javascript/flavours/glitch/actions/timelines.js @@ -12,34 +12,13 @@ export const TIMELINE_SCROLL_TOP = 'TIMELINE_SCROLL_TOP'; export const TIMELINE_DISCONNECT = 'TIMELINE_DISCONNECT'; -export const TIMELINE_CONTEXT_UPDATE = 'CONTEXT_UPDATE'; - export function updateTimeline(timeline, status) { return (dispatch, getState) => { - const parents = []; - - if (status.in_reply_to_id) { - let parent = getState().getIn(['statuses', status.in_reply_to_id]); - - while (parent && parent.get('in_reply_to_id')) { - parents.push(parent.get('id')); - parent = getState().getIn(['statuses', parent.get('in_reply_to_id')]); - } - } - dispatch({ type: TIMELINE_UPDATE, timeline, status, }); - - if (parents.length > 0) { - dispatch({ - type: TIMELINE_CONTEXT_UPDATE, - status, - references: parents, - }); - } }; }; diff --git a/app/javascript/flavours/glitch/components/error_boundary.js b/app/javascript/flavours/glitch/components/error_boundary.js new file mode 100644 index 000000000..142a0c21a --- /dev/null +++ b/app/javascript/flavours/glitch/components/error_boundary.js @@ -0,0 +1,95 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { FormattedMessage } from 'react-intl'; +import { preferencesLink } from 'flavours/glitch/util/backend_links'; + +export default class ErrorBoundary extends React.PureComponent { + + static propTypes = { + children: PropTypes.node, + }; + + state = { + hasError: false, + stackTrace: undefined, + componentStack: undefined, + } + + componentDidCatch(error, info) { + this.setState({ + hasError: true, + stackTrace: error.stack, + componentStack: info && info.componentStack, + }); + } + + handleReload(e) { + e.preventDefault(); + window.location.reload(); + } + + render() { + const { hasError, stackTrace, componentStack } = this.state; + + if (!hasError) return this.props.children; + + let debugInfo = ''; + if (stackTrace) { + debugInfo += 'Stack trace\n-----------\n\n```\n' + stackTrace.toString() + '\n```'; + } + if (componentStack) { + if (debugInfo) { + debugInfo += '\n\n\n'; + } + debugInfo += 'React component stack\n---------------------\n\n```\n' + componentStack.toString() + '\n```'; + } + + return ( + <div tabIndex='-1'> + <div className='error-boundary'> + <h1><FormattedMessage id='web_app_crash.title' defaultMessage="We're sorry, but something went wrong with the Mastodon app." /></h1> + <p> + <FormattedMessage id='web_app_crash.content' defaultMessage='You could try any of the following:' /> + <ul> + <li> + <FormattedMessage + id='web_app_crash.report_issue' + defaultMessage='Report a bug in the {issuetracker}' + values={{ issuetracker: <a href='https://github.com/glitch-soc/mastodon/issues' rel='noopener' target='_blank'><FormattedMessage id='web_app_crash.issue_tracker' defaultMessage='issue tracker' /></a> }} + /> + { debugInfo !== '' && ( + <details> + <summary><FormattedMessage id='web_app_crash.debug_info' defaultMessage='Debug information' /></summary> + <textarea + className='web_app_crash-stacktrace' + value={debugInfo} + rows='10' + readOnly + /> + </details> + )} + </li> + <li> + <FormattedMessage + id='web_app_crash.reload_page' + defaultMessage='{reload} the current page' + values={{ reload: <a href='#' onClick={this.handleReload}><FormattedMessage id='web_app_crash.reload' defaultMessage='Reload' /></a> }} + /> + </li> + { preferencesLink !== undefined && ( + <li> + <FormattedMessage + id='web_app_crash.change_your_settings' + defaultMessage='Change your {settings}' + values={{ settings: <a href={preferencesLink}><FormattedMessage id='web_app_crash.settings' defaultMessage='settings' /></a> }} + /> + </li> + )} + </ul> + </p> + </div> + </div> + ); + } + +} diff --git a/app/javascript/flavours/glitch/containers/mastodon.js b/app/javascript/flavours/glitch/containers/mastodon.js index 4bd9cb75e..4fb6be476 100644 --- a/app/javascript/flavours/glitch/containers/mastodon.js +++ b/app/javascript/flavours/glitch/containers/mastodon.js @@ -12,6 +12,7 @@ import { connectUserStream } from 'flavours/glitch/actions/streaming'; import { IntlProvider, addLocaleData } from 'react-intl'; import { getLocale } from 'locales'; import initialState from 'flavours/glitch/util/initial_state'; +import ErrorBoundary from 'flavours/glitch/components/error_boundary'; const { localeData, messages } = getLocale(); addLocaleData(localeData); @@ -61,11 +62,13 @@ export default class Mastodon extends React.PureComponent { return ( <IntlProvider locale={locale} messages={messages}> <Provider store={store}> - <BrowserRouter basename='/web'> - <ScrollContext> - <Route path='/' component={UI} /> - </ScrollContext> - </BrowserRouter> + <ErrorBoundary> + <BrowserRouter basename='/web'> + <ScrollContext> + <Route path='/' component={UI} /> + </ScrollContext> + </BrowserRouter> + </ErrorBoundary> </Provider> </IntlProvider> ); diff --git a/app/javascript/flavours/glitch/features/list_timeline/index.js b/app/javascript/flavours/glitch/features/list_timeline/index.js index 2e77ba235..ef829b937 100644 --- a/app/javascript/flavours/glitch/features/list_timeline/index.js +++ b/app/javascript/flavours/glitch/features/list_timeline/index.js @@ -9,7 +9,7 @@ import { addColumn, removeColumn, moveColumn } from 'flavours/glitch/actions/col import { FormattedMessage, defineMessages, injectIntl } from 'react-intl'; import { connectListStream } from 'flavours/glitch/actions/streaming'; import { expandListTimeline } from 'flavours/glitch/actions/timelines'; -import { fetchList, deleteList } from 'flavours/glitch/actions/lists'; +import { fetchList, deleteList, updateList } from 'flavours/glitch/actions/lists'; import { openModal } from 'flavours/glitch/actions/modal'; import MissingIndicator from 'flavours/glitch/components/missing_indicator'; import LoadingIndicator from 'flavours/glitch/components/loading_indicator'; @@ -17,6 +17,9 @@ import LoadingIndicator from 'flavours/glitch/components/loading_indicator'; const messages = defineMessages({ deleteMessage: { id: 'confirmations.delete_list.message', defaultMessage: 'Are you sure you want to permanently delete this list?' }, deleteConfirm: { id: 'confirmations.delete_list.confirm', defaultMessage: 'Delete' }, + all_replies: { id: 'lists.replies_policy.all_replies', defaultMessage: 'any followed user' }, + no_replies: { id: 'lists.replies_policy.no_replies', defaultMessage: 'no one' }, + list_replies: { id: 'lists.replies_policy.list_replies', defaultMessage: 'members of the list' }, }); const mapStateToProps = (state, props) => ({ @@ -111,11 +114,18 @@ export default class ListTimeline extends React.PureComponent { })); } + handleRepliesPolicyChange = ({ target }) => { + const { dispatch, list } = this.props; + const { id } = this.props.params; + this.props.dispatch(updateList(id, undefined, false, target.value)); + } + render () { - const { hasUnread, columnId, multiColumn, list } = this.props; + const { hasUnread, columnId, multiColumn, list, intl } = this.props; const { id } = this.props.params; const pinned = !!columnId; const title = list ? list.get('title') : id; + const replies_policy = list ? list.get('replies_policy') : undefined; if (typeof list === 'undefined') { return ( @@ -157,6 +167,24 @@ export default class ListTimeline extends React.PureComponent { </button> </div> + { replies_policy !== undefined && ( + <div> + <div className='column-settings__row'> + <fieldset> + <legend><FormattedMessage id='lists.replies_policy.title' defaultMessage='Show replies to:' /></legend> + { ['no_replies', 'list_replies', 'all_replies'].map(policy => ( + <div className='setting-radio'> + <input className='setting-radio__input' id={['setting', 'radio', id, policy].join('-')} type='radio' value={policy} checked={replies_policy === policy} onChange={this.handleRepliesPolicyChange} /> + <label className='setting-radio__label' htmlFor={['setting', 'radio', id, policy].join('-')}> + <FormattedMessage {...messages[policy]} /> + </label> + </div> + ))} + </fieldset> + </div> + </div> + )} + <hr /> </ColumnHeader> diff --git a/app/javascript/flavours/glitch/features/status/index.js b/app/javascript/flavours/glitch/features/status/index.js index cfa1450f6..d2d5a05c8 100644 --- a/app/javascript/flavours/glitch/features/status/index.js +++ b/app/javascript/flavours/glitch/features/status/index.js @@ -1,3 +1,4 @@ +import Immutable from 'immutable'; import React from 'react'; import { connect } from 'react-redux'; import PropTypes from 'prop-types'; @@ -57,13 +58,49 @@ const messages = defineMessages({ const makeMapStateToProps = () => { const getStatus = makeGetStatus(); - const mapStateToProps = (state, props) => ({ - status: getStatus(state, { id: props.params.statusId }), - settings: state.get('local_settings'), - ancestorsIds: state.getIn(['contexts', 'ancestors', props.params.statusId]), - descendantsIds: state.getIn(['contexts', 'descendants', props.params.statusId]), - askReplyConfirmation: state.getIn(['compose', 'text']).trim().length !== 0, - }); + const mapStateToProps = (state, props) => { + const status = getStatus(state, { id: props.params.statusId }); + let ancestorsIds = Immutable.List(); + let descendantsIds = Immutable.List(); + + if (status) { + ancestorsIds = ancestorsIds.withMutations(mutable => { + let id = status.get('in_reply_to_id'); + + while (id) { + mutable.unshift(id); + id = state.getIn(['contexts', 'inReplyTos', id]); + } + }); + + descendantsIds = descendantsIds.withMutations(mutable => { + const ids = [status.get('id')]; + + while (ids.length > 0) { + let id = ids.shift(); + const replies = state.getIn(['contexts', 'replies', id]); + + if (status.get('id') !== id) { + mutable.push(id); + } + + if (replies) { + replies.reverse().forEach(reply => { + ids.unshift(reply); + }); + } + } + }); + } + + return { + status, + ancestorsIds, + descendantsIds, + settings: state.get('local_settings'), + askReplyConfirmation: state.getIn(['compose', 'text']).trim().length !== 0, + }; + }; return mapStateToProps; }; @@ -91,26 +128,36 @@ export default class Status extends ImmutablePureComponent { fullscreen: false, isExpanded: undefined, threadExpanded: undefined, + statusId: undefined, }; - componentWillMount () { - this.props.dispatch(fetchStatus(this.props.params.statusId)); - } - componentDidMount () { attachFullscreenListener(this.onFullScreenChange); - } + this.props.dispatch(fetchStatus(this.props.params.statusId)); - componentWillReceiveProps (nextProps) { - if (this.state.isExpanded === undefined) { - const isExpanded = autoUnfoldCW(nextProps.settings, nextProps.status); - if (isExpanded !== undefined) this.setState({ isExpanded: isExpanded }); + const { status, ancestorsIds } = this.props; + + if (status && ancestorsIds && ancestorsIds.size > 0) { + const element = this.node.querySelectorAll('.focusable')[ancestorsIds.size - 1]; + + window.requestAnimationFrame(() => { + element.scrollIntoView(true); + }); } - if (nextProps.params.statusId !== this.props.params.statusId && nextProps.params.statusId) { - this._scrolledIntoView = false; - this.props.dispatch(fetchStatus(nextProps.params.statusId)); - this.setState({ isExpanded: autoUnfoldCW(nextProps.settings, nextProps.status), threadExpanded: undefined }); + } + + static getDerivedStateFromProps(props, state) { + if (state.statusId === props.params.statusId || !props.params.statusId) { + return null; } + + props.dispatch(fetchStatus(props.params.statusId)); + + return { + threadExpanded: undefined, + isExpanded: autoUnfoldCW(props.settings, props.status), + statusId: props.params.statusId, + }; } handleExpandedToggle = () => { @@ -338,20 +385,17 @@ export default class Status extends ImmutablePureComponent { this.node = c; } - componentDidUpdate () { - if (this._scrolledIntoView) { - return; - } - - const { status, ancestorsIds } = this.props; + componentDidUpdate (prevProps) { + if (this.props.params.statusId && (this.props.params.statusId !== prevProps.params.statusId || prevProps.ancestorsIds.size < this.props.ancestorsIds.size)) { + const { status, ancestorsIds } = this.props; - if (status && ancestorsIds && ancestorsIds.size > 0) { - const element = this.node.querySelectorAll('.focusable')[ancestorsIds.size - 1]; + if (status && ancestorsIds && ancestorsIds.size > 0) { + const element = this.node.querySelectorAll('.focusable')[ancestorsIds.size - 1]; - window.requestAnimationFrame(() => { - element.scrollIntoView(true); - }); - this._scrolledIntoView = true; + window.requestAnimationFrame(() => { + element.scrollIntoView(true); + }); + } } } diff --git a/app/javascript/flavours/glitch/features/ui/components/bundle.js b/app/javascript/flavours/glitch/features/ui/components/bundle.js index fc88e0c70..8f0d7b8b1 100644 --- a/app/javascript/flavours/glitch/features/ui/components/bundle.js +++ b/app/javascript/flavours/glitch/features/ui/components/bundle.js @@ -52,6 +52,11 @@ class Bundle extends React.Component { load = (props) => { const { fetchComponent, onFetch, onFetchSuccess, onFetchFail, renderDelay } = props || this.props; + if (fetchComponent === undefined) { + this.setState({ mod: null }); + return Promise.resolve(); + } + onFetch(); if (Bundle.cache[fetchComponent.name]) { diff --git a/app/javascript/flavours/glitch/features/video/index.js b/app/javascript/flavours/glitch/features/video/index.js index 4c2e5e62b..30592707c 100644 --- a/app/javascript/flavours/glitch/features/video/index.js +++ b/app/javascript/flavours/glitch/features/video/index.js @@ -108,6 +108,7 @@ export default class Video extends React.PureComponent { state = { currentTime: 0, duration: 0, + volume: 0.5, paused: true, dragging: false, containerWidth: false, @@ -117,6 +118,15 @@ export default class Video extends React.PureComponent { revealed: this.props.revealed === undefined ? (displayMedia !== 'hide_all' && !this.props.sensitive || displayMedia === 'show_all') : this.props.revealed, }; + // hard coded in components.scss + // any way to get ::before values programatically? + volWidth = 50; + volOffset = 70; + volHandleOffset = v => { + const offset = v * this.volWidth + this.volOffset; + return (offset > 110) ? 110 : offset; + } + setPlayerRef = c => { this.player = c; @@ -135,6 +145,10 @@ export default class Video extends React.PureComponent { this.seek = c; } + setVolumeRef = c => { + this.volume = c; + } + handleMouseDownRoot = e => { e.preventDefault(); e.stopPropagation(); @@ -155,6 +169,43 @@ export default class Video extends React.PureComponent { }); } + handleVolumeMouseDown = e => { + + document.addEventListener('mousemove', this.handleMouseVolSlide, true); + document.addEventListener('mouseup', this.handleVolumeMouseUp, true); + document.addEventListener('touchmove', this.handleMouseVolSlide, true); + document.addEventListener('touchend', this.handleVolumeMouseUp, true); + + this.handleMouseVolSlide(e); + + e.preventDefault(); + e.stopPropagation(); + } + + handleVolumeMouseUp = () => { + document.removeEventListener('mousemove', this.handleMouseVolSlide, true); + document.removeEventListener('mouseup', this.handleVolumeMouseUp, true); + document.removeEventListener('touchmove', this.handleMouseVolSlide, true); + document.removeEventListener('touchend', this.handleVolumeMouseUp, true); + } + + handleMouseVolSlide = throttle(e => { + + const rect = this.volume.getBoundingClientRect(); + const x = (e.clientX - rect.left) / this.volWidth; //x position within the element. + + if(!isNaN(x)) { + var slideamt = x; + if(x > 1) { + slideamt = 1; + } else if(x < 0) { + slideamt = 0; + } + this.video.volume = slideamt; + this.setState({ volume: slideamt }); + } + }, 60); + handleMouseDown = e => { document.addEventListener('mousemove', this.handleMouseMove, true); document.addEventListener('mouseup', this.handleMouseUp, true); @@ -290,10 +341,13 @@ export default class Video extends React.PureComponent { render () { const { preview, src, inline, startTime, onOpenVideo, onCloseVideo, intl, alt, letterbox, fullwidth, detailed, sensitive } = this.props; - const { containerWidth, currentTime, duration, buffer, dragging, paused, fullscreen, hovered, muted, revealed } = this.state; + const { containerWidth, currentTime, duration, volume, buffer, dragging, paused, fullscreen, hovered, muted, revealed } = this.state; const progress = (currentTime / duration) * 100; const playerStyle = {}; + const volumeWidth = (muted) ? 0 : volume * this.volWidth; + const volumeHandleLoc = (muted) ? this.volHandleOffset(0) : this.volHandleOffset(volume); + const computedClass = classNames('video-player', { inactive: !revealed, detailed, inline: inline && !fullscreen, fullscreen, letterbox, 'full-width': fullwidth }); let { width, height } = this.props; @@ -346,6 +400,7 @@ export default class Video extends React.PureComponent { title={alt} width={width} height={height} + volume={volume} onClick={this.togglePlay} onPlay={this.handlePlay} onPause={this.handlePause} @@ -374,9 +429,15 @@ export default class Video extends React.PureComponent { <div className='video-player__buttons-bar'> <div className='video-player__buttons left'> <button type='button' aria-label={intl.formatMessage(paused ? messages.play : messages.pause)} onClick={this.togglePlay}><i className={classNames('fa fa-fw', { 'fa-play': paused, 'fa-pause': !paused })} /></button> - <button type='button' aria-label={intl.formatMessage(muted ? messages.unmute : messages.mute)} onClick={this.toggleMute}><i className={classNames('fa fa-fw', { 'fa-volume-off': muted, 'fa-volume-up': !muted })} /></button> - - {!onCloseVideo && <button type='button' aria-label={intl.formatMessage(messages.hide)} onClick={this.toggleReveal}><i className='fa fa-fw fa-eye' /></button>} + <button type='button' aria-label={intl.formatMessage(muted ? messages.unmute : messages.mute)} onMouseEnter={this.volumeSlider} onMouseLeave={this.volumeSlider} onClick={this.toggleMute}><i className={classNames('fa fa-fw', { 'fa-volume-off': muted, 'fa-volume-up': !muted })} /></button> + <div className='video-player__volume' onMouseDown={this.handleVolumeMouseDown} ref={this.setVolumeRef}> + <div className='video-player__volume__current' style={{ width: `${volumeWidth}px` }} /> + <span + className={classNames('video-player__volume__handle')} + tabIndex='0' + style={{ left: `${volumeHandleLoc}px` }} + /> + </div> {(detailed || fullscreen) && <span> @@ -388,6 +449,7 @@ export default class Video extends React.PureComponent { </div> <div className='video-player__buttons right'> + {!onCloseVideo && <button type='button' aria-label={intl.formatMessage(messages.hide)} onClick={this.toggleReveal}><i className='fa fa-fw fa-eye' /></button>} {(!fullscreen && onOpenVideo) && <button type='button' aria-label={intl.formatMessage(messages.expand)} onClick={this.handleOpenVideo}><i className='fa fa-fw fa-expand' /></button>} {onCloseVideo && <button type='button' aria-label={intl.formatMessage(messages.close)} onClick={this.handleCloseVideo}><i className='fa fa-fw fa-compress' /></button>} <button type='button' aria-label={intl.formatMessage(fullscreen ? messages.exit_fullscreen : messages.fullscreen)} onClick={this.toggleFullscreen}><i className={classNames('fa fa-fw', { 'fa-arrows-alt': !fullscreen, 'fa-compress': fullscreen })} /></button> diff --git a/app/javascript/flavours/glitch/reducers/contexts.js b/app/javascript/flavours/glitch/reducers/contexts.js index effd70756..73b25fe3f 100644 --- a/app/javascript/flavours/glitch/reducers/contexts.js +++ b/app/javascript/flavours/glitch/reducers/contexts.js @@ -3,38 +3,63 @@ import { ACCOUNT_MUTE_SUCCESS, } from 'flavours/glitch/actions/accounts'; import { CONTEXT_FETCH_SUCCESS } from 'flavours/glitch/actions/statuses'; -import { TIMELINE_DELETE, TIMELINE_CONTEXT_UPDATE } from 'flavours/glitch/actions/timelines'; +import { TIMELINE_DELETE, TIMELINE_UPDATE } from 'flavours/glitch/actions/timelines'; import { Map as ImmutableMap, List as ImmutableList } from 'immutable'; +import compareId from 'flavours/glitch/util/compare_id'; const initialState = ImmutableMap({ - ancestors: ImmutableMap(), - descendants: ImmutableMap(), + inReplyTos: ImmutableMap(), + replies: ImmutableMap(), }); -const normalizeContext = (state, id, ancestors, descendants) => { - const ancestorsIds = ImmutableList(ancestors.map(ancestor => ancestor.id)); - const descendantsIds = ImmutableList(descendants.map(descendant => descendant.id)); +const normalizeContext = (immutableState, id, ancestors, descendants) => immutableState.withMutations(state => { + state.update('inReplyTos', immutableAncestors => immutableAncestors.withMutations(inReplyTos => { + state.update('replies', immutableDescendants => immutableDescendants.withMutations(replies => { + function addReply({ id, in_reply_to_id }) { + if (in_reply_to_id && !inReplyTos.has(id)) { - return state.withMutations(map => { - map.setIn(['ancestors', id], ancestorsIds); - map.setIn(['descendants', id], descendantsIds); - }); -}; + replies.update(in_reply_to_id, ImmutableList(), siblings => { + const index = siblings.findLastIndex(sibling => compareId(sibling, id) < 0); + return siblings.insert(index + 1, id); + }); + + inReplyTos.set(id, in_reply_to_id); + } + } + + // We know in_reply_to_id of statuses but `id` itself. + // So we assume that the status of the id replies to last ancestors. + + ancestors.forEach(addReply); + + if (ancestors[0]) { + addReply({ id, in_reply_to_id: ancestors[ancestors.length - 1].id }); + } + + descendants.forEach(addReply); + })); + })); +}); const deleteFromContexts = (immutableState, ids) => immutableState.withMutations(state => { - state.update('ancestors', immutableAncestors => immutableAncestors.withMutations(ancestors => { - state.update('descendants', immutableDescendants => immutableDescendants.withMutations(descendants => { + state.update('inReplyTos', immutableAncestors => immutableAncestors.withMutations(inReplyTos => { + state.update('replies', immutableDescendants => immutableDescendants.withMutations(replies => { ids.forEach(id => { - descendants.get(id, ImmutableList()).forEach(descendantId => { - ancestors.update(descendantId, ImmutableList(), list => list.filterNot(itemId => itemId === id)); - }); + const inReplyToIdOfId = inReplyTos.get(id); + const repliesOfId = replies.get(id); + const siblings = replies.get(inReplyToIdOfId); + + if (siblings) { + replies.set(inReplyToIdOfId, siblings.filterNot(sibling => sibling === id)); + } - ancestors.get(id, ImmutableList()).forEach(ancestorId => { - descendants.update(ancestorId, ImmutableList(), list => list.filterNot(itemId => itemId === id)); - }); - descendants.delete(id); - ancestors.delete(id); + if (repliesOfId) { + repliesOfId.forEach(reply => inReplyTos.delete(reply)); + } + + inReplyTos.delete(id); + replies.delete(id); }); })); })); @@ -47,23 +72,23 @@ const filterContexts = (state, relationship, statuses) => { return deleteFromContexts(state, ownedStatusIds); }; -const updateContext = (state, status, references) => { - return state.update('descendants', map => { - references.forEach(parentId => { - map = map.update(parentId, ImmutableList(), list => { - if (list.includes(status.id)) { - return list; - } +const updateContext = (state, status) => { + if (status.in_reply_to_id) { + return state.withMutations(mutable => { + const replies = mutable.getIn(['replies', status.in_reply_to_id], ImmutableList()); - return list.push(status.id); - }); + mutable.setIn(['inReplyTos', status.id], status.in_reply_to_id); + + if (!replies.includes(status.id)) { + mutable.setIn(['replies', status.in_reply_to_id], replies.push(status.id)); + } }); + } - return map; - }); + return state; }; -export default function contexts(state = initialState, action) { +export default function replies(state = initialState, action) { switch(action.type) { case ACCOUNT_BLOCK_SUCCESS: case ACCOUNT_MUTE_SUCCESS: @@ -72,8 +97,8 @@ export default function contexts(state = initialState, action) { return normalizeContext(state, action.id, action.ancestors, action.descendants); case TIMELINE_DELETE: return deleteFromContexts(state, [action.id]); - case TIMELINE_CONTEXT_UPDATE: - return updateContext(state, action.status, action.references); + case TIMELINE_UPDATE: + return updateContext(state, action.status); default: return state; } diff --git a/app/javascript/flavours/glitch/styles/components/error_boundary.scss b/app/javascript/flavours/glitch/styles/components/error_boundary.scss new file mode 100644 index 000000000..f9bf425f8 --- /dev/null +++ b/app/javascript/flavours/glitch/styles/components/error_boundary.scss @@ -0,0 +1,32 @@ +.error-boundary { + h1 { + font-size: 26px; + line-height: 36px; + font-weight: 400; + margin-bottom: 8px; + } + + p { + color: $primary-text-color; + font-size: 15px; + line-height: 20px; + + a { + color: $primary-text-color; + text-decoration: underline; + } + + ul { + list-style: disc; + margin-left: 0; + padding-left: 1em; + } + + textarea.web_app_crash-stacktrace { + width: 100%; + resize: none; + white-space: pre; + font-family: $font-monospace, monospace; + } + } +} diff --git a/app/javascript/flavours/glitch/styles/components/index.scss b/app/javascript/flavours/glitch/styles/components/index.scss index b16b13d87..873dfa98d 100644 --- a/app/javascript/flavours/glitch/styles/components/index.scss +++ b/app/javascript/flavours/glitch/styles/components/index.scss @@ -1062,6 +1062,7 @@ } .setting-toggle__label, +.setting-radio__label, .setting-meta__label { color: $darker-text-color; display: inline-block; @@ -1070,6 +1071,27 @@ vertical-align: middle; } +.setting-radio { + display: block; + line-height: 18px; +} + +.setting-radio__label { + margin-bottom: 0; +} + +.column-settings__row legend { + color: $darker-text-color; + cursor: default; + display: block; + font-weight: 500; + margin-top: 10px; +} + +.setting-radio__input { + vertical-align: middle; +} + .setting-meta__label { float: right; } @@ -1241,3 +1263,4 @@ noscript { @import 'lists'; @import 'emoji_picker'; @import 'local_settings'; +@import 'error_boundary'; diff --git a/app/javascript/flavours/glitch/styles/components/media.scss b/app/javascript/flavours/glitch/styles/components/media.scss index 40a144de4..e8011bde9 100644 --- a/app/javascript/flavours/glitch/styles/components/media.scss +++ b/app/javascript/flavours/glitch/styles/components/media.scss @@ -277,6 +277,19 @@ z-index: 100; } +.detailed, +.fullscreen { + .video-player__volume__current, + .video-player__volume::before { + bottom: 27px; + } + + .video-player__volume__handle { + bottom: 23px; + } + +} + .video-player { overflow: hidden; position: relative; @@ -432,7 +445,7 @@ &__time-current { color: $white; - margin-left: 10px; + margin-left: 60px; } &__time-sep { @@ -445,6 +458,48 @@ color: $white; } + &__volume { + cursor: pointer; + height: 24px; + display: inline; + + &::before { + content: ""; + width: 50px; + background: rgba($white, 0.35); + border-radius: 4px; + display: block; + position: absolute; + height: 4px; + left: 70px; + bottom: 20px; + } + + &__current { + display: block; + position: absolute; + height: 4px; + border-radius: 4px; + left: 70px; + bottom: 20px; + background: lighten($ui-highlight-color, 8%); + } + + &__handle { + position: absolute; + z-index: 3; + border-radius: 50%; + width: 12px; + height: 12px; + bottom: 16px; + left: 70px; + transition: opacity .1s ease; + background: lighten($ui-highlight-color, 8%); + box-shadow: 1px 2px 6px rgba($base-shadow-color, 0.2); + pointer-events: none; + } + } + &__seek { cursor: pointer; height: 24px; diff --git a/app/javascript/flavours/glitch/styles/forms.scss b/app/javascript/flavours/glitch/styles/forms.scss index 46ef85774..4f96204f2 100644 --- a/app/javascript/flavours/glitch/styles/forms.scss +++ b/app/javascript/flavours/glitch/styles/forms.scss @@ -266,7 +266,7 @@ code { font-family: inherit; font-size: 14px; color: $primary-text-color; - display: block; + display: inline-block; width: auto; position: relative; padding-top: 5px; diff --git a/app/javascript/mastodon/actions/timelines.js b/app/javascript/mastodon/actions/timelines.js index 81c4c8425..215adc4ea 100644 --- a/app/javascript/mastodon/actions/timelines.js +++ b/app/javascript/mastodon/actions/timelines.js @@ -15,7 +15,7 @@ export const TIMELINE_SCROLL_TOP = 'TIMELINE_SCROLL_TOP'; export const TIMELINE_DISCONNECT = 'TIMELINE_DISCONNECT'; export function updateTimeline(timeline, status, accept) { - return (dispatch, getState) => { + return dispatch => { if (typeof accept === 'function' && !accept(status)) { return; } diff --git a/app/javascript/mastodon/features/hashtag_timeline/components/column_settings.js b/app/javascript/mastodon/features/hashtag_timeline/components/column_settings.js index 82936c838..9c9f62d82 100644 --- a/app/javascript/mastodon/features/hashtag_timeline/components/column_settings.js +++ b/app/javascript/mastodon/features/hashtag_timeline/components/column_settings.js @@ -5,8 +5,8 @@ import { injectIntl, FormattedMessage } from 'react-intl'; import Toggle from 'react-toggle'; import AsyncSelect from 'react-select/lib/Async'; -@injectIntl -export default class ColumnSettings extends React.PureComponent { +export default @injectIntl +class ColumnSettings extends React.PureComponent { static propTypes = { settings: ImmutablePropTypes.map.isRequired, diff --git a/app/javascript/mastodon/features/hashtag_timeline/index.js b/app/javascript/mastodon/features/hashtag_timeline/index.js index 86658cb66..c2e026d13 100644 --- a/app/javascript/mastodon/features/hashtag_timeline/index.js +++ b/app/javascript/mastodon/features/hashtag_timeline/index.js @@ -9,6 +9,7 @@ import { expandHashtagTimeline, clearTimeline } from '../../actions/timelines'; import { addColumn, removeColumn, moveColumn } from '../../actions/columns'; import { FormattedMessage } from 'react-intl'; import { connectHashtagStream } from '../../actions/streaming'; +import { isEqual } from 'lodash'; const mapStateToProps = (state, props) => ({ hasUnread: state.getIn(['timelines', `hashtag:${props.params.id}`, 'unread']) > 0, @@ -41,13 +42,13 @@ class HashtagTimeline extends React.PureComponent { title = () => { let title = [this.props.params.id]; if (this.additionalFor('any')) { - title.push(<FormattedMessage id='hashtag.column_header.tag_mode.any' values={{ additional: this.additionalFor('any') }} defaultMessage=' or {additional}' />); + title.push(' ', <FormattedMessage id='hashtag.column_header.tag_mode.any' values={{ additional: this.additionalFor('any') }} defaultMessage='or {additional}' />); } if (this.additionalFor('all')) { - title.push(<FormattedMessage id='hashtag.column_header.tag_mode.all' values={{ additional: this.additionalFor('all') }} defaultMessage=' and {additional}' />); + title.push(' ', <FormattedMessage id='hashtag.column_header.tag_mode.all' values={{ additional: this.additionalFor('all') }} defaultMessage='and {additional}' />); } if (this.additionalFor('none')) { - title.push(<FormattedMessage id='hashtag.column_header.tag_mode.none' values={{ additional: this.additionalFor('none') }} defaultMessage=' without {additional}' />); + title.push(' ', <FormattedMessage id='hashtag.column_header.tag_mode.none' values={{ additional: this.additionalFor('none') }} defaultMessage='without {additional}' />); } return title; } @@ -100,7 +101,7 @@ class HashtagTimeline extends React.PureComponent { componentWillReceiveProps (nextProps) { const { dispatch, params } = this.props; const { id, tags } = nextProps.params; - if (id !== params.id || tags !== params.tags) { + if (id !== params.id || !isEqual(tags, params.tags)) { this._unsubscribe(); this._subscribe(dispatch, id, tags); this.props.dispatch(clearTimeline(`hashtag:${id}`)); diff --git a/app/javascript/mastodon/features/video/index.js b/app/javascript/mastodon/features/video/index.js index 67f7580b9..3650fddb6 100644 --- a/app/javascript/mastodon/features/video/index.js +++ b/app/javascript/mastodon/features/video/index.js @@ -105,6 +105,7 @@ class Video extends React.PureComponent { state = { currentTime: 0, duration: 0, + volume: 0.5, paused: true, dragging: false, containerWidth: false, @@ -114,6 +115,15 @@ class Video extends React.PureComponent { revealed: displayMedia !== 'hide_all' && !this.props.sensitive || displayMedia === 'show_all', }; + // hard coded in components.scss + // any way to get ::before values programatically? + volWidth = 50; + volOffset = 70; + volHandleOffset = v => { + const offset = v * this.volWidth + this.volOffset; + return (offset > 110) ? 110 : offset; + } + setPlayerRef = c => { this.player = c; @@ -132,6 +142,10 @@ class Video extends React.PureComponent { this.seek = c; } + setVolumeRef = c => { + this.volume = c; + } + handleClickRoot = e => e.stopPropagation(); handlePlay = () => { @@ -149,6 +163,43 @@ class Video extends React.PureComponent { }); } + handleVolumeMouseDown = e => { + + document.addEventListener('mousemove', this.handleMouseVolSlide, true); + document.addEventListener('mouseup', this.handleVolumeMouseUp, true); + document.addEventListener('touchmove', this.handleMouseVolSlide, true); + document.addEventListener('touchend', this.handleVolumeMouseUp, true); + + this.handleMouseVolSlide(e); + + e.preventDefault(); + e.stopPropagation(); + } + + handleVolumeMouseUp = () => { + document.removeEventListener('mousemove', this.handleMouseVolSlide, true); + document.removeEventListener('mouseup', this.handleVolumeMouseUp, true); + document.removeEventListener('touchmove', this.handleMouseVolSlide, true); + document.removeEventListener('touchend', this.handleVolumeMouseUp, true); + } + + handleMouseVolSlide = throttle(e => { + + const rect = this.volume.getBoundingClientRect(); + const x = (e.clientX - rect.left) / this.volWidth; //x position within the element. + + if(!isNaN(x)) { + var slideamt = x; + if(x > 1) { + slideamt = 1; + } else if(x < 0) { + slideamt = 0; + } + this.video.volume = slideamt; + this.setState({ volume: slideamt }); + } + }, 60); + handleMouseDown = e => { document.addEventListener('mousemove', this.handleMouseMove, true); document.addEventListener('mouseup', this.handleMouseUp, true); @@ -273,8 +324,11 @@ class Video extends React.PureComponent { render () { const { preview, src, inline, startTime, onOpenVideo, onCloseVideo, intl, alt, detailed, sensitive } = this.props; - const { containerWidth, currentTime, duration, buffer, dragging, paused, fullscreen, hovered, muted, revealed } = this.state; + const { containerWidth, currentTime, duration, volume, buffer, dragging, paused, fullscreen, hovered, muted, revealed } = this.state; const progress = (currentTime / duration) * 100; + + const volumeWidth = (muted) ? 0 : volume * this.volWidth; + const volumeHandleLoc = (muted) ? this.volHandleOffset(0) : this.volHandleOffset(volume); const playerStyle = {}; let { width, height } = this.props; @@ -326,6 +380,7 @@ class Video extends React.PureComponent { title={alt} width={width} height={height} + volume={volume} onClick={this.togglePlay} onPlay={this.handlePlay} onPause={this.handlePause} @@ -354,9 +409,15 @@ class Video extends React.PureComponent { <div className='video-player__buttons-bar'> <div className='video-player__buttons left'> <button type='button' aria-label={intl.formatMessage(paused ? messages.play : messages.pause)} onClick={this.togglePlay}><i className={classNames('fa fa-fw', { 'fa-play': paused, 'fa-pause': !paused })} /></button> - <button type='button' aria-label={intl.formatMessage(muted ? messages.unmute : messages.mute)} onClick={this.toggleMute}><i className={classNames('fa fa-fw', { 'fa-volume-off': muted, 'fa-volume-up': !muted })} /></button> - - {!onCloseVideo && <button type='button' aria-label={intl.formatMessage(messages.hide)} onClick={this.toggleReveal}><i className='fa fa-fw fa-eye' /></button>} + <button type='button' aria-label={intl.formatMessage(muted ? messages.unmute : messages.mute)} onMouseEnter={this.volumeSlider} onMouseLeave={this.volumeSlider} onClick={this.toggleMute}><i className={classNames('fa fa-fw', { 'fa-volume-off': muted, 'fa-volume-up': !muted })} /></button> + <div className='video-player__volume' onMouseDown={this.handleVolumeMouseDown} ref={this.setVolumeRef}> + <div className='video-player__volume__current' style={{ width: `${volumeWidth}px` }} /> + <span + className={classNames('video-player__volume__handle')} + tabIndex='0' + style={{ left: `${volumeHandleLoc}px` }} + /> + </div> {(detailed || fullscreen) && <span> @@ -368,6 +429,7 @@ class Video extends React.PureComponent { </div> <div className='video-player__buttons right'> + {!onCloseVideo && <button type='button' aria-label={intl.formatMessage(messages.hide)} onClick={this.toggleReveal}><i className='fa fa-fw fa-eye' /></button>} {(!fullscreen && onOpenVideo) && <button type='button' aria-label={intl.formatMessage(messages.expand)} onClick={this.handleOpenVideo}><i className='fa fa-fw fa-expand' /></button>} {onCloseVideo && <button type='button' aria-label={intl.formatMessage(messages.close)} onClick={this.handleCloseVideo}><i className='fa fa-fw fa-compress' /></button>} <button type='button' aria-label={intl.formatMessage(fullscreen ? messages.exit_fullscreen : messages.fullscreen)} onClick={this.toggleFullscreen}><i className={classNames('fa fa-fw', { 'fa-arrows-alt': !fullscreen, 'fa-compress': fullscreen })} /></button> diff --git a/app/javascript/mastodon/locales/ar.json b/app/javascript/mastodon/locales/ar.json index 8cd9ba773..2d73f84e0 100644 --- a/app/javascript/mastodon/locales/ar.json +++ b/app/javascript/mastodon/locales/ar.json @@ -93,7 +93,7 @@ "confirmations.redraft.confirm": "إزالة و إعادة الصياغة", "confirmations.redraft.message": "هل أنت متأكد من أنك تريد حذف هذا المنشور و إعادة صياغته ؟ سوف تفقد جميع الإعجابات و الترقيات أما الردود المتصلة به فستُصبِح يتيمة.", "confirmations.reply.confirm": "رد", - "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?", + "confirmations.reply.message": "الرد في الحين سوف يُعيد كتابة الرسالة التي أنت بصدد كتابتها. متأكد من أنك تريد المواصلة؟", "confirmations.unfollow.confirm": "إلغاء المتابعة", "confirmations.unfollow.message": "متأكد من أنك تريد إلغاء متابعة {name} ؟", "embed.instructions": "يمكنكم إدماج هذا المنشور على موقعكم الإلكتروني عن طريق نسخ الشفرة أدناه.", @@ -112,6 +112,7 @@ "emoji_button.search_results": "نتائج البحث", "emoji_button.symbols": "رموز", "emoji_button.travel": "أماكن و أسفار", + "empty_column.account_timeline": "No toots here!", "empty_column.blocks": "لم تقم بحظر أي مستخدِم بعد.", "empty_column.community": "الخط الزمني المحلي فارغ. أكتب شيئا ما للعامة كبداية !", "empty_column.direct": "لم تتلق أية رسالة خاصة مباشِرة بعد. سوف يتم عرض الرسائل المباشرة هنا إن قمت بإرسال واحدة أو تلقيت البعض منها.", @@ -137,6 +138,13 @@ "getting_started.open_source_notice": "ماستدون برنامج مفتوح المصدر. يمكنك المساهمة، أو الإبلاغ عن تقارير الأخطاء، على جيت هب {github}.", "getting_started.security": "الأمان", "getting_started.terms": "شروط الخدمة", + "hashtag.column_header.tag_mode.all": "and {additional}", + "hashtag.column_header.tag_mode.any": "or {additional}", + "hashtag.column_header.tag_mode.none": "without {additional}", + "hashtag.column_settings.tag_mode.all": "All of these", + "hashtag.column_settings.tag_mode.any": "Any of these", + "hashtag.column_settings.tag_mode.none": "None of these", + "hashtag.column_settings.tag_toggle": "Include additional tags in this column", "home.column_settings.basic": "أساسية", "home.column_settings.show_reblogs": "عرض الترقيات", "home.column_settings.show_replies": "عرض الردود", @@ -313,10 +321,11 @@ "status.show_less_all": "طي الكل", "status.show_more": "أظهر المزيد", "status.show_more_all": "توسيع الكل", + "status.show_thread": "Show thread", "status.unmute_conversation": "فك الكتم عن المحادثة", "status.unpin": "فك التدبيس من الملف الشخصي", - "suggestions.dismiss": "Dismiss suggestion", - "suggestions.header": "You might be interested in…", + "suggestions.dismiss": "إلغاء الإقتراح", + "suggestions.header": "يمكن أن يهمك…", "tabs_bar.federated_timeline": "الموحَّد", "tabs_bar.home": "الرئيسية", "tabs_bar.local_timeline": "المحلي", diff --git a/app/javascript/mastodon/locales/ast.json b/app/javascript/mastodon/locales/ast.json index ab0f5b892..e22c46e9e 100644 --- a/app/javascript/mastodon/locales/ast.json +++ b/app/javascript/mastodon/locales/ast.json @@ -2,19 +2,19 @@ "account.add_or_remove_from_list": "Add or Remove from lists", "account.badges.bot": "Robó", "account.block": "Bloquiar a @{name}", - "account.block_domain": "Hide everything from {domain}", + "account.block_domain": "Anubrir tolo de {domain}", "account.blocked": "Blocked", "account.direct": "Unviar un mensaxe direutu a @{name}", - "account.disclaimer_full": "Information below may reflect the user's profile incompletely.", - "account.domain_blocked": "Domain hidden", - "account.edit_profile": "Editar perfil", - "account.endorse": "Feature on profile", + "account.disclaimer_full": "La información d'embaxo podría reflexar de mou incompletu'l perfil del usuariu.", + "account.domain_blocked": "Dominiu anubríu", + "account.edit_profile": "Editar el perfil", + "account.endorse": "Destacar nel perfil", "account.follow": "Follow", "account.followers": "Siguidores", - "account.followers.empty": "No one follows this user yet.", - "account.follows": "Follows", + "account.followers.empty": "Naide sigue a esti usuariu entá.", + "account.follows": "Sigue a", "account.follows.empty": "Esti usuariu entá nun sigue a naide.", - "account.follows_you": "Follows you", + "account.follows_you": "Síguete", "account.hide_reblogs": "Hide boosts from @{name}", "account.link_verified_on": "Ownership of this link was checked on {date}", "account.media": "Media", @@ -30,12 +30,12 @@ "account.share": "Share @{name}'s profile", "account.show_reblogs": "Show boosts from @{name}", "account.unblock": "Desbloquiar a @{name}", - "account.unblock_domain": "Unhide {domain}", + "account.unblock_domain": "Amosar {domain}", "account.unendorse": "Don't feature on profile", "account.unfollow": "Unfollow", "account.unmute": "Unmute @{name}", "account.unmute_notifications": "Unmute notifications from @{name}", - "account.view_full_profile": "View full profile", + "account.view_full_profile": "Ver el perfil completu", "alert.unexpected.message": "Asocedió un fallu inesperáu.", "alert.unexpected.title": "¡Ups!", "boost_modal.combo": "Pues primir {combo} pa saltar esto la próxima vegada", @@ -46,7 +46,7 @@ "bundle_modal_error.message": "Something went wrong while loading this component.", "bundle_modal_error.retry": "Try again", "column.blocks": "Usuarios bloquiaos", - "column.community": "Local timeline", + "column.community": "Llinia temporal llocal", "column.direct": "Mensaxes direutos", "column.domain_blocks": "Dominios anubríos", "column.favourites": "Favoritos", @@ -61,7 +61,7 @@ "column_header.hide_settings": "Hide settings", "column_header.moveLeft_settings": "Mover la columna a la esquierda", "column_header.moveRight_settings": "Mover la columna a la drecha", - "column_header.pin": "Pin", + "column_header.pin": "Fixar", "column_header.show_settings": "Show settings", "column_header.unpin": "Desfixar", "column_subheading.settings": "Axustes", @@ -84,47 +84,48 @@ "confirmations.block.message": "¿De xuru que quies bloquiar a {name}?", "confirmations.delete.confirm": "Delete", "confirmations.delete.message": "¿De xuru que quies desaniciar esti estáu?", - "confirmations.delete_list.confirm": "Delete", + "confirmations.delete_list.confirm": "Desaniciar", "confirmations.delete_list.message": "¿De xuru que quies desaniciar dafechu esta llista?", - "confirmations.domain_block.confirm": "Hide entire domain", + "confirmations.domain_block.confirm": "Anubrir tol dominiu", "confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable. You will not see content from that domain in any public timelines or your notifications. Your followers from that domain will be removed.", "confirmations.mute.confirm": "Mute", "confirmations.mute.message": "¿De xuru que quies silenciar a {name}?", - "confirmations.redraft.confirm": "Delete & redraft", + "confirmations.redraft.confirm": "Desaniciar y reeditar", "confirmations.redraft.message": "Are you sure you want to delete this status and re-draft it? You will lose all replies, boosts and favourites to it.", "confirmations.reply.confirm": "Reply", "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?", "confirmations.unfollow.confirm": "Unfollow", - "confirmations.unfollow.message": "Are you sure you want to unfollow {name}?", - "embed.instructions": "Embed this status on your website by copying the code below.", - "embed.preview": "Here is what it will look like:", - "emoji_button.activity": "Actividá", + "confirmations.unfollow.message": "¿De xuru que quies dexar de siguir a {name}?", + "embed.instructions": "Empotra esti estáu nun sitiu web copiando'l códigu d'embaxo.", + "embed.preview": "Asina ye como va vese:", + "emoji_button.activity": "Actividaes", "emoji_button.custom": "Custom", "emoji_button.flags": "Banderes", - "emoji_button.food": "Comída y bébora", + "emoji_button.food": "Comida y bébora", "emoji_button.label": "Insert emoji", "emoji_button.nature": "Natura", "emoji_button.not_found": "¡Nun hai fustaxes! (╯°□°)╯︵ ┻━┻", "emoji_button.objects": "Oxetos", "emoji_button.people": "Xente", - "emoji_button.recent": "Frequently used", - "emoji_button.search": "Search...", + "emoji_button.recent": "Úsase davezu", + "emoji_button.search": "Guetar...", "emoji_button.search_results": "Search results", "emoji_button.symbols": "Símbolos", "emoji_button.travel": "Viaxes y llugares", + "empty_column.account_timeline": "No toots here!", "empty_column.blocks": "Entá nun bloquiesti a dengún usuariu.", "empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!", - "empty_column.direct": "Entá nun tienes dengún mensaxe direutu. Cuando unvies o recibas dalgún, va apaecer equí", + "empty_column.direct": "Entá nun tienes dengún mensaxe direutu. Cuando unvies o recibas dalgún, va apaecer equí.", "empty_column.domain_blocks": "Entá nun hai dominios anubríos.", "empty_column.favourited_statuses": "You don't have any favourite toots yet. When you favourite one, it will show up here.", "empty_column.favourites": "No one has favourited this toot yet. When someone does, they will show up here.", "empty_column.follow_requests": "Entá nun tienes denguna solicitú de siguimientu. Cuando recibas una, va amosase equí.", "empty_column.hashtag": "There is nothing in this hashtag yet.", - "empty_column.home": "Your home timeline is empty! Visit {public} or use search to get started and meet other users.", + "empty_column.home": "¡Tienes la llinia temporal balera! Visita {public} o usa la gueta pa entamar y conocer a otros usuarios.", "empty_column.home.public_timeline": "la llinia temporal pública", - "empty_column.list": "There is nothing in this list yet. When members of this list post new statuses, they will appear here.", + "empty_column.list": "Entá nun hai nada nesta llista. Cuando los miembros d'esta llista espublicen estaos nuevos, van apaecer equí.", "empty_column.lists": "Entá nun tienes denguna llista. Cuando crees una, va amosase equí.", - "empty_column.mutes": "Enta nun silenciesti a dengún usuariu.", + "empty_column.mutes": "Entá nun silenciesti a dengún usuariu.", "empty_column.notifications": "Entá nun tienes dengún avisu. Interactua con otros p'aniciar la conversación.", "empty_column.public": "There is nothing here! Write something publicly, or manually follow users from other instances to fill it up", "follow_request.authorize": "Autorizar", @@ -132,17 +133,24 @@ "getting_started.developers": "Desendolcadores", "getting_started.documentation": "Documentación", "getting_started.find_friends": "Alcontrar collacios de Twitter", - "getting_started.heading": "Getting started", + "getting_started.heading": "Entamu", "getting_started.invite": "Convidar xente", "getting_started.open_source_notice": "Mastodon ye software de códigu abiertu. Pues collaborar o informar de fallos en {github} (GitHub).", "getting_started.security": "Seguranza", "getting_started.terms": "Términos del serviciu", + "hashtag.column_header.tag_mode.all": "and {additional}", + "hashtag.column_header.tag_mode.any": "or {additional}", + "hashtag.column_header.tag_mode.none": "without {additional}", + "hashtag.column_settings.tag_mode.all": "All of these", + "hashtag.column_settings.tag_mode.any": "Any of these", + "hashtag.column_settings.tag_mode.none": "None of these", + "hashtag.column_settings.tag_toggle": "Include additional tags in this column", "home.column_settings.basic": "Basic", - "home.column_settings.show_reblogs": "Show boosts", - "home.column_settings.show_replies": "Show replies", + "home.column_settings.show_reblogs": "Amosar toots compartíos", + "home.column_settings.show_replies": "Amosar rempuestes", "keyboard_shortcuts.back": "pa dir p'atrás", "keyboard_shortcuts.blocked": "p'abrir la llista d'usuarios bloquiaos", - "keyboard_shortcuts.boost": "to boost", + "keyboard_shortcuts.boost": "pa compartir un toot", "keyboard_shortcuts.column": "to focus a status in one of the columns", "keyboard_shortcuts.compose": "to focus the compose textarea", "keyboard_shortcuts.description": "Descripción", @@ -174,29 +182,29 @@ "lightbox.close": "Close", "lightbox.next": "Siguiente", "lightbox.previous": "Previous", - "lists.account.add": "Add to list", - "lists.account.remove": "Remove from list", - "lists.delete": "Delete list", - "lists.edit": "Edit list", + "lists.account.add": "Amestar a la llista", + "lists.account.remove": "Desaniciar de la llista", + "lists.delete": "Desaniciar la llista", + "lists.edit": "Editar la llista", "lists.new.create": "Add list", - "lists.new.title_placeholder": "New list title", - "lists.search": "Search among people you follow", - "lists.subheading": "Your lists", - "loading_indicator.label": "Loading...", + "lists.new.title_placeholder": "Títulu nuevu de la llista", + "lists.search": "Guetar ente la xente que sigues", + "lists.subheading": "Les tos llistes", + "loading_indicator.label": "Cargando...", "media_gallery.toggle_visible": "Toggle visibility", "missing_indicator.label": "Nun s'alcontró", "missing_indicator.sublabel": "Esti recursu nun pudo alcontrase", "mute_modal.hide_notifications": "Hide notifications from this user?", - "navigation_bar.apps": "Aplicaciones móviles", + "navigation_bar.apps": "Aplicaciones pa móviles", "navigation_bar.blocks": "Usuarios bloquiaos", - "navigation_bar.community_timeline": "Local timeline", + "navigation_bar.community_timeline": "Llinia temporal llocal", "navigation_bar.compose": "Compose new toot", "navigation_bar.direct": "Mensaxes direutos", "navigation_bar.discover": "Discover", "navigation_bar.domain_blocks": "Dominios anubríos", - "navigation_bar.edit_profile": "Editar perfil", + "navigation_bar.edit_profile": "Editar el perfil", "navigation_bar.favourites": "Favoritos", - "navigation_bar.filters": "Muted words", + "navigation_bar.filters": "Pallabres silenciaes", "navigation_bar.follow_requests": "Solicitúes de siguimientu", "navigation_bar.info": "Tocante a esta instancia", "navigation_bar.keyboard_shortcuts": "Atayos", @@ -211,15 +219,15 @@ "notification.favourite": "{name} favourited your status", "notification.follow": "{name} siguióte", "notification.mention": "{name} mentóte", - "notification.reblog": "{name} boosted your status", + "notification.reblog": "{name} compartió'l to estáu", "notifications.clear": "Llimpiar avisos", "notifications.clear_confirmation": "¿De xuru que quies llimpiar dafechu tolos avisos?", "notifications.column_settings.alert": "Avisos d'escritoriu", - "notifications.column_settings.favourite": "Favourites:", + "notifications.column_settings.favourite": "Favoritos:", "notifications.column_settings.follow": "Siguidores nuevos:", "notifications.column_settings.mention": "Menciones:", "notifications.column_settings.push": "Push notifications", - "notifications.column_settings.reblog": "Boosts:", + "notifications.column_settings.reblog": "Toots compartíos:", "notifications.column_settings.show": "Amosar en columna", "notifications.column_settings.sound": "Reproducir soníu", "notifications.group": "{count} avisos", @@ -239,7 +247,7 @@ "onboarding.page_six.github": "Mastodon is free open-source software. You can report bugs, request features, or contribute to the code on {github}.", "onboarding.page_six.guidelines": "community guidelines", "onboarding.page_six.read_guidelines": "Please read {domain}'s {guidelines}!", - "onboarding.page_six.various_app": "aplicaciones móviles", + "onboarding.page_six.various_app": "aplicaciones pa móviles", "onboarding.page_three.profile": "Edit your profile to change your avatar, bio, and display name. There, you will also find other preferences.", "onboarding.page_three.search": "Use the search bar to find people and look at hashtags, such as {illustration} and {introductions}. To look for a person who is not on this instance, use their full handle.", "onboarding.page_two.compose": "Write posts from the compose column. You can upload images, change privacy settings, and add content warnings with the icons below.", @@ -253,7 +261,7 @@ "privacy.public.short": "Public", "privacy.unlisted.long": "Do not show in public timelines", "privacy.unlisted.short": "Unlisted", - "regeneration_indicator.label": "Loading…", + "regeneration_indicator.label": "Cargando…", "regeneration_indicator.sublabel": "Your home feed is being prepared!", "relative_time.days": "{number}d", "relative_time.hours": "{number}h", @@ -268,20 +276,20 @@ "report.submit": "Submit", "report.target": "Report {target}", "search.placeholder": "Search", - "search_popout.search_format": "Advanced search format", + "search_popout.search_format": "Formatu de gueta avanzada", "search_popout.tips.full_text": "Simple text returns statuses you have written, favourited, boosted, or have been mentioned in, as well as matching usernames, display names, and hashtags.", "search_popout.tips.hashtag": "etiqueta", "search_popout.tips.status": "estáu", "search_popout.tips.text": "Simple text returns matching display names, usernames and hashtags", "search_popout.tips.user": "usuariu", "search_results.accounts": "Xente", - "search_results.hashtags": "Hashtags", + "search_results.hashtags": "Etiquetes", "search_results.statuses": "Toots", "search_results.total": "{count, number} {count, plural, one {result} other {results}}", "standalone.public_title": "A look inside...", "status.block": "Bloquiar a @{name}", - "status.cancel_reblog_private": "Unboost", - "status.cannot_reblog": "This post cannot be boosted", + "status.cancel_reblog_private": "Dexar de compartir", + "status.cannot_reblog": "Esti artículu nun pue compartise", "status.delete": "Delete", "status.detailed_status": "Detailed conversation view", "status.direct": "Unviar un mensaxe direutu a @{name}", @@ -289,54 +297,55 @@ "status.favourite": "Favourite", "status.filtered": "Filtered", "status.load_more": "Cargar más", - "status.media_hidden": "Media hidden", + "status.media_hidden": "Mediu anubríu", "status.mention": "Mentar a @{name}", "status.more": "Más", "status.mute": "Silenciar a @{name}", - "status.mute_conversation": "Mute conversation", + "status.mute_conversation": "Silenciar la conversación", "status.open": "Espander esti estáu", - "status.pin": "Pin on profile", - "status.pinned": "Pinned toot", + "status.pin": "Fixar nel perfil", + "status.pinned": "Toot fixáu", "status.read_more": "Read more", - "status.reblog": "Boost", - "status.reblog_private": "Boost to original audience", - "status.reblogged_by": "{name} boosted", - "status.reblogs.empty": "No one has boosted this toot yet. When someone does, they will show up here.", - "status.redraft": "Delete & re-draft", + "status.reblog": "Compartir", + "status.reblog_private": "Compartir cola audiencia orixinal", + "status.reblogged_by": "{name} compartió", + "status.reblogs.empty": "Naide nun compartió esti toot entá. Cuando daquién lo faiga, va amosase equí.", + "status.redraft": "Desaniciar y reeditar", "status.reply": "Responder", "status.replyAll": "Reply to thread", "status.report": "Report @{name}", - "status.sensitive_toggle": "Click to view", - "status.sensitive_warning": "Sensitive content", + "status.sensitive_toggle": "Fai clic pa velu", + "status.sensitive_warning": "Conteníu sensible", "status.share": "Share", "status.show_less": "Amosar menos", "status.show_less_all": "Show less for all", "status.show_more": "Amosar más", "status.show_more_all": "Show more for all", + "status.show_thread": "Show thread", "status.unmute_conversation": "Unmute conversation", - "status.unpin": "Unpin from profile", + "status.unpin": "Desfixar del perfil", "suggestions.dismiss": "Dismiss suggestion", "suggestions.header": "You might be interested in…", "tabs_bar.federated_timeline": "Federated", "tabs_bar.home": "Aniciu", - "tabs_bar.local_timeline": "Local", + "tabs_bar.local_timeline": "Llocal", "tabs_bar.notifications": "Avisos", "tabs_bar.search": "Search", "trends.count_by_accounts": "{count} {rawCount, plural, one {person} other {people}} talking", "ui.beforeunload": "El borrador va perdese si coles de Mastodon.", "upload_area.title": "Drag & drop to upload", "upload_button.label": "Add media", - "upload_form.description": "Describe for the visually impaired", + "upload_form.description": "Descripción pa discapacitaos visuales", "upload_form.focus": "Crop", - "upload_form.undo": "Delete", - "upload_progress.label": "Uploading...", - "video.close": "Close video", - "video.exit_fullscreen": "Exit full screen", - "video.expand": "Expand video", - "video.fullscreen": "Full screen", - "video.hide": "Hide video", - "video.mute": "Mute sound", - "video.pause": "Pause", - "video.play": "Play", + "upload_form.undo": "Desaniciar", + "upload_progress.label": "Xubiendo...", + "video.close": "Zarrar el videu", + "video.exit_fullscreen": "Colar de la pantalla completa", + "video.expand": "Espander el videu", + "video.fullscreen": "Pantalla completa", + "video.hide": "Anubrir el videu", + "video.mute": "Silenciar el soníu", + "video.pause": "Posar", + "video.play": "Reproducir", "video.unmute": "Unmute sound" } diff --git a/app/javascript/mastodon/locales/bg.json b/app/javascript/mastodon/locales/bg.json index 853361b80..1a5a70593 100644 --- a/app/javascript/mastodon/locales/bg.json +++ b/app/javascript/mastodon/locales/bg.json @@ -112,6 +112,7 @@ "emoji_button.search_results": "Search results", "emoji_button.symbols": "Symbols", "emoji_button.travel": "Travel & Places", + "empty_column.account_timeline": "No toots here!", "empty_column.blocks": "You haven't blocked any users yet.", "empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!", "empty_column.direct": "You don't have any direct messages yet. When you send or receive one, it will show up here.", @@ -137,6 +138,13 @@ "getting_started.open_source_notice": "Mastodon е софтуер с отворен код. Можеш да помогнеш или да докладваш за проблеми в Github: {github}.", "getting_started.security": "Security", "getting_started.terms": "Terms of service", + "hashtag.column_header.tag_mode.all": "and {additional}", + "hashtag.column_header.tag_mode.any": "or {additional}", + "hashtag.column_header.tag_mode.none": "without {additional}", + "hashtag.column_settings.tag_mode.all": "All of these", + "hashtag.column_settings.tag_mode.any": "Any of these", + "hashtag.column_settings.tag_mode.none": "None of these", + "hashtag.column_settings.tag_toggle": "Include additional tags in this column", "home.column_settings.basic": "Basic", "home.column_settings.show_reblogs": "Show boosts", "home.column_settings.show_replies": "Show replies", @@ -313,6 +321,7 @@ "status.show_less_all": "Show less for all", "status.show_more": "Show more", "status.show_more_all": "Show more for all", + "status.show_thread": "Show thread", "status.unmute_conversation": "Unmute conversation", "status.unpin": "Unpin from profile", "suggestions.dismiss": "Dismiss suggestion", diff --git a/app/javascript/mastodon/locales/ca.json b/app/javascript/mastodon/locales/ca.json index f4c5f97be..bc1fd8950 100644 --- a/app/javascript/mastodon/locales/ca.json +++ b/app/javascript/mastodon/locales/ca.json @@ -112,6 +112,7 @@ "emoji_button.search_results": "Resultats de la cerca", "emoji_button.symbols": "Símbols", "emoji_button.travel": "Viatges i Llocs", + "empty_column.account_timeline": "No toots here!", "empty_column.blocks": "Encara no has bloquejat cap usuari.", "empty_column.community": "La línia de temps local és buida. Escriu alguna cosa públicament per fer rodar la pilota!", "empty_column.direct": "Encara no tens missatges directes. Quan enviïs o rebis un, es mostrarà aquí.", @@ -137,6 +138,13 @@ "getting_started.open_source_notice": "Mastodon és un programari de codi obert. Pots contribuir o informar de problemes a GitHub a {github}.", "getting_started.security": "Seguretat", "getting_started.terms": "Termes del servei", + "hashtag.column_header.tag_mode.all": "and {additional}", + "hashtag.column_header.tag_mode.any": "or {additional}", + "hashtag.column_header.tag_mode.none": "without {additional}", + "hashtag.column_settings.tag_mode.all": "All of these", + "hashtag.column_settings.tag_mode.any": "Any of these", + "hashtag.column_settings.tag_mode.none": "None of these", + "hashtag.column_settings.tag_toggle": "Include additional tags in this column", "home.column_settings.basic": "Bàsic", "home.column_settings.show_reblogs": "Mostrar impulsos", "home.column_settings.show_replies": "Mostrar respostes", @@ -313,10 +321,11 @@ "status.show_less_all": "Mostra menys per a tot", "status.show_more": "Mostra més", "status.show_more_all": "Mostra més per a tot", + "status.show_thread": "Show thread", "status.unmute_conversation": "Activar conversació", "status.unpin": "Deslliga del perfil", - "suggestions.dismiss": "Dismiss suggestion", - "suggestions.header": "You might be interested in…", + "suggestions.dismiss": "Descartar suggeriment", + "suggestions.header": "És possible que t’interessi…", "tabs_bar.federated_timeline": "Federada", "tabs_bar.home": "Inici", "tabs_bar.local_timeline": "Local", diff --git a/app/javascript/mastodon/locales/co.json b/app/javascript/mastodon/locales/co.json index f322ce53d..45bf0dc43 100644 --- a/app/javascript/mastodon/locales/co.json +++ b/app/javascript/mastodon/locales/co.json @@ -112,6 +112,7 @@ "emoji_button.search_results": "Risultati di a cerca", "emoji_button.symbols": "Simbuli", "emoji_button.travel": "Lochi è Viaghju", + "empty_column.account_timeline": "No toots here!", "empty_column.blocks": "Per avà ùn avete bluccatu manc'un utilizatore.", "empty_column.community": "Ùn c'hè nunda indè a linea lucale. Scrivete puru qualcosa!", "empty_column.direct": "Ùn avete ancu nisun missaghju direttu. S'è voi mandate o ricevete unu, u vidarete quì.", @@ -137,6 +138,13 @@ "getting_started.open_source_notice": "Mastodon ghjè un lugiziale liberu. Pudete cuntribuisce à u codice o a traduzione, o palisà un bug, nant'à GitHub: {github}.", "getting_started.security": "Sicurità", "getting_started.terms": "Cundizione di u serviziu", + "hashtag.column_header.tag_mode.all": "and {additional}", + "hashtag.column_header.tag_mode.any": "or {additional}", + "hashtag.column_header.tag_mode.none": "without {additional}", + "hashtag.column_settings.tag_mode.all": "All of these", + "hashtag.column_settings.tag_mode.any": "Any of these", + "hashtag.column_settings.tag_mode.none": "None of these", + "hashtag.column_settings.tag_toggle": "Include additional tags in this column", "home.column_settings.basic": "Bàsichi", "home.column_settings.show_reblogs": "Vede e spartere", "home.column_settings.show_replies": "Vede e risposte", @@ -278,7 +286,7 @@ "search_results.hashtags": "Hashtag", "search_results.statuses": "Statuti", "search_results.total": "{count, number} {count, plural, one {risultatu} other {risultati}}", - "standalone.public_title": "Una vista di...", + "standalone.public_title": "Una vista à l'internu...", "status.block": "Bluccà @{name}", "status.cancel_reblog_private": "Ùn sparte più", "status.cannot_reblog": "Stu statutu ùn pò micca esse spartutu", @@ -313,10 +321,11 @@ "status.show_less_all": "Ripiegà tuttu", "status.show_more": "Slibrà", "status.show_more_all": "Slibrà tuttu", + "status.show_thread": "Show thread", "status.unmute_conversation": "Ùn piattà più a cunversazione", "status.unpin": "Spuntarulà da u prufile", - "suggestions.dismiss": "Dismiss suggestion", - "suggestions.header": "You might be interested in…", + "suggestions.dismiss": "Righjittà a pruposta", + "suggestions.header": "Site forse interessatu·a da…", "tabs_bar.federated_timeline": "Glubale", "tabs_bar.home": "Accolta", "tabs_bar.local_timeline": "Lucale", diff --git a/app/javascript/mastodon/locales/cs.json b/app/javascript/mastodon/locales/cs.json index e809eb136..80fab00c3 100644 --- a/app/javascript/mastodon/locales/cs.json +++ b/app/javascript/mastodon/locales/cs.json @@ -39,7 +39,7 @@ "alert.unexpected.message": "Objevila se neočekávaná chyba.", "alert.unexpected.title": "Jejda!", "boost_modal.combo": "Příště můžete pro přeskočení kliknout na {combo}", - "bundle_column_error.body": "Při načtení tohoto prvku se něco pokazilo.", + "bundle_column_error.body": "Při načítání tohoto komponentu se něco pokazilo.", "bundle_column_error.retry": "Zkuste to znovu", "bundle_column_error.title": "Chyba sítě", "bundle_modal_error.close": "Zavřít", @@ -50,7 +50,7 @@ "column.direct": "Přímé zprávy", "column.domain_blocks": "Skryté domény", "column.favourites": "Oblíbené", - "column.follow_requests": "Žádosti o sledování", + "column.follow_requests": "Požadavky o sledování", "column.home": "Domů", "column.lists": "Seznamy", "column.mutes": "Ignorovaní uživatelé", @@ -66,7 +66,7 @@ "column_header.unpin": "Odepnout", "column_subheading.settings": "Nastavení", "community.column_settings.media_only": "Pouze média", - "compose_form.direct_message_warning": "Tento toot bude vidielný pouze zmíněným uživatelům.", + "compose_form.direct_message_warning": "Tento toot bude odeslán pouze zmíněným uživatelům.", "compose_form.direct_message_warning_learn_more": "Zjistit více", "compose_form.hashtag_warning": "Tento toot nebude zobrazen pod žádným hashtagem, neboť je neuvedený. Pouze veřejné tooty mohou být vyhledány podle hashtagu.", "compose_form.lock_disclaimer": "Váš účet není {locked}. Kdokoliv vás může sledovat a vidět vaše příspěvky pouze pro sledovatele.", @@ -112,6 +112,7 @@ "emoji_button.search_results": "Výsledky hledání", "emoji_button.symbols": "Symboly", "emoji_button.travel": "Cestování a místa", + "empty_column.account_timeline": "No toots here!", "empty_column.blocks": "Ještě jste nezablokoval/a žádného uživatele.", "empty_column.community": "Místní časová osa je prázdná. Napište něco veřejně a rozhýbejte to tu!", "empty_column.direct": "Ještě nemáte žádné přímé zprávy. Pokud nějakou pošlete nebo dostanete, zobrazí se zde.", @@ -137,6 +138,13 @@ "getting_started.open_source_notice": "Mastodon je otevřený software. Na GitHubu k němu můžete přispět nebo nahlásit chyby: {github}.", "getting_started.security": "Zabezpečení", "getting_started.terms": "Podmínky používání", + "hashtag.column_header.tag_mode.all": "and {additional}", + "hashtag.column_header.tag_mode.any": "or {additional}", + "hashtag.column_header.tag_mode.none": "without {additional}", + "hashtag.column_settings.tag_mode.all": "All of these", + "hashtag.column_settings.tag_mode.any": "Any of these", + "hashtag.column_settings.tag_mode.none": "None of these", + "hashtag.column_settings.tag_toggle": "Include additional tags in this column", "home.column_settings.basic": "Základní", "home.column_settings.show_reblogs": "Zobrazit boosty", "home.column_settings.show_replies": "Zobrazit odpovědi", @@ -147,7 +155,7 @@ "keyboard_shortcuts.compose": "k zaměření na psací prostor", "keyboard_shortcuts.description": "Popis", "keyboard_shortcuts.direct": "k otevření sloupce s přímými zprávami", - "keyboard_shortcuts.down": "k přesunutí dolů v seznamu", + "keyboard_shortcuts.down": "k posunutí dolů v seznamu", "keyboard_shortcuts.enter": "k otevření příspěvku", "keyboard_shortcuts.favourite": "k oblíbení", "keyboard_shortcuts.favourites": "k otevření seznamu oblíbených", @@ -197,7 +205,7 @@ "navigation_bar.edit_profile": "Upravit profil", "navigation_bar.favourites": "Oblíbené", "navigation_bar.filters": "Skrytá slova", - "navigation_bar.follow_requests": "Žádosti o sledování", + "navigation_bar.follow_requests": "Požadavky o sledování", "navigation_bar.info": "O této instanci", "navigation_bar.keyboard_shortcuts": "Klávesové zkratky", "navigation_bar.lists": "Seznamy", @@ -269,15 +277,15 @@ "report.target": "Nahlásit {target}", "search.placeholder": "Hledat", "search_popout.search_format": "Pokročilé vyhledávání", - "search_popout.tips.full_text": "Jednoduchý textový výpis příspěvků, které jste napsal/a, oblíbil/a si, boostnul/a, nebo v nich byl/a zmíněn/a, včetně odpovídajících přezdívek, jmen a hashtagů.", + "search_popout.tips.full_text": "Jednoduchý textový výpis příspěvků, které jste napsal/a, oblíbil/a si, boostnul/a, nebo v nich byl/a zmíněn/a, včetně odpovídajících přezdívek, zobrazovaných jmen a hashtagů.", "search_popout.tips.hashtag": "hashtag", "search_popout.tips.status": "příspěvek", - "search_popout.tips.text": "Jednoduchý textový výpis odpovídajících jmen, přezdívek a hashtagů", + "search_popout.tips.text": "Jednoduchý textový výpis odpovídajících zobrazovaných jmen, přezdívek a hashtagů", "search_popout.tips.user": "uživatel", "search_results.accounts": "Lidé", "search_results.hashtags": "Hashtagy", "search_results.statuses": "Tooty", - "search_results.total": "{count, number} {count, plural, one {výsledek} other {výsledků}}", + "search_results.total": "{count, number} {count, plural, one {výsledek} few {výsledky} many {výsledku} other {výsledků}}", "standalone.public_title": "Nahlédněte dovnitř...", "status.block": "Zablokovat uživatele @{name}", "status.cancel_reblog_private": "Zrušit boost", @@ -313,16 +321,17 @@ "status.show_less_all": "Zobrazit méně pro všechny", "status.show_more": "Zobrazit více", "status.show_more_all": "Zobrazit více pro všechny", + "status.show_thread": "Show thread", "status.unmute_conversation": "Přestat ignorovat konverzaci", "status.unpin": "Odepnout z profilu", - "suggestions.dismiss": "Dismiss suggestion", - "suggestions.header": "You might be interested in…", + "suggestions.dismiss": "Odmítnout návrh", + "suggestions.header": "Mohlo by vás zajímat…", "tabs_bar.federated_timeline": "Federovaná", "tabs_bar.home": "Domů", "tabs_bar.local_timeline": "Místní", "tabs_bar.notifications": "Oznámení", "tabs_bar.search": "Hledat", - "trends.count_by_accounts": "{count} {rawCount, plural, one {člověk} other {lidí}} diskutuje", + "trends.count_by_accounts": "{count} {rawCount, plural, one {člověk} few {lidé} many {lidí} other {lidí}} hovoří", "ui.beforeunload": "Váš koncept se ztratí, pokud Mastodon opustíte.", "upload_area.title": "Přetažením nahrajete", "upload_button.label": "Přidat média (JPEG, PNG, GIF, WebM, MP4, MOV)", diff --git a/app/javascript/mastodon/locales/cy.json b/app/javascript/mastodon/locales/cy.json index 71a34272e..4047b54d6 100644 --- a/app/javascript/mastodon/locales/cy.json +++ b/app/javascript/mastodon/locales/cy.json @@ -112,6 +112,7 @@ "emoji_button.search_results": "Canlyniadau chwilio", "emoji_button.symbols": "Symbolau", "emoji_button.travel": "Teithio & Llefydd", + "empty_column.account_timeline": "No toots here!", "empty_column.blocks": "Nid ydych wedi blocio unrhyw ddefnyddwyr eto.", "empty_column.community": "Mae'r ffrwd lleol yn wag. Ysgrifenwch rhywbeth yn gyhoeddus i gael dechrau arni!", "empty_column.direct": "Nid oes gennych unrhyw negeseuon preifat eto. Pan y byddwch yn anfon neu derbyn un, mi fydd yn ymddangos yma.", @@ -137,6 +138,13 @@ "getting_started.open_source_notice": "Mae Mastodon yn feddalwedd côd agored. Mae modd cyfrannu neu adrodd materion ar GitHUb ar {github}.", "getting_started.security": "Diogelwch", "getting_started.terms": "Telerau Gwasanaeth", + "hashtag.column_header.tag_mode.all": "and {additional}", + "hashtag.column_header.tag_mode.any": "or {additional}", + "hashtag.column_header.tag_mode.none": "without {additional}", + "hashtag.column_settings.tag_mode.all": "All of these", + "hashtag.column_settings.tag_mode.any": "Any of these", + "hashtag.column_settings.tag_mode.none": "None of these", + "hashtag.column_settings.tag_toggle": "Include additional tags in this column", "home.column_settings.basic": "Syml", "home.column_settings.show_reblogs": "Dangos bŵstiau", "home.column_settings.show_replies": "Dangos ymatebion", @@ -313,6 +321,7 @@ "status.show_less_all": "Dangos llai i bawb", "status.show_more": "Dangos mwy", "status.show_more_all": "Dangos mwy i bawb", + "status.show_thread": "Show thread", "status.unmute_conversation": "Dad-dawelu sgwrs", "status.unpin": "Dadbinio o'r proffil", "suggestions.dismiss": "Dismiss suggestion", diff --git a/app/javascript/mastodon/locales/da.json b/app/javascript/mastodon/locales/da.json index 54cae027f..133f9e696 100644 --- a/app/javascript/mastodon/locales/da.json +++ b/app/javascript/mastodon/locales/da.json @@ -92,8 +92,8 @@ "confirmations.mute.message": "Er du sikker på, du vil dæmpe {name}?", "confirmations.redraft.confirm": "Slet & omskriv", "confirmations.redraft.message": "Er du sikker på, du vil slette denne status og omskrive den? Favoritter og fremhævelser vil gå tabt og svar til det oprindelige opslag vil blive forældreløse.", - "confirmations.reply.confirm": "Reply", - "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?", + "confirmations.reply.confirm": "Svar", + "confirmations.reply.message": "Hvis du svarer nu vil du overskrive den besked du er ved at skrive. Er du sikker på, du vil fortsætte?", "confirmations.unfollow.confirm": "Følg ikke længere", "confirmations.unfollow.message": "Er du sikker på, du ikke længere vil følge {name}?", "embed.instructions": "Indlejre denne status på din side ved at kopiere nedenstående kode.", @@ -112,6 +112,7 @@ "emoji_button.search_results": "Søgeresultater", "emoji_button.symbols": "Symboler", "emoji_button.travel": "Rejser & steder", + "empty_column.account_timeline": "No toots here!", "empty_column.blocks": "Du har ikke blokeret nogen endnu.", "empty_column.community": "Den lokale tidslinje er tom. Skriv noget offentligt for at starte lavinen!", "empty_column.direct": "Du har endnu ingen direkte beskeder. Når du sender eller modtager en, vil den vises her.", @@ -137,6 +138,13 @@ "getting_started.open_source_notice": "Mastodon er et open source software. Du kan bidrage eller rapporterer fejl på GitHub {github}.", "getting_started.security": "Sikkerhed", "getting_started.terms": "Vilkår", + "hashtag.column_header.tag_mode.all": "and {additional}", + "hashtag.column_header.tag_mode.any": "or {additional}", + "hashtag.column_header.tag_mode.none": "without {additional}", + "hashtag.column_settings.tag_mode.all": "All of these", + "hashtag.column_settings.tag_mode.any": "Any of these", + "hashtag.column_settings.tag_mode.none": "None of these", + "hashtag.column_settings.tag_toggle": "Include additional tags in this column", "home.column_settings.basic": "Grundlæggende", "home.column_settings.show_reblogs": "Vis fremhævelser", "home.column_settings.show_replies": "Vis svar", @@ -297,7 +305,7 @@ "status.open": "Udvid denne status", "status.pin": "Fastgør til profil", "status.pinned": "Fastgjort trut", - "status.read_more": "Read more", + "status.read_more": "Læs mere", "status.reblog": "Fremhæv", "status.reblog_private": "Fremhæv til oprindeligt publikum", "status.reblogged_by": "{name} fremhævede", @@ -313,6 +321,7 @@ "status.show_less_all": "Vis mindre for alle", "status.show_more": "Vis mere", "status.show_more_all": "Vis mere for alle", + "status.show_thread": "Show thread", "status.unmute_conversation": "Fjern dæmpningen fra samtale", "status.unpin": "Fjern som fastgjort fra profil", "suggestions.dismiss": "Dismiss suggestion", diff --git a/app/javascript/mastodon/locales/de.json b/app/javascript/mastodon/locales/de.json index a81a52d51..6bba6114e 100644 --- a/app/javascript/mastodon/locales/de.json +++ b/app/javascript/mastodon/locales/de.json @@ -112,6 +112,7 @@ "emoji_button.search_results": "Suchergebnisse", "emoji_button.symbols": "Symbole", "emoji_button.travel": "Reisen und Orte", + "empty_column.account_timeline": "No toots here!", "empty_column.blocks": "Du hast keine Profile blockiert.", "empty_column.community": "Die lokale Zeitleiste ist leer. Schreibe einen öffentlichen Beitrag, um den Ball ins Rollen zu bringen!", "empty_column.direct": "Du hast noch keine Direktnachrichten erhalten. Wenn du eine sendest oder empfängst, wird sie hier zu sehen sein.", @@ -137,6 +138,13 @@ "getting_started.open_source_notice": "Mastodon ist quelloffene Software. Du kannst auf GitHub unter {github} dazu beitragen oder Probleme melden.", "getting_started.security": "Sicherheit", "getting_started.terms": "Nutzungsbedingungen", + "hashtag.column_header.tag_mode.all": "and {additional}", + "hashtag.column_header.tag_mode.any": "or {additional}", + "hashtag.column_header.tag_mode.none": "without {additional}", + "hashtag.column_settings.tag_mode.all": "All of these", + "hashtag.column_settings.tag_mode.any": "Any of these", + "hashtag.column_settings.tag_mode.none": "None of these", + "hashtag.column_settings.tag_toggle": "Include additional tags in this column", "home.column_settings.basic": "Einfach", "home.column_settings.show_reblogs": "Geteilte Beiträge anzeigen", "home.column_settings.show_replies": "Antworten anzeigen", @@ -313,6 +321,7 @@ "status.show_less_all": "Zeige weniger für alles", "status.show_more": "Mehr anzeigen", "status.show_more_all": "Zeige mehr für alles", + "status.show_thread": "Show thread", "status.unmute_conversation": "Stummschaltung von Thread aufheben", "status.unpin": "Vom Profil lösen", "suggestions.dismiss": "Dismiss suggestion", diff --git a/app/javascript/mastodon/locales/el.json b/app/javascript/mastodon/locales/el.json index 06356f8e6..ba332be3f 100644 --- a/app/javascript/mastodon/locales/el.json +++ b/app/javascript/mastodon/locales/el.json @@ -112,6 +112,7 @@ "emoji_button.search_results": "Αποτελέσματα αναζήτησης", "emoji_button.symbols": "Σύμβολα", "emoji_button.travel": "Ταξίδια & Τοποθεσίες", + "empty_column.account_timeline": "No toots here!", "empty_column.blocks": "Δεν έχεις αποκλείσει κανέναν χρήστη ακόμα.", "empty_column.community": "Η τοπική ροή είναι κενή. Γράψε κάτι δημόσιο παραμύθι ν' αρχινίσει!", "empty_column.direct": "Δεν έχεις προσωπικά μηνύματα ακόμα. Όταν στείλεις ή λάβεις κανένα, θα εμφανιστεί εδώ.", @@ -137,6 +138,13 @@ "getting_started.open_source_notice": "Το Mastodon είναι ελεύθερο λογισμικό. Μπορείς να συνεισφέρεις ή να αναφέρεις ζητήματα στο GitHub στο {github}.", "getting_started.security": "Ασφάλεια", "getting_started.terms": "Όροι χρήσης", + "hashtag.column_header.tag_mode.all": "and {additional}", + "hashtag.column_header.tag_mode.any": "or {additional}", + "hashtag.column_header.tag_mode.none": "without {additional}", + "hashtag.column_settings.tag_mode.all": "All of these", + "hashtag.column_settings.tag_mode.any": "Any of these", + "hashtag.column_settings.tag_mode.none": "None of these", + "hashtag.column_settings.tag_toggle": "Include additional tags in this column", "home.column_settings.basic": "Βασικά", "home.column_settings.show_reblogs": "Εμφάνιση προωθήσεων", "home.column_settings.show_replies": "Εμφάνιση απαντήσεων", @@ -313,6 +321,7 @@ "status.show_less_all": "Δείξε λιγότερα για όλα", "status.show_more": "Δείξε περισσότερα", "status.show_more_all": "Δείξε περισσότερα για όλα", + "status.show_thread": "Show thread", "status.unmute_conversation": "Διέκοψε την αποσιώπηση της συζήτησης", "status.unpin": "Ξεκαρφίτσωσε από το προφίλ", "suggestions.dismiss": "Dismiss suggestion", diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json index 16f680fa3..b0b9de26f 100644 --- a/app/javascript/mastodon/locales/en.json +++ b/app/javascript/mastodon/locales/en.json @@ -142,9 +142,9 @@ "getting_started.open_source_notice": "Mastodon is open source software. You can contribute or report issues on GitHub at {github}.", "getting_started.security": "Security", "getting_started.terms": "Terms of service", - "hashtag.column_header.tag_mode.all": "{tag} and {additional}", - "hashtag.column_header.tag_mode.any": "{tag} or {additional}", - "hashtag.column_header.tag_mode.none": "{tag} without {additional}", + "hashtag.column_header.tag_mode.all": "and {additional}", + "hashtag.column_header.tag_mode.any": "or {additional}", + "hashtag.column_header.tag_mode.none": "without {additional}", "hashtag.column_settings.tag_mode.all": "All of these", "hashtag.column_settings.tag_mode.any": "Any of these", "hashtag.column_settings.tag_mode.none": "None of these", diff --git a/app/javascript/mastodon/locales/eo.json b/app/javascript/mastodon/locales/eo.json index ef9f99abb..f7a303cdd 100644 --- a/app/javascript/mastodon/locales/eo.json +++ b/app/javascript/mastodon/locales/eo.json @@ -112,6 +112,7 @@ "emoji_button.search_results": "Serĉaj rezultoj", "emoji_button.symbols": "Simboloj", "emoji_button.travel": "Vojaĝoj kaj lokoj", + "empty_column.account_timeline": "No toots here!", "empty_column.blocks": "You haven't blocked any users yet.", "empty_column.community": "La loka tempolinio estas malplena. Skribu ion por plenigi ĝin!", "empty_column.direct": "Vi ankoraŭ ne havas rektan mesaĝon. Kiam vi sendos aŭ ricevos iun, ĝi aperos ĉi tie.", @@ -137,6 +138,13 @@ "getting_started.open_source_notice": "Mastodon estas malfermitkoda programo. Vi povas kontribui aŭ raporti problemojn en GitHub je {github}.", "getting_started.security": "Sekureco", "getting_started.terms": "Uzkondiĉoj", + "hashtag.column_header.tag_mode.all": "and {additional}", + "hashtag.column_header.tag_mode.any": "or {additional}", + "hashtag.column_header.tag_mode.none": "without {additional}", + "hashtag.column_settings.tag_mode.all": "All of these", + "hashtag.column_settings.tag_mode.any": "Any of these", + "hashtag.column_settings.tag_mode.none": "None of these", + "hashtag.column_settings.tag_toggle": "Include additional tags in this column", "home.column_settings.basic": "Bazaj agordoj", "home.column_settings.show_reblogs": "Montri diskonigojn", "home.column_settings.show_replies": "Montri respondojn", @@ -313,6 +321,7 @@ "status.show_less_all": "Malgrandigi ĉiujn", "status.show_more": "Grandigi", "status.show_more_all": "Grandigi ĉiujn", + "status.show_thread": "Show thread", "status.unmute_conversation": "Malsilentigi konversacion", "status.unpin": "Depingli de profilo", "suggestions.dismiss": "Dismiss suggestion", diff --git a/app/javascript/mastodon/locales/es.json b/app/javascript/mastodon/locales/es.json index 511209809..7b8cfe3f3 100644 --- a/app/javascript/mastodon/locales/es.json +++ b/app/javascript/mastodon/locales/es.json @@ -112,6 +112,7 @@ "emoji_button.search_results": "Resultados de búsqueda", "emoji_button.symbols": "Símbolos", "emoji_button.travel": "Viajes y lugares", + "empty_column.account_timeline": "No toots here!", "empty_column.blocks": "Aún no has bloqueado a ningún usuario.", "empty_column.community": "La línea de tiempo local está vacía. ¡Escribe algo para empezar la fiesta!", "empty_column.direct": "Aún no tienes ningún mensaje directo. Cuando envíes o recibas uno, se mostrará aquí.", @@ -137,6 +138,13 @@ "getting_started.open_source_notice": "Mastodon es software libre. Puedes contribuir o reportar errores en {github}.", "getting_started.security": "Seguridad", "getting_started.terms": "Términos de servicio", + "hashtag.column_header.tag_mode.all": "and {additional}", + "hashtag.column_header.tag_mode.any": "or {additional}", + "hashtag.column_header.tag_mode.none": "without {additional}", + "hashtag.column_settings.tag_mode.all": "All of these", + "hashtag.column_settings.tag_mode.any": "Any of these", + "hashtag.column_settings.tag_mode.none": "None of these", + "hashtag.column_settings.tag_toggle": "Include additional tags in this column", "home.column_settings.basic": "Básico", "home.column_settings.show_reblogs": "Mostrar retoots", "home.column_settings.show_replies": "Mostrar respuestas", @@ -313,6 +321,7 @@ "status.show_less_all": "Mostrar menos para todo", "status.show_more": "Mostrar más", "status.show_more_all": "Mostrar más para todo", + "status.show_thread": "Show thread", "status.unmute_conversation": "Dejar de silenciar conversación", "status.unpin": "Dejar de fijar", "suggestions.dismiss": "Dismiss suggestion", diff --git a/app/javascript/mastodon/locales/eu.json b/app/javascript/mastodon/locales/eu.json index fb129967e..8ce3b9ba3 100644 --- a/app/javascript/mastodon/locales/eu.json +++ b/app/javascript/mastodon/locales/eu.json @@ -14,16 +14,16 @@ "account.followers.empty": "Ez du inork erabiltzaile hau jarraitzen oraindik.", "account.follows": "Jarraitzen", "account.follows.empty": "Erabiltzaile honek ez du inor jarraitzen oraindik.", - "account.follows_you": "Jarraitzen zaitu", + "account.follows_you": "Jarraitzen dizu", "account.hide_reblogs": "Ezkutatu @{name}(r)en bultzadak", - "account.link_verified_on": "Ownership of this link was checked on {date}", + "account.link_verified_on": "Esteka honen jabetzaren egiaztaketa data: {date}", "account.media": "Media", "account.mention": "Aipatu @{name}", "account.moved_to": "{name} hona lekualdatu da:", "account.mute": "Mututu @{name}", "account.mute_notifications": "Mututu @{name}(r)en jakinarazpenak", "account.muted": "Mutututa", - "account.posts": "Toot-ak", + "account.posts": "Tootak", "account.posts_with_replies": "Toot eta erantzunak", "account.report": "Salatu @{name}", "account.requested": "Onarpenaren zain. Klikatu jarraitzeko eskaera ezeztatzeko", @@ -92,8 +92,8 @@ "confirmations.mute.message": "Ziur {name} mututu nahi duzula?", "confirmations.redraft.confirm": "Ezabatu eta berridatzi", "confirmations.redraft.message": "Ziur mezu hau ezabatu eta berridatzi nahi duzula? Gogokoak eta bultzadak galduko dira eta jaso dituen erantzunak umezurtz geratuko dira.", - "confirmations.reply.confirm": "Reply", - "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?", + "confirmations.reply.confirm": "Erantzun", + "confirmations.reply.message": "Orain erantzuteak idazten ari zaren mezua gainidatziko du. Ziur jarraitu nahi duzula?", "confirmations.unfollow.confirm": "Utzi jarraitzeari", "confirmations.unfollow.message": "Ziur {name} jarraitzeari utzi nahi diozula?", "embed.instructions": "Txertatu mezu hau zure webgunean beheko kodea kopatuz.", @@ -112,6 +112,7 @@ "emoji_button.search_results": "Bilaketaren emaitzak", "emoji_button.symbols": "Sinboloak", "emoji_button.travel": "Bidaiak eta tokiak", + "empty_column.account_timeline": "No toots here!", "empty_column.blocks": "Ez duzu erabiltzailerik blokeatu oraindik.", "empty_column.community": "Denbora-lerro lokala hutsik dago. Idatzi zerbait publikoki pilota biraka jartzeko!", "empty_column.direct": "Ez duzu mezu zuzenik oraindik. Baten bat bidali edo jasotzen duzunean, hemen agertuko da.", @@ -137,6 +138,13 @@ "getting_started.open_source_notice": "Mastodon software librea da. Ekarpenak egin ditzakezu edo akatsen berri eman GitHub bidez: {github}.", "getting_started.security": "Segurtasuna", "getting_started.terms": "Erabilera baldintzak", + "hashtag.column_header.tag_mode.all": "and {additional}", + "hashtag.column_header.tag_mode.any": "or {additional}", + "hashtag.column_header.tag_mode.none": "without {additional}", + "hashtag.column_settings.tag_mode.all": "All of these", + "hashtag.column_settings.tag_mode.any": "Any of these", + "hashtag.column_settings.tag_mode.none": "None of these", + "hashtag.column_settings.tag_toggle": "Include additional tags in this column", "home.column_settings.basic": "Oinarrizkoa", "home.column_settings.show_reblogs": "Erakutsi bultzadak", "home.column_settings.show_replies": "Erakutsi erantzunak", @@ -255,8 +263,8 @@ "privacy.unlisted.short": "Zerrendatu gabea", "regeneration_indicator.label": "Kargatzen…", "regeneration_indicator.sublabel": "Zure hasiera-jarioa prestatzen ari da!", - "relative_time.days": "{number}d", - "relative_time.hours": "{number}h", + "relative_time.days": "{number}e", + "relative_time.hours": "{number}o", "relative_time.just_now": "orain", "relative_time.minutes": "{number}m", "relative_time.seconds": "{number}s", @@ -297,7 +305,7 @@ "status.open": "Hedatu mezu hau", "status.pin": "Finkatu profilean", "status.pinned": "Finkatutako toot-a", - "status.read_more": "Read more", + "status.read_more": "Irakurri gehiago", "status.reblog": "Bultzada", "status.reblog_private": "Bultzada jatorrizko hartzaileei", "status.reblogged_by": "{name}(r)en bultzada", @@ -313,10 +321,11 @@ "status.show_less_all": "Erakutsi denetarik gutxiago", "status.show_more": "Erakutsi gehiago", "status.show_more_all": "Erakutsi denetarik gehiago", + "status.show_thread": "Show thread", "status.unmute_conversation": "Desmututu elkarrizketa", "status.unpin": "Desfinkatu profiletik", - "suggestions.dismiss": "Dismiss suggestion", - "suggestions.header": "You might be interested in…", + "suggestions.dismiss": "Errefusatu proposamena", + "suggestions.header": "Hau interesatu dakizuke…", "tabs_bar.federated_timeline": "Federatua", "tabs_bar.home": "Hasiera", "tabs_bar.local_timeline": "Lokala", diff --git a/app/javascript/mastodon/locales/fa.json b/app/javascript/mastodon/locales/fa.json index e1d7d9628..befdb3804 100644 --- a/app/javascript/mastodon/locales/fa.json +++ b/app/javascript/mastodon/locales/fa.json @@ -112,6 +112,7 @@ "emoji_button.search_results": "نتایج جستجو", "emoji_button.symbols": "نمادها", "emoji_button.travel": "سفر و مکان", + "empty_column.account_timeline": "No toots here!", "empty_column.blocks": "شما هنوز هیچ کسی را مسدود نکردهاید.", "empty_column.community": "فهرست نوشتههای محلی خالی است. چیزی بنویسید تا چرخش بچرخد!", "empty_column.direct": "شما هیچ پیغام مستقیمی ندارید. اگر چنین پیغامی بگیرید یا بفرستید اینجا نمایش خواهد یافت.", @@ -137,6 +138,13 @@ "getting_started.open_source_notice": "ماستدون یک نرمافزار آزاد است. میتوانید در ساخت آن مشارکت کنید یا مشکلاتش را در {github} گزارش دهید.", "getting_started.security": "امنیت", "getting_started.terms": "شرایط استفاده", + "hashtag.column_header.tag_mode.all": "and {additional}", + "hashtag.column_header.tag_mode.any": "or {additional}", + "hashtag.column_header.tag_mode.none": "without {additional}", + "hashtag.column_settings.tag_mode.all": "All of these", + "hashtag.column_settings.tag_mode.any": "Any of these", + "hashtag.column_settings.tag_mode.none": "None of these", + "hashtag.column_settings.tag_toggle": "Include additional tags in this column", "home.column_settings.basic": "اصلی", "home.column_settings.show_reblogs": "نمایش بازبوقها", "home.column_settings.show_replies": "نمایش پاسخها", @@ -313,6 +321,7 @@ "status.show_less_all": "نمایش کمتر همه", "status.show_more": "نمایش", "status.show_more_all": "نمایش بیشتر همه", + "status.show_thread": "Show thread", "status.unmute_conversation": "باصداکردن گفتگو", "status.unpin": "برداشتن نوشتهٔ ثابت نمایه", "suggestions.dismiss": "Dismiss suggestion", diff --git a/app/javascript/mastodon/locales/fi.json b/app/javascript/mastodon/locales/fi.json index abbcded90..bb1725533 100644 --- a/app/javascript/mastodon/locales/fi.json +++ b/app/javascript/mastodon/locales/fi.json @@ -8,15 +8,15 @@ "account.disclaimer_full": "Alla olevat käyttäjän profiilitiedot saattavat olla epätäydellisiä.", "account.domain_blocked": "Verkko-osoite piilotettu", "account.edit_profile": "Muokkaa", - "account.endorse": "Feature on profile", + "account.endorse": "Suosittele profiilissasi", "account.follow": "Seuraa", "account.followers": "Seuraajia", - "account.followers.empty": "No one follows this user yet.", + "account.followers.empty": "Tällä käyttäjällä ei ole vielä seuraajia.", "account.follows": "Seuraa", - "account.follows.empty": "This user doesn't follow anyone yet.", + "account.follows.empty": "Tämä käyttäjä ei vielä seuraa ketään.", "account.follows_you": "Seuraa sinua", "account.hide_reblogs": "Piilota buustaukset käyttäjältä @{name}", - "account.link_verified_on": "Ownership of this link was checked on {date}", + "account.link_verified_on": "Tämän linkin omistaja tarkistettiin {date}", "account.media": "Media", "account.mention": "Mainitse @{name}", "account.moved_to": "{name} on muuttanut instanssiin:", @@ -31,7 +31,7 @@ "account.show_reblogs": "Näytä buustaukset käyttäjältä @{name}", "account.unblock": "Salli @{name}", "account.unblock_domain": "Näytä {domain}", - "account.unendorse": "Don't feature on profile", + "account.unendorse": "Poista suosittelu profiilistasi", "account.unfollow": "Lakkaa seuraamasta", "account.unmute": "Poista käyttäjän @{name} mykistys", "account.unmute_notifications": "Poista mykistys käyttäjän @{name} ilmoituksilta", @@ -65,7 +65,7 @@ "column_header.show_settings": "Näytä asetukset", "column_header.unpin": "Poista kiinnitys", "column_subheading.settings": "Asetukset", - "community.column_settings.media_only": "Media Only", + "community.column_settings.media_only": "Vain media", "compose_form.direct_message_warning": "Tämä tuuttaus näkyy vain mainituille käyttäjille.", "compose_form.direct_message_warning_learn_more": "Lisätietoja", "compose_form.hashtag_warning": "Tämä tuuttaus ei näy hashtag-hauissa, koska se on listaamaton. Hashtagien avulla voi hakea vain julkisia tuuttauksia.", @@ -90,10 +90,10 @@ "confirmations.domain_block.message": "Haluatko aivan varmasti estää koko verkko-osoitteen {domain}? Useimmiten jokunen kohdistettu esto ja mykistys riittää, ja se on suositeltavampi tapa toimia.", "confirmations.mute.confirm": "Mykistä", "confirmations.mute.message": "Haluatko varmasti mykistää käyttäjän {name}?", - "confirmations.redraft.confirm": "Delete & redraft", + "confirmations.redraft.confirm": "Poista & palauta muokattavaksi", "confirmations.redraft.message": "Are you sure you want to delete this status and re-draft it? You will lose all replies, boosts and favourites to it.", - "confirmations.reply.confirm": "Reply", - "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?", + "confirmations.reply.confirm": "Vastaa", + "confirmations.reply.message": "Jos vastaat nyt, vastaus korvaa tällä hetkellä työstämäsi viestin. Oletko varma, että haluat jatkaa?", "confirmations.unfollow.confirm": "Lakkaa seuraamasta", "confirmations.unfollow.message": "Haluatko varmasti lakata seuraamasta käyttäjää {name}?", "embed.instructions": "Upota statuspäivitys sivullesi kopioimalla alla oleva koodi.", @@ -112,61 +112,69 @@ "emoji_button.search_results": "Hakutulokset", "emoji_button.symbols": "Symbolit", "emoji_button.travel": "Matkailu", - "empty_column.blocks": "You haven't blocked any users yet.", + "empty_column.account_timeline": "No toots here!", + "empty_column.blocks": "Et ole vielä estänyt yhtään käyttäjää.", "empty_column.community": "Paikallinen aikajana on tyhjä. Homma lähtee käyntiin, kun kirjoitat jotain julkista!", "empty_column.direct": "Sinulla ei ole vielä yhtään viestiä yksittäiselle käyttäjälle. Kun lähetät tai vastaanotat sellaisen, se näkyy täällä.", - "empty_column.domain_blocks": "There are no hidden domains yet.", - "empty_column.favourited_statuses": "You don't have any favourite toots yet. When you favourite one, it will show up here.", - "empty_column.favourites": "No one has favourited this toot yet. When someone does, they will show up here.", - "empty_column.follow_requests": "You don't have any follow requests yet. When you receive one, it will show up here.", + "empty_column.domain_blocks": "Yhtään verkko-osoitetta ei ole vielä piilotettu.", + "empty_column.favourited_statuses": "Et ole vielä lisännyt tuuttauksia suosikkeihisi. Kun teet niin, tuuttaus näkyy tässä.", + "empty_column.favourites": "Kukaan ei ole vielä lisännyt tätä tuuttausta suosikkeihinsa. Kun joku tekee niin, näkyy kyseinen henkilö tässä.", + "empty_column.follow_requests": "Sinulla ei ole vielä seurauspyyntöjä. Kun saat sellaisen, näkyy se tässä.", "empty_column.hashtag": "Tällä hashtagilla ei ole vielä mitään.", "empty_column.home": "Kotiaikajanasi on tyhjä! {public} ja hakutoiminto auttavat alkuun ja kohtaamaan muita käyttäjiä.", "empty_column.home.public_timeline": "yleinen aikajana", "empty_column.list": "Lista on vielä tyhjä. Listan jäsenten julkaisemat tilapäivitykset tulevat tähän näkyviin.", - "empty_column.lists": "You don't have any lists yet. When you create one, it will show up here.", - "empty_column.mutes": "You haven't muted any users yet.", + "empty_column.lists": "Sinulla ei ole vielä yhtään listaa. Kun luot sellaisen, näkyy se tässä.", + "empty_column.mutes": "Et ole mykistänyt vielä yhtään käyttäjää.", "empty_column.notifications": "Sinulle ei ole vielä ilmoituksia. Aloita keskustelu juttelemalla muille.", "empty_column.public": "Täällä ei ole mitään! Saat sisältöä, kun kirjoitat jotain julkisesti tai käyt manuaalisesti seuraamassa muiden instanssien käyttäjiä", "follow_request.authorize": "Valtuuta", "follow_request.reject": "Hylkää", - "getting_started.developers": "Developers", + "getting_started.developers": "Kehittäjille", "getting_started.documentation": "Documentation", - "getting_started.find_friends": "Find friends from Twitter", + "getting_started.find_friends": "Löydä ystäväsi Twitteristä", "getting_started.heading": "Aloitus", - "getting_started.invite": "Invite people", + "getting_started.invite": "Kutsu ihmisiä", "getting_started.open_source_notice": "Mastodon on avoimen lähdekoodin ohjelma. Voit avustaa tai raportoida ongelmia GitHubissa: {github}.", - "getting_started.security": "Security", - "getting_started.terms": "Terms of service", + "getting_started.security": "Tunnukset", + "getting_started.terms": "Käyttöehdot", + "hashtag.column_header.tag_mode.all": "and {additional}", + "hashtag.column_header.tag_mode.any": "or {additional}", + "hashtag.column_header.tag_mode.none": "without {additional}", + "hashtag.column_settings.tag_mode.all": "All of these", + "hashtag.column_settings.tag_mode.any": "Any of these", + "hashtag.column_settings.tag_mode.none": "None of these", + "hashtag.column_settings.tag_toggle": "Include additional tags in this column", "home.column_settings.basic": "Perusasetukset", "home.column_settings.show_reblogs": "Näytä buustaukset", "home.column_settings.show_replies": "Näytä vastaukset", "keyboard_shortcuts.back": "liiku taaksepäin", - "keyboard_shortcuts.blocked": "to open blocked users list", + "keyboard_shortcuts.blocked": "avaa lista estetyistä käyttäjistä", "keyboard_shortcuts.boost": "buustaa", "keyboard_shortcuts.column": "siirrä fokus tietyn sarakkeen tilapäivitykseen", "keyboard_shortcuts.compose": "siirry tekstinsyöttöön", "keyboard_shortcuts.description": "Kuvaus", - "keyboard_shortcuts.direct": "to open direct messages column", + "keyboard_shortcuts.direct": "avaa pikaviestisarake", "keyboard_shortcuts.down": "siirry listassa alaspäin", "keyboard_shortcuts.enter": "avaa tilapäivitys", "keyboard_shortcuts.favourite": "tykkää", - "keyboard_shortcuts.favourites": "to open favourites list", - "keyboard_shortcuts.federated": "to open federated timeline", + "keyboard_shortcuts.favourites": "avaa lista suosikeista", + "keyboard_shortcuts.federated": "avaa yleinen aikajana", "keyboard_shortcuts.heading": "Näppäinkomennot", - "keyboard_shortcuts.home": "to open home timeline", + "keyboard_shortcuts.home": "avaa kotiaikajana", "keyboard_shortcuts.hotkey": "Pikanäppäin", "keyboard_shortcuts.legend": "näytä tämä selite", - "keyboard_shortcuts.local": "to open local timeline", + "keyboard_shortcuts.local": "avaa paikallinen aikajana", "keyboard_shortcuts.mention": "mainitse julkaisija", - "keyboard_shortcuts.muted": "to open muted users list", - "keyboard_shortcuts.my_profile": "to open your profile", - "keyboard_shortcuts.notifications": "to open notifications column", - "keyboard_shortcuts.pinned": "to open pinned toots list", - "keyboard_shortcuts.profile": "to open author's profile", + "keyboard_shortcuts.muted": "avaa lista mykistetyistä käyttäjistä", + "keyboard_shortcuts.my_profile": "avaa profiilisi", + "keyboard_shortcuts.notifications": "avaa ilmoitukset-sarake", + "keyboard_shortcuts.pinned": "avaa lista kiinnitetyistä tuuttauksista", + "keyboard_shortcuts.profile": "avaa kirjoittajan profiili", "keyboard_shortcuts.reply": "vastaa", - "keyboard_shortcuts.requests": "to open follow requests list", + "keyboard_shortcuts.requests": "avaa lista seurauspyynnöistä", "keyboard_shortcuts.search": "siirry hakukenttään", - "keyboard_shortcuts.start": "to open \"get started\" column", + "keyboard_shortcuts.start": "avaa \"Aloitus\" -sarake", "keyboard_shortcuts.toggle_hidden": "näytä/piilota sisältövaroituksella merkitty teksti", "keyboard_shortcuts.toot": "ala kirjoittaa uutta tuuttausta", "keyboard_shortcuts.unfocus": "siirry pois tekstikentästä tai hakukentästä", @@ -187,16 +195,16 @@ "missing_indicator.label": "Ei löytynyt", "missing_indicator.sublabel": "Tätä resurssia ei löytynyt", "mute_modal.hide_notifications": "Piilota tältä käyttäjältä tulevat ilmoitukset?", - "navigation_bar.apps": "Mobile apps", + "navigation_bar.apps": "Mobiiliapplikaatiot", "navigation_bar.blocks": "Estetyt käyttäjät", "navigation_bar.community_timeline": "Paikallinen aikajana", - "navigation_bar.compose": "Compose new toot", + "navigation_bar.compose": "Kirjoita uusi tuuttaus", "navigation_bar.direct": "Viestit", "navigation_bar.discover": "Discover", "navigation_bar.domain_blocks": "Piilotetut verkkotunnukset", "navigation_bar.edit_profile": "Muokkaa profiilia", "navigation_bar.favourites": "Suosikit", - "navigation_bar.filters": "Muted words", + "navigation_bar.filters": "Mykistetyt sanat", "navigation_bar.follow_requests": "Seuraamispyynnöt", "navigation_bar.info": "Tietoa tästä instanssista", "navigation_bar.keyboard_shortcuts": "Näppäinkomennot", @@ -207,7 +215,7 @@ "navigation_bar.pins": "Kiinnitetyt tuuttaukset", "navigation_bar.preferences": "Asetukset", "navigation_bar.public_timeline": "Yleinen aikajana", - "navigation_bar.security": "Security", + "navigation_bar.security": "Tunnukset", "notification.favourite": "{name} tykkäsi tilastasi", "notification.follow": "{name} seurasi sinua", "notification.mention": "{name} mainitsi sinut", @@ -287,7 +295,7 @@ "status.direct": "Viesti käyttäjälle @{name}", "status.embed": "Upota", "status.favourite": "Tykkää", - "status.filtered": "Filtered", + "status.filtered": "Suodatettu", "status.load_more": "Lataa lisää", "status.media_hidden": "Media piilotettu", "status.mention": "Mainitse @{name}", @@ -297,12 +305,12 @@ "status.open": "Laajenna tilapäivitys", "status.pin": "Kiinnitä profiiliin", "status.pinned": "Kiinnitetty tuuttaus", - "status.read_more": "Read more", + "status.read_more": "Näytä enemmän", "status.reblog": "Buustaa", "status.reblog_private": "Buustaa alkuperäiselle yleisölle", "status.reblogged_by": "{name} buustasi", "status.reblogs.empty": "No one has boosted this toot yet. When someone does, they will show up here.", - "status.redraft": "Delete & re-draft", + "status.redraft": "Poista & palauta muokattavaksi", "status.reply": "Vastaa", "status.replyAll": "Vastaa ketjuun", "status.report": "Raportoi @{name}", @@ -313,6 +321,7 @@ "status.show_less_all": "Näytä vähemmän kaikista", "status.show_more": "Näytä lisää", "status.show_more_all": "Näytä lisää kaikista", + "status.show_thread": "Show thread", "status.unmute_conversation": "Poista keskustelun mykistys", "status.unpin": "Irrota profiilista", "suggestions.dismiss": "Dismiss suggestion", diff --git a/app/javascript/mastodon/locales/fr.json b/app/javascript/mastodon/locales/fr.json index c6cb3cba8..85cafb18c 100644 --- a/app/javascript/mastodon/locales/fr.json +++ b/app/javascript/mastodon/locales/fr.json @@ -112,6 +112,7 @@ "emoji_button.search_results": "Résultats de la recherche", "emoji_button.symbols": "Symboles", "emoji_button.travel": "Lieux & Voyages", + "empty_column.account_timeline": "No toots here!", "empty_column.blocks": "Vous n’avez bloqué aucun utilisateur pour le moment.", "empty_column.community": "Le fil public local est vide. Écrivez donc quelque chose pour le remplir !", "empty_column.direct": "Vous n’avez pas encore de messages directs. Lorsque vous en enverrez ou recevrez un, il s’affichera ici.", @@ -137,6 +138,13 @@ "getting_started.open_source_notice": "Mastodon est un logiciel libre. Vous pouvez contribuer et envoyer vos commentaires et rapports de bogues via {github} sur GitHub.", "getting_started.security": "Sécurité", "getting_started.terms": "Conditions d’utilisation", + "hashtag.column_header.tag_mode.all": "and {additional}", + "hashtag.column_header.tag_mode.any": "or {additional}", + "hashtag.column_header.tag_mode.none": "without {additional}", + "hashtag.column_settings.tag_mode.all": "All of these", + "hashtag.column_settings.tag_mode.any": "Any of these", + "hashtag.column_settings.tag_mode.none": "None of these", + "hashtag.column_settings.tag_toggle": "Include additional tags in this column", "home.column_settings.basic": "Basique", "home.column_settings.show_reblogs": "Afficher les partages", "home.column_settings.show_replies": "Afficher les réponses", @@ -313,10 +321,11 @@ "status.show_less_all": "Tout replier", "status.show_more": "Déplier", "status.show_more_all": "Tout déplier", + "status.show_thread": "Show thread", "status.unmute_conversation": "Ne plus masquer la conversation", "status.unpin": "Retirer du profil", - "suggestions.dismiss": "Dismiss suggestion", - "suggestions.header": "You might be interested in…", + "suggestions.dismiss": "Rejeter la suggestion", + "suggestions.header": "Vous pourriez être intéressé par.…", "tabs_bar.federated_timeline": "Fil public global", "tabs_bar.home": "Accueil", "tabs_bar.local_timeline": "Fil public local", diff --git a/app/javascript/mastodon/locales/gl.json b/app/javascript/mastodon/locales/gl.json index 98011dac7..f2a8aec3a 100644 --- a/app/javascript/mastodon/locales/gl.json +++ b/app/javascript/mastodon/locales/gl.json @@ -112,6 +112,7 @@ "emoji_button.search_results": "Resultados da busca", "emoji_button.symbols": "Símbolos", "emoji_button.travel": "Viaxes e Lugares", + "empty_column.account_timeline": "No toots here!", "empty_column.blocks": "Non bloqueou ningunha usuaria polo de agora.", "empty_column.community": "A liña temporal local está baldeira. Escriba algo de xeito público para que rule!", "empty_column.direct": "Aínda non ten mensaxes directas. Cando envíe ou reciba unha, aparecerá aquí.", @@ -137,6 +138,13 @@ "getting_started.open_source_notice": "Mastodon é software de código aberto. Pode contribuír ou informar de fallos en GitHub en {github}.", "getting_started.security": "Seguridade", "getting_started.terms": "Termos do servizo", + "hashtag.column_header.tag_mode.all": "and {additional}", + "hashtag.column_header.tag_mode.any": "or {additional}", + "hashtag.column_header.tag_mode.none": "without {additional}", + "hashtag.column_settings.tag_mode.all": "All of these", + "hashtag.column_settings.tag_mode.any": "Any of these", + "hashtag.column_settings.tag_mode.none": "None of these", + "hashtag.column_settings.tag_toggle": "Include additional tags in this column", "home.column_settings.basic": "Básico", "home.column_settings.show_reblogs": "Mostrar repeticións", "home.column_settings.show_replies": "Mostrar respostas", @@ -313,10 +321,11 @@ "status.show_less_all": "Mostrar menos para todas", "status.show_more": "Mostrar máis", "status.show_more_all": "Mostrar máis para todas", + "status.show_thread": "Show thread", "status.unmute_conversation": "Non acalar a conversa", "status.unpin": "Despegar do perfil", - "suggestions.dismiss": "Dismiss suggestion", - "suggestions.header": "You might be interested in…", + "suggestions.dismiss": "Rexeitar suxestión", + "suggestions.header": "Podería estar interesada en…", "tabs_bar.federated_timeline": "Federado", "tabs_bar.home": "Inicio", "tabs_bar.local_timeline": "Local", diff --git a/app/javascript/mastodon/locales/he.json b/app/javascript/mastodon/locales/he.json index d0c96917e..3bcd825ae 100644 --- a/app/javascript/mastodon/locales/he.json +++ b/app/javascript/mastodon/locales/he.json @@ -112,6 +112,7 @@ "emoji_button.search_results": "תוצאות חיפוש", "emoji_button.symbols": "סמלים", "emoji_button.travel": "טיולים ואתרים", + "empty_column.account_timeline": "No toots here!", "empty_column.blocks": "You haven't blocked any users yet.", "empty_column.community": "טור הסביבה ריק. יש לפרסם משהו כדי שדברים יתרחילו להתגלגל!", "empty_column.direct": "You don't have any direct messages yet. When you send or receive one, it will show up here.", @@ -137,6 +138,13 @@ "getting_started.open_source_notice": "מסטודון היא תוכנה חופשית (בקוד פתוח). ניתן לתרום או לדווח על בעיות בגיטהאב: {github}.", "getting_started.security": "Security", "getting_started.terms": "Terms of service", + "hashtag.column_header.tag_mode.all": "and {additional}", + "hashtag.column_header.tag_mode.any": "or {additional}", + "hashtag.column_header.tag_mode.none": "without {additional}", + "hashtag.column_settings.tag_mode.all": "All of these", + "hashtag.column_settings.tag_mode.any": "Any of these", + "hashtag.column_settings.tag_mode.none": "None of these", + "hashtag.column_settings.tag_toggle": "Include additional tags in this column", "home.column_settings.basic": "למתחילים", "home.column_settings.show_reblogs": "הצגת הדהודים", "home.column_settings.show_replies": "הצגת תגובות", @@ -313,6 +321,7 @@ "status.show_less_all": "Show less for all", "status.show_more": "הראה יותר", "status.show_more_all": "Show more for all", + "status.show_thread": "Show thread", "status.unmute_conversation": "הסרת השתקת שיחה", "status.unpin": "לשחרר מקיבוע באודות", "suggestions.dismiss": "Dismiss suggestion", diff --git a/app/javascript/mastodon/locales/hr.json b/app/javascript/mastodon/locales/hr.json index c50138e23..33d2b3e37 100644 --- a/app/javascript/mastodon/locales/hr.json +++ b/app/javascript/mastodon/locales/hr.json @@ -112,6 +112,7 @@ "emoji_button.search_results": "Search results", "emoji_button.symbols": "Simboli", "emoji_button.travel": "Putovanja & Mjesta", + "empty_column.account_timeline": "No toots here!", "empty_column.blocks": "You haven't blocked any users yet.", "empty_column.community": "Lokalni timeline je prazan. Napiši nešto javno kako bi pokrenuo stvari!", "empty_column.direct": "You don't have any direct messages yet. When you send or receive one, it will show up here.", @@ -137,6 +138,13 @@ "getting_started.open_source_notice": "Mastodon je softver otvorenog koda. Možeš pridonijeti ili prijaviti probleme na GitHubu {github}.", "getting_started.security": "Security", "getting_started.terms": "Terms of service", + "hashtag.column_header.tag_mode.all": "and {additional}", + "hashtag.column_header.tag_mode.any": "or {additional}", + "hashtag.column_header.tag_mode.none": "without {additional}", + "hashtag.column_settings.tag_mode.all": "All of these", + "hashtag.column_settings.tag_mode.any": "Any of these", + "hashtag.column_settings.tag_mode.none": "None of these", + "hashtag.column_settings.tag_toggle": "Include additional tags in this column", "home.column_settings.basic": "Osnovno", "home.column_settings.show_reblogs": "Pokaži boostove", "home.column_settings.show_replies": "Pokaži odgovore", @@ -313,6 +321,7 @@ "status.show_less_all": "Show less for all", "status.show_more": "Pokaži više", "status.show_more_all": "Show more for all", + "status.show_thread": "Show thread", "status.unmute_conversation": "Poništi utišavanje razgovora", "status.unpin": "Unpin from profile", "suggestions.dismiss": "Dismiss suggestion", diff --git a/app/javascript/mastodon/locales/hu.json b/app/javascript/mastodon/locales/hu.json index 90d186d57..51d65f98c 100644 --- a/app/javascript/mastodon/locales/hu.json +++ b/app/javascript/mastodon/locales/hu.json @@ -112,6 +112,7 @@ "emoji_button.search_results": "Keresési találatok", "emoji_button.symbols": "Szimbólumok", "emoji_button.travel": "Utazás és Helyek", + "empty_column.account_timeline": "No toots here!", "empty_column.blocks": "You haven't blocked any users yet.", "empty_column.community": "A helyi idővonal üres. Írj egy publikus stástuszt, hogy elindítsd a labdát!", "empty_column.direct": "You don't have any direct messages yet. When you send or receive one, it will show up here.", @@ -137,6 +138,13 @@ "getting_started.open_source_notice": "Mastodon egy nyílt forráskódú szoftver. Hozzájárulás vagy problémák jelentése a GitHub-on {github}.", "getting_started.security": "Security", "getting_started.terms": "Terms of service", + "hashtag.column_header.tag_mode.all": "and {additional}", + "hashtag.column_header.tag_mode.any": "or {additional}", + "hashtag.column_header.tag_mode.none": "without {additional}", + "hashtag.column_settings.tag_mode.all": "All of these", + "hashtag.column_settings.tag_mode.any": "Any of these", + "hashtag.column_settings.tag_mode.none": "None of these", + "hashtag.column_settings.tag_toggle": "Include additional tags in this column", "home.column_settings.basic": "Alap", "home.column_settings.show_reblogs": "Ismétlések mutatása", "home.column_settings.show_replies": "Válaszok mutatása", @@ -313,6 +321,7 @@ "status.show_less_all": "Show less for all", "status.show_more": "Többet", "status.show_more_all": "Show more for all", + "status.show_thread": "Show thread", "status.unmute_conversation": "Beszélgetés némításának elvonása", "status.unpin": "Kitűzés eltávolítása a profilról", "suggestions.dismiss": "Dismiss suggestion", diff --git a/app/javascript/mastodon/locales/hy.json b/app/javascript/mastodon/locales/hy.json index 388cc4381..76c96ff03 100644 --- a/app/javascript/mastodon/locales/hy.json +++ b/app/javascript/mastodon/locales/hy.json @@ -112,6 +112,7 @@ "emoji_button.search_results": "Որոնման արդյունքներ", "emoji_button.symbols": "Նշաններ", "emoji_button.travel": "Ուղեւորություն եւ տեղանքներ", + "empty_column.account_timeline": "No toots here!", "empty_column.blocks": "You haven't blocked any users yet.", "empty_column.community": "Տեղական հոսքը դատա՛րկ է։ Հրապարակային մի բան գրիր շարժիչը խոդ տալու համար։", "empty_column.direct": "You don't have any direct messages yet. When you send or receive one, it will show up here.", @@ -137,6 +138,13 @@ "getting_started.open_source_notice": "Մաստոդոնը բաց ելատեքստով ծրագրակազմ է։ Կարող ես ներդրում անել կամ վրեպներ զեկուցել ԳիթՀաբում՝ {github}։", "getting_started.security": "Security", "getting_started.terms": "Terms of service", + "hashtag.column_header.tag_mode.all": "and {additional}", + "hashtag.column_header.tag_mode.any": "or {additional}", + "hashtag.column_header.tag_mode.none": "without {additional}", + "hashtag.column_settings.tag_mode.all": "All of these", + "hashtag.column_settings.tag_mode.any": "Any of these", + "hashtag.column_settings.tag_mode.none": "None of these", + "hashtag.column_settings.tag_toggle": "Include additional tags in this column", "home.column_settings.basic": "Հիմնական", "home.column_settings.show_reblogs": "Ցուցադրել տարածածները", "home.column_settings.show_replies": "Ցուցադրել պատասխանները", @@ -313,6 +321,7 @@ "status.show_less_all": "Show less for all", "status.show_more": "Ավելին", "status.show_more_all": "Show more for all", + "status.show_thread": "Show thread", "status.unmute_conversation": "Ապալռեցնել խոսակցությունը", "status.unpin": "Հանել անձնական էջից", "suggestions.dismiss": "Dismiss suggestion", diff --git a/app/javascript/mastodon/locales/id.json b/app/javascript/mastodon/locales/id.json index 4f3b654ab..5280d96c2 100644 --- a/app/javascript/mastodon/locales/id.json +++ b/app/javascript/mastodon/locales/id.json @@ -112,6 +112,7 @@ "emoji_button.search_results": "Hasil pencarian", "emoji_button.symbols": "Simbol", "emoji_button.travel": "Tempat Wisata", + "empty_column.account_timeline": "No toots here!", "empty_column.blocks": "You haven't blocked any users yet.", "empty_column.community": "Linimasa lokal masih kosong. Tulis sesuatu secara publik dan buat roda berputar!", "empty_column.direct": "You don't have any direct messages yet. When you send or receive one, it will show up here.", @@ -137,6 +138,13 @@ "getting_started.open_source_notice": "Mastodon adalah perangkat lunak yang bersifat terbuka. Anda dapat berkontribusi atau melaporkan permasalahan/bug di Github {github}.", "getting_started.security": "Security", "getting_started.terms": "Terms of service", + "hashtag.column_header.tag_mode.all": "and {additional}", + "hashtag.column_header.tag_mode.any": "or {additional}", + "hashtag.column_header.tag_mode.none": "without {additional}", + "hashtag.column_settings.tag_mode.all": "All of these", + "hashtag.column_settings.tag_mode.any": "Any of these", + "hashtag.column_settings.tag_mode.none": "None of these", + "hashtag.column_settings.tag_toggle": "Include additional tags in this column", "home.column_settings.basic": "Dasar", "home.column_settings.show_reblogs": "Tampilkan boost", "home.column_settings.show_replies": "Tampilkan balasan", @@ -313,6 +321,7 @@ "status.show_less_all": "Show less for all", "status.show_more": "Tampilkan semua", "status.show_more_all": "Show more for all", + "status.show_thread": "Show thread", "status.unmute_conversation": "Unmute conversation", "status.unpin": "Unpin from profile", "suggestions.dismiss": "Dismiss suggestion", diff --git a/app/javascript/mastodon/locales/io.json b/app/javascript/mastodon/locales/io.json index 55a5ba748..a8a162d82 100644 --- a/app/javascript/mastodon/locales/io.json +++ b/app/javascript/mastodon/locales/io.json @@ -112,6 +112,7 @@ "emoji_button.search_results": "Search results", "emoji_button.symbols": "Symbols", "emoji_button.travel": "Travel & Places", + "empty_column.account_timeline": "No toots here!", "empty_column.blocks": "You haven't blocked any users yet.", "empty_column.community": "La lokala tempolineo esas vakua. Skribez ulo publike por iniciar la agiveso!", "empty_column.direct": "You don't have any direct messages yet. When you send or receive one, it will show up here.", @@ -137,6 +138,13 @@ "getting_started.open_source_notice": "Mastodon esas programaro kun apertita kodexo. Tu povas kontributar o signalar problemi en GitHub ye {github}.", "getting_started.security": "Security", "getting_started.terms": "Terms of service", + "hashtag.column_header.tag_mode.all": "and {additional}", + "hashtag.column_header.tag_mode.any": "or {additional}", + "hashtag.column_header.tag_mode.none": "without {additional}", + "hashtag.column_settings.tag_mode.all": "All of these", + "hashtag.column_settings.tag_mode.any": "Any of these", + "hashtag.column_settings.tag_mode.none": "None of these", + "hashtag.column_settings.tag_toggle": "Include additional tags in this column", "home.column_settings.basic": "Simpla", "home.column_settings.show_reblogs": "Montrar repeti", "home.column_settings.show_replies": "Montrar respondi", @@ -313,6 +321,7 @@ "status.show_less_all": "Show less for all", "status.show_more": "Montrar plue", "status.show_more_all": "Show more for all", + "status.show_thread": "Show thread", "status.unmute_conversation": "Unmute conversation", "status.unpin": "Unpin from profile", "suggestions.dismiss": "Dismiss suggestion", diff --git a/app/javascript/mastodon/locales/it.json b/app/javascript/mastodon/locales/it.json index d6f6ff3e2..7907909c5 100644 --- a/app/javascript/mastodon/locales/it.json +++ b/app/javascript/mastodon/locales/it.json @@ -112,6 +112,7 @@ "emoji_button.search_results": "Risultati della ricerca", "emoji_button.symbols": "Simboli", "emoji_button.travel": "Viaggi e luoghi", + "empty_column.account_timeline": "No toots here!", "empty_column.blocks": "Non hai ancora bloccato nessun utente.", "empty_column.community": "La timeline locale è vuota. Condividi qualcosa pubblicamente per dare inizio alla festa!", "empty_column.direct": "Non hai ancora nessun messaggio diretto. Quando ne manderai o riceverai qualcuno, apparirà qui.", @@ -137,6 +138,13 @@ "getting_started.open_source_notice": "Mastodon è un software open source. Puoi contribuire o segnalare errori su GitHub all'indirizzo {github}.", "getting_started.security": "Sicurezza", "getting_started.terms": "Condizioni del servizio", + "hashtag.column_header.tag_mode.all": "and {additional}", + "hashtag.column_header.tag_mode.any": "or {additional}", + "hashtag.column_header.tag_mode.none": "without {additional}", + "hashtag.column_settings.tag_mode.all": "All of these", + "hashtag.column_settings.tag_mode.any": "Any of these", + "hashtag.column_settings.tag_mode.none": "None of these", + "hashtag.column_settings.tag_toggle": "Include additional tags in this column", "home.column_settings.basic": "Semplice", "home.column_settings.show_reblogs": "Mostra post condivisi", "home.column_settings.show_replies": "Mostra risposte", @@ -313,10 +321,11 @@ "status.show_less_all": "Mostra meno per tutti", "status.show_more": "Mostra di più", "status.show_more_all": "Mostra di più per tutti", + "status.show_thread": "Show thread", "status.unmute_conversation": "Annulla silenzia conversazione", "status.unpin": "Non fissare in cima al profilo", - "suggestions.dismiss": "Dismiss suggestion", - "suggestions.header": "You might be interested in…", + "suggestions.dismiss": "Elimina suggerimento", + "suggestions.header": "Ti potrebbe interessare…", "tabs_bar.federated_timeline": "Federazione", "tabs_bar.home": "Home", "tabs_bar.local_timeline": "Locale", diff --git a/app/javascript/mastodon/locales/ja.json b/app/javascript/mastodon/locales/ja.json index a79f9db86..06fe71e6b 100644 --- a/app/javascript/mastodon/locales/ja.json +++ b/app/javascript/mastodon/locales/ja.json @@ -142,9 +142,9 @@ "getting_started.open_source_notice": "Mastodonはオープンソースソフトウェアです。誰でもGitHub({github})から開発に参加したり、問題を報告したりできます。", "getting_started.security": "セキュリティ", "getting_started.terms": "プライバシーポリシー", - "hashtag.column_header.tag_mode.all": " と {additional}", - "hashtag.column_header.tag_mode.any": " か {additional}", - "hashtag.column_header.tag_mode.none": " ({additional} を除く)", + "hashtag.column_header.tag_mode.all": "と {additional}", + "hashtag.column_header.tag_mode.any": "か {additional}", + "hashtag.column_header.tag_mode.none": "({additional} を除く)", "hashtag.column_settings.tag_mode.all": "すべてを含む", "hashtag.column_settings.tag_mode.any": "いずれかを含む", "hashtag.column_settings.tag_mode.none": "これらを除く", @@ -326,7 +326,7 @@ "status.show_less_all": "全て隠す", "status.show_more": "もっと見る", "status.show_more_all": "全て見る", - "status.show_thread": "続きを読む", + "status.show_thread": "スレッドを表示", "status.unmute_conversation": "会話のミュートを解除", "status.unpin": "プロフィールの固定表示を解除", "suggestions.dismiss": "隠す", diff --git a/app/javascript/mastodon/locales/ka.json b/app/javascript/mastodon/locales/ka.json index 5d6537b90..cbb639136 100644 --- a/app/javascript/mastodon/locales/ka.json +++ b/app/javascript/mastodon/locales/ka.json @@ -112,6 +112,7 @@ "emoji_button.search_results": "ძებნის შედეგები", "emoji_button.symbols": "სიმბოლოები", "emoji_button.travel": "მოგზაურობა და ადგილები", + "empty_column.account_timeline": "No toots here!", "empty_column.blocks": "You haven't blocked any users yet.", "empty_column.community": "ლოკალური თაიმლაინი ცარიელია. დაწერეთ რაიმე ღიად ან ქენით რაიმე სხვა!", "empty_column.direct": "ჯერ პირდაპირი წერილები არ გაქვთ. როდესაც მიიღებთ ან გააგზავნით, გამოჩნდება აქ.", @@ -137,6 +138,13 @@ "getting_started.open_source_notice": "მასტოდონი ღია პროგრამაა. შეგიძლიათ შეუწყოთ ხელი ან შექმნათ პრობემის რეპორტი {github}-ზე.", "getting_started.security": "უსაფრთხოება", "getting_started.terms": "მომსახურების პირობები", + "hashtag.column_header.tag_mode.all": "and {additional}", + "hashtag.column_header.tag_mode.any": "or {additional}", + "hashtag.column_header.tag_mode.none": "without {additional}", + "hashtag.column_settings.tag_mode.all": "All of these", + "hashtag.column_settings.tag_mode.any": "Any of these", + "hashtag.column_settings.tag_mode.none": "None of these", + "hashtag.column_settings.tag_toggle": "Include additional tags in this column", "home.column_settings.basic": "ძირითადი", "home.column_settings.show_reblogs": "ბუსტების ჩვენება", "home.column_settings.show_replies": "პასუხების ჩვენება", @@ -313,6 +321,7 @@ "status.show_less_all": "აჩვენე ნაკლები ყველაზე", "status.show_more": "აჩვენე მეტი", "status.show_more_all": "აჩვენე მეტი ყველაზე", + "status.show_thread": "Show thread", "status.unmute_conversation": "საუბარზე გაჩუმების მოშორება", "status.unpin": "პროფილიდან პინის მოშორება", "suggestions.dismiss": "Dismiss suggestion", diff --git a/app/javascript/mastodon/locales/ko.json b/app/javascript/mastodon/locales/ko.json index a7228d4d5..cd481b9e5 100644 --- a/app/javascript/mastodon/locales/ko.json +++ b/app/javascript/mastodon/locales/ko.json @@ -112,6 +112,7 @@ "emoji_button.search_results": "검색 결과", "emoji_button.symbols": "기호", "emoji_button.travel": "여행과 장소", + "empty_column.account_timeline": "No toots here!", "empty_column.blocks": "아직 아무도 차단하지 않았습니다.", "empty_column.community": "로컬 타임라인에 아무 것도 없습니다. 아무거나 적어 보세요!", "empty_column.direct": "아직 다이렉트 메시지가 없습니다. 다이렉트 메시지를 보내거나 받은 경우, 여기에 표시 됩니다.", @@ -137,6 +138,13 @@ "getting_started.open_source_notice": "Mastodon은 오픈 소스 소프트웨어입니다. 누구나 GitHub({github})에서 개발에 참여하거나, 문제를 보고할 수 있습니다.", "getting_started.security": "보안", "getting_started.terms": "이용 약관", + "hashtag.column_header.tag_mode.all": "and {additional}", + "hashtag.column_header.tag_mode.any": "or {additional}", + "hashtag.column_header.tag_mode.none": "without {additional}", + "hashtag.column_settings.tag_mode.all": "All of these", + "hashtag.column_settings.tag_mode.any": "Any of these", + "hashtag.column_settings.tag_mode.none": "None of these", + "hashtag.column_settings.tag_toggle": "Include additional tags in this column", "home.column_settings.basic": "기본 설정", "home.column_settings.show_reblogs": "부스트 표시", "home.column_settings.show_replies": "답글 표시", @@ -313,10 +321,11 @@ "status.show_less_all": "모두 접기", "status.show_more": "더 보기", "status.show_more_all": "모두 펼치기", + "status.show_thread": "Show thread", "status.unmute_conversation": "이 대화의 뮤트 해제하기", "status.unpin": "고정 해제", - "suggestions.dismiss": "Dismiss suggestion", - "suggestions.header": "You might be interested in…", + "suggestions.dismiss": "추천 지우기", + "suggestions.header": "이것에 관심이 있을 것 같습니다…", "tabs_bar.federated_timeline": "연합", "tabs_bar.home": "홈", "tabs_bar.local_timeline": "로컬", diff --git a/app/javascript/mastodon/locales/ms.json b/app/javascript/mastodon/locales/ms.json new file mode 100644 index 000000000..3e243b743 --- /dev/null +++ b/app/javascript/mastodon/locales/ms.json @@ -0,0 +1,351 @@ +{ + "account.add_or_remove_from_list": "Add or Remove from lists", + "account.badges.bot": "Bot", + "account.block": "Block @{name}", + "account.block_domain": "Hide everything from {domain}", + "account.blocked": "Blocked", + "account.direct": "Direct message @{name}", + "account.disclaimer_full": "Information below may reflect the user's profile incompletely.", + "account.domain_blocked": "Domain hidden", + "account.edit_profile": "Edit profile", + "account.endorse": "Feature on profile", + "account.follow": "Follow", + "account.followers": "Followers", + "account.followers.empty": "No one follows this user yet.", + "account.follows": "Follows", + "account.follows.empty": "This user doesn't follow anyone yet.", + "account.follows_you": "Follows you", + "account.hide_reblogs": "Hide boosts from @{name}", + "account.link_verified_on": "Ownership of this link was checked on {date}", + "account.media": "Media", + "account.mention": "Mention @{name}", + "account.moved_to": "{name} has moved to:", + "account.mute": "Mute @{name}", + "account.mute_notifications": "Mute notifications from @{name}", + "account.muted": "Muted", + "account.posts": "Toots", + "account.posts_with_replies": "Toots and replies", + "account.report": "Report @{name}", + "account.requested": "Awaiting approval. Click to cancel follow request", + "account.share": "Share @{name}'s profile", + "account.show_reblogs": "Show boosts from @{name}", + "account.unblock": "Unblock @{name}", + "account.unblock_domain": "Unhide {domain}", + "account.unendorse": "Don't feature on profile", + "account.unfollow": "Unfollow", + "account.unmute": "Unmute @{name}", + "account.unmute_notifications": "Unmute notifications from @{name}", + "account.view_full_profile": "View full profile", + "alert.unexpected.message": "An unexpected error occurred.", + "alert.unexpected.title": "Oops!", + "boost_modal.combo": "You can press {combo} to skip this next time", + "bundle_column_error.body": "Something went wrong while loading this component.", + "bundle_column_error.retry": "Try again", + "bundle_column_error.title": "Network error", + "bundle_modal_error.close": "Close", + "bundle_modal_error.message": "Something went wrong while loading this component.", + "bundle_modal_error.retry": "Try again", + "column.blocks": "Blocked users", + "column.community": "Local timeline", + "column.direct": "Direct messages", + "column.domain_blocks": "Hidden domains", + "column.favourites": "Favourites", + "column.follow_requests": "Follow requests", + "column.home": "Home", + "column.lists": "Lists", + "column.mutes": "Muted users", + "column.notifications": "Notifications", + "column.pins": "Pinned toot", + "column.public": "Federated timeline", + "column_back_button.label": "Back", + "column_header.hide_settings": "Hide settings", + "column_header.moveLeft_settings": "Move column to the left", + "column_header.moveRight_settings": "Move column to the right", + "column_header.pin": "Pin", + "column_header.show_settings": "Show settings", + "column_header.unpin": "Unpin", + "column_subheading.settings": "Settings", + "community.column_settings.media_only": "Media Only", + "compose_form.direct_message_warning": "This toot will only be sent to all the mentioned users.", + "compose_form.direct_message_warning_learn_more": "Learn more", + "compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.", + "compose_form.lock_disclaimer": "Your account is not {locked}. Anyone can follow you to view your follower-only posts.", + "compose_form.lock_disclaimer.lock": "locked", + "compose_form.placeholder": "What is on your mind?", + "compose_form.publish": "Toot", + "compose_form.publish_loud": "{publish}!", + "compose_form.sensitive.marked": "Media is marked as sensitive", + "compose_form.sensitive.unmarked": "Media is not marked as sensitive", + "compose_form.spoiler.marked": "Text is hidden behind warning", + "compose_form.spoiler.unmarked": "Text is not hidden", + "compose_form.spoiler_placeholder": "Write your warning here", + "confirmation_modal.cancel": "Cancel", + "confirmations.block.confirm": "Block", + "confirmations.block.message": "Are you sure you want to block {name}?", + "confirmations.delete.confirm": "Delete", + "confirmations.delete.message": "Are you sure you want to delete this status?", + "confirmations.delete_list.confirm": "Delete", + "confirmations.delete_list.message": "Are you sure you want to permanently delete this list?", + "confirmations.domain_block.confirm": "Hide entire domain", + "confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable. You will not see content from that domain in any public timelines or your notifications. Your followers from that domain will be removed.", + "confirmations.mute.confirm": "Mute", + "confirmations.mute.message": "Are you sure you want to mute {name}?", + "confirmations.redraft.confirm": "Delete & redraft", + "confirmations.redraft.message": "Are you sure you want to delete this status and re-draft it? Favourites and boosts will be lost, and replies to the original post will be orphaned.", + "confirmations.reply.confirm": "Reply", + "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?", + "confirmations.unfollow.confirm": "Unfollow", + "confirmations.unfollow.message": "Are you sure you want to unfollow {name}?", + "embed.instructions": "Embed this status on your website by copying the code below.", + "embed.preview": "Here is what it will look like:", + "emoji_button.activity": "Activity", + "emoji_button.custom": "Custom", + "emoji_button.flags": "Flags", + "emoji_button.food": "Food & Drink", + "emoji_button.label": "Insert emoji", + "emoji_button.nature": "Nature", + "emoji_button.not_found": "No emojos!! (╯°□°)╯︵ ┻━┻", + "emoji_button.objects": "Objects", + "emoji_button.people": "People", + "emoji_button.recent": "Frequently used", + "emoji_button.search": "Search...", + "emoji_button.search_results": "Search results", + "emoji_button.symbols": "Symbols", + "emoji_button.travel": "Travel & Places", + "empty_column.account_timeline": "No toots here!", + "empty_column.blocks": "You haven't blocked any users yet.", + "empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!", + "empty_column.direct": "You don't have any direct messages yet. When you send or receive one, it will show up here.", + "empty_column.domain_blocks": "There are no hidden domains yet.", + "empty_column.favourited_statuses": "You don't have any favourite toots yet. When you favourite one, it will show up here.", + "empty_column.favourites": "No one has favourited this toot yet. When someone does, they will show up here.", + "empty_column.follow_requests": "You don't have any follow requests yet. When you receive one, it will show up here.", + "empty_column.hashtag": "There is nothing in this hashtag yet.", + "empty_column.home": "Your home timeline is empty! Visit {public} or use search to get started and meet other users.", + "empty_column.home.public_timeline": "the public timeline", + "empty_column.list": "There is nothing in this list yet. When members of this list post new statuses, they will appear here.", + "empty_column.lists": "You don't have any lists yet. When you create one, it will show up here.", + "empty_column.mutes": "You haven't muted any users yet.", + "empty_column.notifications": "You don't have any notifications yet. Interact with others to start the conversation.", + "empty_column.public": "There is nothing here! Write something publicly, or manually follow users from other instances to fill it up", + "follow_request.authorize": "Authorize", + "follow_request.reject": "Reject", + "getting_started.developers": "Developers", + "getting_started.documentation": "Documentation", + "getting_started.find_friends": "Find friends from Twitter", + "getting_started.heading": "Getting started", + "getting_started.invite": "Invite people", + "getting_started.open_source_notice": "Mastodon is open source software. You can contribute or report issues on GitHub at {github}.", + "getting_started.security": "Security", + "getting_started.terms": "Terms of service", + "hashtag.column_header.tag_mode.all": "and {additional}", + "hashtag.column_header.tag_mode.any": "or {additional}", + "hashtag.column_header.tag_mode.none": "without {additional}", + "hashtag.column_settings.tag_mode.all": "All of these", + "hashtag.column_settings.tag_mode.any": "Any of these", + "hashtag.column_settings.tag_mode.none": "None of these", + "hashtag.column_settings.tag_toggle": "Include additional tags in this column", + "home.column_settings.basic": "Basic", + "home.column_settings.show_reblogs": "Show boosts", + "home.column_settings.show_replies": "Show replies", + "keyboard_shortcuts.back": "to navigate back", + "keyboard_shortcuts.blocked": "to open blocked users list", + "keyboard_shortcuts.boost": "to boost", + "keyboard_shortcuts.column": "to focus a status in one of the columns", + "keyboard_shortcuts.compose": "to focus the compose textarea", + "keyboard_shortcuts.description": "Description", + "keyboard_shortcuts.direct": "to open direct messages column", + "keyboard_shortcuts.down": "to move down in the list", + "keyboard_shortcuts.enter": "to open status", + "keyboard_shortcuts.favourite": "to favourite", + "keyboard_shortcuts.favourites": "to open favourites list", + "keyboard_shortcuts.federated": "to open federated timeline", + "keyboard_shortcuts.heading": "Keyboard Shortcuts", + "keyboard_shortcuts.home": "to open home timeline", + "keyboard_shortcuts.hotkey": "Hotkey", + "keyboard_shortcuts.legend": "to display this legend", + "keyboard_shortcuts.local": "to open local timeline", + "keyboard_shortcuts.mention": "to mention author", + "keyboard_shortcuts.muted": "to open muted users list", + "keyboard_shortcuts.my_profile": "to open your profile", + "keyboard_shortcuts.notifications": "to open notifications column", + "keyboard_shortcuts.pinned": "to open pinned toots list", + "keyboard_shortcuts.profile": "to open author's profile", + "keyboard_shortcuts.reply": "to reply", + "keyboard_shortcuts.requests": "to open follow requests list", + "keyboard_shortcuts.search": "to focus search", + "keyboard_shortcuts.start": "to open \"get started\" column", + "keyboard_shortcuts.toggle_hidden": "to show/hide text behind CW", + "keyboard_shortcuts.toot": "to start a brand new toot", + "keyboard_shortcuts.unfocus": "to un-focus compose textarea/search", + "keyboard_shortcuts.up": "to move up in the list", + "lightbox.close": "Close", + "lightbox.next": "Next", + "lightbox.previous": "Previous", + "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": "Loading...", + "media_gallery.toggle_visible": "Toggle visibility", + "missing_indicator.label": "Not found", + "missing_indicator.sublabel": "This resource could not be found", + "mute_modal.hide_notifications": "Hide notifications from this user?", + "navigation_bar.apps": "Mobile apps", + "navigation_bar.blocks": "Blocked users", + "navigation_bar.community_timeline": "Local timeline", + "navigation_bar.compose": "Compose new toot", + "navigation_bar.direct": "Direct messages", + "navigation_bar.discover": "Discover", + "navigation_bar.domain_blocks": "Hidden domains", + "navigation_bar.edit_profile": "Edit profile", + "navigation_bar.favourites": "Favourites", + "navigation_bar.filters": "Muted words", + "navigation_bar.follow_requests": "Follow requests", + "navigation_bar.info": "About this instance", + "navigation_bar.keyboard_shortcuts": "Hotkeys", + "navigation_bar.lists": "Lists", + "navigation_bar.logout": "Logout", + "navigation_bar.mutes": "Muted users", + "navigation_bar.personal": "Personal", + "navigation_bar.pins": "Pinned toots", + "navigation_bar.preferences": "Preferences", + "navigation_bar.public_timeline": "Federated timeline", + "navigation_bar.security": "Security", + "notification.favourite": "{name} favourited your status", + "notification.follow": "{name} followed you", + "notification.mention": "{name} mentioned you", + "notification.reblog": "{name} boosted your status", + "notifications.clear": "Clear notifications", + "notifications.clear_confirmation": "Are you sure you want to permanently clear all your notifications?", + "notifications.column_settings.alert": "Desktop notifications", + "notifications.column_settings.favourite": "Favourites:", + "notifications.column_settings.follow": "New followers:", + "notifications.column_settings.mention": "Mentions:", + "notifications.column_settings.push": "Push notifications", + "notifications.column_settings.reblog": "Boosts:", + "notifications.column_settings.show": "Show in column", + "notifications.column_settings.sound": "Play sound", + "notifications.group": "{count} notifications", + "onboarding.done": "Done", + "onboarding.next": "Next", + "onboarding.page_five.public_timelines": "The local timeline shows public posts from everyone on {domain}. The federated timeline shows public posts from everyone who people on {domain} follow. These are the Public Timelines, a great way to discover new people.", + "onboarding.page_four.home": "The home timeline shows posts from people you follow.", + "onboarding.page_four.notifications": "The notifications column shows when someone interacts with you.", + "onboarding.page_one.federation": "Mastodon is a network of independent servers joining up to make one larger social network. We call these servers instances.", + "onboarding.page_one.full_handle": "Your full handle", + "onboarding.page_one.handle_hint": "This is what you would tell your friends to search for.", + "onboarding.page_one.welcome": "Welcome to Mastodon!", + "onboarding.page_six.admin": "Your instance's admin is {admin}.", + "onboarding.page_six.almost_done": "Almost done...", + "onboarding.page_six.appetoot": "Bon Appetoot!", + "onboarding.page_six.apps_available": "There are {apps} available for iOS, Android and other platforms.", + "onboarding.page_six.github": "Mastodon is free open-source software. You can report bugs, request features, or contribute to the code on {github}.", + "onboarding.page_six.guidelines": "community guidelines", + "onboarding.page_six.read_guidelines": "Please read {domain}'s {guidelines}!", + "onboarding.page_six.various_app": "mobile apps", + "onboarding.page_three.profile": "Edit your profile to change your avatar, bio, and display name. There, you will also find other preferences.", + "onboarding.page_three.search": "Use the search bar to find people and look at hashtags, such as {illustration} and {introductions}. To look for a person who is not on this instance, use their full handle.", + "onboarding.page_two.compose": "Write posts from the compose column. You can upload images, change privacy settings, and add content warnings with the icons below.", + "onboarding.skip": "Skip", + "privacy.change": "Adjust status privacy", + "privacy.direct.long": "Post to mentioned users only", + "privacy.direct.short": "Direct", + "privacy.private.long": "Post to followers only", + "privacy.private.short": "Followers-only", + "privacy.public.long": "Post to public timelines", + "privacy.public.short": "Public", + "privacy.unlisted.long": "Do not show in public timelines", + "privacy.unlisted.short": "Unlisted", + "regeneration_indicator.label": "Loading…", + "regeneration_indicator.sublabel": "Your home feed is being prepared!", + "relative_time.days": "{number}d", + "relative_time.hours": "{number}h", + "relative_time.just_now": "now", + "relative_time.minutes": "{number}m", + "relative_time.seconds": "{number}s", + "reply_indicator.cancel": "Cancel", + "report.forward": "Forward to {target}", + "report.forward_hint": "The account is from another server. Send an anonymized copy of the report there as well?", + "report.hint": "The report will be sent to your instance moderators. You can provide an explanation of why you are reporting this account below:", + "report.placeholder": "Additional comments", + "report.submit": "Submit", + "report.target": "Report {target}", + "search.placeholder": "Search", + "search_popout.search_format": "Advanced search format", + "search_popout.tips.full_text": "Simple text returns statuses you have written, favourited, boosted, or have been mentioned in, as well as matching usernames, display names, and hashtags.", + "search_popout.tips.hashtag": "hashtag", + "search_popout.tips.status": "status", + "search_popout.tips.text": "Simple text returns matching display names, usernames and hashtags", + "search_popout.tips.user": "user", + "search_results.accounts": "People", + "search_results.hashtags": "Hashtags", + "search_results.statuses": "Toots", + "search_results.total": "{count, number} {count, plural, one {result} other {results}}", + "standalone.public_title": "A look inside...", + "status.block": "Block @{name}", + "status.cancel_reblog_private": "Unboost", + "status.cannot_reblog": "This post cannot be boosted", + "status.delete": "Delete", + "status.detailed_status": "Detailed conversation view", + "status.direct": "Direct message @{name}", + "status.embed": "Embed", + "status.favourite": "Favourite", + "status.filtered": "Filtered", + "status.load_more": "Load more", + "status.media_hidden": "Media hidden", + "status.mention": "Mention @{name}", + "status.more": "More", + "status.mute": "Mute @{name}", + "status.mute_conversation": "Mute conversation", + "status.open": "Expand this status", + "status.pin": "Pin on profile", + "status.pinned": "Pinned toot", + "status.read_more": "Read more", + "status.reblog": "Boost", + "status.reblog_private": "Boost to original audience", + "status.reblogged_by": "{name} boosted", + "status.reblogs.empty": "No one has boosted this toot yet. When someone does, they will show up here.", + "status.redraft": "Delete & re-draft", + "status.reply": "Reply", + "status.replyAll": "Reply to thread", + "status.report": "Report @{name}", + "status.sensitive_toggle": "Click to view", + "status.sensitive_warning": "Sensitive content", + "status.share": "Share", + "status.show_less": "Show less", + "status.show_less_all": "Show less for all", + "status.show_more": "Show more", + "status.show_more_all": "Show more for all", + "status.show_thread": "Show thread", + "status.unmute_conversation": "Unmute conversation", + "status.unpin": "Unpin from profile", + "suggestions.dismiss": "Dismiss suggestion", + "suggestions.header": "You might be interested in…", + "tabs_bar.federated_timeline": "Federated", + "tabs_bar.home": "Home", + "tabs_bar.local_timeline": "Local", + "tabs_bar.notifications": "Notifications", + "tabs_bar.search": "Search", + "trends.count_by_accounts": "{count} {rawCount, plural, one {person} other {people}} talking", + "ui.beforeunload": "Your draft will be lost if you leave Mastodon.", + "upload_area.title": "Drag & drop to upload", + "upload_button.label": "Add media (JPEG, PNG, GIF, WebM, MP4, MOV)", + "upload_form.description": "Describe for the visually impaired", + "upload_form.focus": "Crop", + "upload_form.undo": "Delete", + "upload_progress.label": "Uploading...", + "video.close": "Close video", + "video.exit_fullscreen": "Exit full screen", + "video.expand": "Expand video", + "video.fullscreen": "Full screen", + "video.hide": "Hide video", + "video.mute": "Mute sound", + "video.pause": "Pause", + "video.play": "Play", + "video.unmute": "Unmute sound" +} diff --git a/app/javascript/mastodon/locales/nl.json b/app/javascript/mastodon/locales/nl.json index ec53a66b4..d8dea93d6 100644 --- a/app/javascript/mastodon/locales/nl.json +++ b/app/javascript/mastodon/locales/nl.json @@ -112,6 +112,7 @@ "emoji_button.search_results": "Zoekresultaten", "emoji_button.symbols": "Symbolen", "emoji_button.travel": "Reizen en plekken", + "empty_column.account_timeline": "No toots here!", "empty_column.blocks": "Jij hebt nog geen enkele gebruiker geblokkeerd.", "empty_column.community": "De lokale tijdlijn is nog leeg. Toot iets in het openbaar om de bal aan het rollen te krijgen!", "empty_column.direct": "Je hebt nog geen directe berichten. Wanneer je er een verzend of ontvangt, zijn deze hier te zien.", @@ -137,6 +138,13 @@ "getting_started.open_source_notice": "Mastodon is vrije software. Je kunt bijdragen of problemen melden op GitHub via {github}.", "getting_started.security": "Beveiliging", "getting_started.terms": "Voorwaarden", + "hashtag.column_header.tag_mode.all": "and {additional}", + "hashtag.column_header.tag_mode.any": "or {additional}", + "hashtag.column_header.tag_mode.none": "without {additional}", + "hashtag.column_settings.tag_mode.all": "All of these", + "hashtag.column_settings.tag_mode.any": "Any of these", + "hashtag.column_settings.tag_mode.none": "None of these", + "hashtag.column_settings.tag_toggle": "Include additional tags in this column", "home.column_settings.basic": "Algemeen", "home.column_settings.show_reblogs": "Boosts tonen", "home.column_settings.show_replies": "Reacties tonen", @@ -313,10 +321,11 @@ "status.show_less_all": "Alles minder tonen", "status.show_more": "Meer tonen", "status.show_more_all": "Alles meer tonen", - "status.unmute_conversation": "Conversatie niet langer negeren", + "status.show_thread": "Show thread", + "status.unmute_conversation": "Gesprek niet langer negeren", "status.unpin": "Van profielpagina losmaken", - "suggestions.dismiss": "Dismiss suggestion", - "suggestions.header": "You might be interested in…", + "suggestions.dismiss": "Suggestie verwerpen", + "suggestions.header": "Je bent waarschijnlijk ook geïnteresseerd in…", "tabs_bar.federated_timeline": "Globaal", "tabs_bar.home": "Start", "tabs_bar.local_timeline": "Lokaal", diff --git a/app/javascript/mastodon/locales/no.json b/app/javascript/mastodon/locales/no.json index d827a9816..ea4e76de4 100644 --- a/app/javascript/mastodon/locales/no.json +++ b/app/javascript/mastodon/locales/no.json @@ -112,6 +112,7 @@ "emoji_button.search_results": "Søkeresultat", "emoji_button.symbols": "Symboler", "emoji_button.travel": "Reise & steder", + "empty_column.account_timeline": "No toots here!", "empty_column.blocks": "You haven't blocked any users yet.", "empty_column.community": "Den lokale tidslinjen er tom. Skriv noe offentlig for å få snøballen til å rulle!", "empty_column.direct": "You don't have any direct messages yet. When you send or receive one, it will show up here.", @@ -137,6 +138,13 @@ "getting_started.open_source_notice": "Mastodon er fri programvare. Du kan bidra eller rapportere problemer på GitHub på {github}.", "getting_started.security": "Security", "getting_started.terms": "Terms of service", + "hashtag.column_header.tag_mode.all": "and {additional}", + "hashtag.column_header.tag_mode.any": "or {additional}", + "hashtag.column_header.tag_mode.none": "without {additional}", + "hashtag.column_settings.tag_mode.all": "All of these", + "hashtag.column_settings.tag_mode.any": "Any of these", + "hashtag.column_settings.tag_mode.none": "None of these", + "hashtag.column_settings.tag_toggle": "Include additional tags in this column", "home.column_settings.basic": "Enkel", "home.column_settings.show_reblogs": "Vis fremhevinger", "home.column_settings.show_replies": "Vis svar", @@ -313,6 +321,7 @@ "status.show_less_all": "Show less for all", "status.show_more": "Vis mer", "status.show_more_all": "Show more for all", + "status.show_thread": "Show thread", "status.unmute_conversation": "Ikke demp samtale", "status.unpin": "Angre festing på profilen", "suggestions.dismiss": "Dismiss suggestion", diff --git a/app/javascript/mastodon/locales/oc.json b/app/javascript/mastodon/locales/oc.json index 49da27568..ec0507e15 100644 --- a/app/javascript/mastodon/locales/oc.json +++ b/app/javascript/mastodon/locales/oc.json @@ -112,6 +112,7 @@ "emoji_button.search_results": "Resultats de recèrca", "emoji_button.symbols": "Simbòls", "emoji_button.travel": "Viatges & lòcs", + "empty_column.account_timeline": "No toots here!", "empty_column.blocks": "Avètz pas blocat degun pel moment.", "empty_column.community": "Lo flux public local es void. Escrivètz quicòm per lo garnir !", "empty_column.direct": "Avètz pas encara cap de messatges. Quand ne mandatz un o que ne recebètz un, serà mostrat aquí.", @@ -137,6 +138,13 @@ "getting_started.open_source_notice": "Mastodon es un logicial liure. Podètz contribuir e mandar vòstres comentaris e rapòrt de bug via {github} sus GitHub.", "getting_started.security": "Seguretat", "getting_started.terms": "Condicions d’utilizacion", + "hashtag.column_header.tag_mode.all": "and {additional}", + "hashtag.column_header.tag_mode.any": "or {additional}", + "hashtag.column_header.tag_mode.none": "without {additional}", + "hashtag.column_settings.tag_mode.all": "All of these", + "hashtag.column_settings.tag_mode.any": "Any of these", + "hashtag.column_settings.tag_mode.none": "None of these", + "hashtag.column_settings.tag_toggle": "Include additional tags in this column", "home.column_settings.basic": "Basic", "home.column_settings.show_reblogs": "Mostrar los partatges", "home.column_settings.show_replies": "Mostrar las responsas", @@ -313,6 +321,7 @@ "status.show_less_all": "Los tornar plegar totes", "status.show_more": "Desplegar", "status.show_more_all": "Los desplegar totes", + "status.show_thread": "Show thread", "status.unmute_conversation": "Tornar mostrar la conversacion", "status.unpin": "Tirar del perfil", "suggestions.dismiss": "Regetar la suggestion", diff --git a/app/javascript/mastodon/locales/pl.json b/app/javascript/mastodon/locales/pl.json index ed9956d2d..1fb8df0ad 100644 --- a/app/javascript/mastodon/locales/pl.json +++ b/app/javascript/mastodon/locales/pl.json @@ -116,6 +116,7 @@ "emoji_button.search_results": "Wyniki wyszukiwania", "emoji_button.symbols": "Symbole", "emoji_button.travel": "Podróże i miejsca", + "empty_column.account_timeline": "No toots here!", "empty_column.blocks": "Nie zablokowałeś(-aś) jeszcze żadnego użytkownika.", "empty_column.community": "Lokalna oś czasu jest pusta. Napisz coś publicznie, aby zagaić!", "empty_column.direct": "Nie masz żadnych wiadomości bezpośrednich. Kiedy dostaniesz lub wyślesz jakąś, pojawi się ona tutaj.", @@ -141,6 +142,13 @@ "getting_started.open_source_notice": "Mastodon jest oprogramowaniem o otwartym źródle. Możesz pomóc w rozwoju lub zgłaszać błędy na GitHubie tutaj: {github}.", "getting_started.security": "Bezpieczeństwo", "getting_started.terms": "Zasady użytkowania", + "hashtag.column_header.tag_mode.all": "and {additional}", + "hashtag.column_header.tag_mode.any": "or {additional}", + "hashtag.column_header.tag_mode.none": "without {additional}", + "hashtag.column_settings.tag_mode.all": "All of these", + "hashtag.column_settings.tag_mode.any": "Any of these", + "hashtag.column_settings.tag_mode.none": "None of these", + "hashtag.column_settings.tag_toggle": "Include additional tags in this column", "home.column_settings.basic": "Podstawowe", "home.column_settings.show_reblogs": "Pokazuj podbicia", "home.column_settings.show_replies": "Pokazuj odpowiedzi", @@ -318,6 +326,7 @@ "status.show_less_all": "Zwiń wszystkie", "status.show_more": "Rozwiń", "status.show_more_all": "Rozwiń wszystkie", + "status.show_thread": "Show thread", "status.unmute_conversation": "Cofnij wyciszenie konwersacji", "status.unpin": "Odepnij z profilu", "suggestions.dismiss": "Dismiss suggestion", diff --git a/app/javascript/mastodon/locales/pt-BR.json b/app/javascript/mastodon/locales/pt-BR.json index 440a39c00..61811c53d 100644 --- a/app/javascript/mastodon/locales/pt-BR.json +++ b/app/javascript/mastodon/locales/pt-BR.json @@ -112,6 +112,7 @@ "emoji_button.search_results": "Resultados da busca", "emoji_button.symbols": "Símbolos", "emoji_button.travel": "Viagens & Lugares", + "empty_column.account_timeline": "No toots here!", "empty_column.blocks": "Você ainda não bloqueou nenhum usuário.", "empty_column.community": "A timeline local está vazia. Escreva algo publicamente para começar!", "empty_column.direct": "Você não tem nenhuma mensagem direta ainda. Quando você enviar ou receber uma, as mensagens aparecerão por aqui.", @@ -137,6 +138,13 @@ "getting_started.open_source_notice": "Mastodon é um software de código aberto. Você pode contribuir ou reportar problemas na página do GitHub do projeto: {github}.", "getting_started.security": "Segurança", "getting_started.terms": "Termos de serviço", + "hashtag.column_header.tag_mode.all": "and {additional}", + "hashtag.column_header.tag_mode.any": "or {additional}", + "hashtag.column_header.tag_mode.none": "without {additional}", + "hashtag.column_settings.tag_mode.all": "All of these", + "hashtag.column_settings.tag_mode.any": "Any of these", + "hashtag.column_settings.tag_mode.none": "None of these", + "hashtag.column_settings.tag_toggle": "Include additional tags in this column", "home.column_settings.basic": "Básico", "home.column_settings.show_reblogs": "Mostrar compartilhamentos", "home.column_settings.show_replies": "Mostrar as respostas", @@ -203,7 +211,7 @@ "navigation_bar.lists": "Listas", "navigation_bar.logout": "Sair", "navigation_bar.mutes": "Usuários silenciados", - "navigation_bar.personal": "Personal", + "navigation_bar.personal": "Pessoal", "navigation_bar.pins": "Postagens fixadas", "navigation_bar.preferences": "Preferências", "navigation_bar.public_timeline": "Global", @@ -313,6 +321,7 @@ "status.show_less_all": "Mostrar menos para todas as mensagens", "status.show_more": "Mostrar mais", "status.show_more_all": "Mostrar mais para todas as mensagens", + "status.show_thread": "Show thread", "status.unmute_conversation": "Desativar silêncio desta conversa", "status.unpin": "Desafixar do perfil", "suggestions.dismiss": "Dismiss suggestion", diff --git a/app/javascript/mastodon/locales/pt.json b/app/javascript/mastodon/locales/pt.json index 94d01f2a4..c03001080 100644 --- a/app/javascript/mastodon/locales/pt.json +++ b/app/javascript/mastodon/locales/pt.json @@ -112,6 +112,7 @@ "emoji_button.search_results": "Resultados da pesquisa", "emoji_button.symbols": "Símbolos", "emoji_button.travel": "Viagens & Lugares", + "empty_column.account_timeline": "No toots here!", "empty_column.blocks": "You haven't blocked any users yet.", "empty_column.community": "Ainda não existe conteúdo local para mostrar!", "empty_column.direct": "You don't have any direct messages yet. When you send or receive one, it will show up here.", @@ -137,6 +138,13 @@ "getting_started.open_source_notice": "Mastodon é software de fonte aberta. Podes contribuir ou repostar problemas no GitHub do projecto: {github}.", "getting_started.security": "Security", "getting_started.terms": "Terms of service", + "hashtag.column_header.tag_mode.all": "and {additional}", + "hashtag.column_header.tag_mode.any": "or {additional}", + "hashtag.column_header.tag_mode.none": "without {additional}", + "hashtag.column_settings.tag_mode.all": "All of these", + "hashtag.column_settings.tag_mode.any": "Any of these", + "hashtag.column_settings.tag_mode.none": "None of these", + "hashtag.column_settings.tag_toggle": "Include additional tags in this column", "home.column_settings.basic": "Básico", "home.column_settings.show_reblogs": "Mostrar as partilhas", "home.column_settings.show_replies": "Mostrar as respostas", @@ -313,6 +321,7 @@ "status.show_less_all": "Show less for all", "status.show_more": "Mostrar mais", "status.show_more_all": "Show more for all", + "status.show_thread": "Show thread", "status.unmute_conversation": "Deixar de silenciar esta conversa", "status.unpin": "Não fixar no perfil", "suggestions.dismiss": "Dismiss suggestion", diff --git a/app/javascript/mastodon/locales/ro.json b/app/javascript/mastodon/locales/ro.json index ed6f2c7b1..fc196e820 100644 --- a/app/javascript/mastodon/locales/ro.json +++ b/app/javascript/mastodon/locales/ro.json @@ -112,6 +112,7 @@ "emoji_button.search_results": "Rezultatele căutării", "emoji_button.symbols": "Simboluri", "emoji_button.travel": "Călătorii si Locuri", + "empty_column.account_timeline": "No toots here!", "empty_column.blocks": "Nu ai blocat nici un utilizator incă.", "empty_column.community": "Fluxul local este gol. Scrie ceva public pentru a împinge bila la vale!", "empty_column.direct": "Nu ai nici un mesaj direct incă. Când trimiți sau primești unul, vor fi afișate aici.", @@ -137,6 +138,13 @@ "getting_started.open_source_notice": "Mastodon este o rețea de socializare de tip open source. Puteți contribuii la dezvoltarea ei sau să semnalați erorile pe GitHub la {github}.", "getting_started.security": "Securitate", "getting_started.terms": "Termenii de Utilizare", + "hashtag.column_header.tag_mode.all": "and {additional}", + "hashtag.column_header.tag_mode.any": "or {additional}", + "hashtag.column_header.tag_mode.none": "without {additional}", + "hashtag.column_settings.tag_mode.all": "All of these", + "hashtag.column_settings.tag_mode.any": "Any of these", + "hashtag.column_settings.tag_mode.none": "None of these", + "hashtag.column_settings.tag_toggle": "Include additional tags in this column", "home.column_settings.basic": "De bază", "home.column_settings.show_reblogs": "Arată redistribuirile", "home.column_settings.show_replies": "Arată răspunsurile", @@ -313,6 +321,7 @@ "status.show_less_all": "Arată mai puțin pentru toți", "status.show_more": "Arată mai mult", "status.show_more_all": "Arată mai mult pentru toți", + "status.show_thread": "Show thread", "status.unmute_conversation": "Repornește conversația", "status.unpin": "Eliberează din profil", "suggestions.dismiss": "Dismiss suggestion", diff --git a/app/javascript/mastodon/locales/ru.json b/app/javascript/mastodon/locales/ru.json index d41cbd09d..3e2979c1b 100644 --- a/app/javascript/mastodon/locales/ru.json +++ b/app/javascript/mastodon/locales/ru.json @@ -112,6 +112,7 @@ "emoji_button.search_results": "Результаты поиска", "emoji_button.symbols": "Символы", "emoji_button.travel": "Путешествия", + "empty_column.account_timeline": "No toots here!", "empty_column.blocks": "Вы ещё никого не заблокировали.", "empty_column.community": "Локальная лента пуста. Напишите что-нибудь, чтобы разогреть народ!", "empty_column.direct": "У Вас пока нет личных сообщений. Когда Вы начнёте их отправлять или получать, они появятся здесь.", @@ -137,6 +138,13 @@ "getting_started.open_source_notice": "Mastodon - сервис с открытым исходным кодом. Вы можете помочь проекту или сообщить о проблемах на GitHub по адресу {github}.", "getting_started.security": "Безопасность", "getting_started.terms": "Условия использования", + "hashtag.column_header.tag_mode.all": "and {additional}", + "hashtag.column_header.tag_mode.any": "or {additional}", + "hashtag.column_header.tag_mode.none": "without {additional}", + "hashtag.column_settings.tag_mode.all": "All of these", + "hashtag.column_settings.tag_mode.any": "Any of these", + "hashtag.column_settings.tag_mode.none": "None of these", + "hashtag.column_settings.tag_toggle": "Include additional tags in this column", "home.column_settings.basic": "Основные", "home.column_settings.show_reblogs": "Показывать продвижения", "home.column_settings.show_replies": "Показывать ответы", @@ -313,6 +321,7 @@ "status.show_less_all": "Свернуть для всех", "status.show_more": "Развернуть", "status.show_more_all": "Развернуть для всех", + "status.show_thread": "Show thread", "status.unmute_conversation": "Снять глушение с треда", "status.unpin": "Открепить от профиля", "suggestions.dismiss": "Dismiss suggestion", diff --git a/app/javascript/mastodon/locales/sk.json b/app/javascript/mastodon/locales/sk.json index 8d1547d66..e03cdef89 100644 --- a/app/javascript/mastodon/locales/sk.json +++ b/app/javascript/mastodon/locales/sk.json @@ -16,7 +16,7 @@ "account.follows.empty": "Tento užívateľ ešte nikoho nenásleduje.", "account.follows_you": "Následuje ťa", "account.hide_reblogs": "Skryť povýšenia od @{name}", - "account.link_verified_on": "Ownership of this link was checked on {date}", + "account.link_verified_on": "Vlastníctvo tohto odkazu bolo skontrolované {date}", "account.media": "Médiá", "account.mention": "Spomeň @{name}", "account.moved_to": "{name} sa presunul/a na:", @@ -92,8 +92,8 @@ "confirmations.mute.message": "Naozaj chcete ignorovať {name}?", "confirmations.redraft.confirm": "Vyčistiť a prepísať", "confirmations.redraft.message": "Si si istý/á, že chceš premazať a prepísať tento príspevok? Jeho nadobudnuté odpovede, povýšenia a obľúbenia, ale i odpovede na pôvodný príspevok budú odlúčené.", - "confirmations.reply.confirm": "Reply", - "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?", + "confirmations.reply.confirm": "Odpovedať", + "confirmations.reply.message": "Odpovedaním akurát teraz prepíšeš správu, ktorú máš práve rozpísanú. Si si istý/á, že chceš pokračovať?", "confirmations.unfollow.confirm": "Nesledovať", "confirmations.unfollow.message": "Naozaj chcete prestať sledovať {name}?", "embed.instructions": "Umiestni kód uvedený nižšie pre pridanie tohto statusu na tvoju web stránku.", @@ -112,6 +112,7 @@ "emoji_button.search_results": "Nájdené", "emoji_button.symbols": "Symboly", "emoji_button.travel": "Cestovanie a miesta", + "empty_column.account_timeline": "No toots here!", "empty_column.blocks": "Ešte si nikoho nezablokoval/a.", "empty_column.community": "Lokálna časová os je prázdna. Napíšte niečo, aby sa to tu začalo hýbať!", "empty_column.direct": "Ešte nemáš žiadne súkromné správy. Keď nejakú pošleš, alebo dostaneš, ukáže sa tu.", @@ -137,6 +138,13 @@ "getting_started.open_source_notice": "Mastodon je softvér s otvoreným kódom. Nahlásiť chyby, alebo prispievať môžeš na GitHube v {github}.", "getting_started.security": "Zabezpečenie", "getting_started.terms": "Podmienky prevozu", + "hashtag.column_header.tag_mode.all": "and {additional}", + "hashtag.column_header.tag_mode.any": "or {additional}", + "hashtag.column_header.tag_mode.none": "without {additional}", + "hashtag.column_settings.tag_mode.all": "All of these", + "hashtag.column_settings.tag_mode.any": "Any of these", + "hashtag.column_settings.tag_mode.none": "None of these", + "hashtag.column_settings.tag_toggle": "Include additional tags in this column", "home.column_settings.basic": "Základné", "home.column_settings.show_reblogs": "Zobraziť povýšené", "home.column_settings.show_replies": "Ukázať odpovede", @@ -297,7 +305,7 @@ "status.open": "Otvoriť tento status", "status.pin": "Pripni na profil", "status.pinned": "Pripnutý príspevok", - "status.read_more": "Read more", + "status.read_more": "Čítaj ďalej", "status.reblog": "Povýšiť", "status.reblog_private": "Povýš k pôvodnému publiku", "status.reblogged_by": "{name} povýšil/a", @@ -313,10 +321,11 @@ "status.show_less_all": "Všetkým ukáž menej", "status.show_more": "Ukáž viac", "status.show_more_all": "Všetkým ukáž viac", + "status.show_thread": "Show thread", "status.unmute_conversation": "Prestať ignorovať konverzáciu", "status.unpin": "Odopnúť z profilu", - "suggestions.dismiss": "Dismiss suggestion", - "suggestions.header": "You might be interested in…", + "suggestions.dismiss": "Zavrhni návrh", + "suggestions.header": "Mohlo by ťa zaujímať…", "tabs_bar.federated_timeline": "Federovaná", "tabs_bar.home": "Domov", "tabs_bar.local_timeline": "Lokálna", diff --git a/app/javascript/mastodon/locales/sl.json b/app/javascript/mastodon/locales/sl.json index 01f2ccbf9..080ab8ffc 100644 --- a/app/javascript/mastodon/locales/sl.json +++ b/app/javascript/mastodon/locales/sl.json @@ -11,11 +11,11 @@ "account.endorse": "Zmožnost profila", "account.follow": "Sledi", "account.followers": "Sledilci", - "account.followers.empty": "Nihče ne sledi tega uporabnika.", + "account.followers.empty": "Nihče ne sledi temu uporabniku.", "account.follows": "Sledi", "account.follows.empty": "Ta uporabnik še ne sledi nikomur.", "account.follows_you": "Ti sledi", - "account.hide_reblogs": "Skrij napuhke od @{name}", + "account.hide_reblogs": "Skrij sunke od @{name}", "account.link_verified_on": "Lastništvo te povezave je bilo preverjeno {date}", "account.media": "Mediji", "account.mention": "Omeni @{name}", @@ -112,6 +112,7 @@ "emoji_button.search_results": "Rezultati iskanja", "emoji_button.symbols": "Simboli", "emoji_button.travel": "Potovanja in Kraji", + "empty_column.account_timeline": "No toots here!", "empty_column.blocks": "Niste še blokirali nobenega uporabnika.", "empty_column.community": "Lokalna časovnica je prazna. Napišite nekaj javnega, da se bo žoga zakotalila!", "empty_column.direct": "Nimate še nobenih neposrednih sporočil. Ko ga pošljete ali prejmete, se prikaže tukaj.", @@ -137,6 +138,13 @@ "getting_started.open_source_notice": "Mastodon je odprtokodna programska oprema. V GitHubu na {github} lahko prispevate ali poročate o napakah.", "getting_started.security": "Security", "getting_started.terms": "Terms of service", + "hashtag.column_header.tag_mode.all": "and {additional}", + "hashtag.column_header.tag_mode.any": "or {additional}", + "hashtag.column_header.tag_mode.none": "without {additional}", + "hashtag.column_settings.tag_mode.all": "All of these", + "hashtag.column_settings.tag_mode.any": "Any of these", + "hashtag.column_settings.tag_mode.none": "None of these", + "hashtag.column_settings.tag_toggle": "Include additional tags in this column", "home.column_settings.basic": "Osnovno", "home.column_settings.show_reblogs": "Pokaži sunke", "home.column_settings.show_replies": "Pokaži odgovore", @@ -313,6 +321,7 @@ "status.show_less_all": "Prikaži manj za vse", "status.show_more": "Prikaži več", "status.show_more_all": "Prikaži več za vse", + "status.show_thread": "Show thread", "status.unmute_conversation": "Odtišaj pogovor", "status.unpin": "Odpni iz profila", "suggestions.dismiss": "Dismiss suggestion", diff --git a/app/javascript/mastodon/locales/sr-Latn.json b/app/javascript/mastodon/locales/sr-Latn.json index b3075d2f1..feaeb95c1 100644 --- a/app/javascript/mastodon/locales/sr-Latn.json +++ b/app/javascript/mastodon/locales/sr-Latn.json @@ -112,6 +112,7 @@ "emoji_button.search_results": "Rezultati pretrage", "emoji_button.symbols": "Simboli", "emoji_button.travel": "Putovanja & mesta", + "empty_column.account_timeline": "No toots here!", "empty_column.blocks": "You haven't blocked any users yet.", "empty_column.community": "Lokalna lajna je prazna. Napišite nešto javno da lajna produva!", "empty_column.direct": "You don't have any direct messages yet. When you send or receive one, it will show up here.", @@ -137,6 +138,13 @@ "getting_started.open_source_notice": "Mastodont je softver otvorenog koda. Možete mu doprineti ili prijaviti probleme preko GitHub-a na {github}.", "getting_started.security": "Security", "getting_started.terms": "Terms of service", + "hashtag.column_header.tag_mode.all": "and {additional}", + "hashtag.column_header.tag_mode.any": "or {additional}", + "hashtag.column_header.tag_mode.none": "without {additional}", + "hashtag.column_settings.tag_mode.all": "All of these", + "hashtag.column_settings.tag_mode.any": "Any of these", + "hashtag.column_settings.tag_mode.none": "None of these", + "hashtag.column_settings.tag_toggle": "Include additional tags in this column", "home.column_settings.basic": "Osnovno", "home.column_settings.show_reblogs": "Prikaži i podržavanja", "home.column_settings.show_replies": "Prikaži odgovore", @@ -313,6 +321,7 @@ "status.show_less_all": "Show less for all", "status.show_more": "Prikaži više", "status.show_more_all": "Show more for all", + "status.show_thread": "Show thread", "status.unmute_conversation": "Uključi prepisku", "status.unpin": "Otkači sa profila", "suggestions.dismiss": "Dismiss suggestion", diff --git a/app/javascript/mastodon/locales/sr.json b/app/javascript/mastodon/locales/sr.json index 4ed720c9f..7e3c3f213 100644 --- a/app/javascript/mastodon/locales/sr.json +++ b/app/javascript/mastodon/locales/sr.json @@ -112,6 +112,7 @@ "emoji_button.search_results": "Резултати претраге", "emoji_button.symbols": "Симболи", "emoji_button.travel": "Путовања и места", + "empty_column.account_timeline": "No toots here!", "empty_column.blocks": "Још увек немате блокираних корисника.", "empty_column.community": "Локална временска линија је празна. Напишите нешто јавно да започнете!", "empty_column.direct": "Још увек немате директних порука. Када пошаљете или примите једну, појавиће се овде.", @@ -137,6 +138,13 @@ "getting_started.open_source_notice": "Мастoдон је софтвер отвореног кода. Можете му допринети или пријавити проблеме преко ГитХаба на {github}.", "getting_started.security": "Безбедност", "getting_started.terms": "Услови коришћења", + "hashtag.column_header.tag_mode.all": "and {additional}", + "hashtag.column_header.tag_mode.any": "or {additional}", + "hashtag.column_header.tag_mode.none": "without {additional}", + "hashtag.column_settings.tag_mode.all": "All of these", + "hashtag.column_settings.tag_mode.any": "Any of these", + "hashtag.column_settings.tag_mode.none": "None of these", + "hashtag.column_settings.tag_toggle": "Include additional tags in this column", "home.column_settings.basic": "Основно", "home.column_settings.show_reblogs": "Прикажи и подржавања", "home.column_settings.show_replies": "Прикажи одговоре", @@ -313,6 +321,7 @@ "status.show_less_all": "Прикажи мање за све", "status.show_more": "Прикажи више", "status.show_more_all": "Прикажи више за све", + "status.show_thread": "Show thread", "status.unmute_conversation": "Укључи преписку", "status.unpin": "Откачи са профила", "suggestions.dismiss": "Dismiss suggestion", diff --git a/app/javascript/mastodon/locales/sv.json b/app/javascript/mastodon/locales/sv.json index 7beee3cdc..6910b181d 100644 --- a/app/javascript/mastodon/locales/sv.json +++ b/app/javascript/mastodon/locales/sv.json @@ -112,6 +112,7 @@ "emoji_button.search_results": "Sökresultat", "emoji_button.symbols": "Symboler", "emoji_button.travel": "Resor & Platser", + "empty_column.account_timeline": "No toots here!", "empty_column.blocks": "You haven't blocked any users yet.", "empty_column.community": "Den lokala tidslinjen är tom. Skriv något offentligt för att få bollen att rulla!", "empty_column.direct": "Du har inga direktmeddelanden än. När du skickar eller tar emot kommer den att dyka upp här.", @@ -137,6 +138,13 @@ "getting_started.open_source_notice": "Mastodon är programvara med öppen källkod. Du kan bidra eller rapportera problem via GitHub på {github}.", "getting_started.security": "Säkerhet", "getting_started.terms": "Användarvillkor", + "hashtag.column_header.tag_mode.all": "and {additional}", + "hashtag.column_header.tag_mode.any": "or {additional}", + "hashtag.column_header.tag_mode.none": "without {additional}", + "hashtag.column_settings.tag_mode.all": "All of these", + "hashtag.column_settings.tag_mode.any": "Any of these", + "hashtag.column_settings.tag_mode.none": "None of these", + "hashtag.column_settings.tag_toggle": "Include additional tags in this column", "home.column_settings.basic": "Grundläggande", "home.column_settings.show_reblogs": "Visa knuffar", "home.column_settings.show_replies": "Visa svar", @@ -313,6 +321,7 @@ "status.show_less_all": "Visa mindre för alla", "status.show_more": "Visa mer", "status.show_more_all": "Visa mer för alla", + "status.show_thread": "Show thread", "status.unmute_conversation": "Öppna konversation", "status.unpin": "Ångra fäst i profil", "suggestions.dismiss": "Dismiss suggestion", diff --git a/app/javascript/mastodon/locales/ta.json b/app/javascript/mastodon/locales/ta.json index 0c712e84c..3e243b743 100644 --- a/app/javascript/mastodon/locales/ta.json +++ b/app/javascript/mastodon/locales/ta.json @@ -112,6 +112,7 @@ "emoji_button.search_results": "Search results", "emoji_button.symbols": "Symbols", "emoji_button.travel": "Travel & Places", + "empty_column.account_timeline": "No toots here!", "empty_column.blocks": "You haven't blocked any users yet.", "empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!", "empty_column.direct": "You don't have any direct messages yet. When you send or receive one, it will show up here.", @@ -137,6 +138,13 @@ "getting_started.open_source_notice": "Mastodon is open source software. You can contribute or report issues on GitHub at {github}.", "getting_started.security": "Security", "getting_started.terms": "Terms of service", + "hashtag.column_header.tag_mode.all": "and {additional}", + "hashtag.column_header.tag_mode.any": "or {additional}", + "hashtag.column_header.tag_mode.none": "without {additional}", + "hashtag.column_settings.tag_mode.all": "All of these", + "hashtag.column_settings.tag_mode.any": "Any of these", + "hashtag.column_settings.tag_mode.none": "None of these", + "hashtag.column_settings.tag_toggle": "Include additional tags in this column", "home.column_settings.basic": "Basic", "home.column_settings.show_reblogs": "Show boosts", "home.column_settings.show_replies": "Show replies", @@ -313,6 +321,7 @@ "status.show_less_all": "Show less for all", "status.show_more": "Show more", "status.show_more_all": "Show more for all", + "status.show_thread": "Show thread", "status.unmute_conversation": "Unmute conversation", "status.unpin": "Unpin from profile", "suggestions.dismiss": "Dismiss suggestion", diff --git a/app/javascript/mastodon/locales/te.json b/app/javascript/mastodon/locales/te.json index c602362bf..e5cfe4240 100644 --- a/app/javascript/mastodon/locales/te.json +++ b/app/javascript/mastodon/locales/te.json @@ -16,7 +16,7 @@ "account.follows.empty": "ఈ వినియోగదారి ఇంకా ఎవరినీ అనుసరించడంలేదు.", "account.follows_you": "మిమ్మల్ని అనుసరిస్తున్నారు", "account.hide_reblogs": "@{name} నుంచి బూస్ట్ లను దాచిపెట్టు", - "account.link_verified_on": "Ownership of this link was checked on {date}", + "account.link_verified_on": "ఈ లంకె యొక్క యాజమాన్యం {date}న పరీక్షించబడింది", "account.media": "మీడియా", "account.mention": "@{name}ను ప్రస్తావించు", "account.moved_to": "{name} ఇక్కడికి మారారు:", @@ -92,8 +92,8 @@ "confirmations.mute.message": "{name}ను మీరు ఖచ్చితంగా మ్యూట్ చేయాలనుకుంటున్నారా?", "confirmations.redraft.confirm": "తొలగించు & తిరగరాయు", "confirmations.redraft.message": "మీరు ఖచ్చితంగా ఈ స్టేటస్ ని తొలగించి తిరగరాయాలనుకుంటున్నారా? ఈ స్టేటస్ యొక్క బూస్ట్ లు మరియు ఇష్టాలు పోతాయి,మరియు ప్రత్యుత్తరాలు అనాధలు అయిపోతాయి.", - "confirmations.reply.confirm": "Reply", - "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?", + "confirmations.reply.confirm": "ప్రత్యుత్తరమివ్వు", + "confirmations.reply.message": "ఇప్పుడే ప్రత్యుత్తరం ఇస్తే మీరు ప్రస్తుతం వ్రాస్తున్న సందేశం తిరగరాయబడుతుంది. మీరు ఖచ్చితంగా కొనసాగించాలనుకుంటున్నారా?", "confirmations.unfollow.confirm": "అనుసరించవద్దు", "confirmations.unfollow.message": "{name}ను మీరు ఖచ్చితంగా అనుసరించవద్దనుకుంటున్నారా?", "embed.instructions": "దిగువ కోడ్ను కాపీ చేయడం ద్వారా మీ వెబ్సైట్లో ఈ స్టేటస్ ని పొందుపరచండి.", @@ -112,6 +112,7 @@ "emoji_button.search_results": "శోధన ఫలితాలు", "emoji_button.symbols": "చిహ్నాలు", "emoji_button.travel": "ప్రయాణం & ప్రదేశాలు", + "empty_column.account_timeline": "No toots here!", "empty_column.blocks": "మీరు ఇంకా ఏ వినియోగదారులనూ బ్లాక్ చేయలేదు.", "empty_column.community": "స్థానిక కాలక్రమం ఖాళీగా ఉంది. మొదలుపెట్టడానికి బహిరంగంగా ఏదో ఒకటి వ్రాయండి!", "empty_column.direct": "మీకు ఇంకా ఏ ప్రత్యక్ష సందేశాలు లేవు. మీరు ఒకదాన్ని పంపినప్పుడు లేదా స్వీకరించినప్పుడు, అది ఇక్కడ చూపబడుతుంది.", @@ -137,6 +138,13 @@ "getting_started.open_source_notice": "మాస్టొడొన్ ఓపెన్ సోర్స్ సాఫ్ట్వేర్. మీరు {github} వద్ద GitHub పై సమస్యలను నివేదించవచ్చు లేదా తోడ్పడచ్చు.", "getting_started.security": "భద్రత", "getting_started.terms": "సేవా నిబంధనలు", + "hashtag.column_header.tag_mode.all": "and {additional}", + "hashtag.column_header.tag_mode.any": "or {additional}", + "hashtag.column_header.tag_mode.none": "without {additional}", + "hashtag.column_settings.tag_mode.all": "All of these", + "hashtag.column_settings.tag_mode.any": "Any of these", + "hashtag.column_settings.tag_mode.none": "None of these", + "hashtag.column_settings.tag_toggle": "Include additional tags in this column", "home.column_settings.basic": "ప్రాథమిక", "home.column_settings.show_reblogs": "బూస్ట్ లను చూపించు", "home.column_settings.show_replies": "ప్రత్యుత్తరాలను చూపించు", @@ -297,7 +305,7 @@ "status.open": "ఈ స్టేటస్ ను విస్తరించు", "status.pin": "ప్రొఫైల్లో అతికించు", "status.pinned": "అతికించిన టూట్", - "status.read_more": "Read more", + "status.read_more": "ఇంకా చదవండి", "status.reblog": "బూస్ట్", "status.reblog_private": "అసలు ప్రేక్షకులకు బూస్ట్ చేయి", "status.reblogged_by": "{name} బూస్ట్ చేసారు", @@ -313,10 +321,11 @@ "status.show_less_all": "అన్నిటికీ తక్కువ చూపించు", "status.show_more": "ఇంకా చూపించు", "status.show_more_all": "అన్నిటికీ ఇంకా చూపించు", + "status.show_thread": "Show thread", "status.unmute_conversation": "సంభాషణను అన్మ్యూట్ చేయి", "status.unpin": "ప్రొఫైల్ నుండి పీకివేయు", - "suggestions.dismiss": "Dismiss suggestion", - "suggestions.header": "You might be interested in…", + "suggestions.dismiss": "సూచనను రద్దు చేయి", + "suggestions.header": "మీకు వీటి మీద ఆసక్తి ఉండవచ్చు…", "tabs_bar.federated_timeline": "సమాఖ్య", "tabs_bar.home": "హోమ్", "tabs_bar.local_timeline": "స్థానిక", diff --git a/app/javascript/mastodon/locales/th.json b/app/javascript/mastodon/locales/th.json index 86d8c9b2b..a85cc63dc 100644 --- a/app/javascript/mastodon/locales/th.json +++ b/app/javascript/mastodon/locales/th.json @@ -112,6 +112,7 @@ "emoji_button.search_results": "Search results", "emoji_button.symbols": "Symbols", "emoji_button.travel": "Travel & Places", + "empty_column.account_timeline": "No toots here!", "empty_column.blocks": "You haven't blocked any users yet.", "empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!", "empty_column.direct": "You don't have any direct messages yet. When you send or receive one, it will show up here.", @@ -137,6 +138,13 @@ "getting_started.open_source_notice": "Mastodon is open source software. You can contribute or report issues on GitHub at {github}.", "getting_started.security": "Security", "getting_started.terms": "Terms of service", + "hashtag.column_header.tag_mode.all": "and {additional}", + "hashtag.column_header.tag_mode.any": "or {additional}", + "hashtag.column_header.tag_mode.none": "without {additional}", + "hashtag.column_settings.tag_mode.all": "All of these", + "hashtag.column_settings.tag_mode.any": "Any of these", + "hashtag.column_settings.tag_mode.none": "None of these", + "hashtag.column_settings.tag_toggle": "Include additional tags in this column", "home.column_settings.basic": "Basic", "home.column_settings.show_reblogs": "Show boosts", "home.column_settings.show_replies": "Show replies", @@ -313,6 +321,7 @@ "status.show_less_all": "Show less for all", "status.show_more": "Show more", "status.show_more_all": "Show more for all", + "status.show_thread": "Show thread", "status.unmute_conversation": "Unmute conversation", "status.unpin": "Unpin from profile", "suggestions.dismiss": "Dismiss suggestion", diff --git a/app/javascript/mastodon/locales/tr.json b/app/javascript/mastodon/locales/tr.json index 98ae1185d..e1d0f33c4 100644 --- a/app/javascript/mastodon/locales/tr.json +++ b/app/javascript/mastodon/locales/tr.json @@ -112,6 +112,7 @@ "emoji_button.search_results": "Search results", "emoji_button.symbols": "Semboller", "emoji_button.travel": "Seyahat ve Yerler", + "empty_column.account_timeline": "No toots here!", "empty_column.blocks": "You haven't blocked any users yet.", "empty_column.community": "Yerel zaman tüneliniz boş. Daha fazla eğlence için herkese açık bir gönderi paylaşın.", "empty_column.direct": "You don't have any direct messages yet. When you send or receive one, it will show up here.", @@ -137,6 +138,13 @@ "getting_started.open_source_notice": "Mastodon açık kaynaklı bir yazılımdır. Github {github}. {apps} üzerinden katkıda bulunabilir, hata raporlayabilirsiniz.", "getting_started.security": "Security", "getting_started.terms": "Terms of service", + "hashtag.column_header.tag_mode.all": "and {additional}", + "hashtag.column_header.tag_mode.any": "or {additional}", + "hashtag.column_header.tag_mode.none": "without {additional}", + "hashtag.column_settings.tag_mode.all": "All of these", + "hashtag.column_settings.tag_mode.any": "Any of these", + "hashtag.column_settings.tag_mode.none": "None of these", + "hashtag.column_settings.tag_toggle": "Include additional tags in this column", "home.column_settings.basic": "Temel", "home.column_settings.show_reblogs": "Boost edilenleri göster", "home.column_settings.show_replies": "Cevapları göster", @@ -313,6 +321,7 @@ "status.show_less_all": "Show less for all", "status.show_more": "Daha fazlası", "status.show_more_all": "Show more for all", + "status.show_thread": "Show thread", "status.unmute_conversation": "Unmute conversation", "status.unpin": "Unpin from profile", "suggestions.dismiss": "Dismiss suggestion", diff --git a/app/javascript/mastodon/locales/uk.json b/app/javascript/mastodon/locales/uk.json index 95a947f78..08c30833b 100644 --- a/app/javascript/mastodon/locales/uk.json +++ b/app/javascript/mastodon/locales/uk.json @@ -112,6 +112,7 @@ "emoji_button.search_results": "Результати пошуку", "emoji_button.symbols": "Символи", "emoji_button.travel": "Подорожі", + "empty_column.account_timeline": "No toots here!", "empty_column.blocks": "You haven't blocked any users yet.", "empty_column.community": "Локальна стрічка пуста. Напишіть щось, щоб розігріти народ!", "empty_column.direct": "У вас ще немає прямих повідомлень. Коли ви відправите чи отримаєте якесь, воно з'явиться тут.", @@ -137,6 +138,13 @@ "getting_started.open_source_notice": "Mastodon - програма з відкритим вихідним кодом. Ви можете допомогти проекту, або повідомити про проблеми на GitHub за адресою {github}.", "getting_started.security": "Безпека", "getting_started.terms": "Умови використання", + "hashtag.column_header.tag_mode.all": "and {additional}", + "hashtag.column_header.tag_mode.any": "or {additional}", + "hashtag.column_header.tag_mode.none": "without {additional}", + "hashtag.column_settings.tag_mode.all": "All of these", + "hashtag.column_settings.tag_mode.any": "Any of these", + "hashtag.column_settings.tag_mode.none": "None of these", + "hashtag.column_settings.tag_toggle": "Include additional tags in this column", "home.column_settings.basic": "Основні", "home.column_settings.show_reblogs": "Показувати передмухи", "home.column_settings.show_replies": "Показувати відповіді", @@ -313,6 +321,7 @@ "status.show_less_all": "Show less for all", "status.show_more": "Розгорнути", "status.show_more_all": "Show more for all", + "status.show_thread": "Show thread", "status.unmute_conversation": "Зняти глушення з діалогу", "status.unpin": "Unpin from profile", "suggestions.dismiss": "Dismiss suggestion", diff --git a/app/javascript/mastodon/locales/zh-CN.json b/app/javascript/mastodon/locales/zh-CN.json index 3d837001a..e24910153 100644 --- a/app/javascript/mastodon/locales/zh-CN.json +++ b/app/javascript/mastodon/locales/zh-CN.json @@ -112,6 +112,7 @@ "emoji_button.search_results": "搜索结果", "emoji_button.symbols": "符号", "emoji_button.travel": "旅行和地点", + "empty_column.account_timeline": "No toots here!", "empty_column.blocks": "You haven't blocked any users yet.", "empty_column.community": "本站时间轴暂时没有内容,快嘟几个来抢头香啊!", "empty_column.direct": "你还没有使用过私信。当你发出或者收到私信时,它会在这里显示。", @@ -137,6 +138,13 @@ "getting_started.open_source_notice": "Mastodon 是一个开源软件。欢迎前往 GitHub({github})贡献代码或反馈问题。", "getting_started.security": "帐户安全", "getting_started.terms": "使用条款", + "hashtag.column_header.tag_mode.all": "and {additional}", + "hashtag.column_header.tag_mode.any": "or {additional}", + "hashtag.column_header.tag_mode.none": "without {additional}", + "hashtag.column_settings.tag_mode.all": "All of these", + "hashtag.column_settings.tag_mode.any": "Any of these", + "hashtag.column_settings.tag_mode.none": "None of these", + "hashtag.column_settings.tag_toggle": "Include additional tags in this column", "home.column_settings.basic": "基本设置", "home.column_settings.show_reblogs": "显示转嘟", "home.column_settings.show_replies": "显示回复", @@ -313,6 +321,7 @@ "status.show_less_all": "隐藏所有内容", "status.show_more": "显示内容", "status.show_more_all": "显示所有内容", + "status.show_thread": "Show thread", "status.unmute_conversation": "不再隐藏此对话", "status.unpin": "在个人资料页面取消置顶", "suggestions.dismiss": "Dismiss suggestion", diff --git a/app/javascript/mastodon/locales/zh-HK.json b/app/javascript/mastodon/locales/zh-HK.json index 035a645b8..7e1d4c73b 100644 --- a/app/javascript/mastodon/locales/zh-HK.json +++ b/app/javascript/mastodon/locales/zh-HK.json @@ -112,6 +112,7 @@ "emoji_button.search_results": "搜尋結果", "emoji_button.symbols": "符號", "emoji_button.travel": "旅遊景物", + "empty_column.account_timeline": "No toots here!", "empty_column.blocks": "You haven't blocked any users yet.", "empty_column.community": "本站時間軸暫時未有內容,快寫一點東西來搶頭香啊!", "empty_column.direct": "你沒有個人訊息。當你發出或接收個人訊息,就會在這裡出現。", @@ -137,6 +138,13 @@ "getting_started.open_source_notice": "Mastodon(萬象)是一個開放源碼的軟件。你可以在官方 GitHub ({github}) 貢獻或者回報問題。", "getting_started.security": "帳戶安全", "getting_started.terms": "服務條款", + "hashtag.column_header.tag_mode.all": "and {additional}", + "hashtag.column_header.tag_mode.any": "or {additional}", + "hashtag.column_header.tag_mode.none": "without {additional}", + "hashtag.column_settings.tag_mode.all": "All of these", + "hashtag.column_settings.tag_mode.any": "Any of these", + "hashtag.column_settings.tag_mode.none": "None of these", + "hashtag.column_settings.tag_toggle": "Include additional tags in this column", "home.column_settings.basic": "基本", "home.column_settings.show_reblogs": "顯示被轉推的文章", "home.column_settings.show_replies": "顯示回應文章", @@ -313,6 +321,7 @@ "status.show_less_all": "減少顯示這類文章", "status.show_more": "顯示更多", "status.show_more_all": "顯示更多這類文章", + "status.show_thread": "Show thread", "status.unmute_conversation": "解禁對話", "status.unpin": "解除置頂", "suggestions.dismiss": "Dismiss suggestion", diff --git a/app/javascript/mastodon/locales/zh-TW.json b/app/javascript/mastodon/locales/zh-TW.json index acacc571d..4261c9345 100644 --- a/app/javascript/mastodon/locales/zh-TW.json +++ b/app/javascript/mastodon/locales/zh-TW.json @@ -112,6 +112,7 @@ "emoji_button.search_results": "搜尋結果", "emoji_button.symbols": "符號", "emoji_button.travel": "旅遊與地點", + "empty_column.account_timeline": "No toots here!", "empty_column.blocks": "你還沒有封鎖任何使用者。", "empty_column.community": "本地時間軸是空的。公開寫點什麼吧!", "empty_column.direct": "你還沒有使用過私訊。當你發出或著收到私訊時,它會在這裡顯示。", @@ -137,6 +138,13 @@ "getting_started.open_source_notice": "Mastodon 是開源軟體。你可以在 GitHub {github} 上做出貢獻或是回報問題。", "getting_started.security": "登入資訊", "getting_started.terms": "使用條款", + "hashtag.column_header.tag_mode.all": "and {additional}", + "hashtag.column_header.tag_mode.any": "or {additional}", + "hashtag.column_header.tag_mode.none": "without {additional}", + "hashtag.column_settings.tag_mode.all": "All of these", + "hashtag.column_settings.tag_mode.any": "Any of these", + "hashtag.column_settings.tag_mode.none": "None of these", + "hashtag.column_settings.tag_toggle": "Include additional tags in this column", "home.column_settings.basic": "基本", "home.column_settings.show_reblogs": "顯示轉推", "home.column_settings.show_replies": "顯示回應", @@ -313,6 +321,7 @@ "status.show_less_all": "減少顯示這類嘟文", "status.show_more": "顯示更多", "status.show_more_all": "顯示更多這類嘟文", + "status.show_thread": "Show thread", "status.unmute_conversation": "解除此對話的靜音", "status.unpin": "解除置頂", "suggestions.dismiss": "Dismiss suggestion", diff --git a/app/javascript/packs/public.js b/app/javascript/packs/public.js index 9cf783c84..47c4bf75c 100644 --- a/app/javascript/packs/public.js +++ b/app/javascript/packs/public.js @@ -47,7 +47,7 @@ function main() { content.textContent = timeAgoString({ formatMessage: ({ id, defaultMessage }, values) => (new IntlMessageFormat(messages[id] || defaultMessage, locale)).format(values), formatDate: (date, options) => (new Intl.DateTimeFormat(locale, options)).format(date), - }, datetime, now, datetime.getFullYear()); + }, datetime, now, now.getFullYear()); }); const reactComponents = document.querySelectorAll('[data-component]'); diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index 0ee0b002f..fc55163bc 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -4658,6 +4658,19 @@ a.status-card.compact:hover { z-index: 5; } +.detailed, +.fullscreen { + .video-player__volume__current, + .video-player__volume::before { + bottom: 27px; + } + + .video-player__volume__handle { + bottom: 23px; + } + +} + .video-player { overflow: hidden; position: relative; @@ -4806,7 +4819,7 @@ a.status-card.compact:hover { &__time-current { color: $white; - margin-left: 10px; + margin-left: 60px; } &__time-sep { @@ -4819,6 +4832,48 @@ a.status-card.compact:hover { color: $white; } + &__volume { + cursor: pointer; + height: 24px; + display: inline; + + &::before { + content: ""; + width: 50px; + background: rgba($white, 0.35); + border-radius: 4px; + display: block; + position: absolute; + height: 4px; + left: 70px; + bottom: 20px; + } + + &__current { + display: block; + position: absolute; + height: 4px; + border-radius: 4px; + left: 70px; + bottom: 20px; + background: lighten($ui-highlight-color, 8%); + } + + &__handle { + position: absolute; + z-index: 3; + border-radius: 50%; + width: 12px; + height: 12px; + bottom: 16px; + left: 70px; + transition: opacity .1s ease; + background: lighten($ui-highlight-color, 8%); + box-shadow: 1px 2px 6px rgba($base-shadow-color, 0.2); + pointer-events: none; + } + } + &__seek { cursor: pointer; height: 24px; diff --git a/app/javascript/styles/mastodon/forms.scss b/app/javascript/styles/mastodon/forms.scss index 46ef85774..4f96204f2 100644 --- a/app/javascript/styles/mastodon/forms.scss +++ b/app/javascript/styles/mastodon/forms.scss @@ -266,7 +266,7 @@ code { font-family: inherit; font-size: 14px; color: $primary-text-color; - display: block; + display: inline-block; width: auto; position: relative; padding-top: 5px; diff --git a/app/lib/activitypub/activity.rb b/app/lib/activitypub/activity.rb index 999954cb5..0a729011f 100644 --- a/app/lib/activitypub/activity.rb +++ b/app/lib/activitypub/activity.rb @@ -129,4 +129,10 @@ class ActivityPub::Activity ::FetchRemoteStatusService.new.call(@object['url']) end end + + def lock_or_return(key, expire_after = 7.days.seconds) + yield if redis.set(key, true, nx: true, ex: expire_after) + ensure + redis.del(key) + end end diff --git a/app/lib/activitypub/activity/delete.rb b/app/lib/activitypub/activity/delete.rb index 457047ac0..8270fed1b 100644 --- a/app/lib/activitypub/activity/delete.rb +++ b/app/lib/activitypub/activity/delete.rb @@ -12,8 +12,10 @@ class ActivityPub::Activity::Delete < ActivityPub::Activity private def delete_person - SuspendAccountService.new.call(@account) - @account.destroy! + lock_or_return("delete_in_progress:#{@account.id}") do + SuspendAccountService.new.call(@account) + @account.destroy! + end end def delete_note diff --git a/app/lib/entity_cache.rb b/app/lib/entity_cache.rb index 2aa37389c..8fff544a0 100644 --- a/app/lib/entity_cache.rb +++ b/app/lib/entity_cache.rb @@ -21,7 +21,7 @@ class EntityCache end unless uncached_ids.empty? - uncached = CustomEmoji.where(shortcode: shortcodes, domain: domain, disabled: false).map { |item| [item.shortcode, item] }.to_h + uncached = CustomEmoji.where(shortcode: shortcodes, domain: domain, disabled: false).each_with_object({}) { |item, h| h[item.shortcode] = item } uncached.each_value { |item| Rails.cache.write(to_key(:emoji, item.shortcode, domain), item, expires_in: MAX_EXPIRATION) } end diff --git a/app/lib/feed_manager.rb b/app/lib/feed_manager.rb index 3d7db2721..0cdb178c1 100644 --- a/app/lib/feed_manager.rb +++ b/app/lib/feed_manager.rb @@ -40,7 +40,12 @@ class FeedManager end def push_to_list(list, status) - return false if status.reply? && status.in_reply_to_account_id != status.account_id + if status.reply? && status.in_reply_to_account_id != status.account_id + should_filter = status.in_reply_to_account_id != list.account_id + should_filter &&= !list.show_all_replies? + should_filter &&= !(list.show_list_replies? && ListAccount.where(list_id: list.id, account_id: status.in_reply_to_account_id).exists?) + return false if should_filter + end return false unless add_to_feed(:list, list.id, status) trim(:list, list.id) PushUpdateWorker.perform_async(list.account_id, status.id, "timeline:list:#{list.id}") if push_update_required?("timeline:list:#{list.id}") diff --git a/app/lib/formatter.rb b/app/lib/formatter.rb index d13884ec8..05fd9eeb1 100644 --- a/app/lib/formatter.rb +++ b/app/lib/formatter.rb @@ -128,9 +128,9 @@ class Formatter return html if emojis.empty? emoji_map = if animate - emojis.map { |e| [e.shortcode, full_asset_url(e.image.url)] }.to_h + emojis.each_with_object({}) { |e, h| h[e.shortcode] = full_asset_url(e.image.url) } else - emojis.map { |e| [e.shortcode, full_asset_url(e.image.url(:static))] }.to_h + emojis.each_with_object({}) { |e, h| h[e.shortcode] = full_asset_url(e.image.url(:static)) } end i = -1 diff --git a/app/lib/request.rb b/app/lib/request.rb index 73b495ce1..4a81773e3 100644 --- a/app/lib/request.rb +++ b/app/lib/request.rb @@ -2,6 +2,17 @@ require 'ipaddr' require 'socket' +require 'resolv' + +# Monkey-patch the HTTP.rb timeout class to avoid using a timeout block +# around the Socket#open method, since we use our own timeout blocks inside +# that method +class HTTP::Timeout::PerOperation + def connect(socket_class, host, port, nodelay = false) + @socket = socket_class.open(host, port) + @socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1) if nodelay + end +end class Request REQUEST_TARGET = '(request-target)' @@ -45,7 +56,7 @@ class Request end begin - yield response.extend(ClientLimit) + yield response.extend(ClientLimit) if block_given? ensure http_client.close end @@ -94,7 +105,11 @@ class Request end def timeout - { connect: 1, read: 10, write: 10 } + # We enforce a 1s timeout on DNS resolving, 10s timeout on socket opening + # and 5s timeout on the TLS handshake, meaning the worst case should take + # about 16s in total + + { connect: 5, read: 10, write: 10 } end def http_client @@ -139,17 +154,34 @@ class Request class Socket < TCPSocket class << self def open(host, *args) - return super host, *args if thru_hidden_service? host + return super(host, *args) if thru_hidden_service?(host) + outer_e = nil - Addrinfo.foreach(host, nil, nil, :SOCK_STREAM) do |address| - begin - raise Mastodon::HostValidationError if PrivateAddressCheck.private_address? IPAddr.new(address.ip_address) - return super address.ip_address, *args - rescue => e - outer_e = e + + Resolv::DNS.open do |dns| + dns.timeouts = 1 + + addresses = dns.getaddresses(host).take(2) + time_slot = 10.0 / addresses.size + + addresses.each do |address| + begin + raise Mastodon::HostValidationError if PrivateAddressCheck.private_address?(IPAddr.new(address.to_s)) + + ::Timeout.timeout(time_slot, HTTP::TimeoutError) do + return super(address.to_s, *args) + end + rescue => e + outer_e = e + end end end - raise outer_e if outer_e + + if outer_e + raise outer_e + else + raise SocketError, "No address for #{host}" + end end alias new open diff --git a/app/lib/settings/scoped_settings.rb b/app/lib/settings/scoped_settings.rb index 70de7b792..343996e8a 100644 --- a/app/lib/settings/scoped_settings.rb +++ b/app/lib/settings/scoped_settings.rb @@ -32,7 +32,7 @@ module Settings def all_as_records vars = thing_scoped - records = vars.map { |r| [r.var, r] }.to_h + records = vars.each_with_object({}) { |r, h| h[r.var] = r } Setting.default_settings.each do |key, default_value| next if records.key?(key) || default_value.is_a?(Hash) @@ -66,7 +66,7 @@ module Settings class << self def default_settings - defaulting = DEFAULTING_TO_UNSCOPED.map { |k| [k, Setting[k]] }.to_h + defaulting = DEFAULTING_TO_UNSCOPED.each_with_object({}) { |k, h| h[k] = Setting[k] } Setting.default_settings.merge!(defaulting) end end diff --git a/app/models/account.rb b/app/models/account.rb index bd3dc9c96..645a303c3 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -32,9 +32,6 @@ # suspended :boolean default(FALSE), not null # locked :boolean default(FALSE), not null # header_remote_url :string default(""), not null -# statuses_count :integer default(0), not null -# followers_count :integer default(0), not null -# following_count :integer default(0), not null # last_webfingered_at :datetime # inbox_url :string default(""), not null # outbox_url :string default(""), not null @@ -49,7 +46,7 @@ # class Account < ApplicationRecord - USERNAME_RE = /[a-z0-9_]+([a-z0-9_\.]+[a-z0-9_]+)?/i + USERNAME_RE = /[a-z0-9_]+([a-z0-9_\.-]+[a-z0-9_]+)?/i MENTION_RE = /(?<=^|[^\/[:word:]])@((#{USERNAME_RE})(?:@[a-z0-9\.\-]+[a-z0-9]+)?)/i include AccountAvatar @@ -58,6 +55,7 @@ class Account < ApplicationRecord include AccountInteractions include Attachmentable include Paginable + include AccountCounters MAX_DISPLAY_NAME_LENGTH = (ENV['MAX_DISPLAY_NAME_CHARS'] || 30).to_i MAX_NOTE_LENGTH = (ENV['MAX_BIO_CHARS'] || 500).to_i @@ -124,14 +122,13 @@ class Account < ApplicationRecord scope :remote, -> { where.not(domain: nil) } scope :local, -> { where(domain: nil) } - scope :without_followers, -> { where(followers_count: 0) } - scope :with_followers, -> { where('followers_count > 0') } scope :expiring, ->(time) { remote.where.not(subscription_expires_at: nil).where('subscription_expires_at < ?', time) } scope :partitioned, -> { order(Arel.sql('row_number() over (partition by domain)')) } scope :silenced, -> { where(silenced: true) } scope :suspended, -> { where(suspended: true) } scope :without_suspended, -> { where(suspended: false) } scope :recent, -> { reorder(id: :desc) } + scope :bots, -> { where(actor_type: %w(Application Service)) } scope :alphabetic, -> { order(domain: :asc, username: :asc) } scope :by_domain_accounts, -> { group(:domain).select(:domain, 'COUNT(*) AS accounts_count').order('accounts_count desc') } scope :matches_username, ->(value) { where(arel_table[:username].matches("#{value}%")) } @@ -388,7 +385,9 @@ class Account < ApplicationRecord LIMIT ? SQL - find_by_sql([sql, limit]) + records = find_by_sql([sql, limit]) + ActiveRecord::Associations::Preloader.new.preload(records, :account_stat) + records end def advanced_search_for(terms, account, limit = 10, following = false) @@ -415,7 +414,7 @@ class Account < ApplicationRecord LIMIT ? SQL - find_by_sql([sql, account.id, account.id, account.id, limit]) + records = find_by_sql([sql, account.id, account.id, account.id, limit]) else sql = <<-SQL.squish SELECT @@ -431,8 +430,11 @@ class Account < ApplicationRecord LIMIT ? SQL - find_by_sql([sql, account.id, account.id, limit]) + records = find_by_sql([sql, account.id, account.id, limit]) end + + ActiveRecord::Associations::Preloader.new.preload(records, :account_stat) + records end private diff --git a/app/models/account_filter.rb b/app/models/account_filter.rb index 84364bf1b..b10f50db7 100644 --- a/app/models/account_filter.rb +++ b/app/models/account_filter.rb @@ -5,13 +5,14 @@ class AccountFilter def initialize(params) @params = params + set_defaults! end def results - scope = Account.recent + scope = Account.recent.includes(:user) params.each do |key, value| - scope.merge!(scope_for(key, value)) if value.present? + scope.merge!(scope_for(key, value.to_s.strip)) if value.present? end scope @@ -19,6 +20,11 @@ class AccountFilter private + def set_defaults! + params['local'] = '1' if params['remote'].blank? + params['active'] = '1' if params['suspended'].blank? && params['silenced'].blank? + end + def scope_for(key, value) case key.to_s when 'local' @@ -27,10 +33,10 @@ class AccountFilter Account.remote when 'by_domain' Account.where(domain: value) + when 'active' + Account.without_suspended when 'silenced' Account.silenced - when 'alphabetic' - Account.reorder(nil).alphabetic when 'suspended' Account.suspended when 'username' @@ -40,11 +46,7 @@ class AccountFilter when 'email' accounts_with_users.merge User.matches_email(value) when 'ip' - if valid_ip?(value) - accounts_with_users.merge User.with_recent_ip_address(value) - else - Account.default_scoped - end + valid_ip?(value) ? accounts_with_users.where('users.current_sign_in_ip <<= ?', value) : Account.none when 'staff' accounts_with_users.merge User.staff else @@ -57,8 +59,7 @@ class AccountFilter end def valid_ip?(value) - IPAddr.new(value) - true + IPAddr.new(value) && true rescue IPAddr::InvalidAddressError false end diff --git a/app/models/account_stat.rb b/app/models/account_stat.rb new file mode 100644 index 000000000..d5715268e --- /dev/null +++ b/app/models/account_stat.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +# == Schema Information +# +# Table name: account_stats +# +# id :bigint(8) not null, primary key +# account_id :bigint(8) not null +# statuses_count :bigint(8) default(0), not null +# following_count :bigint(8) default(0), not null +# followers_count :bigint(8) default(0), not null +# created_at :datetime not null +# updated_at :datetime not null +# + +class AccountStat < ApplicationRecord + belongs_to :account, inverse_of: :account_stat + + def increment_count!(key) + update(key => public_send(key) + 1) + end + + def decrement_count!(key) + update(key => [public_send(key) - 1, 0].max) + end +end diff --git a/app/models/concerns/account_counters.rb b/app/models/concerns/account_counters.rb new file mode 100644 index 000000000..fa3ec9a3d --- /dev/null +++ b/app/models/concerns/account_counters.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +module AccountCounters + extend ActiveSupport::Concern + + included do + has_one :account_stat, inverse_of: :account + after_save :save_account_stat + end + + delegate :statuses_count, + :statuses_count=, + :following_count, + :following_count=, + :followers_count, + :followers_count=, + :increment_count!, + :decrement_count!, + to: :account_stat + + def account_stat + super || build_account_stat + end + + private + + def save_account_stat + return unless account_stat&.changed? + account_stat.save + end +end diff --git a/app/models/concerns/account_interactions.rb b/app/models/concerns/account_interactions.rb index ff57a884b..f27d39483 100644 --- a/app/models/concerns/account_interactions.rb +++ b/app/models/concerns/account_interactions.rb @@ -45,9 +45,9 @@ module AccountInteractions end def domain_blocking_map(target_account_ids, account_id) - accounts_map = Account.where(id: target_account_ids).select('id, domain').map { |a| [a.id, a.domain] }.to_h + accounts_map = Account.where(id: target_account_ids).select('id, domain').each_with_object({}) { |a, h| h[a.id] = a.domain } blocked_domains = domain_blocking_map_by_domain(accounts_map.values.compact, account_id) - accounts_map.map { |id, domain| [id, blocked_domains[domain]] }.to_h + accounts_map.reduce({}) { |h, (id, domain)| h.merge(id => blocked_domains[domain]) } end def domain_blocking_map_by_domain(target_domains, account_id) diff --git a/app/models/concerns/status_threading_concern.rb b/app/models/concerns/status_threading_concern.rb index fa441469c..b9c800c2a 100644 --- a/app/models/concerns/status_threading_concern.rb +++ b/app/models/concerns/status_threading_concern.rb @@ -8,7 +8,7 @@ module StatusThreadingConcern end def descendants(limit, account = nil, max_child_id = nil, since_child_id = nil, depth = nil) - find_statuses_from_tree_path(descendant_ids(limit, max_child_id, since_child_id, depth), account) + find_statuses_from_tree_path(descendant_ids(limit, max_child_id, since_child_id, depth), account, promote: true) end private @@ -76,7 +76,7 @@ module StatusThreadingConcern descendants_with_self - [self] end - def find_statuses_from_tree_path(ids, account) + def find_statuses_from_tree_path(ids, account, promote: false) statuses = statuses_with_accounts(ids).to_a account_ids = statuses.map(&:account_id).uniq domains = statuses.map(&:account_domain).compact.uniq @@ -86,6 +86,28 @@ module StatusThreadingConcern # Order ancestors/descendants by tree path statuses.sort_by! { |status| ids.index(status.id) } + + # Bring self-replies to the top + if promote + promote_by!(statuses) { |status| status.in_reply_to_account_id == status.account_id } + else + statuses + end + end + + def promote_by!(arr) + insert_at = arr.find_index { |item| !yield(item) } + + return arr if insert_at.nil? + + arr.each_with_index do |item, index| + next if index <= insert_at || !yield(item) + + arr.insert(insert_at, arr.delete_at(index)) + insert_at += 1 + end + + arr end def relations_map_for_account(account, account_ids, domains) diff --git a/app/models/follow.rb b/app/models/follow.rb index 7ad56eb78..87fa11425 100644 --- a/app/models/follow.rb +++ b/app/models/follow.rb @@ -16,11 +16,8 @@ class Follow < ApplicationRecord include Paginable include RelationshipCacheable - belongs_to :account, counter_cache: :following_count - - belongs_to :target_account, - class_name: 'Account', - counter_cache: :followers_count + belongs_to :account + belongs_to :target_account, class_name: 'Account' has_one :notification, as: :activity, dependent: :destroy @@ -39,7 +36,9 @@ class Follow < ApplicationRecord end before_validation :set_uri, only: :create + after_create :increment_cache_counters after_destroy :remove_endorsements + after_destroy :decrement_cache_counters private @@ -50,4 +49,14 @@ class Follow < ApplicationRecord def remove_endorsements AccountPin.where(target_account_id: target_account_id, account_id: account_id).delete_all end + + def increment_cache_counters + account&.increment_count!(:following_count) + target_account&.increment_count!(:followers_count) + end + + def decrement_cache_counters + account&.decrement_count!(:following_count) + target_account&.decrement_count!(:followers_count) + end end diff --git a/app/models/identity.rb b/app/models/identity.rb index a5e0c09ec..8cc65aef4 100644 --- a/app/models/identity.rb +++ b/app/models/identity.rb @@ -3,12 +3,12 @@ # # Table name: identities # -# id :integer not null, primary key -# user_id :integer # provider :string default(""), not null # uid :string default(""), not null # created_at :datetime not null # updated_at :datetime not null +# id :bigint(8) not null, primary key +# user_id :bigint(8) # class Identity < ApplicationRecord diff --git a/app/models/list.rb b/app/models/list.rb index c9c94fca1..8493046e5 100644 --- a/app/models/list.rb +++ b/app/models/list.rb @@ -3,11 +3,12 @@ # # Table name: lists # -# id :bigint(8) not null, primary key -# account_id :bigint(8) not null -# title :string default(""), not null -# created_at :datetime not null -# updated_at :datetime not null +# id :bigint(8) not null, primary key +# account_id :bigint(8) not null +# title :string default(""), not null +# created_at :datetime not null +# updated_at :datetime not null +# replies_policy :integer default("list_replies"), not null # class List < ApplicationRecord @@ -15,6 +16,8 @@ class List < ApplicationRecord PER_ACCOUNT_LIMIT = 50 + enum replies_policy: [:list_replies, :all_replies, :no_replies], _prefix: :show + belongs_to :account, optional: true has_many :list_accounts, inverse_of: :list, dependent: :destroy diff --git a/app/models/media_attachment.rb b/app/models/media_attachment.rb index 0f787ebc4..a034b55fd 100644 --- a/app/models/media_attachment.rb +++ b/app/models/media_attachment.rb @@ -77,6 +77,7 @@ class MediaAttachment < ApplicationRecord format: 'mp4', convert_options: { output: { + 'loglevel' => 'fatal', 'movflags' => 'faststart', 'pix_fmt' => 'yuv420p', 'vf' => 'scale=\'trunc(iw/2)*2:trunc(ih/2)*2\'', diff --git a/app/models/notification.rb b/app/models/notification.rb index 78b180301..2f0a9b78c 100644 --- a/app/models/notification.rb +++ b/app/models/notification.rb @@ -75,7 +75,7 @@ class Notification < ApplicationRecord return if account_ids.empty? - accounts = Account.where(id: account_ids).map { |a| [a.id, a] }.to_h + accounts = Account.where(id: account_ids).includes(:account_stat).each_with_object({}) { |a, h| h[a.id] = a } cached_items.each do |item| item.from_account = accounts[item.from_account_id] diff --git a/app/models/setting.rb b/app/models/setting.rb index 033d09fd5..a5878e96a 100644 --- a/app/models/setting.rb +++ b/app/models/setting.rb @@ -40,7 +40,7 @@ class Setting < RailsSettings::Base def all_as_records vars = thing_scoped - records = vars.map { |r| [r.var, r] }.to_h + records = vars.each_with_object({}) { |r, h| h[r.var] = r } default_settings.each do |key, default_value| next if records.key?(key) || default_value.is_a?(Hash) diff --git a/app/models/status.rb b/app/models/status.rb index e73f11503..65cd97c51 100644 --- a/app/models/status.rb +++ b/app/models/status.rb @@ -99,17 +99,16 @@ class Status < ApplicationRecord scope :not_local_only, -> { where(local_only: [false, nil]) } - cache_associated :account, - :application, + cache_associated :application, :media_attachments, :conversation, :status_stat, :tags, :preview_cards, :stream_entry, - active_mentions: :account, + account: :account_stat, + active_mentions: { account: :account_stat }, reblog: [ - :account, :application, :stream_entry, :tags, @@ -117,9 +116,10 @@ class Status < ApplicationRecord :media_attachments, :conversation, :status_stat, - active_mentions: :account, + account: :account_stat, + active_mentions: { account: :account_stat }, ], - thread: :account + thread: { account: :account_stat } delegate :domain, to: :account, prefix: true @@ -328,7 +328,7 @@ class Status < ApplicationRecord end def favourites_map(status_ids, account_id) - Favourite.select('status_id').where(status_id: status_ids).where(account_id: account_id).map { |f| [f.status_id, true] }.to_h + Favourite.select('status_id').where(status_id: status_ids).where(account_id: account_id).each_with_object({}) { |f, h| h[f.status_id] = true } end def bookmarks_map(status_ids, account_id) @@ -336,15 +336,15 @@ class Status < ApplicationRecord end def reblogs_map(status_ids, account_id) - select('reblog_of_id').where(reblog_of_id: status_ids).where(account_id: account_id).reorder(nil).map { |s| [s.reblog_of_id, true] }.to_h + select('reblog_of_id').where(reblog_of_id: status_ids).where(account_id: account_id).reorder(nil).each_with_object({}) { |s, h| h[s.reblog_of_id] = true } end def mutes_map(conversation_ids, account_id) - ConversationMute.select('conversation_id').where(conversation_id: conversation_ids).where(account_id: account_id).map { |m| [m.conversation_id, true] }.to_h + ConversationMute.select('conversation_id').where(conversation_id: conversation_ids).where(account_id: account_id).each_with_object({}) { |m, h| h[m.conversation_id] = true } end def pins_map(status_ids, account_id) - StatusPin.select('status_id').where(status_id: status_ids).where(account_id: account_id).map { |p| [p.status_id, true] }.to_h + StatusPin.select('status_id').where(status_id: status_ids).where(account_id: account_id).each_with_object({}) { |p, h| h[p.status_id] = true } end def reload_stale_associations!(cached_items) @@ -359,7 +359,7 @@ class Status < ApplicationRecord return if account_ids.empty? - accounts = Account.where(id: account_ids).map { |a| [a.id, a] }.to_h + accounts = Account.where(id: account_ids).includes(:account_stat).each_with_object({}) { |a, h| h[a.id] = a } cached_items.each do |item| item.account = accounts[item.account_id] @@ -471,6 +471,8 @@ class Status < ApplicationRecord end def set_conversation + self.thread = thread.reblog if thread&.reblog? + self.reply = !(in_reply_to_id.nil? && thread.nil?) unless reply if reply? && !thread.nil? @@ -501,12 +503,7 @@ class Status < ApplicationRecord def increment_counter_caches return if direct_visibility? - if association(:account).loaded? - account.update_attribute(:statuses_count, account.statuses_count + 1) - else - Account.where(id: account_id).update_all('statuses_count = COALESCE(statuses_count, 0) + 1') - end - + account&.increment_count!(:statuses_count) reblog&.increment_count!(:reblogs_count) if reblog? thread&.increment_count!(:replies_count) if in_reply_to_id.present? && (public_visibility? || unlisted_visibility?) end @@ -514,12 +511,7 @@ class Status < ApplicationRecord def decrement_counter_caches return if direct_visibility? || marked_for_mass_destruction? - if association(:account).loaded? - account.update_attribute(:statuses_count, [account.statuses_count - 1, 0].max) - else - Account.where(id: account_id).update_all('statuses_count = GREATEST(COALESCE(statuses_count, 0) - 1, 0)') - end - + account&.decrement_count!(:statuses_count) reblog&.decrement_count!(:reblogs_count) if reblog? thread&.decrement_count!(:replies_count) if in_reply_to_id.present? && (public_visibility? || unlisted_visibility?) end diff --git a/app/models/trending_tags.rb b/app/models/trending_tags.rb index c559651c6..3a8be2164 100644 --- a/app/models/trending_tags.rb +++ b/app/models/trending_tags.rb @@ -18,7 +18,7 @@ class TrendingTags def get(limit) key = "#{KEY}:#{Time.now.utc.beginning_of_day.to_i}" tag_ids = redis.zrevrange(key, 0, limit - 1).map(&:to_i) - tags = Tag.where(id: tag_ids).to_a.map { |tag| [tag.id, tag] }.to_h + tags = Tag.where(id: tag_ids).to_a.each_with_object({}) { |tag, h| h[tag.id] = tag } tag_ids.map { |tag_id| tags[tag_id] }.compact end diff --git a/app/models/user.rb b/app/models/user.rb index b9e18eecd..704523d34 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -83,7 +83,6 @@ class User < ApplicationRecord scope :inactive, -> { where(arel_table[:current_sign_in_at].lt(ACTIVE_DURATION.ago)) } scope :active, -> { confirmed.where(arel_table[:current_sign_in_at].gteq(ACTIVE_DURATION.ago)).joins(:account).where(accounts: { suspended: false }) } scope :matches_email, ->(value) { where(arel_table[:email].matches("#{value}%")) } - scope :with_recent_ip_address, ->(value) { where(arel_table[:current_sign_in_ip].eq(value).or(arel_table[:last_sign_in_ip].eq(value))) } before_validation :sanitize_languages diff --git a/app/presenters/instance_presenter.rb b/app/presenters/instance_presenter.rb index 5d22962cf..d8670f124 100644 --- a/app/presenters/instance_presenter.rb +++ b/app/presenters/instance_presenter.rb @@ -18,11 +18,11 @@ class InstancePresenter end def user_count - Rails.cache.fetch('user_count') { User.confirmed.count } + Rails.cache.fetch('user_count') { User.confirmed.joins(:account).merge(Account.without_suspended).count } end def status_count - Rails.cache.fetch('local_status_count') { Account.local.sum(:statuses_count) } + Rails.cache.fetch('local_status_count') { Account.local.joins(:account_stat).sum('account_stats.statuses_count') }.to_i end def domain_count diff --git a/app/serializers/rest/filter_serializer.rb b/app/serializers/rest/filter_serializer.rb index 3134be371..57205630b 100644 --- a/app/serializers/rest/filter_serializer.rb +++ b/app/serializers/rest/filter_serializer.rb @@ -3,4 +3,8 @@ class REST::FilterSerializer < ActiveModel::Serializer attributes :id, :phrase, :context, :whole_word, :expires_at, :irreversible + + def id + object.id.to_s + end end diff --git a/app/serializers/rest/list_serializer.rb b/app/serializers/rest/list_serializer.rb index 977da7439..3e87f7119 100644 --- a/app/serializers/rest/list_serializer.rb +++ b/app/serializers/rest/list_serializer.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class REST::ListSerializer < ActiveModel::Serializer - attributes :id, :title + attributes :id, :title, :replies_policy def id object.id.to_s diff --git a/app/services/batched_remove_status_service.rb b/app/services/batched_remove_status_service.rb index b7296cf7c..fc412c7d4 100644 --- a/app/services/batched_remove_status_service.rb +++ b/app/services/batched_remove_status_service.rb @@ -12,12 +12,12 @@ class BatchedRemoveStatusService < BaseService def call(statuses) statuses = Status.where(id: statuses.map(&:id)).includes(:account, :stream_entry).flat_map { |status| [status] + status.reblogs.includes(:account, :stream_entry).to_a } - @mentions = statuses.map { |s| [s.id, s.active_mentions.includes(:account).to_a] }.to_h - @tags = statuses.map { |s| [s.id, s.tags.pluck(:name)] }.to_h + @mentions = statuses.each_with_object({}) { |s, h| h[s.id] = s.active_mentions.includes(:account).to_a } + @tags = statuses.each_with_object({}) { |s, h| h[s.id] = s.tags.pluck(:name) } @stream_entry_batches = [] @salmon_batches = [] - @json_payloads = statuses.map { |s| [s.id, Oj.dump(event: :delete, payload: s.id.to_s)] }.to_h + @json_payloads = statuses.each_with_object({}) { |s, h| h[s.id] = Oj.dump(event: :delete, payload: s.id.to_s) } @activity_xml = {} # Ensure that rendered XML reflects destroyed state diff --git a/app/services/fetch_atom_service.rb b/app/services/fetch_atom_service.rb index 550e75f33..d6508a988 100644 --- a/app/services/fetch_atom_service.rb +++ b/app/services/fetch_atom_service.rb @@ -29,7 +29,7 @@ class FetchAtomService < BaseService def perform_request(&block) accept = 'text/html' - accept = 'application/activity+json, application/ld+json, application/atom+xml, ' + accept unless @unsupported_activity + accept = 'application/activity+json, application/ld+json; profile="https://www.w3.org/ns/activitystreams", application/atom+xml, ' + accept unless @unsupported_activity Request.new(:get, @url).add_headers('Accept' => accept).perform(&block) end @@ -39,7 +39,7 @@ class FetchAtomService < BaseService if response.mime_type == 'application/atom+xml' [@url, { prefetched_body: response.body_with_limit }, :ostatus] - elsif ['application/activity+json', 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"'].include?(response.mime_type) + elsif ['application/activity+json', 'application/ld+json'].include?(response.mime_type) body = response.body_with_limit json = body_to_json(body) if supported_context?(json) && equals_or_includes_any?(json['type'], ActivityPub::FetchRemoteAccountService::SUPPORTED_TYPES) && json['inbox'].present? diff --git a/app/services/hashtag_query_service.rb b/app/services/hashtag_query_service.rb index 86558a446..5773d78c6 100644 --- a/app/services/hashtag_query_service.rb +++ b/app/services/hashtag_query_service.rb @@ -2,15 +2,14 @@ class HashtagQueryService < BaseService def call(tag, params, account = nil, local = false) - any = tags_for(params[:any]) + tags = tags_for(Array(tag.name) | Array(params[:any])).pluck(:id) all = tags_for(params[:all]) none = tags_for(params[:none]) - @query = Status.as_tag_timeline(tag, account, local) - .tagged_with_all(all) - .tagged_with_none(none) - @query = @query.distinct.or(self.class.new.call(any, params.except(:any), account, local).distinct) if any - @query + Status.distinct + .as_tag_timeline(tags, account, local) + .tagged_with_all(all) + .tagged_with_none(none) end private diff --git a/app/views/accounts/show.html.haml b/app/views/accounts/show.html.haml index b825b82cb..0ee9dd7de 100644 --- a/app/views/accounts/show.html.haml +++ b/app/views/accounts/show.html.haml @@ -8,8 +8,8 @@ %meta{ name: 'robots', content: 'noindex' }/ %link{ rel: 'salmon', href: api_salmon_url(@account.id) }/ - %link{ rel: 'alternate', type: 'application/rss+xml', href: account_url(@account, format: 'rss') }/ %link{ rel: 'alternate', type: 'application/atom+xml', href: account_url(@account, format: 'atom') }/ + %link{ rel: 'alternate', type: 'application/rss+xml', href: account_url(@account, format: 'rss') }/ %link{ rel: 'alternate', type: 'application/activity+json', href: ActivityPub::TagManager.instance.uri_for(@account) }/ - if @older_url diff --git a/app/views/admin/accounts/_account.html.haml b/app/views/admin/accounts/_account.html.haml index c6e63152d..0fadaae1e 100644 --- a/app/views/admin/accounts/_account.html.haml +++ b/app/views/admin/accounts/_account.html.haml @@ -1,18 +1,15 @@ %tr - %td.username - = account.username %td - - unless account.local? - = link_to account.domain, admin_accounts_path(by_domain: account.domain) + = admin_account_link_to(account) %td - - if account.local? - - if account.user.nil? - = t("admin.accounts.moderation.suspended") - - else - = t("admin.accounts.roles.#{account.user.role}") + %div{ style: 'margin: -2px 0' }= account_badge(account, all: true) + %td + - if account.user_current_sign_in_ip + %samp= account.user_current_sign_in_ip - else - = account.protocol.humanize + \- %td - = table_link_to 'circle', t('admin.accounts.web'), web_path("accounts/#{account.id}") - = table_link_to 'globe', t('admin.accounts.public'), TagManager.instance.url_for(account) - = table_link_to 'pencil', t('admin.accounts.edit'), admin_account_path(account.id) + - if account.user_current_sign_in_at + %time.time-ago{ datetime: account.user_current_sign_in_at.iso8601, title: l(account.user_current_sign_in_at) }= l account.user_current_sign_in_at + - else + \- diff --git a/app/views/admin/accounts/index.html.haml b/app/views/admin/accounts/index.html.haml index 4bee73adc..0d31eee36 100644 --- a/app/views/admin/accounts/index.html.haml +++ b/app/views/admin/accounts/index.html.haml @@ -5,41 +5,19 @@ .filter-subset %strong= t('admin.accounts.location.title') %ul - %li= filter_link_to t('admin.accounts.location.all'), local: nil, remote: nil - %li - - if selected? local: '1', remote: nil - = filter_link_to t('admin.accounts.location.local'), {local: nil, remote: nil}, {local: '1', remote: nil} - - else - = filter_link_to t('admin.accounts.location.local'), local: '1', remote: nil - %li - - if selected? remote: '1', local: nil - = filter_link_to t('admin.accounts.location.remote'), {remote: nil, local: nil}, {remote: '1', local: nil} - - else - = filter_link_to t('admin.accounts.location.remote'), remote: '1', local: nil + %li= filter_link_to t('admin.accounts.location.local'), remote: nil + %li= filter_link_to t('admin.accounts.location.remote'), remote: '1' .filter-subset %strong= t('admin.accounts.moderation.title') %ul - %li= filter_link_to t('admin.accounts.moderation.all'), silenced: nil, suspended: nil - %li - - if selected? silenced: '1' - = filter_link_to t('admin.accounts.moderation.silenced'), {silenced: nil}, {silenced: '1'} - - else - = filter_link_to t('admin.accounts.moderation.silenced'), silenced: '1' - %li - - if selected? suspended: '1' - = filter_link_to t('admin.accounts.moderation.suspended'), {suspended: nil}, {suspended: '1'} - - else - = filter_link_to t('admin.accounts.moderation.suspended'), suspended: '1' + %li= filter_link_to t('admin.accounts.moderation.active'), silenced: nil, suspended: nil + %li= filter_link_to t('admin.accounts.moderation.silenced'), silenced: '1', suspended: nil + %li= filter_link_to t('admin.accounts.moderation.suspended'), suspended: '1', silenced: nil .filter-subset %strong= t('admin.accounts.role') %ul %li= filter_link_to t('admin.accounts.moderation.all'), staff: nil %li= filter_link_to t('admin.accounts.roles.staff'), staff: '1' - .filter-subset - %strong= t('admin.accounts.order.title') - %ul - %li= filter_link_to t('admin.accounts.order.most_recent'), alphabetic: nil - %li= filter_link_to t('admin.accounts.order.alphabetic'), alphabetic: '1' = form_tag admin_accounts_url, method: 'GET', class: 'simple_form' do .fields-group @@ -60,9 +38,9 @@ %thead %tr %th= t('admin.accounts.username') - %th= t('admin.accounts.domain') - %th - %th + %th= t('admin.accounts.role') + %th= t('admin.accounts.most_recent_ip') + %th= t('admin.accounts.most_recent_activity') %tbody = render @accounts diff --git a/app/views/admin/accounts/show.html.haml b/app/views/admin/accounts/show.html.haml index 17f1f224d..c1a5fc1bd 100644 --- a/app/views/admin/accounts/show.html.haml +++ b/app/views/admin/accounts/show.html.haml @@ -68,7 +68,7 @@ %time.formatted{ datetime: @account.user_current_sign_in_at.iso8601, title: l(@account.user_current_sign_in_at) } = l @account.user_current_sign_in_at - else - Never + \- - else %tr %th= t('admin.accounts.profile_url') diff --git a/app/views/auth/registrations/edit.html.haml b/app/views/auth/registrations/edit.html.haml index 7fc08a23b..694461fdf 100644 --- a/app/views/auth/registrations/edit.html.haml +++ b/app/views/auth/registrations/edit.html.haml @@ -9,13 +9,14 @@ = f.input :email, wrapper: :with_label, input_html: { 'aria-label' => t('simple_form.labels.defaults.email') }, required: true, hint: false .fields-group - = f.input :password, wrapper: :with_label, input_html: { 'aria-label' => t('simple_form.labels.defaults.new_password'), :autocomplete => 'off' }, hint: false + = f.input :current_password, wrapper: :with_label, input_html: { 'aria-label' => t('simple_form.labels.defaults.current_password'), :autocomplete => 'off' }, required: true .fields-group - = f.input :password_confirmation, wrapper: :with_label, label: t('simple_form.labels.defaults.confirm_new_password'), input_html: { 'aria-label' => t('simple_form.labels.defaults.confirm_new_password'), :autocomplete => 'off' } + = f.input :password, wrapper: :with_label, label: t('simple_form.labels.defaults.new_password'), input_html: { 'aria-label' => t('simple_form.labels.defaults.new_password'), :autocomplete => 'off' }, hint: false .fields-group - = f.input :current_password, wrapper: :with_label, input_html: { 'aria-label' => t('simple_form.labels.defaults.current_password'), :autocomplete => 'off' }, required: true + = f.input :password_confirmation, wrapper: :with_label, label: t('simple_form.labels.defaults.confirm_new_password'), input_html: { 'aria-label' => t('simple_form.labels.defaults.confirm_new_password'), :autocomplete => 'off' } + .actions = f.button :button, t('generic.save_changes'), type: :submit diff --git a/app/views/settings/profiles/show.html.haml b/app/views/settings/profiles/show.html.haml index 6c4a8fdfb..2ba236fb5 100644 --- a/app/views/settings/profiles/show.html.haml +++ b/app/views/settings/profiles/show.html.haml @@ -14,9 +14,10 @@ = render 'application/card', account: @account .fields-row__column.fields-group.fields-row__column-6 + = f.input :header, wrapper: :with_label, input_html: { accept: AccountHeader::IMAGE_MIME_TYPES.join(',') }, hint: t('simple_form.hints.defaults.header', dimensions: '1500x500', size: number_to_human_size(AccountHeader::LIMIT)) + = f.input :avatar, wrapper: :with_label, input_html: { accept: AccountAvatar::IMAGE_MIME_TYPES.join(',') }, hint: t('simple_form.hints.defaults.avatar', dimensions: '400x400', size: number_to_human_size(AccountAvatar::LIMIT)) - = f.input :header, wrapper: :with_label, input_html: { accept: AccountHeader::IMAGE_MIME_TYPES.join(',') }, hint: t('simple_form.hints.defaults.header', dimensions: '1500x500', size: number_to_human_size(AccountHeader::LIMIT)) %hr.spacer/ diff --git a/app/workers/activitypub/delivery_worker.rb b/app/workers/activitypub/delivery_worker.rb index adbb496d9..f9c385ea3 100644 --- a/app/workers/activitypub/delivery_worker.rb +++ b/app/workers/activitypub/delivery_worker.rb @@ -11,6 +11,8 @@ class ActivityPub::DeliveryWorker HEADERS = { 'Content-Type' => 'application/activity+json' }.freeze def perform(json, source_account_id, inbox_url, options = {}) + return if DeliveryFailureTracker.unavailable?(inbox_url) + @options = options.with_indifferent_access @json = json @source_account = Account.find(source_account_id) |