diff options
87 files changed, 2370 insertions, 357 deletions
diff --git a/Dockerfile b/Dockerfile index 7cca02ecf..d455116da 100644 --- a/Dockerfile +++ b/Dockerfile @@ -61,6 +61,9 @@ RUN apk -U upgrade \ && rm -rf /tmp/* /var/cache/apk/* COPY Gemfile Gemfile.lock package.json yarn.lock .yarnclean /mastodon/ +COPY stack-fix.c /lib +RUN gcc -shared -fPIC /lib/stack-fix.c -o /lib/stack-fix.so +RUN rm /lib/stack-fix.c RUN bundle config build.nokogiri --with-iconv-lib=/usr/local/lib --with-iconv-include=/usr/local/include \ && bundle install -j$(getconf _NPROCESSORS_ONLN) --deployment --without test development \ diff --git a/app/controllers/api/base_controller.rb b/app/controllers/api/base_controller.rb index 5983c0fbe..52e68ab35 100644 --- a/app/controllers/api/base_controller.rb +++ b/app/controllers/api/base_controller.rb @@ -6,8 +6,8 @@ class Api::BaseController < ApplicationController include RateLimitHeaders - skip_before_action :verify_authenticity_token skip_before_action :store_current_location + protect_from_forgery with: :null_session rescue_from ActiveRecord::RecordInvalid, Mastodon::ValidationError do |e| render json: { error: e.to_s }, status: 422 diff --git a/app/controllers/settings/flavours_controller.rb b/app/controllers/settings/flavours_controller.rb index 865d5a479..634387715 100644 --- a/app/controllers/settings/flavours_controller.rb +++ b/app/controllers/settings/flavours_controller.rb @@ -1,13 +1,12 @@ # frozen_string_literal: true class Settings::FlavoursController < Settings::BaseController - def index redirect_to action: 'show', flavour: current_flavour end def show - unless Themes.instance.flavours.include?(params[:flavour]) or params[:flavour] == current_flavour + unless Themes.instance.flavours.include?(params[:flavour]) || (params[:flavour] == current_flavour) redirect_to action: 'show', flavour: current_flavour end @@ -16,7 +15,7 @@ class Settings::FlavoursController < Settings::BaseController end def update - user_settings.update(user_settings_params(params[:flavour]).to_h) + user_settings.update(user_settings_params) redirect_to action: 'show', flavour: params[:flavour] end @@ -26,10 +25,8 @@ class Settings::FlavoursController < Settings::BaseController UserSettingsDecorator.new(current_user) end - def user_settings_params(flavour) - params.require(:user).merge({ setting_flavour: flavour }).permit( - :setting_flavour, - :setting_skin - ) + def user_settings_params + { setting_flavour: params.require(:flavour), + setting_skin: params.dig(:user, :setting_skin) }.with_indifferent_access end end diff --git a/app/javascript/flavours/glitch/actions/favourites.js b/app/javascript/flavours/glitch/actions/favourites.js index decdcee4f..0c0f3af44 100644 --- a/app/javascript/flavours/glitch/actions/favourites.js +++ b/app/javascript/flavours/glitch/actions/favourites.js @@ -10,6 +10,10 @@ export const FAVOURITED_STATUSES_EXPAND_FAIL = 'FAVOURITED_STATUSES_EXPAND_FA export function fetchFavouritedStatuses() { return (dispatch, getState) => { + if (getState().getIn(['status_lists', 'favourites', 'isLoading'])) { + return; + } + dispatch(fetchFavouritedStatusesRequest()); api(getState).get('/api/v1/favourites').then(response => { @@ -46,7 +50,7 @@ export function expandFavouritedStatuses() { return (dispatch, getState) => { const url = getState().getIn(['status_lists', 'favourites', 'next'], null); - if (url === null) { + if (url === null || getState().getIn(['status_lists', 'favourites', 'isLoading'])) { return; } diff --git a/app/javascript/flavours/glitch/actions/notifications.js b/app/javascript/flavours/glitch/actions/notifications.js index 9b9ebf86d..cf27eff90 100644 --- a/app/javascript/flavours/glitch/actions/notifications.js +++ b/app/javascript/flavours/glitch/actions/notifications.js @@ -42,7 +42,7 @@ const fetchRelatedRelationships = (dispatch, notifications) => { const unescapeHTML = (html) => { const wrapper = document.createElement('div'); - html = html.replace(/<br \/>|<br>|\n/, ' '); + html = html.replace(/<br \/>|<br>|\n/g, ' '); wrapper.innerHTML = html; return wrapper.textContent; }; diff --git a/app/javascript/flavours/glitch/actions/push_notifications/index.js b/app/javascript/flavours/glitch/actions/push_notifications/index.js index 376b55b62..2ffec500a 100644 --- a/app/javascript/flavours/glitch/actions/push_notifications/index.js +++ b/app/javascript/flavours/glitch/actions/push_notifications/index.js @@ -15,9 +15,9 @@ export { register, }; -export function changeAlerts(key, value) { +export function changeAlerts(path, value) { return dispatch => { - dispatch(setAlerts(key, value)); + dispatch(setAlerts(path, value)); dispatch(saveSettings()); }; } diff --git a/app/javascript/flavours/glitch/actions/push_notifications/registerer.js b/app/javascript/flavours/glitch/actions/push_notifications/registerer.js index 3003d4149..5ad11f73f 100644 --- a/app/javascript/flavours/glitch/actions/push_notifications/registerer.js +++ b/app/javascript/flavours/glitch/actions/push_notifications/registerer.js @@ -1,4 +1,4 @@ -import axios from 'axios'; +import api from 'flavours/glitch/util/api'; import { pushNotificationsSetting } from 'flavours/glitch/util/settings'; import { setBrowserSupport, setSubscription, clearSubscription } from './setter'; @@ -35,7 +35,7 @@ const subscribe = (registration) => const unsubscribe = ({ registration, subscription }) => subscription ? subscription.unsubscribe().then(() => registration) : registration; -const sendSubscriptionToBackend = (subscription, me) => { +const sendSubscriptionToBackend = (getState, subscription, me) => { const params = { subscription }; if (me) { @@ -45,7 +45,7 @@ const sendSubscriptionToBackend = (subscription, me) => { } } - return axios.post('/api/web/push_subscriptions', params).then(response => response.data); + return api(getState).post('/api/web/push_subscriptions', params).then(response => response.data); }; // Last one checks for payload support: https://web-push-book.gauntface.com/chapter-06/01-non-standards-browsers/#no-payload @@ -85,13 +85,13 @@ export function register () { } else { // Something went wrong, try to subscribe again return unsubscribe({ registration, subscription }).then(subscribe).then( - subscription => sendSubscriptionToBackend(subscription, me)); + subscription => sendSubscriptionToBackend(getState, subscription, me)); } } // No subscription, try to subscribe return subscribe(registration).then( - subscription => sendSubscriptionToBackend(subscription, me)); + subscription => sendSubscriptionToBackend(getState, subscription, me)); }) .then(subscription => { // If we got a PushSubscription (and not a subscription object from the backend) @@ -137,7 +137,7 @@ export function saveSettings() { const alerts = state.get('alerts'); const data = { alerts }; - axios.put(`/api/web/push_subscriptions/${subscription.get('id')}`, { + api(getState).put(`/api/web/push_subscriptions/${subscription.get('id')}`, { data, }).then(() => { const me = getState().getIn(['meta', 'me']); diff --git a/app/javascript/flavours/glitch/actions/push_notifications/setter.js b/app/javascript/flavours/glitch/actions/push_notifications/setter.js index a2cc41c5a..5561766bf 100644 --- a/app/javascript/flavours/glitch/actions/push_notifications/setter.js +++ b/app/javascript/flavours/glitch/actions/push_notifications/setter.js @@ -23,11 +23,11 @@ export function clearSubscription () { }; } -export function setAlerts (key, value) { +export function setAlerts (path, value) { return dispatch => { dispatch({ type: SET_ALERTS, - key, + path, value, }); }; diff --git a/app/javascript/flavours/glitch/actions/settings.js b/app/javascript/flavours/glitch/actions/settings.js index 79adca18c..87b2ae76d 100644 --- a/app/javascript/flavours/glitch/actions/settings.js +++ b/app/javascript/flavours/glitch/actions/settings.js @@ -1,14 +1,14 @@ -import axios from 'axios'; +import api from 'flavours/glitch/util/api'; import { debounce } from 'lodash'; export const SETTING_CHANGE = 'SETTING_CHANGE'; export const SETTING_SAVE = 'SETTING_SAVE'; -export function changeSetting(key, value) { +export function changeSetting(path, value) { return dispatch => { dispatch({ type: SETTING_CHANGE, - key, + path, value, }); @@ -21,9 +21,9 @@ const debouncedSave = debounce((dispatch, getState) => { return; } - const data = getState().get('settings').filter((_, key) => key !== 'saved').toJS(); + const data = getState().get('settings').filter((_, path) => path !== 'saved').toJS(); - axios.put('/api/web/settings', { data }).then(() => dispatch({ type: SETTING_SAVE })); + api(getState).put('/api/web/settings', { data }).then(() => dispatch({ type: SETTING_SAVE })); }, 5000, { trailing: true }); export function saveSettings() { diff --git a/app/javascript/flavours/glitch/components/account.js b/app/javascript/flavours/glitch/components/account.js index bb1979cc7..265ee94f6 100644 --- a/app/javascript/flavours/glitch/components/account.js +++ b/app/javascript/flavours/glitch/components/account.js @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { Fragment } from 'react'; import ImmutablePropTypes from 'react-immutable-proptypes'; import PropTypes from 'prop-types'; import Avatar from './avatar'; @@ -94,12 +94,12 @@ export default class Account extends ImmutablePureComponent { hidingNotificationsButton = <IconButton active icon='bell-slash' title={intl.formatMessage(messages.mute_notifications, { name: account.get('username') })} onClick={this.handleMuteNotifications} />; } buttons = ( - <div> + <Fragment> <IconButton active icon='volume-up' title={intl.formatMessage(messages.unmute, { name: account.get('username') })} onClick={this.handleMute} /> {hidingNotificationsButton} - </div> + </Fragment> ); - } else { + } else if (!account.get('moved')) { buttons = <IconButton icon={following ? 'user-times' : 'user-plus'} title={intl.formatMessage(following ? messages.unfollow : messages.follow)} onClick={this.handleFollow} active={following} />; } } diff --git a/app/javascript/flavours/glitch/components/media_gallery.js b/app/javascript/flavours/glitch/components/media_gallery.js index d2e80de49..6928af6d6 100644 --- a/app/javascript/flavours/glitch/components/media_gallery.js +++ b/app/javascript/flavours/glitch/components/media_gallery.js @@ -9,7 +9,26 @@ import classNames from 'classnames'; import { autoPlayGif } from 'flavours/glitch/util/initial_state'; const messages = defineMessages({ - toggle_visible: { id: 'media_gallery.toggle_visible', defaultMessage: 'Toggle visibility' }, + hidden: { + defaultMessage: 'Media hidden', + id: 'status.media_hidden', + }, + sensitive: { + defaultMessage: 'Sensitive', + id: 'media_gallery.sensitive', + }, + toggle: { + defaultMessage: 'Click to view', + id: 'status.sensitive_toggle', + }, + toggle_visible: { + defaultMessage: 'Toggle visibility', + id: 'media_gallery.toggle_visible', + }, + warning: { + defaultMessage: 'Sensitive content', + id: 'status.sensitive_warning', + }, }); class Item extends React.PureComponent { @@ -206,48 +225,79 @@ export default class MediaGallery extends React.PureComponent { this.props.onOpenMedia(this.props.media, index); } - isStandaloneEligible() { - const { media, standalone } = this.props; - return standalone && media.size === 1 && media.getIn([0, 'meta', 'small', 'aspect']); - } - render () { - const { media, intl, sensitive, letterbox, fullwidth } = this.props; + const { + handleClick, + handleOpen, + } = this; + const { + fullwidth, + intl, + letterbox, + media, + sensitive, + standalone, + } = this.props; const { visible } = this.state; const size = media.take(4).size; - - let children; - - if (!visible) { - let warning; - - if (sensitive) { - warning = <FormattedMessage id='status.sensitive_warning' defaultMessage='Sensitive content' />; - } else { - warning = <FormattedMessage id='status.media_hidden' defaultMessage='Media hidden' />; - } - - children = ( - <button className='media-spoiler' onClick={this.handleOpen}> - <span className='media-spoiler__warning'>{warning}</span> - <span className='media-spoiler__trigger'><FormattedMessage id='status.sensitive_toggle' defaultMessage='Click to view' /></span> - </button> - ); - } else { - if (this.isStandaloneEligible()) { - children = <Item standalone onClick={this.handleClick} attachment={media.get(0)} />; - } else { - children = media.take(4).map((attachment, i) => <Item key={attachment.get('id')} onClick={this.handleClick} attachment={attachment} index={i} size={size} letterbox={letterbox} />); - } - } + const computedClass = classNames('media-gallery', `size-${size}`, { 'full-width': fullwidth }); return ( - <div className={`media-gallery size-${size} ${fullwidth ? 'full-width' : ''}`}> - <div className={classNames('spoiler-button', { 'spoiler-button--visible': visible })}> - <IconButton title={intl.formatMessage(messages.toggle_visible)} icon={visible ? 'eye' : 'eye-slash'} overlay onClick={this.handleOpen} /> - </div> - - {children} + <div className={computedClass}> + {visible ? ( + <div className='sensitive-info'> + <IconButton + icon='eye' + onClick={handleOpen} + overlay + title={intl.formatMessage(messages.toggle_visible)} + /> + {sensitive ? ( + <span className='sensitive-marker'> + <FormattedMessage {...messages.sensitive} /> + </span> + ) : null} + </div> + ) : null} + {function () { + switch (true) { + case !visible: + return ( + <button + className='media-spoiler' + onClick={handleOpen} + > + <span className='media-spoiler__warning'> + <FormattedMessage {...(sensitive ? messages.warning : messages.hidden)} /> + </span> + <span className='media-spoiler__trigger'> + <FormattedMessage {...messages.toggle} /> + </span> + </button> + ); + case standalone && media.size === 1 && !!media.getIn([0, 'meta', 'small', 'aspect']): + return ( + <Item + attachment={media.get(0)} + onClick={handleClick} + standalone + /> + ); + default: + return media.take(4).map( + (attachment, i) => ( + <Item + attachment={attachment} + index={i} + key={attachment.get('id')} + letterbox={letterbox} + onClick={handleClick} + size={size} + /> + ) + ); + } + }()} </div> ); } diff --git a/app/javascript/flavours/glitch/components/status.js b/app/javascript/flavours/glitch/components/status.js index b8a0fd180..4feb9180b 100644 --- a/app/javascript/flavours/glitch/components/status.js +++ b/app/javascript/flavours/glitch/components/status.js @@ -121,15 +121,15 @@ export default class Status extends ImmutablePureComponent { if (function () { switch (true) { - case collapse: - case autoCollapseSettings.get('all'): - case autoCollapseSettings.get('notifications') && muted: + case !!collapse: + case !!autoCollapseSettings.get('all'): + case autoCollapseSettings.get('notifications') && !!muted: case autoCollapseSettings.get('lengthy') && node.clientHeight > ( status.get('media_attachments').size && !muted ? 650 : 400 ): case autoCollapseSettings.get('reblogs') && prepend === 'reblogged_by': case autoCollapseSettings.get('replies') && status.get('in_reply_to_id', null) !== null: - case autoCollapseSettings.get('media') && !(status.get('spoiler_text').length) && status.get('media_attachments').size: + case autoCollapseSettings.get('media') && !(status.get('spoiler_text').length) && !!status.get('media_attachments').size: return true; default: return false; diff --git a/app/javascript/flavours/glitch/features/community_timeline/containers/column_settings_container.js b/app/javascript/flavours/glitch/features/community_timeline/containers/column_settings_container.js index 84234a836..39387abb9 100644 --- a/app/javascript/flavours/glitch/features/community_timeline/containers/column_settings_container.js +++ b/app/javascript/flavours/glitch/features/community_timeline/containers/column_settings_container.js @@ -8,8 +8,8 @@ const mapStateToProps = state => ({ const mapDispatchToProps = dispatch => ({ - onChange (key, checked) { - dispatch(changeSetting(['community', ...key], checked)); + onChange (path, checked) { + dispatch(changeSetting(['community', ...path], checked)); }, }); diff --git a/app/javascript/flavours/glitch/features/composer/index.js b/app/javascript/flavours/glitch/features/composer/index.js index cae9bf9f2..29a2f4775 100644 --- a/app/javascript/flavours/glitch/features/composer/index.js +++ b/app/javascript/flavours/glitch/features/composer/index.js @@ -350,10 +350,10 @@ class Composer extends React.Component { acceptContentTypes={acceptContentTypes} advancedOptions={advancedOptions} disabled={isSubmitting} - full={media.size >= 4 || media.some( + full={media ? media.size >= 4 || media.some( item => item.get('type') === 'video' - )} - hasMedia={!!media.size} + ) : false} + hasMedia={media && !!media.size} intl={intl} onChangeAdvancedOption={onChangeAdvancedOption} onChangeSensitivity={onChangeSensitivity} @@ -369,7 +369,7 @@ class Composer extends React.Component { spoiler={spoiler} /> <ComposerPublisher - countText={`${spoilerText}${countableText(text)}${advancedOptions.get('do_not_federate') ? ' 👁️' : ''}`} + countText={`${spoilerText}${countableText(text)}${advancedOptions && advancedOptions.get('do_not_federate') ? ' 👁️' : ''}`} disabled={isSubmitting || isUploading || !!text.length && !text.trim().length} intl={intl} onSecondarySubmit={handleSecondarySubmit} diff --git a/app/javascript/flavours/glitch/features/composer/options/dropdown/content/index.js b/app/javascript/flavours/glitch/features/composer/options/dropdown/content/index.js index 28bdfc0db..b3a472999 100644 --- a/app/javascript/flavours/glitch/features/composer/options/dropdown/content/index.js +++ b/app/javascript/flavours/glitch/features/composer/options/dropdown/content/index.js @@ -96,7 +96,7 @@ export default class ComposerOptionsDropdownContent extends React.PureComponent transform: `scale(${scaleX}, ${scaleY})`, }} > - {items.map( + {items ? items.map( ({ name, ...rest @@ -110,7 +110,7 @@ export default class ComposerOptionsDropdownContent extends React.PureComponent options={rest} /> ) - )} + ) : null} </div> )} </Motion> @@ -127,7 +127,7 @@ ComposerOptionsDropdownContent.propTypes = { name: PropTypes.string.isRequired, on: PropTypes.bool, text: PropTypes.node, - })).isRequired, + })), onChange: PropTypes.func, onClose: PropTypes.func, style: PropTypes.object, diff --git a/app/javascript/flavours/glitch/features/composer/options/dropdown/content/item/index.js b/app/javascript/flavours/glitch/features/composer/options/dropdown/content/item/index.js index 605c945bd..68a52083f 100644 --- a/app/javascript/flavours/glitch/features/composer/options/dropdown/content/item/index.js +++ b/app/javascript/flavours/glitch/features/composer/options/dropdown/content/item/index.js @@ -104,7 +104,10 @@ export default class ComposerOptionsDropdownContentItem extends React.PureCompon <strong>{text}</strong> {meta} </div> - ) : <div className='content'>{text}</div>} + ) : + <div className='content'> + <strong>{text}</strong> + </div>} </div> ); } diff --git a/app/javascript/flavours/glitch/features/composer/options/index.js b/app/javascript/flavours/glitch/features/composer/options/index.js index 954508c11..c129622bc 100644 --- a/app/javascript/flavours/glitch/features/composer/options/index.js +++ b/app/javascript/flavours/glitch/features/composer/options/index.js @@ -292,31 +292,29 @@ export default class ComposerOptions extends React.PureComponent { onClick={onToggleSpoiler} title={intl.formatMessage(messages.spoiler)} /> - {advancedOptions ? ( - <Dropdown - active={advancedOptions.some(value => !!value)} - disabled={disabled} - icon='ellipsis-h' - items={[ - { - meta: <FormattedMessage {...messages.local_only_long} />, - name: 'do_not_federate', - on: advancedOptions.get('do_not_federate'), - text: <FormattedMessage {...messages.local_only_short} />, - }, - { - meta: <FormattedMessage {...messages.threaded_mode_long} />, - name: 'threaded_mode', - on: advancedOptions.get('threaded_mode'), - text: <FormattedMessage {...messages.threaded_mode_short} />, - }, - ]} - onChange={onChangeAdvancedOption} - onModalClose={onModalClose} - onModalOpen={onModalOpen} - title={intl.formatMessage(messages.advanced_options_icon_title)} - /> - ) : null} + <Dropdown + active={advancedOptions && advancedOptions.some(value => !!value)} + disabled={disabled} + icon='ellipsis-h' + items={advancedOptions ? [ + { + meta: <FormattedMessage {...messages.local_only_long} />, + name: 'do_not_federate', + on: advancedOptions.get('do_not_federate'), + text: <FormattedMessage {...messages.local_only_short} />, + }, + { + meta: <FormattedMessage {...messages.threaded_mode_long} />, + name: 'threaded_mode', + on: advancedOptions.get('threaded_mode'), + text: <FormattedMessage {...messages.threaded_mode_short} />, + }, + ] : null} + onChange={onChangeAdvancedOption} + onModalClose={onModalClose} + onModalOpen={onModalOpen} + title={intl.formatMessage(messages.advanced_options_icon_title)} + /> </div> ); } diff --git a/app/javascript/flavours/glitch/features/direct_timeline/containers/column_settings_container.js b/app/javascript/flavours/glitch/features/direct_timeline/containers/column_settings_container.js index d3e4b4216..7292af264 100644 --- a/app/javascript/flavours/glitch/features/direct_timeline/containers/column_settings_container.js +++ b/app/javascript/flavours/glitch/features/direct_timeline/containers/column_settings_container.js @@ -8,8 +8,8 @@ const mapStateToProps = state => ({ const mapDispatchToProps = dispatch => ({ - onChange (key, checked) { - dispatch(changeSetting(['direct', ...key], checked)); + onChange (path, checked) { + dispatch(changeSetting(['direct', ...path], checked)); }, }); diff --git a/app/javascript/flavours/glitch/features/favourited_statuses/index.js b/app/javascript/flavours/glitch/features/favourited_statuses/index.js index e20dda718..301a5ae4f 100644 --- a/app/javascript/flavours/glitch/features/favourited_statuses/index.js +++ b/app/javascript/flavours/glitch/features/favourited_statuses/index.js @@ -9,6 +9,7 @@ import { addColumn, removeColumn, moveColumn } from 'flavours/glitch/actions/col import StatusList from 'flavours/glitch/components/status_list'; import { defineMessages, injectIntl } from 'react-intl'; import ImmutablePureComponent from 'react-immutable-pure-component'; +import { debounce } from 'lodash'; const messages = defineMessages({ heading: { id: 'column.favourites', defaultMessage: 'Favourites' }, @@ -16,6 +17,7 @@ const messages = defineMessages({ const mapStateToProps = state => ({ statusIds: state.getIn(['status_lists', 'favourites', 'items']), + isLoading: state.getIn(['status_lists', 'favourites', 'isLoading'], true), hasMore: !!state.getIn(['status_lists', 'favourites', 'next']), }); @@ -30,6 +32,7 @@ export default class Favourites extends ImmutablePureComponent { columnId: PropTypes.string, multiColumn: PropTypes.bool, hasMore: PropTypes.bool, + isLoading: PropTypes.bool, }; componentWillMount () { @@ -59,12 +62,12 @@ export default class Favourites extends ImmutablePureComponent { this.column = c; } - handleScrollToBottom = () => { + handleScrollToBottom = debounce(() => { this.props.dispatch(expandFavouritedStatuses()); - } + }, 300, { leading: true }) render () { - const { intl, statusIds, columnId, multiColumn, hasMore } = this.props; + const { intl, statusIds, columnId, multiColumn, hasMore, isLoading } = this.props; const pinned = !!columnId; return ( @@ -85,6 +88,7 @@ export default class Favourites extends ImmutablePureComponent { statusIds={statusIds} scrollKey={`favourited_statuses-${columnId}`} hasMore={hasMore} + isLoading={isLoading} onScrollToBottom={this.handleScrollToBottom} /> </Column> diff --git a/app/javascript/flavours/glitch/features/getting_started/index.js b/app/javascript/flavours/glitch/features/getting_started/index.js index 1b05c4da1..0077f193b 100644 --- a/app/javascript/flavours/glitch/features/getting_started/index.js +++ b/app/javascript/flavours/glitch/features/getting_started/index.js @@ -79,7 +79,7 @@ export default class GettingStarted extends ImmutablePureComponent { render () { const { intl, myAccount, columns, multiColumn, lists } = this.props; - let navItems = []; + const navItems = []; let listItems = []; if (multiColumn) { diff --git a/app/javascript/flavours/glitch/features/home_timeline/containers/column_settings_container.js b/app/javascript/flavours/glitch/features/home_timeline/containers/column_settings_container.js index 19a8e792f..16747151b 100644 --- a/app/javascript/flavours/glitch/features/home_timeline/containers/column_settings_container.js +++ b/app/javascript/flavours/glitch/features/home_timeline/containers/column_settings_container.js @@ -8,8 +8,8 @@ const mapStateToProps = state => ({ const mapDispatchToProps = dispatch => ({ - onChange (key, checked) { - dispatch(changeSetting(['home', ...key], checked)); + onChange (path, checked) { + dispatch(changeSetting(['home', ...path], checked)); }, onSave () { diff --git a/app/javascript/flavours/glitch/features/notifications/components/column_settings.js b/app/javascript/flavours/glitch/features/notifications/components/column_settings.js index 23545185c..d9638aaf3 100644 --- a/app/javascript/flavours/glitch/features/notifications/components/column_settings.js +++ b/app/javascript/flavours/glitch/features/notifications/components/column_settings.js @@ -14,8 +14,8 @@ export default class ColumnSettings extends React.PureComponent { onClear: PropTypes.func.isRequired, }; - onPushChange = (key, checked) => { - this.props.onChange(['push', ...key], checked); + onPushChange = (path, checked) => { + this.props.onChange(['push', ...path], checked); } render () { diff --git a/app/javascript/flavours/glitch/features/notifications/containers/column_settings_container.js b/app/javascript/flavours/glitch/features/notifications/containers/column_settings_container.js index 95109fe4d..9585ea556 100644 --- a/app/javascript/flavours/glitch/features/notifications/containers/column_settings_container.js +++ b/app/javascript/flavours/glitch/features/notifications/containers/column_settings_container.js @@ -18,11 +18,11 @@ const mapStateToProps = state => ({ const mapDispatchToProps = (dispatch, { intl }) => ({ - onChange (key, checked) { - if (key[0] === 'push') { - dispatch(changePushNotifications(key.slice(1), checked)); + onChange (path, checked) { + if (path[0] === 'push') { + dispatch(changePushNotifications(path.slice(1), checked)); } else { - dispatch(changeSetting(['notifications', ...key], checked)); + dispatch(changeSetting(['notifications', ...path], checked)); } }, diff --git a/app/javascript/flavours/glitch/features/public_timeline/containers/column_settings_container.js b/app/javascript/flavours/glitch/features/public_timeline/containers/column_settings_container.js index b13e20645..f042adbe6 100644 --- a/app/javascript/flavours/glitch/features/public_timeline/containers/column_settings_container.js +++ b/app/javascript/flavours/glitch/features/public_timeline/containers/column_settings_container.js @@ -8,8 +8,8 @@ const mapStateToProps = state => ({ const mapDispatchToProps = dispatch => ({ - onChange (key, checked) { - dispatch(changeSetting(['public', ...key], checked)); + onChange (path, checked) { + dispatch(changeSetting(['public', ...path], checked)); }, }); diff --git a/app/javascript/flavours/glitch/features/ui/components/embed_modal.js b/app/javascript/flavours/glitch/features/ui/components/embed_modal.js index 1afffb51b..f3553f4a9 100644 --- a/app/javascript/flavours/glitch/features/ui/components/embed_modal.js +++ b/app/javascript/flavours/glitch/features/ui/components/embed_modal.js @@ -2,7 +2,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import ImmutablePureComponent from 'react-immutable-pure-component'; import { FormattedMessage, injectIntl } from 'react-intl'; -import axios from 'axios'; +import api from 'flavours/glitch/util/api'; @injectIntl export default class EmbedModal extends ImmutablePureComponent { @@ -23,7 +23,7 @@ export default class EmbedModal extends ImmutablePureComponent { this.setState({ loading: true }); - axios.post('/api/web/embed', { url }).then(res => { + api().post('/api/web/embed', { url }).then(res => { this.setState({ loading: false, oembed: res.data }); const iframeDocument = this.iframe.contentWindow.document; diff --git a/app/javascript/flavours/glitch/features/ui/components/onboarding_modal.js b/app/javascript/flavours/glitch/features/ui/components/onboarding_modal.js index 91a83f330..4c910daec 100644 --- a/app/javascript/flavours/glitch/features/ui/components/onboarding_modal.js +++ b/app/javascript/flavours/glitch/features/ui/components/onboarding_modal.js @@ -38,11 +38,6 @@ PageOne.propTypes = { domain: PropTypes.string.isRequired, }; -const composerState = { - showSearch: true, - text: 'Awoo! #introductions', -}; - const PageTwo = ({ intl, myAccount }) => ( <div className='onboarding-modal__page onboarding-modal__page-two'> <div className='figure non-interactive'> @@ -50,7 +45,8 @@ const PageTwo = ({ intl, myAccount }) => ( <DrawerAccount account={myAccount} /> <RawComposer intl={intl} - state={composerState} + privacy='public' + text='Awoo! #introductions' /> </div> </div> diff --git a/app/javascript/flavours/glitch/locales/en.js b/app/javascript/flavours/glitch/locales/en.js index de6af0990..fb3763ced 100644 --- a/app/javascript/flavours/glitch/locales/en.js +++ b/app/javascript/flavours/glitch/locales/en.js @@ -34,6 +34,8 @@ const messages = { 'status.collapse': 'Collapse', 'status.uncollapse': 'Uncollapse', + 'media_gallery.sensitive': 'Sensitive', + 'favourite_modal.combo': 'You can press {combo} to skip this next time', 'home.column_settings.show_direct': 'Show DMs', diff --git a/app/javascript/flavours/glitch/locales/pl.js b/app/javascript/flavours/glitch/locales/pl.js index e38385715..527fe1d2d 100644 --- a/app/javascript/flavours/glitch/locales/pl.js +++ b/app/javascript/flavours/glitch/locales/pl.js @@ -34,6 +34,8 @@ const messages = { 'status.collapse': 'Zwiń', 'status.uncollapse': 'Rozwiń', + 'media_gallery.sensitive': 'Zawartość wrażliwa', + 'favourite_modal.combo': 'Możesz nacisnąć {combo}, aby pominąć to następnym razem', 'home.column_settings.show_direct': 'Pokaż wiadomości bezpośrednie', @@ -52,9 +54,13 @@ const messages = { 'compose.attach.doodle': 'Narysuj coś', 'compose.attach': 'Załącz coś', - 'advanced-options.local-only.short': 'Tylko lokalnie', - 'advanced-options.local-only.long': 'Nie wysyłaj na inne instancje', + 'advanced_options.local-only.short': 'Tylko lokalnie', + 'advanced_options.local-only.long': 'Nie wysyłaj na inne instancje', + 'advanced_options.local-only.tooltip': 'Ten wpis jest widoczny tylko lokalnie', 'advanced_options.icon_title': 'Ustawienia zaawansowane', + 'advanced_options.threaded_mode.short': 'Tryb wątków', + 'advanced_options.threaded_mode.long': 'Przechodzi do tworzenia odpowiedzi po publikacji wpisu', + 'advanced_options.threaded_mode.tooltip': 'Włączono tryb wątków', }; export default Object.assign({}, inherited, messages); diff --git a/app/javascript/flavours/glitch/reducers/compose.js b/app/javascript/flavours/glitch/reducers/compose.js index 24f76cf86..722670cf1 100644 --- a/app/javascript/flavours/glitch/reducers/compose.js +++ b/app/javascript/flavours/glitch/reducers/compose.js @@ -142,7 +142,7 @@ function continueThread (state, status) { 'advanced_options', map => map.merge(new ImmutableMap({ do_not_federate: /👁\ufe0f?\u200b?(?:<\/p>)?$/.test(status.content) })) ); - map.set('privacy', privacyPreference(status.visibility, state.get('default_privacy'))); + map.set('privacy', status.visibility); map.set('sensitive', false); map.update('media_attachments', list => list.clear()); map.set('idempotencyKey', uuid()); diff --git a/app/javascript/flavours/glitch/reducers/push_notifications.js b/app/javascript/flavours/glitch/reducers/push_notifications.js index 4eba2a5e8..1b47ca962 100644 --- a/app/javascript/flavours/glitch/reducers/push_notifications.js +++ b/app/javascript/flavours/glitch/reducers/push_notifications.js @@ -44,7 +44,7 @@ export default function push_subscriptions(state = initialState, action) { case CLEAR_SUBSCRIPTION: return initialState; case SET_ALERTS: - return state.setIn(action.key, action.value); + return state.setIn(action.path, action.value); default: return state; } diff --git a/app/javascript/flavours/glitch/reducers/settings.js b/app/javascript/flavours/glitch/reducers/settings.js index aaf7938df..c04f262da 100644 --- a/app/javascript/flavours/glitch/reducers/settings.js +++ b/app/javascript/flavours/glitch/reducers/settings.js @@ -101,7 +101,7 @@ export default function settings(state = initialState, action) { return hydrate(state, action.state.get('settings')); case SETTING_CHANGE: return state - .setIn(action.key, action.value) + .setIn(action.path, action.value) .set('saved', false); case COLUMN_ADD: return state diff --git a/app/javascript/flavours/glitch/reducers/status_lists.js b/app/javascript/flavours/glitch/reducers/status_lists.js index 5a3d0db0c..6de81c6b1 100644 --- a/app/javascript/flavours/glitch/reducers/status_lists.js +++ b/app/javascript/flavours/glitch/reducers/status_lists.js @@ -1,6 +1,10 @@ import { + FAVOURITED_STATUSES_FETCH_REQUEST, FAVOURITED_STATUSES_FETCH_SUCCESS, + FAVOURITED_STATUSES_FETCH_FAIL, + FAVOURITED_STATUSES_EXPAND_REQUEST, FAVOURITED_STATUSES_EXPAND_SUCCESS, + FAVOURITED_STATUSES_EXPAND_FAIL, } from 'flavours/glitch/actions/favourites'; import { PINNED_STATUSES_FETCH_SUCCESS, @@ -30,6 +34,7 @@ const normalizeList = (state, listType, statuses, next) => { return state.update(listType, listMap => listMap.withMutations(map => { map.set('next', next); map.set('loaded', true); + map.set('isLoading', false); map.set('items', ImmutableList(statuses.map(item => item.id))); })); }; @@ -37,6 +42,7 @@ const normalizeList = (state, listType, statuses, next) => { const appendToList = (state, listType, statuses, next) => { return state.update(listType, listMap => listMap.withMutations(map => { map.set('next', next); + map.set('isLoading', false); map.set('items', map.get('items').concat(statuses.map(item => item.id))); })); }; @@ -55,6 +61,12 @@ const removeOneFromList = (state, listType, status) => { export default function statusLists(state = initialState, action) { switch(action.type) { + case FAVOURITED_STATUSES_FETCH_REQUEST: + case FAVOURITED_STATUSES_EXPAND_REQUEST: + return state.setIn(['favourites', 'isLoading'], true); + case FAVOURITED_STATUSES_FETCH_FAIL: + case FAVOURITED_STATUSES_EXPAND_FAIL: + return state.setIn(['favourites', 'isLoading'], false); case FAVOURITED_STATUSES_FETCH_SUCCESS: return normalizeList(state, 'favourites', action.statuses, action.next); case FAVOURITED_STATUSES_EXPAND_SUCCESS: diff --git a/app/javascript/flavours/glitch/styles/admin.scss b/app/javascript/flavours/glitch/styles/admin.scss index 4e923bb98..bdfa50814 100644 --- a/app/javascript/flavours/glitch/styles/admin.scss +++ b/app/javascript/flavours/glitch/styles/admin.scss @@ -396,10 +396,12 @@ } } + &__content { + max-width: calc(100% - 90px); + } + &__title { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; + word-wrap: break-word; } &__timestamp { @@ -413,7 +415,7 @@ color: $ui-primary-color; font-family: 'mastodon-font-monospace', monospace; font-size: 12px; - white-space: nowrap; + word-wrap: break-word; min-height: 20px; } diff --git a/app/javascript/flavours/glitch/styles/components/index.scss b/app/javascript/flavours/glitch/styles/components/index.scss index 967620397..ca6fd9e99 100644 --- a/app/javascript/flavours/glitch/styles/components/index.scss +++ b/app/javascript/flavours/glitch/styles/components/index.scss @@ -1568,6 +1568,39 @@ } } +.drawer__pager { + box-sizing: border-box; + padding: 0; + flex-grow: 1; + position: relative; + overflow: hidden; + display: flex; +} + +.drawer__inner { + position: absolute; + top: 0; + left: 0; + background: lighten($ui-base-color, 13%) url('~images/wave-drawer.png') no-repeat bottom / 100% auto; + box-sizing: border-box; + padding: 0; + display: flex; + flex-direction: column; + overflow: hidden; + overflow-y: auto; + width: 100%; + height: 100%; + + &.darker { + background: $ui-base-color; + } + + > .mastodon { + background: url('~images/mastodon-ui.png') no-repeat left bottom / contain; + flex: 1; + } +} + .pseudo-drawer { background: lighten($ui-base-color, 13%); font-size: 13px; @@ -1848,6 +1881,11 @@ cursor: default; } +.getting-started__wrapper, +.getting_started { + background: $ui-base-color; +} + .getting-started__wrapper { position: relative; overflow-y: auto; @@ -2454,17 +2492,29 @@ font-weight: 500; } -.spoiler-button { - display: none; - left: 4px; +.sensitive-info { + display: flex; + flex-direction: row; + align-items: center; position: absolute; - text-shadow: 0 1px 1px $base-shadow-color, 1px 0 1px $base-shadow-color; top: 4px; + left: 4px; z-index: 100; +} - &.spoiler-button--visible { - display: block; - } +.sensitive-marker { + margin: 0 3px; + border-radius: 2px; + padding: 2px 6px; + color: rgba($primary-text-color, 0.8); + background: rgba($base-overlay-background, 0.5); + font-size: 12px; + line-height: 15px; + text-transform: uppercase; + opacity: .9; + transition: opacity .1s ease; + + .media-gallery:hover & { opacity: 1 } } .modal-container--preloader { @@ -2781,6 +2831,112 @@ filter: none; } +.search { + position: relative; +} + +.search__input { + outline: 0; + box-sizing: border-box; + display: block; + width: 100%; + border: none; + padding: 10px; + padding-right: 30px; + font-family: inherit; + background: $ui-base-color; + color: $ui-primary-color; + font-size: 14px; + margin: 0; + + &::-moz-focus-inner { + border: 0; + } + + &::-moz-focus-inner, + &:focus, + &:active { + outline: 0 !important; + } + + &:focus { + background: lighten($ui-base-color, 4%); + } + + @media screen and (max-width: 600px) { + font-size: 16px; + } +} + +.search__icon { + .fa { + position: absolute; + top: 10px; + right: 10px; + z-index: 2; + display: inline-block; + opacity: 0; + transition: all 100ms linear; + font-size: 18px; + width: 18px; + height: 18px; + color: $ui-secondary-color; + cursor: default; + pointer-events: none; + + &.active { + pointer-events: auto; + opacity: 0.3; + } + } + + .fa-search { + transform: rotate(90deg); + + &.active { + pointer-events: none; + transform: rotate(0deg); + } + } + + .fa-times-circle { + top: 11px; + transform: rotate(0deg); + cursor: pointer; + + &.active { + transform: rotate(90deg); + } + + &:hover { + color: $primary-text-color; + } + } +} + +.search-results__header { + color: $ui-base-lighter-color; + background: lighten($ui-base-color, 2%); + border-bottom: 1px solid darken($ui-base-color, 4%); + padding: 15px 10px; + font-size: 14px; + font-weight: 500; +} + +.search-results__hashtag { + display: block; + padding: 10px; + color: $ui-secondary-color; + text-decoration: none; + + &:hover, + &:active, + &:focus { + color: lighten($ui-secondary-color, 4%); + text-decoration: underline; + } +} + .modal-root { transition: opacity 0.3s linear; will-change: opacity; diff --git a/app/javascript/flavours/glitch/theme.yml b/app/javascript/flavours/glitch/theme.yml index 8ccd8fa65..100e89e3e 100644 --- a/app/javascript/flavours/glitch/theme.yml +++ b/app/javascript/flavours/glitch/theme.yml @@ -1,7 +1,7 @@ # (REQUIRED) The location of the pack files. pack: about: packs/about.js - admin: + admin: packs/public.js auth: common: filename: packs/common.js diff --git a/app/javascript/flavours/glitch/util/api.js b/app/javascript/flavours/glitch/util/api.js index ecc703c0a..0be08d7fd 100644 --- a/app/javascript/flavours/glitch/util/api.js +++ b/app/javascript/flavours/glitch/util/api.js @@ -1,4 +1,5 @@ import axios from 'axios'; +import ready from './ready'; import LinkHeader from './link_header'; export const getLinks = response => { @@ -11,10 +12,17 @@ export const getLinks = response => { return LinkHeader.parse(value); }; +let csrfHeader = {}; +function setCSRFHeader() { + const csrfToken = document.querySelector('meta[name=csrf-token]').content; + csrfHeader['X-CSRF-Token'] = csrfToken; +} +ready(setCSRFHeader); + export default getState => axios.create({ - headers: { + headers: Object.assign(csrfHeader, getState ? { 'Authorization': `Bearer ${getState().getIn(['meta', 'access_token'], '')}`, - }, + } : {}), transformResponse: [function (data) { try { diff --git a/app/javascript/flavours/glitch/util/async-components.js b/app/javascript/flavours/glitch/util/async-components.js index b90f1b8c8..2aa9659e8 100644 --- a/app/javascript/flavours/glitch/util/async-components.js +++ b/app/javascript/flavours/glitch/util/async-components.js @@ -27,15 +27,15 @@ export function HashtagTimeline () { } export function ListTimeline () { - return import(/* webpackChunkName: "features/list_timeline" */'flavours/glitch/features/list_timeline'); + return import(/* webpackChunkName: "flavours/glitch/async/list_timeline" */'flavours/glitch/features/list_timeline'); } export function Lists () { - return import(/* webpackChunkName: "features/lists" */'flavours/glitch/features/lists'); + return import(/* webpackChunkName: "flavours/glitch/async/lists" */'flavours/glitch/features/lists'); } export function ListEditor () { - return import(/* webpackChunkName: "features/list_editor" */'flavours/glitch/features/list_editor'); + return import(/* webpackChunkName: "flavours/glitch/async/list_editor" */'flavours/glitch/features/list_editor'); } export function DirectTimeline() { @@ -51,7 +51,7 @@ export function GettingStarted () { } export function KeyboardShortcuts () { - return import(/* webpackChunkName: "features/keyboard_shortcuts" */'flavours/glitch/features/keyboard_shortcuts'); + return import(/* webpackChunkName: "flavours/glitch/async/keyboard_shortcuts" */'flavours/glitch/features/keyboard_shortcuts'); } export function PinnedStatuses () { diff --git a/app/javascript/flavours/vanilla/theme.yml b/app/javascript/flavours/vanilla/theme.yml index 0b27c31bb..6f6a32c37 100644 --- a/app/javascript/flavours/vanilla/theme.yml +++ b/app/javascript/flavours/vanilla/theme.yml @@ -1,7 +1,7 @@ # (REQUIRED) The location of the pack files inside `pack_directory`. pack: about: about.js - admin: + admin: public.js auth: common: filename: common.js diff --git a/app/javascript/mastodon/actions/push_notifications/registerer.js b/app/javascript/mastodon/actions/push_notifications/registerer.js index 1d040bc8c..5f47a5501 100644 --- a/app/javascript/mastodon/actions/push_notifications/registerer.js +++ b/app/javascript/mastodon/actions/push_notifications/registerer.js @@ -1,4 +1,4 @@ -import axios from 'axios'; +import api from '../../api'; import { pushNotificationsSetting } from '../../settings'; import { setBrowserSupport, setSubscription, clearSubscription } from './setter'; @@ -35,7 +35,7 @@ const subscribe = (registration) => const unsubscribe = ({ registration, subscription }) => subscription ? subscription.unsubscribe().then(() => registration) : registration; -const sendSubscriptionToBackend = (subscription, me) => { +const sendSubscriptionToBackend = (getState, subscription, me) => { const params = { subscription }; if (me) { @@ -45,7 +45,7 @@ const sendSubscriptionToBackend = (subscription, me) => { } } - return axios.post('/api/web/push_subscriptions', params).then(response => response.data); + return api(getState).post('/api/web/push_subscriptions', params).then(response => response.data); }; // Last one checks for payload support: https://web-push-book.gauntface.com/chapter-06/01-non-standards-browsers/#no-payload @@ -85,13 +85,13 @@ export function register () { } else { // Something went wrong, try to subscribe again return unsubscribe({ registration, subscription }).then(subscribe).then( - subscription => sendSubscriptionToBackend(subscription, me)); + subscription => sendSubscriptionToBackend(getState, subscription, me)); } } // No subscription, try to subscribe return subscribe(registration).then( - subscription => sendSubscriptionToBackend(subscription, me)); + subscription => sendSubscriptionToBackend(getState, subscription, me)); }) .then(subscription => { // If we got a PushSubscription (and not a subscription object from the backend) @@ -137,7 +137,7 @@ export function saveSettings() { const alerts = state.get('alerts'); const data = { alerts }; - axios.put(`/api/web/push_subscriptions/${subscription.get('id')}`, { + api(getState).put(`/api/web/push_subscriptions/${subscription.get('id')}`, { data, }).then(() => { const me = getState().getIn(['meta', 'me']); diff --git a/app/javascript/mastodon/actions/settings.js b/app/javascript/mastodon/actions/settings.js index aeef43527..b96383daa 100644 --- a/app/javascript/mastodon/actions/settings.js +++ b/app/javascript/mastodon/actions/settings.js @@ -1,4 +1,4 @@ -import axios from 'axios'; +import api from '../api'; import { debounce } from 'lodash'; export const SETTING_CHANGE = 'SETTING_CHANGE'; @@ -23,7 +23,7 @@ const debouncedSave = debounce((dispatch, getState) => { const data = getState().get('settings').filter((_, path) => path !== 'saved').toJS(); - axios.put('/api/web/settings', { data }).then(() => dispatch({ type: SETTING_SAVE })); + api(getState).put('/api/web/settings', { data }).then(() => dispatch({ type: SETTING_SAVE })); }, 5000, { trailing: true }); export function saveSettings() { diff --git a/app/javascript/mastodon/api.js b/app/javascript/mastodon/api.js index ecc703c0a..0be08d7fd 100644 --- a/app/javascript/mastodon/api.js +++ b/app/javascript/mastodon/api.js @@ -1,4 +1,5 @@ import axios from 'axios'; +import ready from './ready'; import LinkHeader from './link_header'; export const getLinks = response => { @@ -11,10 +12,17 @@ export const getLinks = response => { return LinkHeader.parse(value); }; +let csrfHeader = {}; +function setCSRFHeader() { + const csrfToken = document.querySelector('meta[name=csrf-token]').content; + csrfHeader['X-CSRF-Token'] = csrfToken; +} +ready(setCSRFHeader); + export default getState => axios.create({ - headers: { + headers: Object.assign(csrfHeader, getState ? { 'Authorization': `Bearer ${getState().getIn(['meta', 'access_token'], '')}`, - }, + } : {}), transformResponse: [function (data) { try { diff --git a/app/javascript/mastodon/components/column_header.js b/app/javascript/mastodon/components/column_header.js index 80a8fbdb3..c300db89b 100644 --- a/app/javascript/mastodon/components/column_header.js +++ b/app/javascript/mastodon/components/column_header.js @@ -23,7 +23,6 @@ export default class ColumnHeader extends React.PureComponent { icon: PropTypes.string.isRequired, active: PropTypes.bool, multiColumn: PropTypes.bool, - focusable: PropTypes.bool, showBackButton: PropTypes.bool, children: PropTypes.node, pinned: PropTypes.bool, @@ -32,10 +31,6 @@ export default class ColumnHeader extends React.PureComponent { onClick: PropTypes.func, }; - static defaultProps = { - focusable: true, - } - state = { collapsed: true, animating: false, @@ -68,7 +63,7 @@ export default class ColumnHeader extends React.PureComponent { } render () { - const { title, icon, active, children, pinned, onPin, multiColumn, focusable, showBackButton, intl: { formatMessage } } = this.props; + const { title, icon, active, children, pinned, onPin, multiColumn, showBackButton, intl: { formatMessage } } = this.props; const { collapsed, animating } = this.state; const wrapperClassName = classNames('column-header__wrapper', { @@ -135,11 +130,13 @@ export default class ColumnHeader extends React.PureComponent { return ( <div className={wrapperClassName}> - <h1 tabIndex={focusable ? 0 : null} role='button' className={buttonClassName} aria-label={title} onClick={this.handleTitleClick}> - <i className={`fa fa-fw fa-${icon} column-header__icon`} /> - <span className='column-header__title'> - {title} - </span> + <h1 className={buttonClassName}> + <button onClick={this.handleTitleClick}> + <i className={`fa fa-fw fa-${icon} column-header__icon`} /> + <span className='column-header__title'> + {title} + </span> + </button> <div className='column-header__buttons'> {backButton} diff --git a/app/javascript/mastodon/features/ui/components/embed_modal.js b/app/javascript/mastodon/features/ui/components/embed_modal.js index 1afffb51b..d440a8826 100644 --- a/app/javascript/mastodon/features/ui/components/embed_modal.js +++ b/app/javascript/mastodon/features/ui/components/embed_modal.js @@ -2,7 +2,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import ImmutablePureComponent from 'react-immutable-pure-component'; import { FormattedMessage, injectIntl } from 'react-intl'; -import axios from 'axios'; +import api from '../../../api'; @injectIntl export default class EmbedModal extends ImmutablePureComponent { @@ -23,7 +23,7 @@ export default class EmbedModal extends ImmutablePureComponent { this.setState({ loading: true }); - axios.post('/api/web/embed', { url }).then(res => { + api().post('/api/web/embed', { url }).then(res => { this.setState({ loading: false, oembed: res.data }); const iframeDocument = this.iframe.contentWindow.document; diff --git a/app/javascript/mastodon/locales/ar.json b/app/javascript/mastodon/locales/ar.json index f1bb465d9..795b27707 100644 --- a/app/javascript/mastodon/locales/ar.json +++ b/app/javascript/mastodon/locales/ar.json @@ -67,7 +67,7 @@ "confirmations.delete_list.confirm": "Delete", "confirmations.delete_list.message": "هل تود حقا حذف هذه القائمة ؟", "confirmations.domain_block.confirm": "إخفاء إسم النطاق كاملا", - "confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.", + "confirmations.domain_block.message": "متأكد من أنك تود حظر إسم النطاق {domain} بالكامل ؟ في غالب الأحيان يُستَحسَن كتم أو حظر بعض الحسابات بدلا من حظر نطاق بالكامل.", "confirmations.mute.confirm": "أكتم", "confirmations.mute.message": "هل أنت متأكد أنك تريد كتم {name} ؟", "confirmations.unfollow.confirm": "إلغاء المتابعة", @@ -92,7 +92,7 @@ "empty_column.hashtag": "ليس هناك بعدُ أي محتوى ذو علاقة بهذا الوسم.", "empty_column.home": "إنك لا تتبع بعد أي شخص إلى حد الآن. زر {public} أو استخدام حقل البحث لكي تبدأ على التعرف على مستخدمين آخرين.", "empty_column.home.public_timeline": "الخيط العام", - "empty_column.list": "هذه القائمة فارغة.", + "empty_column.list": "هذه القائمة فارغة مؤقتا و لكن سوف تمتلئ تدريجيا عندما يبدأ الأعضاء المُنتَمين إليها بنشر تبويقات.", "empty_column.notifications": "لم تتلق أي إشعار بعدُ. تفاعل مع المستخدمين الآخرين لإنشاء محادثة.", "empty_column.public": "لا يوجد أي شيء هنا ! قم بنشر شيء ما للعامة، أو إتبع مستخدمين آخرين في الخوادم المثيلة الأخرى لملء خيط المحادثات العام", "follow_request.authorize": "ترخيص", @@ -123,7 +123,7 @@ "keyboard_shortcuts.reply": "للردّ", "keyboard_shortcuts.search": "للتركيز على البحث", "keyboard_shortcuts.toot": "لتحرير تبويق جديد", - "keyboard_shortcuts.unfocus": "to un-focus compose textarea/search", + "keyboard_shortcuts.unfocus": "لإلغاء التركيز على حقل النص أو نافذة البحث", "keyboard_shortcuts.up": "للإنتقال إلى أعلى القائمة", "lightbox.close": "إغلاق", "lightbox.next": "التالي", diff --git a/app/javascript/mastodon/locales/ca.json b/app/javascript/mastodon/locales/ca.json index 3d2fe2839..3eb0e3d26 100644 --- a/app/javascript/mastodon/locales/ca.json +++ b/app/javascript/mastodon/locales/ca.json @@ -92,7 +92,7 @@ "empty_column.hashtag": "Encara no hi ha res amb aquesta etiqueta.", "empty_column.home": "Encara no segueixes ningú. Visita {public} o fes cerca per començar i conèixer altres usuaris.", "empty_column.home.public_timeline": "la línia de temps pública", - "empty_column.list": "Encara no hi ha res en aquesta llista.", + "empty_column.list": "Encara no hi ha res en aquesta llista. Quan els membres d'aquesta llista publiquin nous estats, apareixeran aquí.", "empty_column.notifications": "Encara no tens notificacions. Interactua amb altres per iniciar la conversa.", "empty_column.public": "No hi ha res aquí! Escriu alguna cosa públicament o segueix manualment usuaris d'altres instàncies per omplir-ho", "follow_request.authorize": "Autoritzar", diff --git a/app/javascript/mastodon/locales/fa.json b/app/javascript/mastodon/locales/fa.json index f6c6f5ced..8c52ffdb4 100644 --- a/app/javascript/mastodon/locales/fa.json +++ b/app/javascript/mastodon/locales/fa.json @@ -7,22 +7,22 @@ "account.followers": "پیگیران", "account.follows": "پی میگیرد", "account.follows_you": "پیگیر شماست", - "account.hide_reblogs": "Hide boosts from @{name}", + "account.hide_reblogs": "پنهان کردن بازبوقهای @{name}", "account.media": "رسانه", "account.mention": "نامبردن از @{name}", - "account.moved_to": "{name} has moved to:", + "account.moved_to": "{name} منتقل شده است به:", "account.mute": "بیصدا کردن @{name}", - "account.mute_notifications": "Mute notifications from @{name}", + "account.mute_notifications": "بیصداکردن اعلانها از طرف @{name}", "account.posts": "نوشتهها", "account.report": "گزارش @{name}", "account.requested": "در انتظار پذیرش", "account.share": "همرسانی نمایهٔ @{name}", - "account.show_reblogs": "Show boosts from @{name}", + "account.show_reblogs": "نشاندادن بازبوقهای @{name}", "account.unblock": "رفع انسداد @{name}", "account.unblock_domain": "رفع پنهانسازی از {domain}", "account.unfollow": "پایان پیگیری", "account.unmute": "باصدا کردن @{name}", - "account.unmute_notifications": "Unmute notifications from @{name}", + "account.unmute_notifications": "باصداکردن اعلانها از طرف @{name}", "account.view_full_profile": "نمایش نمایهٔ کامل", "boost_modal.combo": "دکمهٔ {combo} را بزنید تا دیگر این را نبینید", "bundle_column_error.body": "هنگام بازکردن این بخش خطایی رخ داد.", @@ -36,7 +36,7 @@ "column.favourites": "پسندیدهها", "column.follow_requests": "درخواستهای پیگیری", "column.home": "خانه", - "column.lists": "Lists", + "column.lists": "فهرستها", "column.mutes": "کاربران بیصداشده", "column.notifications": "اعلانها", "column.pins": "نوشتههای ثابت", @@ -65,7 +65,7 @@ "confirmations.delete.confirm": "پاک کن", "confirmations.delete.message": "آیا واقعاً میخواهید این نوشته را پاک کنید؟", "confirmations.delete_list.confirm": "Delete", - "confirmations.delete_list.message": "Are you sure you want to permanently delete this list?", + "confirmations.delete_list.message": "آیا واقعاً میخواهید این فهرست را برای همیشه پاک کنید؟", "confirmations.domain_block.confirm": "پنهانسازی کل دامین", "confirmations.domain_block.message": "آیا جدی جدی میخواهید کل دامین {domain} را مسدود کنید؟ بیشتر وقتها مسدودکردن یا بیصداکردن چند حساب کاربری خاص کافی است و توصیه میشود.", "confirmations.mute.confirm": "بیصدا کن", @@ -92,7 +92,7 @@ "empty_column.hashtag": "هنوز هیچ چیزی با این هشتگ نیست.", "empty_column.home": "شما هنوز پیگیر کسی نیستید. {public} را ببینید یا چیزی را جستجو کنید تا کاربران دیگر را ببینید.", "empty_column.home.public_timeline": "فهرست نوشتههای همهجا", - "empty_column.list": "There is nothing in this list yet.", + "empty_column.list": "در این فهرست هنوز چیزی نیست. وقتی اعضای این فهرست چیزی بنویسند، اینجا ظاهر خواهد شد.", "empty_column.notifications": "هنوز هیچ اعلانی ندارید. به نوشتههای دیگران واکنش نشان دهید تا گفتگو آغاز شود.", "empty_column.public": "اینجا هنوز چیزی نیست! خودتان چیزی بنویسید یا کاربران دیگر را پی بگیرید تا اینجا پر شود", "follow_request.authorize": "اجازه دهید", @@ -108,46 +108,46 @@ "home.column_settings.show_reblogs": "نمایش بازبوقها", "home.column_settings.show_replies": "نمایش پاسخها", "home.settings": "تنظیمات ستون", - "keyboard_shortcuts.back": "to navigate back", - "keyboard_shortcuts.boost": "to boost", - "keyboard_shortcuts.column": "to focus a status in one of the columns", - "keyboard_shortcuts.compose": "to focus the compose textarea", + "keyboard_shortcuts.back": "برای بازگشت", + "keyboard_shortcuts.boost": "برای بازبوقیدن", + "keyboard_shortcuts.column": "برای برجستهکردن یک نوشته در یکی از ستونها", + "keyboard_shortcuts.compose": "برای فعالکردن کادر نوشتهٔ تازه", "keyboard_shortcuts.description": "Description", - "keyboard_shortcuts.down": "to move down in the list", + "keyboard_shortcuts.down": "برای پایینرفتن در فهرست", "keyboard_shortcuts.enter": "to open status", - "keyboard_shortcuts.favourite": "to favourite", + "keyboard_shortcuts.favourite": "برای پسندیدن", "keyboard_shortcuts.heading": "Keyboard Shortcuts", - "keyboard_shortcuts.hotkey": "Hotkey", - "keyboard_shortcuts.legend": "to display this legend", - "keyboard_shortcuts.mention": "to mention author", - "keyboard_shortcuts.reply": "to reply", - "keyboard_shortcuts.search": "to focus search", - "keyboard_shortcuts.toot": "to start a brand new toot", - "keyboard_shortcuts.unfocus": "to un-focus compose textarea/search", - "keyboard_shortcuts.up": "to move up in the list", + "keyboard_shortcuts.hotkey": "میانبر", + "keyboard_shortcuts.legend": "برای نمایش این راهنما", + "keyboard_shortcuts.mention": "برای نامبردن از نویسنده", + "keyboard_shortcuts.reply": "برای پاسخدادن", + "keyboard_shortcuts.search": "برای فعالکردن جستجو", + "keyboard_shortcuts.toot": "برای آغاز یک بوق تازه", + "keyboard_shortcuts.unfocus": "برای برداشتن توجه از نوشتن/جستجو", + "keyboard_shortcuts.up": "برای بالا رفتن در فهرست", "lightbox.close": "بستن", "lightbox.next": "بعدی", "lightbox.previous": "قبلی", - "lists.account.add": "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", + "lists.account.add": "افزودن به فهرست", + "lists.account.remove": "پاککردن از فهرست", + "lists.delete": "حذف فهرست", + "lists.edit": "ویرایش فهرست", + "lists.new.create": "افزودن فهرست", + "lists.new.title_placeholder": "نام فهرست تازه", + "lists.search": "بین کسانی که پی میگیرید بگردید", + "lists.subheading": "فهرستهای شما", "loading_indicator.label": "بارگیری...", "media_gallery.toggle_visible": "تغییر پیدایی", "missing_indicator.label": "پیدا نشد", - "mute_modal.hide_notifications": "Hide notifications from this user?", + "mute_modal.hide_notifications": "اعلانهای این کاربر پنهان شود؟", "navigation_bar.blocks": "کاربران مسدودشده", "navigation_bar.community_timeline": "نوشتههای محلی", "navigation_bar.edit_profile": "ویرایش نمایه", "navigation_bar.favourites": "پسندیدهها", "navigation_bar.follow_requests": "درخواستهای پیگیری", "navigation_bar.info": "اطلاعات تکمیلی", - "navigation_bar.keyboard_shortcuts": "Keyboard shortcuts", - "navigation_bar.lists": "Lists", + "navigation_bar.keyboard_shortcuts": "میانبرهای صفحهکلید", + "navigation_bar.lists": "فهرستها", "navigation_bar.logout": "خروج", "navigation_bar.mutes": "کاربران بیصداشده", "navigation_bar.pins": "نوشتههای ثابت", @@ -174,7 +174,7 @@ "onboarding.page_four.home": "ستون «خانه» نوشتههای کسانی را نشان میدهد که شما پی میگیرید.", "onboarding.page_four.notifications": "ستون «اعلانها» ارتباطهای شما با دیگران را نشان میدهد.", "onboarding.page_one.federation": "ماستدون شبکهای از سرورهای مستقل است که با پیوستن به یکدیگر یک شبکهٔ اجتماعی بزرگ را تشکیل میدهند.", - "onboarding.page_one.handle": "شما روی سرور {domain} هستید، بنابراین شناسهٔ کامل شما {handle} است.", + "onboarding.page_one.handle": "شما روی سرور {domain} هستید، بنابراین شناسهٔ کامل شما {handle} است", "onboarding.page_one.welcome": "به ماستدون خوش آمدید!", "onboarding.page_six.admin": "نشانی مسئول سرور شما {admin} است.", "onboarding.page_six.almost_done": "الان تقریباً آمادهاید...", @@ -199,7 +199,7 @@ "privacy.unlisted.short": "فهرستنشده", "relative_time.days": "{number}d", "relative_time.hours": "{number}h", - "relative_time.just_now": "now", + "relative_time.just_now": "الان", "relative_time.minutes": "{number}m", "relative_time.seconds": "{number}s", "reply_indicator.cancel": "لغو", @@ -222,7 +222,7 @@ "status.load_more": "بیشتر نشان بده", "status.media_hidden": "تصویر پنهان شده", "status.mention": "نامبردن از @{name}", - "status.more": "More", + "status.more": "بیشتر", "status.mute": "Mute @{name}", "status.mute_conversation": "بیصداکردن گفتگو", "status.open": "این نوشته را باز کن", @@ -244,7 +244,7 @@ "tabs_bar.home": "خانه", "tabs_bar.local_timeline": "محلی", "tabs_bar.notifications": "اعلانها", - "ui.beforeunload": "Your draft will be lost if you leave Mastodon.", + "ui.beforeunload": "اگر از ماستدون خارج شوید پیشنویس شما پاک خواهد شد.", "upload_area.title": "برای بارگذاری به اینجا بکشید", "upload_button.label": "افزودن تصویر", "upload_form.description": "نوشتهٔ توضیحی برای کمبینایان و نابینایان", diff --git a/app/javascript/mastodon/locales/gl.json b/app/javascript/mastodon/locales/gl.json index 523dcc924..77f6b82ab 100644 --- a/app/javascript/mastodon/locales/gl.json +++ b/app/javascript/mastodon/locales/gl.json @@ -92,7 +92,7 @@ "empty_column.hashtag": "Aínda non hai nada con esta etiqueta.", "empty_column.home": "A súa liña temporal de inicio está baldeira! Visite {public} ou utilice a busca para atopar outras usuarias.", "empty_column.home.public_timeline": "a liña temporal pública", - "empty_column.list": "Aínda non hai nada en esta lista.", + "empty_column.list": "Aínda non hai nada en esta lista. Cando as usuarias incluídas na lista publiquen mensaxes, aparecerán aquí.", "empty_column.notifications": "Aínda non ten notificacións. Interactúe con outras para iniciar unha conversa.", "empty_column.public": "Nada por aquí! Escriba algo de xeito público, ou siga manualmente usuarias de outras instancias para ir enchéndoa", "follow_request.authorize": "Autorizar", @@ -109,7 +109,7 @@ "home.column_settings.show_replies": "Mostrar respostas", "home.settings": "Axustes da columna", "keyboard_shortcuts.back": "voltar atrás", - "keyboard_shortcuts.boost": "repetir", + "keyboard_shortcuts.boost": "promover", "keyboard_shortcuts.column": "destacar un estado en unha das columnas", "keyboard_shortcuts.compose": "Foco no área de escritura", "keyboard_shortcuts.description": "Descrición", @@ -227,8 +227,8 @@ "status.mute_conversation": "Acalar conversa", "status.open": "Expandir este estado", "status.pin": "Fixar no perfil", - "status.reblog": "Promocionar", - "status.reblogged_by": "{name} promocionado", + "status.reblog": "Promover", + "status.reblogged_by": "{name} promoveu", "status.reply": "Resposta", "status.replyAll": "Resposta a conversa", "status.report": "Informar @{name}", diff --git a/app/javascript/mastodon/locales/nl.json b/app/javascript/mastodon/locales/nl.json index f85cc75c5..6dc7292f1 100644 --- a/app/javascript/mastodon/locales/nl.json +++ b/app/javascript/mastodon/locales/nl.json @@ -100,10 +100,10 @@ "getting_started.appsshort": "Apps", "getting_started.faq": "FAQ", "getting_started.heading": "Beginnen", - "getting_started.open_source_notice": "Mastodon is open-sourcesoftware. Je kunt bijdragen of problemen melden op GitHub via {github}.", + "getting_started.open_source_notice": "Mastodon is vrije software. Je kunt bijdragen of problemen melden op GitHub via {github}.", "getting_started.userguide": "Gebruikersgids", "home.column_settings.advanced": "Geavanceerd", - "home.column_settings.basic": "Basis", + "home.column_settings.basic": "Algemeen", "home.column_settings.filter_regex": "Wegfilteren met reguliere expressies", "home.column_settings.show_reblogs": "Boosts tonen", "home.column_settings.show_replies": "Reacties tonen", @@ -146,7 +146,7 @@ "navigation_bar.favourites": "Favorieten", "navigation_bar.follow_requests": "Volgverzoeken", "navigation_bar.info": "Uitgebreide informatie", - "navigation_bar.keyboard_shortcuts": "Toetsenbord sneltoetsen", + "navigation_bar.keyboard_shortcuts": "Sneltoetsen", "navigation_bar.lists": "Lijsten", "navigation_bar.logout": "Afmelden", "navigation_bar.mutes": "Genegeerde gebruikers", @@ -180,7 +180,7 @@ "onboarding.page_six.almost_done": "Bijna klaar...", "onboarding.page_six.appetoot": "Veel succes!", "onboarding.page_six.apps_available": "Er zijn {apps} beschikbaar voor iOS, Android en andere platformen.", - "onboarding.page_six.github": "Mastodon kost niets, en is open-source- en vrije software. Je kan bugs melden, nieuwe mogelijkheden aanvragen en als ontwikkelaar meewerken op {github}.", + "onboarding.page_six.github": "Mastodon kost niets en is vrije software. Je kan bugs melden, nieuwe mogelijkheden aanvragen en als ontwikkelaar meewerken op {github}.", "onboarding.page_six.guidelines": "communityrichtlijnen", "onboarding.page_six.read_guidelines": "Vergeet niet de {guidelines} van {domain} te lezen!", "onboarding.page_six.various_app": "mobiele apps", diff --git a/app/javascript/mastodon/locales/pl.json b/app/javascript/mastodon/locales/pl.json index 334178e03..d36b1e6ed 100644 --- a/app/javascript/mastodon/locales/pl.json +++ b/app/javascript/mastodon/locales/pl.json @@ -33,6 +33,7 @@ "bundle_modal_error.retry": "Spróbuj ponownie", "column.blocks": "Zablokowani użytkownicy", "column.community": "Lokalna oś czasu", + "column.direct": "Wiadomości bezpośrednie", "column.favourites": "Ulubione", "column.follow_requests": "Prośby o śledzenie", "column.home": "Strona główna", @@ -48,6 +49,9 @@ "column_header.pin": "Przypnij", "column_header.show_settings": "Pokaż ustawienia", "column_header.unpin": "Cofnij przypięcie", + "column.heading": "Różne", + "column.subheading": "Różne opcje", + "column_subheading.lists": "Listy", "column_subheading.navigation": "Nawigacja", "column_subheading.settings": "Ustawienia", "compose_form.hashtag_warning": "Ten wpis nie będzie widoczny pod podanymi hashtagami, ponieważ jest oznaczony jako niewidoczny. Tylko publiczne wpisy mogą zostać znalezione z użyciem hashtagów.", @@ -89,10 +93,11 @@ "emoji_button.symbols": "Symbole", "emoji_button.travel": "Podróże i miejsca", "empty_column.community": "Lokalna oś czasu jest pusta. Napisz coś publicznie, aby zagaić!", + "empty_column.direct": "Nie masz żadnych wiadomości bezpośrednich. Jeżeli wyślesz lub otrzymasz jakąś, będzie tu widoczna.", "empty_column.hashtag": "Nie ma wpisów oznaczonych tym hashtagiem. Możesz napisać pierwszy!", "empty_column.home": "Nie śledzisz nikogo. Odwiedź publiczną oś czasu lub użyj wyszukiwarki, aby znaleźć interesujące Cię profile.", "empty_column.home.public_timeline": "publiczna oś czasu", - "empty_column.list": "Nie ma nic na tej liście.", + "empty_column.list": "Nie ma nic na tej liście. Kiedy członkowie listy dodadzą nowe wpisy, pojawia się one tutaj.", "empty_column.notifications": "Nie masz żadnych powiadomień. Rozpocznij interakcje z innymi użytkownikami.", "empty_column.public": "Tu nic nie ma! Napisz coś publicznie, lub dodaj ludzi z innych instancji, aby to wyświetlić.", "follow_request.authorize": "Autoryzuj", @@ -142,6 +147,7 @@ "mute_modal.hide_notifications": "Chcesz ukryć powiadomienia od tego użytkownika?", "navigation_bar.blocks": "Zablokowani użytkownicy", "navigation_bar.community_timeline": "Lokalna oś czasu", + "navigation_bar.direct": "Wiadomości bezpośrednie", "navigation_bar.edit_profile": "Edytuj profil", "navigation_bar.favourites": "Ulubione", "navigation_bar.follow_requests": "Prośby o śledzenie", @@ -149,6 +155,7 @@ "navigation_bar.keyboard_shortcuts": "Skróty klawiszowe", "navigation_bar.lists": "Listy", "navigation_bar.logout": "Wyloguj", + "navigation_bar.misc": "Różne", "navigation_bar.mutes": "Wyciszeni użytkownicy", "navigation_bar.pins": "Przypięte wpisy", "navigation_bar.preferences": "Preferencje", diff --git a/app/javascript/mastodon/locales/pt-BR.json b/app/javascript/mastodon/locales/pt-BR.json index bc6ae928d..947c6fb2b 100644 --- a/app/javascript/mastodon/locales/pt-BR.json +++ b/app/javascript/mastodon/locales/pt-BR.json @@ -92,7 +92,7 @@ "empty_column.hashtag": "Ainda não há qualquer conteúdo com essa hashtag.", "empty_column.home": "Você ainda não segue usuário algo. Visite a timeline {public} ou use o buscador para procurar e conhecer outros usuários.", "empty_column.home.public_timeline": "global", - "empty_column.list": "Ainda não há nada nesta lista.", + "empty_column.list": "Ainda não há nada nesta lista. Quando membros dessa lista fizerem novas postagens, elas aparecerão aqui.", "empty_column.notifications": "Você ainda não possui notificações. Interaja com outros usuários para começar a conversar.", "empty_column.public": "Não há nada aqui! Escreva algo publicamente ou siga manualmente usuários de outras instâncias", "follow_request.authorize": "Autorizar", diff --git a/app/javascript/mastodon/locales/pt.json b/app/javascript/mastodon/locales/pt.json index f9db2ad08..f566f551b 100644 --- a/app/javascript/mastodon/locales/pt.json +++ b/app/javascript/mastodon/locales/pt.json @@ -35,11 +35,11 @@ "column.community": "Local", "column.favourites": "Favoritos", "column.follow_requests": "Seguidores Pendentes", - "column.home": "Home", + "column.home": "Início", "column.lists": "Listas", "column.mutes": "Utilizadores silenciados", "column.notifications": "Notificações", - "column.pins": "Pinned toot", + "column.pins": "Posts fixos", "column.public": "Global", "column_back_button.label": "Voltar", "column_header.hide_settings": "Esconder preferências", @@ -47,7 +47,7 @@ "column_header.moveRight_settings": "Mover coluna para a direita", "column_header.pin": "Fixar", "column_header.show_settings": "Mostrar preferências", - "column_header.unpin": "Remover fixar", + "column_header.unpin": "Desafixar", "column_subheading.navigation": "Navegação", "column_subheading.settings": "Preferências", "compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.", @@ -92,7 +92,7 @@ "empty_column.hashtag": "Não foram encontradas publicações com essa hashtag.", "empty_column.home": "Ainda não segues qualquer utilizador. Visita {public} ou utiliza a pesquisa para procurar outros utilizadores.", "empty_column.home.public_timeline": "global", - "empty_column.list": "Ainda não existem publicações nesta lista.", + "empty_column.list": "Ainda não existem publicações nesta lista. Quando membros desta lista fizerem novas publicações, elas aparecerão aqui.", "empty_column.notifications": "Não tens notificações. Interage com outros utilizadores para iniciar uma conversa.", "empty_column.public": "Não há nada aqui! Escreve algo publicamente ou segue outros utilizadores para ver aqui os conteúdos públicos", "follow_request.authorize": "Autorizar", @@ -226,7 +226,7 @@ "status.mute": "Mute @{name}", "status.mute_conversation": "Silenciar conversa", "status.open": "Expandir", - "status.pin": "Pin on profile", + "status.pin": "Fixar no perfil", "status.reblog": "Partilhar", "status.reblogged_by": "{name} partilhou", "status.reply": "Responder", @@ -234,7 +234,7 @@ "status.report": "Denunciar @{name}", "status.sensitive_toggle": "Clique para ver", "status.sensitive_warning": "Conteúdo sensível", - "status.share": "Share", + "status.share": "Compartilhar", "status.show_less": "Mostrar menos", "status.show_more": "Mostrar mais", "status.unmute_conversation": "Deixar de silenciar esta conversa", diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index a09a766d0..a2e908683 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -2350,6 +2350,19 @@ position: relative; z-index: 2; outline: 0; + overflow: hidden; + + & > button { + display: flex; + flex: auto; + margin: 0; + border: none; + padding: 0; + color: inherit; + background: transparent; + font: inherit; + text-align: left; + } &.active { box-shadow: 0 1px 0 rgba($ui-highlight-color, 0.3); diff --git a/app/lib/activitypub/activity/announce.rb b/app/lib/activitypub/activity/announce.rb index b84098933..abf2b9b80 100644 --- a/app/lib/activitypub/activity/announce.rb +++ b/app/lib/activitypub/activity/announce.rb @@ -5,7 +5,7 @@ class ActivityPub::Activity::Announce < ActivityPub::Activity original_status = status_from_uri(object_uri) original_status ||= fetch_remote_original_status - return if original_status.nil? || delete_arrived_first?(@json['id']) + return if original_status.nil? || delete_arrived_first?(@json['id']) || !announceable?(original_status) status = Status.find_by(account: @account, reblog: original_status) @@ -33,4 +33,8 @@ class ActivityPub::Activity::Announce < ActivityPub::Activity ::FetchRemoteStatusService.new.call(@object['url']) end end + + def announceable?(status) + status.public_visibility? || status.unlisted_visibility? + end end diff --git a/app/lib/activitypub/tag_manager.rb b/app/lib/activitypub/tag_manager.rb index 0708713e6..fa2a8f7d3 100644 --- a/app/lib/activitypub/tag_manager.rb +++ b/app/lib/activitypub/tag_manager.rb @@ -67,6 +67,8 @@ class ActivityPub::TagManager def cc(status) cc = [] + cc << uri_for(status.reblog.account) if status.reblog? + case status.visibility when 'public' cc << account_followers_url(status.account) diff --git a/app/lib/ostatus/activity/creation.rb b/app/lib/ostatus/activity/creation.rb index f210e134a..b38407cd3 100644 --- a/app/lib/ostatus/activity/creation.rb +++ b/app/lib/ostatus/activity/creation.rb @@ -26,6 +26,9 @@ class OStatus::Activity::Creation < OStatus::Activity::Base cached_reblog = reblog status = nil + # Skip if the reblogged status is not public + return if cached_reblog && !(cached_reblog.public_visibility? || cached_reblog.unlisted_visibility?) + media_attachments = save_media ApplicationRecord.transaction do diff --git a/app/views/auth/registrations/_sessions.html.haml b/app/views/auth/registrations/_sessions.html.haml index c1e9764b3..8424a8901 100644 --- a/app/views/auth/registrations/_sessions.html.haml +++ b/app/views/auth/registrations/_sessions.html.haml @@ -16,7 +16,7 @@ %span{ title: session.user_agent }< = fa_icon "#{session_device_icon(session)} fw", 'aria-label' => session_device_icon(session) = ' ' - = t 'sessions.description', browser: t("sessions.browsers.#{session.browser}"), platform: t("sessions.platforms.#{session.platform}") + = t 'sessions.description', browser: t("sessions.browsers.#{session.browser}", default: "#{session.browser}"), platform: t("sessions.platforms.#{session.platform}", default: "#{session.platform}") %td %samp= session.ip %td diff --git a/app/views/settings/flavours/show.html.haml b/app/views/settings/flavours/show.html.haml index 43c037737..a5126d9c5 100644 --- a/app/views/settings/flavours/show.html.haml +++ b/app/views/settings/flavours/show.html.haml @@ -12,8 +12,9 @@ %hr/ - .fields-group - = f.input :setting_skin, collection: Themes.instance.skins_for(@selected), label_method: lambda { |skin| I18n.t("skins.#{@selected}.#{skin}", default: skin) }, wrapper: :with_label, include_blank: false + - if Themes.instance.skins_for(@selected).length > 1 + .fields-group + = f.input :setting_skin, collection: Themes.instance.skins_for(@selected), label_method: lambda { |skin| I18n.t("skins.#{@selected}.#{skin}", default: skin) }, wrapper: :with_label, include_blank: false .actions = f.button :button, t('generic.use_this'), type: :submit diff --git a/app/views/stream_entries/show.html.haml b/app/views/stream_entries/show.html.haml index b52334a28..cf6671e67 100644 --- a/app/views/stream_entries/show.html.haml +++ b/app/views/stream_entries/show.html.haml @@ -1,5 +1,5 @@ - content_for :page_title do - = t('statuses.title', name: display_name(@account), quote: truncate(@stream_entry.activity.text, length: 50, omission: '…')) + = t('statuses.title', name: display_name(@account), quote: truncate(@stream_entry.activity.spoiler_text.presence || @stream_entry.activity.text, length: 50, omission: '…')) - content_for :header_tags do - if @account.user&.setting_noindex diff --git a/config/initializers/rack_attack.rb b/config/initializers/rack_attack.rb index b38fb302b..b35452f04 100644 --- a/config/initializers/rack_attack.rb +++ b/config/initializers/rack_attack.rb @@ -53,7 +53,7 @@ class Rack::Attack req.ip if req.api_request? end - throttle('protected_paths', limit: 5, period: 5.minutes) do |req| + throttle('protected_paths', limit: 25, period: 5.minutes) do |req| req.ip if req.post? && req.path =~ PROTECTED_PATHS_REGEX end diff --git a/config/locales/activerecord.gl.yml b/config/locales/activerecord.gl.yml new file mode 100644 index 000000000..e38131454 --- /dev/null +++ b/config/locales/activerecord.gl.yml @@ -0,0 +1,13 @@ +--- +gl: + activerecord: + errors: + models: + account: + attributes: + username: + invalid: só letras, números e liñas baixas + status: + attributes: + reblog: + taken: do estado xa existe diff --git a/config/locales/activerecord.pt.yml b/config/locales/activerecord.pt.yml new file mode 100644 index 000000000..556fcfc4f --- /dev/null +++ b/config/locales/activerecord.pt.yml @@ -0,0 +1,13 @@ +--- +pt: + activerecord: + errors: + models: + account: + attributes: + username: + invalid: apenas letras, números e underscores + status: + attributes: + reblog: + taken: do status já existe diff --git a/config/locales/ar.yml b/config/locales/ar.yml index 6dc8bc1bb..82e8e998a 100644 --- a/config/locales/ar.yml +++ b/config/locales/ar.yml @@ -5,13 +5,17 @@ ar: about_this: عن مثيل الخادوم هذا closed_registrations: التسجيلات في مثيل الخادوم هذا مُغلقة حاليًا. contact: للتواصل معنا + contact_missing: غير محدد contact_unavailable: غير متوفر description_headline: ما هو %{domain}? domain_count_after: خوادم أخرى domain_count_before: متصل بـ features: + humane_approach_title: أسلوب يعيد الإعتبار للإنسان not_a_product_title: إنك إنسان و لست سلعة + real_conversation_title: مبني لتحقيق تواصل حقيقي find_another_instance: إبحث عن مثيل خادوم آخر + generic_description: "%{domain} هو سيرفر من بين سيرفرات الشبكة" hosted_on: ماستدون مُستضاف على %{domain} learn_more: تعلم المزيد other_instances: خوادم أخرى @@ -35,15 +39,21 @@ ar: reserved_username: إسم المستخدم محجوز roles: admin: المدير + moderator: مُشرِف unfollow: إلغاء المتابعة admin: account_moderation_notes: + account: مُشرِف created_at: التاريخ delete: حذف accounts: are_you_sure: متأكد ؟ by_domain: النطاق confirm: تأكيد + confirmed: مؤكَّد + disable: تعطيل + disable_two_factor_authentication: تعطيل 2FA + disabled: معطَّل display_name: عرض الإسم domain: النطاق edit: تعديل @@ -53,13 +63,23 @@ ar: followers: المتابِعون follows: يتابع ip: عنوان الإيبي + location: + all: الكل + title: الموقع media_attachments: الوسائط المرفقة + moderation: + all: الكل + most_recent_ip: أحدث عنوان إيبي order: + most_recent: الأحدث title: الترتيب profile_url: رابط الملف الشخصي + protocol: البروتوكول role: التصريحات roles: admin: مدير + moderator: مشرف + staff: الفريق user: مستخدِم search: البحث statuses: المنشورات @@ -113,13 +133,18 @@ ar: delete: حذف media: title: الوسائط + subscriptions: + confirmed: مؤكَّد + topic: الموضوع title: الإدارة application_mailer: - salutation: "%{name}," + salutation: "%{name}،" settings: 'تغيير تفضيلات البريد الإلكتروني : %{link}' signature: إشعارات ماستدون من %{instance} view: 'View:' applications: + created: تم إنشاء التطبيق بنجاح + destroyed: تم حذف التطبيق بنجاح invalid_url: إن الرابط المقدم غير صالح auth: change_password: الهوية @@ -134,8 +159,11 @@ ar: reset_password: إعادة تعيين كلمة المرور set_new_password: تعيين كلمة مرور جديدة authorize_follow: - error: Unfortunately, there was an error looking up the remote account + error: يا للأسف، وقع هناك خطأ إثر عملية البحث عن الحساب عن بعد follow: إتبع + follow_request: 'لقد قمت بإرسال طلب متابعة إلى :' + post_follow: + web: واصل إلى الويب title: إتباع %{acct} datetime: distance_in_words: @@ -153,8 +181,15 @@ ar: x_seconds: "%{count}ث" deletes: bad_password_msg: محاولة جيدة يا هاكرز ! كلمة السر خاطئة + confirm_password: قم بإدخال كلمتك السرية الحالية للتحقق من هويتك proceed: حذف حساب success_msg: تم حذف حسابك بنجاح + errors: + '403': ليس لك الصلاحيات الكافية لعرض هذه الصفحة. + '404': إنّ الصفحة التي تبحث عنها لا وجود لها أصلا. + '410': إنّ الصفحة التي تبحث عنها لم تعد موجودة. + '500': + title: هذه الصفحة خاطئة exports: blocks: قمت بحظر csv: CSV @@ -163,13 +198,15 @@ ar: followers: domain: النطاق followers_count: عدد المتابِعين + purge: تنحية من بين متابعيك + unlocked_warning_title: إنّ حسابك غير مقفل generic: changes_saved_msg: تم حفظ التعديلات بنجاح ! powered_by: مدعوم بـ %{link} save_changes: حفظ التغييرات validation_errors: - one: Something isn't quite right yet! Please review the error below - other: Something isn't quite right yet! Please review %{count} errors below + one: لا يزال هناك خلل ما إلى حد الآن. يُرجى إعادة النظر في الخطأ أسفله + other: هناك شيء ليس على ما يرام ! رجاءًا تحقق من الأخطاء الـ %{count} أسفله imports: preface: You can import certain data like all the people you are following or blocking into your account on this instance, from files created by an export on another instance. success: تم تحميل بياناتك بنجاح وسيتم معالجتها في الوقت المناسب @@ -177,8 +214,16 @@ ar: blocking: قائمة المحظورين following: قائمة المستخدمين المتبوعين upload: تحميل + invites: + delete: تعطيل + expires_in: + '1800': 30 دقيقة + '21600': 6 ساعات + '3600': ساعة + '43200': 12 ساعة + '86400': يوم واحد landing_strip_html: "<strong>%{name}</strong> is a user on %{link_to_root_path}. You can follow them or interact with them if you have an account anywhere in the fediverse.." - landing_strip_signup_html: If you don't, you can <a href="%{sign_up_path}">sign up here</a>. + landing_strip_signup_html: إن كنت لا تملك واحدا، يمكنك <a href="%{sign_up_path}">التسجيل مِن هنا</a>. lists: errors: limit: لقد بلغت الحد الأقصى للقوائم @@ -188,9 +233,11 @@ ar: too_many: لا يمكن إرفاق أكثر من 4 ملفات migrations: acct: username@domain للحساب الجديد + currently_redirecting: 'تم تحويل رابط ملفك الشخصي إلى :' + proceed: حفظ notification_mailer: digest: - body: 'Here is a brief summary of what you missed on %{instance} since your last visit on %{since}:' + body: 'هذه هي الأخبار المختصرة التي قد فاتتك على %{instance}وذلك منذ آخر زيارة لك في %{since} :' mention: "%{name} أشار إليك في :" new_followers_summary: one: لقد حصلت على متابع جديد ! @@ -200,19 +247,19 @@ ar: other: "%{count} إشعارات جديدة منذ زيارتك الأخيرة \U0001F418" favourite: body: 'أُعجب %{name} بمنشورك :' - subject: "%{name} favourited your status" + subject: أُعجِب %{name} بمنشورك follow: body: "%{name} من متتبعيك الآن !" subject: "%{name} من متتبعيك الآن" follow_request: - body: "%{name} has requested to follow you" - subject: 'Pending follower: %{name}' + body: طلب %{name} متابعتك + subject: 'متابع مُعلّق : %{name}' mention: - body: 'You were mentioned by %{name} in:' + body: 'أشار إليك %{name} في :' subject: لقد قام %{name} بذِكرك reblog: - body: 'Your status was boosted by %{name}:' - subject: "%{name} boosted your status" + body: 'قام %{name} بترقية منشورك :' + subject: قام %{name} بترقية منشورك number: human: decimal_units: @@ -227,50 +274,104 @@ ar: pagination: next: التالي prev: السابق + truncate: "…" preferences: languages: اللغات other: إعدادات أخرى publishing: النشر + web: الويب + push_notifications: + favourite: + title: أعجب %{name} بمنشورك + follow: + title: "%{name} من متتبعيك الآن" + group: + title: "%{count} إخطارات" + mention: + action_boost: ترقية + action_expand: عرض المزيد + title: أشار إليك %{name} + reblog: + title: قام %{name} بترقية منشورك remote_follow: acct: قم بإدخال عنوان حسابك username@domain الذي من خلاله تود المتابعة - missing_resource: Could not find the required redirect URL for your account + missing_resource: تعذر العثور على رابط التحويل المطلوب الخاص بحسابك proceed: أكمل المتابعة prompt: 'إنك بصدد متابعة :' + sessions: + activity: آخر نشاط + browser: المتصفح + browsers: + alipay: أليباي + blackberry: بلاك بيري + chrome: كروم + edge: مايكروسوفت إيدج + firefox: فايرفكس + generic: متصفح مجهول + ie: إنترنت إكسبلورر + opera: أوبرا + qq: متصفح كيوكيو + safari: سفاري + current_session: الجلسة الحالية + description: "%{browser} على %{platform}" + ip: عنوان الإيبي + platforms: + android: أندرويد + blackberry: بلاك بيري + chrome_os: نظام كروم أواس + firefox_os: نظام فايرفكس أواس + linux: لينكس + mac: ماك + other: نظام مجهول + windows: ويندوز + title: الجلسات settings: authorized_apps: التطبيقات المرخص لها back: عودة إلى ماستدون + development: التطوير edit_profile: تعديل الملف الشخصي export: تصدير البيانات followers: المتابِعون المُرَخّصون import: إستيراد + notifications: الإخطارات preferences: التفضيلات settings: الإعدادات - two_factor_authentication: اثبات هويّة مزدوج + two_factor_authentication: إثبات الهويّة المزدوج + your_apps: تطبيقاتك statuses: open_in_web: إفتح في الويب over_character_limit: تم تجاوز حد الـ %{max} حرف المسموح بها + pin_errors: + ownership: لا يمكن تدبيس تبويق نشره شخص آخر show_more: أظهر المزيد + title: '%{name} : "%{quote}"' visibilities: private: إعرض فقط لمتتبعيك + private_long: إعرضه لمتتبعيك فقط public: للعامة + public_long: يمكن للجميع رؤيته unlisted: Public, but do not display on the public timeline stream_entries: click_to_show: إضغط للعرض reblogged: رقى sensitive_content: محتوى حساس + terms: + title: شروط الخدمة وسياسة الخصوصية على %{instance} + themes: + default: ماستدون time: formats: default: "%b %d, %Y, %H:%M" two_factor_authentication: - code_hint: Enter the code generated by your authenticator app to confirm - description_html: If you enable <strong>two-factor authentication</strong>, logging in will require you to be in possession of your phone, which will generate tokens for you to enter. + code_hint: قم بإدخال الرمز المُوَلّد عبر تطبيق المصادقة للتأكيد + description_html: في حال تفعيل <strong>المصادقة بخطوتين </strong>، فتسجيل الدخول يتتطلب منك أن يكون بحوزتك هاتفك النقال قصد توليد الرمز الذي سيتم إدخاله. disable: تعطيل enable: تفعيل enabled: نظام المصادقة بخطوتين مُفعَّل enabled_success: تم تفعيل إثبات الهوية المزدوج بنجاح generate_recovery_codes: توليد رموز الإسترجاع - instructions_html: "<strong>Scan this QR code into Google Authenticator or a similiar TOTP app on your phone</strong>. From now on, that app will generate tokens that you will have to enter when logging in." - manual_instructions: 'If you can''t scan the QR code and need to enter it manually, here is the plain-text secret:' + instructions_html: "<strong>قم بمسح رمز الكيو آر عبر Google Authenticator أو أي تطبيق TOTP على جهازك</strong>. من الآن فصاعدا سوف يقوم ذاك التطبيق بتوليد رموز يجب عليك إدخالها عند تسجيل الدخول." + manual_instructions: 'في حالة تعذّر مسح رمز الكيو آر أو طُلب منك إدخال يدوي، يُمْكِنك إدخال هذا النص السري على التطبيق :' recovery_codes: النسخ الإحتياطي لرموز الإسترجاع recovery_codes_regenerated: تم إعادة توليد رموز الإسترجاع الإحتياطية بنجاح setup: تنشيط diff --git a/config/locales/ca.yml b/config/locales/ca.yml index 11bc485da..5fd5b3f6d 100644 --- a/config/locales/ca.yml +++ b/config/locales/ca.yml @@ -116,6 +116,7 @@ ca: roles: admin: Administrador moderator: Moderador + staff: Personal user: Usuari salmon_url: URL Salmon search: Cerca @@ -160,6 +161,7 @@ ca: update_status: "%{name} estat actualizat per %{target}" title: Registre d'auditoria custom_emojis: + by_domain: Domini copied_msg: S'ha creat correctament la còpia local del emoji copy: Copia copy_failed_msg: No s'ha pogut fer una còpia local d'aquest emoji @@ -458,6 +460,9 @@ ca: title: Convida persones landing_strip_html: "<strong>%{name}</strong> és un usuari/a de %{link_to_root_path}. Pots seguir-lo/la o interactuar amb ell/a si tens un compte a qualsevol node del fediverse." landing_strip_signup_html: Si no en tens, pots <a href="%{sign_up_path}">registrar-te aquí</a>. + lists: + errors: + limit: Has assolit la quantitat màxima de llistes media_attachments: validations: images_and_video: No es pot adjuntar un vídeo a una publicació que ja contingui imatges @@ -596,6 +601,7 @@ ca: private: No es pot fixar el toot no públic reblog: No es pot fixar un impuls show_more: Mostrar més + title: '%{name}: "%{quote}"' visibilities: private: Només seguidors private_long: Mostra només als seguidors diff --git a/config/locales/devise.ar.yml b/config/locales/devise.ar.yml index bb91cb372..28a03ff12 100644 --- a/config/locales/devise.ar.yml +++ b/config/locales/devise.ar.yml @@ -3,11 +3,16 @@ ar: devise: confirmations: confirmed: تم التحقق من عنوان بريدك الإلكتروني بنجاح. + send_instructions: سوف تتلقى بعد بضع دقائق رسالةً إلكترونيةً تضم تعليمات التأكيد. إن لم تتلق الرسالة، الرجاء التحقق من إنها ليست ضمن ملف الرسائل غير المرغوب فيها. + send_paranoid_instructions: إن كان عنوان بريدك الإلكتروني موجودا في قاعدة بياناتنا سوف تتلقّى الإرشادات اللازمة لتأكيده خلال بضع دقائق. يُرجى الإطلاع على الرسائل المتلقاة في البريد غير المرغوب فيه أيضا للتحقق من تلقي الرسالة. failure: already_authenticated: لقد تم تسجيل دخولك من قبل. inactive: لم يتم تنشيط حسابك بعد. + invalid: "%{authentication_keys} أو كلمة سر خاطئة." last_attempt: بإمكانك إعادة المحاولة مرة واحدة قبل أن يتم قفل حسابك. locked: إن حسابك مقفل. + not_found_in_database: "%{authentication_keys} أو كلمة سر خاطئة." + timeout: لقد إنتهت مدة صلاحية جلستك. قم بتسجيل الدخول من جديد للمواصلة. unauthenticated: يجب عليك تسجيل الدخول أو إنشاء حساب قبل المواصلة. unconfirmed: يجب عليك تأكيد عنوان بريدك الإلكتروني قبل المواصلة. mailer: @@ -19,12 +24,17 @@ ar: subject: 'ماستدون : تعليمات إستعادة كلمة المرور' unlock_instructions: subject: 'ماستدون : تعليمات فك القفل' + omniauth_callbacks: + failure: تعذرت المصادقة من %{kind} بسبب "%{reason}". + success: تمت المصادقة بنجاح عبر حساب %{kind}. passwords: updated: تم تغيير كلمة المرور بنجاح. أنت مسجل الآن. updated_not_active: تم تغيير كلمة المرور بنجاح. registrations: destroyed: إلى اللقاء ! لقد تم إلغاء حسابك. نتمنى أن نراك مجددا. signed_up: أهلا وسهلا ! تم تسجيل دخولك بنجاح. + signed_up_but_inactive: لقد تمت عملية إنشاء حسابك بنجاح إلاّ أنه لا يمكننا تسجيل دخولك إلاّ بعد قيامك بتفعيله. + signed_up_but_unconfirmed: لقد تم إرسال رسالة تحتوي على رابط للتفعيل إلى عنوان بريدك الإلكتروني. بالضغط على الرابط سوف يتم تفعيل حسابك. لذا يُرجى إلقاء نظرة على ملف الرسائل غير المرغوب فيها إنْ لم تَعثُر على الرسالة السالفة الذِكر. updated: تم تحديث حسابك بنجاح. sessions: already_signed_out: تم تسجيل خروجك بنجاح. diff --git a/config/locales/devise.gl.yml b/config/locales/devise.gl.yml new file mode 100644 index 000000000..8a2b5d563 --- /dev/null +++ b/config/locales/devise.gl.yml @@ -0,0 +1,61 @@ +--- +gl: + devise: + confirmations: + confirmed: O seu enderezo de email foi confirmado con éxito. + send_instructions: Nuns minutos recibirá un correo electrónico con instruccións sobre como confirmar o seu enderezo de correo. Comprobe por favor o cartafol de spam se non recibe este correo. + send_paranoid_instructions: Si o seu enderezo existe na nosa base de datos, recibirá nuns minutos un correo con instruccións sobre como confirmar o enderezo de correo. Por favor comprobe o cartafol de spam si non recibe este correo. + failure: + already_authenticated: Xa está conectada. + inactive: A súa conta aínda non foi activada. + invalid: Contrasinal ou %{authentication_keys} non válidos. + last_attempt: Quédalle un intento antes de que a conta sexa bloqueada. + locked: A súa conta foi bloqueada. + not_found_in_database: Contrasinal ou %{authentication_keys} non válidos. + timeout: Caducou a sesión. Por favor conéctese de novo para seguir. + unauthenticated: Precisa rexistrarse ou conectarse para continuar. + unconfirmed: Debe confirmar o seu enderezo de correo antes de continuar. + mailer: + confirmation_instructions: + subject: 'Mastodon: Instruccións de confirmación para %{instance}' + password_change: + subject: 'Mastodon: contrasinal cambiado' + reset_password_instructions: + subject: 'Mastodon: Instruccións para restablecer o contrasinal' + unlock_instructions: + subject: 'Mastodon: Instruccións para desbloquear' + omniauth_callbacks: + failure: Non podemos autenticala desde %{kind} porque "%{reason}". + success: Autenticouse con éxito desde a conta %{kind}. + passwords: + no_token: Non pode acceder a esta páxina vindo desde un correo de restablecemento de contrasinal. Si vostede chega desde un correo de restablecemento de contrasinal, por favor asegúrese de que utiliza o URL completo proporcionado. + send_instructions: Si o seu enderezo de correo existe na nosa base de datos, nuns minutos recibirá unha ligazón para recuperar o contrasinal. Por favor comprobe o seu cartafol de spam si non recibe este correo. + send_paranoid_instructions: Si o seu enderezo de correo existe na nosa base de datos, recibirá nuns minutos unha ligazón para recuperar o contrasinal. Por favor comprobe o seu cartafol de spam si non recibe este correo. + updated: Cambiou o contrasinal con éxito. Agora xa está conectada. + updated_not_active: Cambiouse o seu contrasinal correctamente. + registrations: + destroyed: Adeus! A súa conta cancelouse con éxito. Agardamos vela de novo. + signed_up: Ben vida! Rexistrouse con éxito. + signed_up_but_inactive: Rexistrouse correctamente. Porén, aínda non podemos conectala porque a súa conta aínda non foi activada. + signed_up_but_locked: Rexistrouse correctamente. Porén, non podemos conectala porque a conta está bloqueada. + signed_up_but_unconfirmed: Foi enviada unha mensaxe con unha ligazón de confirmación ao seu enderezo electrónico. Por favor siga a ligazón para activar a súa conta. Por favor comprobe o cartafol de spam si non recibe este correo. + update_needs_confirmation: Actualizou a súa conta correctamente, pero precisamos verificar o seu enderezo. Por favor comprobe o seu email e siga a ligazón de confirmación para confirmar o seu novo enderezo. Por favor comprobe o cartafol de spam si non recibe este correo. + updated: A súa conta foi actualizada correctamente. + sessions: + already_signed_out: Desconectouse con éxito. + signed_in: Conectouse correctamente. + signed_out: Desconectouse correctamente. + unlocks: + send_instructions: Recibirá nuns minutos un correo con instrucións sobre como desbloquear a súa conta. Por favor comprobe o cartafol de spam si non recibe este correo. + send_paranoid_instructions: Si a conta existe, recibirá un correo nuns minutos sobre como desbloquear a súa conta. Por favor comprobe o cartafol de spam si non recibe este correo. + unlocked: A súa conta foi desbloqueada correctamente. Por favor, conéctese para continuar. + errors: + messages: + already_confirmed: xa foi confirmada, por favor intente conectarse + confirmation_period_expired: precisa ser confirmada en %{period}, por favor solicite unha nova + expired: caducou, por favor solicite unha nova + not_found: non se atopou + not_locked: non foi bloqueada + not_saved: + one: '1 erro evitou que %{resource} fose gardada:' + other: "%{count} erros evitaron que %{resource} fose gardada:" diff --git a/config/locales/doorkeeper.gl.yml b/config/locales/doorkeeper.gl.yml index 863438454..dc9a04f18 100644 --- a/config/locales/doorkeeper.gl.yml +++ b/config/locales/doorkeeper.gl.yml @@ -1,9 +1,11 @@ +--- gl: activerecord: attributes: doorkeeper/application: name: Nome do aplicativo redirect_uri: URI a redireccionar + scopes: Permisos website: Sitio web do aplicativo errors: models: @@ -31,3 +33,87 @@ gl: help: native_redirect_uri: Utilice %{native_redirect_uri} para probas locais redirect_uri: Utilice unha liña por URI + scopes: Separar permisos con espazos. Deixar en blanco para utilizar os permisos por omisión. + index: + application: Aplicativo + callback_url: URL de chamada + delete: Eliminar + name: Nome + new: Novo aplicativo + scopes: Permisos + show: Mostrar + title: Os seus aplicativos + new: + title: Novo aplicativo + show: + actions: Accións + application_id: Chave do cliente + callback_urls: URLs de chamada + scopes: Permisos + secret: Chave secreta do cliente + title: 'Aplicativo: %{name}' + authorizations: + buttons: + authorize: Autorizar + deny: Denegar + error: + title: Algo fallou + new: + able_to: Poderá + prompt: O aplicativo %{client_name} solicita acceso a súa conta + title: Autorización necesaria + show: + title: Copie este código de autorización e pégueo no aplicativo. + authorized_applications: + buttons: + revoke: Retirar autorización + confirmations: + revoke: Está segura? + index: + application: Aplicativo + created_at: Autorizado + date_format: "%d-%m-%Y %H:%M:%S" + scopes: Permisos + title: Os seus aplicativos autorizados + errors: + messages: + access_denied: O propietario do recurso ou o servidor autorizado denegaron a petición. + credential_flow_not_configured: O fluxo do Contrasinal de Credenciais do Dono do Recurso fallou debido a que Doorkeeper.configure.resource_owner_from_credentials non están configuradas. + invalid_client: A autenticación do cliente fallou debido a un cliente descoñecido, non se incluíu autenticación do cliente, ou o método de autenticación non está soportado. + invalid_grant: A validación da autorización proporcionada non é valida, caducou, foi rexeitada, non coincide a redirección URI utilizada na petición de autorización, ou foi proporcionada para outro cliente. + invalid_redirect_uri: A uri de redirección incluída non é válida. + invalid_request: A petición fáltalle un parámetro requerido, inclúe un valor de parámetro non soportado, ou de algún xeito non ten o formato axeitado. + invalid_resource_owner: As credenciais do dono do recurso proporcionadas non son válidas, ou o dono do recurso non pode ser atopado + invalid_scope: O permiso solicitado non é válido, descoñecido, ou mal formado. + invalid_token: + expired: O testemuño de acceso caducou + revoked: O testemuño de acceso foi rexeitado + unknown: O testemuño de acceso non é válido + resource_owner_authenticator_not_configured: O dono do recurso fallou debido a Doorkeeper.configure.resource_owner_authenticator non estar configurado. + server_error: O servidor de autorización atopou un problema non agardado que evitou completar a petición. + temporarily_unavailable: O servidor de autorización non pode atender a petición en este momento debido a unha sobrecarga puntual ou mantemento do servidor. + unauthorized_client: O cliente non está autorizado a realizar a petición utilizando este método. + unsupported_grant_type: O método para proporcionar autorización non está soportado polo servidor de autorización. + unsupported_response_type: O servidor de autorización non soporta este tipo de resposta. + flash: + applications: + create: + notice: Aplicativo creado. + destroy: + notice: Aplicativo eliminado. + update: + notice: Aplicativo actualizado. + authorized_applications: + destroy: + notice: Aplicativo rexeitado. + layouts: + admin: + nav: + applications: Aplicativos + oauth2_provider: Proveedor OAuth2 + application: + title: Precisa autorización OAuth + scopes: + follow: seguir, bloquear, desbloquear e deixar de seguir contas + read: ler os datos da súa conta + write: publicar no seu nome diff --git a/config/locales/doorkeeper.nl.yml b/config/locales/doorkeeper.nl.yml index 5c9c9047f..7ad10f45b 100644 --- a/config/locales/doorkeeper.nl.yml +++ b/config/locales/doorkeeper.nl.yml @@ -84,11 +84,11 @@ nl: invalid_redirect_uri: De opgegeven redirect-URI is ongeldig. invalid_request: Het verzoek mist een vereiste parameter, bevat een niet ondersteunde parameterwaarde of is anderszins onjuist. invalid_resource_owner: De verstrekte resource-eigenaargegevens zijn ongeldig of de resource-eigenaar kan niet worden gevonden - invalid_scope: De opgevraagde scope is ongeldig, onbekend of onjuist. + invalid_scope: De opgevraagde toestemming is ongeldig, onbekend of onjuist. invalid_token: - expired: Het toegangssleutel is verlopen - revoked: Het toegangssleutel is geweigerd - unknown: Het toegangssleutel is ongeldig + expired: Toegangscode verlopen + revoked: Toegangscode ingetrokken + unknown: Toegangscode ongeldig resource_owner_authenticator_not_configured: Het opzoeken van de resource-eigenaar is mislukt omdat Doorkeeper.configure.resource_owner_authenticator niet is ingesteld. server_error: De autorisatieserver is is een onverwachte situatie tegengekomen die het verzoek verhinderde. temporarily_unavailable: De autorisatieserver is momenteel niet in staat het verzoek te behandelen als gevolg van een tijdelijke overbelasting of onderhoud aan de server. diff --git a/config/locales/doorkeeper.pt.yml b/config/locales/doorkeeper.pt.yml index 039b90ffa..e76cd01fd 100644 --- a/config/locales/doorkeeper.pt.yml +++ b/config/locales/doorkeeper.pt.yml @@ -5,7 +5,7 @@ pt: doorkeeper/application: name: Nome da Aplicação redirect_uri: URL de redirecionamento - scopes: Scopes + scopes: Autorizações website: Site da Aplicação errors: models: @@ -33,13 +33,14 @@ pt: help: native_redirect_uri: Usa %{native_redirect_uri} para testes locais redirect_uri: Utiliza uma linha por URI - scopes: Separate scopes with spaces. Leave blank to use the default scopes. + scopes: Separa autorizações com espaços. Deixa em branco para usar autorizações predefinidas. index: application: Aplicações - callback_url: Callback URL + callback_url: URL de retorno delete: Eliminar name: Nome new: Nova Aplicação + scopes: Autorizações show: Mostrar title: As tuas aplicações new: @@ -48,7 +49,7 @@ pt: actions: Ações application_id: Id de Aplicação callback_urls: Callback urls - scopes: Scopes + scopes: Autorizações secret: Segredo title: 'Aplicação: %{name}' authorizations: @@ -72,27 +73,28 @@ pt: application: Aplicação created_at: Criada em date_format: "%Y-%m-%d %H:%M:%S" + scopes: Autorizações title: As tuas aplicações autorizadas errors: messages: - access_denied: The resource owner or authorization server denied the request. - credential_flow_not_configured: Resource Owner Password Credentials flow failed due to Doorkeeper.configure.resource_owner_from_credentials being unconfigured. - invalid_client: Client authentication failed due to unknown client, no client authentication included, or unsupported authentication method. - invalid_grant: The provided authorization grant is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client. - invalid_redirect_uri: The redirect uri included is not valid. - invalid_request: The request is missing a required parameter, includes an unsupported parameter value, or is otherwise malformed. - invalid_resource_owner: The provided resource owner credentials are not valid, or resource owner cannot be found - invalid_scope: The requested scope is invalid, unknown, or malformed. + access_denied: O proprietário do recurso ou servidor de autorização negou o pedido. + credential_flow_not_configured: As credenciais da palavra-passe do proprietário do recurso falhou devido a que Doorkeeper.configure.resource_owner_from_credentials não foram configuradas. + invalid_client: Autenticação do cliente falhou por causa de um cliente desconhecido, nenhum cliente de autenticação incluído ou método de autenticação não suportado. + invalid_grant: A concessão de autorização fornecida é inválida, expirou, foi revogada, não corresponde à URI de redirecionamento usada no pedido de autorização ou foi emitida para outro cliente. + invalid_redirect_uri: A URI de redirecionamento incluída não é válida. + invalid_request: A solicitação não possui um parâmetro requerido, inclui um valor não suportado ou tem outro tipo de formato incorreto. + invalid_resource_owner: As credenciais do proprietário do recurso não são válidas ou o proprietário do recurso não pode ser encontrado + invalid_scope: O âmbito solicitado é inválido, desconhecido ou tem um formato incorreto. invalid_token: expired: O token de acesso expirou revoked: O token de acesso foi revogado unknown: O token de acesso é inválido - resource_owner_authenticator_not_configured: Resource Owner find failed due to Doorkeeper.configure.resource_owner_authenticator being unconfiged. - server_error: The authorization server encountered an unexpected condition which prevented it from fulfilling the request. - temporarily_unavailable: The authorization server is currently unable to handle the request due to a temporary overloading or maintenance of the server. - unauthorized_client: The client is not authorized to perform this request using this method. - unsupported_grant_type: The authorization grant type is not supported by the authorization server. - unsupported_response_type: The authorization server does not support this response type. + resource_owner_authenticator_not_configured: A procura pelo proprietário do recurso falhou porque Doorkeeper.configure.resource_owner_authenticator não foi configurado. + server_error: O servidor de autorização encontrou uma condição inesperada que impediu o cumprimento do pedido . + temporarily_unavailable: O servidor de autorização não é capaz de lidar com o pedido devido a uma sobrecarga ou mantenimento do servidor. + unauthorized_client: O cliente não está autorizado a realizar esta solicitação usando este método. + unsupported_grant_type: O tipo de concessão de autorização não é suportado pelo servidor de autorização. + unsupported_response_type: O servidor de autorização não suporta este tipo de resposta. flash: applications: create: @@ -108,10 +110,10 @@ pt: admin: nav: applications: Aplicações - oauth2_provider: OAuth2 Provider + oauth2_provider: Fornecedor OAuth2 application: title: Autorização OAuth necessária scopes: follow: siga, bloqueie, desbloqueie, e deixa de seguir contas read: tenha acesso aos dados da tua conta - write: públique por ti + write: publique por ti diff --git a/config/locales/fa.yml b/config/locales/fa.yml index 1e3bd0e8b..94d4e7594 100644 --- a/config/locales/fa.yml +++ b/config/locales/fa.yml @@ -39,6 +39,7 @@ fa: followers: پیگیران following: پی میگیرد media: عکس و ویدیو + moved_html: "%{name} حساب خود را به %{new_profile_link} منتقل کرده است:" nothing_here: اینجا چیزی نیست! people_followed_by: کسانی که %{name} پی میگیرد people_who_follow: کسانی که %{name} را پی میگیرند @@ -48,6 +49,7 @@ fa: reserved_username: این نام کاربری در دسترس نیست roles: admin: مدیر + moderator: ناظم unfollow: پایان پیگیری admin: account_moderation_notes: @@ -59,13 +61,19 @@ fa: destroyed_msg: یادداشت مدیر با موفقیت پاک شد! accounts: are_you_sure: آیا مطمئن هستید؟ + by_domain: دامین confirm: تأیید confirmed: تأیید شد + demote: تنزلدادن + disable: غیرفعال disable_two_factor_authentication: غیرفعالسازی ورود دومرحلهای + disabled: غیرفعال display_name: نمایش به نام domain: دامین edit: ویرایش email: ایمیل + enable: فعال + enabled: فعال feed_url: نشانی فید followers: پیگیران followers_url: نشانی پیگیران @@ -77,7 +85,9 @@ fa: local: محلی remote: غیرمستقیم title: مکان + login_status: وضعیت ورود media_attachments: ضمیمههای تصویری + memorialize: تبدیل به یادمان moderation: all: همه silenced: بیصدا شده @@ -94,6 +104,7 @@ fa: outbox_url: نشانی صندوق خروجی perform_full_suspension: انجام تعلیق کامل profile_url: نشانی نمایه + promote: ترفیعدادن protocol: پروتکل public: عمومی push_subscription_expires: عضویت از راه PuSH منقضی شد @@ -101,6 +112,12 @@ fa: reset: بازنشانی reset_password: بازنشانی رمز resubscribe: اشتراک دوباره + role: اجازهها + roles: + admin: مدیر + moderator: ناظم + staff: کارمند + user: کاربر salmon_url: نشانی Salmon search: جستجو shared_inbox_url: نشانی صندوق ورودی مشترک @@ -117,7 +134,34 @@ fa: unsubscribe: لغو اشتراک username: نام کاربری web: وب + action_logs: + actions: + confirm_user: "%{name} نشانی ایمیل کاربر %{target} را تأیید کرد" + create_custom_emoji: "%{name} شکلک تازهٔ %{target} را بارگذاشت" + create_domain_block: "%{name} دامین %{target} را مسدود کرد" + create_email_domain_block: "%{name} دامین ایمیل %{target} را مسدود کرد" + demote_user: "%{name} مقام کاربر %{target} را تنزل داد" + destroy_domain_block: "%{name} دامین %{target} را باز کرد" + destroy_email_domain_block: "%{name} دامین ایمیل %{target} را باز کرد" + destroy_status: "%{name} نوشتهای از %{target} را پاک کرد" + disable_2fa_user: "%{name} اجبار ورود دومرحلهای را برای کاربر %{target} غیرفعال کرد" + disable_custom_emoji: "%{name} شکلک %{target} را غیرفعال کرد" + disable_user: "%{name} ورود را برای کاربر %{target} غیرفعال کرد" + enable_custom_emoji: "%{name} شکلک %{target} را فعال کرد" + enable_user: "%{name} ورود را برای کاربر %{target} فعال کرد" + memorialize_account: "%{name} حساب کاربر %{target} را تبدیل به صفحهٔ یادمان کرد" + promote_user: "%{name} کاربر %{target} را ترفیع داد" + reset_password_user: "%{name} رمز کاربر %{target} را بازنشاند" + resolve_report: "%{name} گزارش %{target} را نادیده گرفت" + silence_account: "%{name} حساب کاربر %{target} را خاموش (بیصدا) کرد" + suspend_account: "%{name} حساب کاربر %{target} را تعلیق کرد" + unsilence_account: "%{name} حساب کاربر %{target} را روشن (باصدا) کرد" + unsuspend_account: "%{name} حساب کاربر %{target} را از تعلیق خارج کرد" + update_custom_emoji: "%{name} شکلک %{target} را بهروز کرد" + update_status: "%{name} نوشتهٔ %{target} را بهروز کرد" + title: سیاههٔ بازرسی custom_emojis: + by_domain: دامین copied_msg: نسخهٔ محلی شکلک با موفقیت ساخته شد copy: نسخهبرداری copy_failed_msg: نشد که نسخهٔ محلی این شکلک ساخته شود @@ -130,11 +174,16 @@ fa: enable: فعالسازی enabled_msg: این شکلک با موفقیت فعال شد image_hint: پروندهٔ PNG حداکثر 50KB + listed: فهرستشده new: title: افزودن شکلک سفارشی + overwrite: بازنویسی shortcode: کد کوتاه shortcode_hint: دستکم ۲ نویسه و تنها شامل حروف، اعداد و زیرخط title: شکلکهای سفارشی + unlisted: فهرستنشده + update_failed_msg: این شکلک نتوانست بهروز شود + updated_msg: شکلک با موفقیت بهروز شد! upload: بارگذاری domain_blocks: add_new: افزودن تازه @@ -145,7 +194,7 @@ fa: create: مسدودسازی hint: مسدودسازی دامین جلوی فهرستشدن حسابها در پایگاه داده را نمیگیرد، بلکه به طور خودکار روشهای مدیریتی را روی فعالیتهای فعلی و گذشتهٔ آن حسابها اعمال میکند. severity: - desc_html: "<strong>بیصداکردن</strong> یک حساب نوشتههای آن را برای همه (به جز پیگیرانش) ناپدید میکند. <strong>معلقکردن</strong> حساب همهٔ نوشتهها، تصویرها، و اطلاعات حساب را پاک میکند." + desc_html: "<strong>بیصداکردن</strong> یک حساب نوشتههای آن را برای همه (به جز پیگیرانش) ناپدید میکند. <strong>معلقکردن</strong> حساب همهٔ نوشتهها، تصویرها، و اطلاعات حساب را پاک میکند. اگر فقط میخواهید جلوی تصویرها و ویدیوها را بگیرید <strong>هیچ</strong> را برگزینید." noop: هیچ silence: بیصداکردن suspend: معلقکردن @@ -184,6 +233,13 @@ fa: reset: بازنشانی search: جستجو title: سرورهای شناختهشده + invites: + filter: + all: همه + available: در دسترس + expired: منقضیشده + title: فیلتر + title: دعوتها reports: action_taken_by: انجامدهنده are_you_sure: آیا مطمئن هستید؟ @@ -222,11 +278,17 @@ fa: deletion: desc_html: هر کسی بتواند حساب خود را پاک کند title: فعالسازی پاککردن حساب + min_invite_role: + disabled: هیچ کس + title: اجازهٔ دعوت به open: desc_html: همه بتوانند حساب باز کنند title: امکان ثبت نام + show_staff_badge: + desc_html: نمایش علامت همکار روی صفحهٔ کاربر + title: نمایش علامت همکار site_description: - desc_html: روی صفحهٔ اصلی نمایش مییابد و همچنین به عنوان تگهای HTML.<br>میتوانید HTML بنویسید, بهویژه <code><a></code> و <code><em></code>. + desc_html: معرفی کوتاهی که روی صفحهٔ اصلی و همچنین به عنوان فرادادهٔ صفحهها نمایش مییابد. میتوانید HTML بنویسید, بهویژه <code><a></code> و <code><em></code>. title: دربارهٔ سایت site_description_extended: desc_html: جای خوبی برای نوشتن سیاستهای کاربری، قانونها، راهنماها، و هر چیزی که ویژهٔ این سرور است. تگهای HTML هم مجاز است @@ -270,7 +332,7 @@ fa: body: کاربر %{reporter} کاربر %{target} را گزارش داد subject: گزارش تازهای برای %{instance} (#%{id}) application_mailer: - salutation: "%{name}," + salutation: "%{name}،" settings: 'تغییر تنظیمات ایمیل: %{link}' signature: اعلانهای ماستدون از %{instance} view: 'نمایش:' @@ -283,15 +345,17 @@ fa: warning: خیلی مواظب این اطلاعات باشید و آن را به هیچ کس ندهید! your_token: کد دسترسی شما auth: - agreement_html: پیش از عضو شدن باید <a href="%{rules_path}">شرایط استفاده</a> و <a href="%{terms_path}">سیاست رازداری</a> ما را بپذیرید. + agreement_html: پیش از عضو شدن باید <a href="%{rules_path}">قوانین این سرور</a> و <a href="%{terms_path}">شرایط استفادهٔ</a> ما را بپذیرید. change_password: امنیت delete_account: پاککردن حساب delete_account_html: اگر میخواهید حساب خود را پاک کنید، از <a href="%{path}">اینجا</a> پیش بروید. از شما درخواست تأیید خواهد شد. didnt_get_confirmation: راهنمایی برای تأیید را دریافت نکردید؟ forgot_password: رمزتان را گم کردهاید؟ - invalid_reset_password_token: Password reset token is invalid or expired. Please request a new one. + invalid_reset_password_token: کد بازنشانی رمز نامعتبر یا منقضی شده است. لطفاً کد دیگری درخواست کنید. login: ورود logout: خروج + migrate_account: نقل مکان به یک حساب دیگر + migrate_account_html: اگر میخواهید این حساب را به حساب دیگری منتقل کنید، <a href="%{path}">اینجا را کلیک کنید</a>. register: عضو شوید resend_confirmation: راهنمایی برای تأیید را دوباره بفرست reset_password: بازنشانی رمز @@ -339,7 +403,7 @@ fa: '500': content: شرمنده، یک چیزی از سمت ما اشتباه شده. title: این صفحه درست نیست - noscript_html: برای استفاده از نسخهٔ تحت وب ماستدون، لطفاً جاوااسکریپت را فعال کنید. یا به جایش میتوانید یک اپ ماستدون را بهکار ببرید. + noscript_html: برای استفاده از نسخهٔ تحت وب ماستدون، لطفاً جاوااسکریپت را فعال کنید. یا به جایش میتوانید <a href="https://github.com/tootsuite/documentation/blob/master/Using-Mastodon/Apps.md">یک اپ ماستدون</a> را بهکار ببرید. exports: blocks: حسابهای مسدودشده csv: CSV @@ -373,12 +437,43 @@ fa: following: فهرست پیگیریها muting: فهرست بیصداشدهها upload: بارگذاری + in_memoriam_html: به یادبود. + invites: + delete: غیرفعالسازی + expired: منقضیشده + expires_in: + '1800': ۳۰ دقیقه + '21600': ۶ ساعت + '3600': ۱ ساعت + '43200': ۱۲ ساعت + '86400': ۱ روز + expires_in_prompt: هیچ وقت + generate: ساختن + max_uses: + one: ۱ بار + other: "%{count} بار" + max_uses_prompt: نامحدود + prompt: با ساختن و اشتراکگذاری یک پیوند، اجازهٔ دسترسی به این سرور را به دیگران بدهید + table: + expires_at: تاریخ انقضا + uses: استفادهها + title: دعوت دیگران landing_strip_html: "<strong>%{name}</strong> کاربری روی %{link_to_root_path} است. شما با داشتن حساب روی هر سروری میتوانید نوشتههای او را پیگیری کرده یا با او ارتباط داشته باشید." landing_strip_signup_html: اگر هنوز حسابی ندارید <a href="%{sign_up_path}">اینجا حساب باز کنید</a>. + lists: + errors: + limit: از این بیشتر نمیشود فهرست داشت media_attachments: validations: images_and_video: نمیتوان برای نوشتهای که تصویر دارد ویدیو بارگذاری کرد too_many: نمیتوان بیشتر از ۴ تصویر بارگذاری کرد + migrations: + acct: username@domain حساب تازه + currently_redirecting: 'نمایهٔ شما منتقل میشود به:' + proceed: ذخیره + updated_msg: تنظیمات نقل مکان حساب شما با موفقیت بهروز شد! + moderation: + title: مدیریت notification_mailer: digest: body: 'خلاصهای از آنچه از زمان آخرین بازدید شما در %{since} روی %{instance} رخ داد :' @@ -491,6 +586,7 @@ fa: export: برونسپاری دادهها followers: پیگیران مورد تأیید import: درونریزی + migrate: انتقال حساب notifications: اعلانها preferences: ترجیحات settings: تنظیمات @@ -500,11 +596,12 @@ fa: open_in_web: بازکردن در وب over_character_limit: از حد مجاز %{max} حرف فراتر رفتید pin_errors: - limit: نوشتههای ثابت بیش از حد + limit: از این بیشتر نمیشود نوشتههای ثابت داشت ownership: نوشتههای دیگران را نمیتوان ثابت کرد private: نوشتههای غیرعمومی را نمیتوان ثابت کرد reblog: بازبوقها را نمیتوان ثابت کرد show_more: نمایش + title: '%{name}: "%{quote}"' visibilities: private: خصوصی private_long: نمایش تنها به پیگیران @@ -587,12 +684,14 @@ fa: <p>این نوشته اقتباسی است از <a href="https://github.com/discourse/discourse">سیاست رازداری Discourse</a>.</p> title: شرایط استفاده و سیاست رازداری %{instance} + themes: + default: ماستدون time: formats: default: "%d %b %Y, %H:%M" two_factor_authentication: code_hint: برای تأیید، کدی را که برنامهٔ تأییدکننده ساخته است وارد کنید - description_html: اگر <strong>ورود دومرحلهای</strong> را فعال کنید، برای ورود به سیستم به تلفن خود نیاز خواهید داشت تا برایتان یک کد موقتی بسازد + description_html: اگر <strong>ورود دومرحلهای</strong> را فعال کنید، برای ورود به سیستم به تلفن خود نیاز خواهید داشت تا برایتان یک کد موقتی بسازد. disable: غیرفعالکردن enable: فعالکردن enabled: ورود دومرحلهای فعال است @@ -603,7 +702,7 @@ fa: manual_instructions: 'اگر نمیتوانید کدها را اسکن کنید و باید آنها را دستی وارد کنید، متن کد امنیتی اینجاست:' recovery_codes: پشتیبانگیری از کدهای بازیابی recovery_codes_regenerated: کدهای بازیابی با موفقیت ساخته شدند - recovery_instructions_html: اگر تلفن خود را گم کردید، میتوانید با یکی از کدهای بازیابی زیر کنترل حساب خود را به دست بگیرید. این کدها را در جای امنی نگه دارید، مثلاً آنها را چاپ کنید و کنار سایر مدارک مهم خود قرار دهید + recovery_instructions_html: اگر تلفن خود را گم کردید، میتوانید با یکی از کدهای بازیابی زیر کنترل حساب خود را به دست بگیرید. <strong>این کدها را در جای امنی نگه دارید.</strong> مثلاً آنها را چاپ کنید و کنار سایر مدارک مهم خود قرار دهید setup: راه اندازی wrong_code: کدی که وارد کردید نامعتبر بود! آیا ساعت سرور و ساعت دستگاه شما درست تنظیم شدهاند؟ users: diff --git a/config/locales/gl.yml b/config/locales/gl.yml new file mode 100644 index 000000000..ca72bf183 --- /dev/null +++ b/config/locales/gl.yml @@ -0,0 +1,710 @@ +--- +gl: + about: + about_hashtag_html: Estas son mensaxes públicas etiquetadas con <strong>#%{hashtag}</strong>. Pode interactuar con elas si ten unha conta nalgures do fediverso. + about_mastodon_html: Mastodon é unha rede social que se basea en protocolos web abertos e libres, software de código aberto. É descentralizada como o correo electrónico. + about_this: Sobre + closed_registrations: O rexistro en esta instancia está pechado en este intre. Porén! Pode atopar unha instancia diferente para obter unha conta e ter acceso exactamente a misma rede desde alí. + contact: Contacto + contact_missing: Non establecido + contact_unavailable: N/A + description_headline: Qué é %{domain}? + domain_count_after: outras instancias + domain_count_before: Conectada a + extended_description_html: | + <h3>Un bo lugar para regras</h3> + <p>A descrición extendida aínda non se proporcionou.</p> + features: + humane_approach_body: Aprendendo dos erros de outras redes, Mastodon intenta tomar decisións éticas de deseño para loitar contra os usos incorrectos da rede. + humane_approach_title: Unha aproximación máis humana + not_a_product_body: Mastodon non é unha rede comercial. Sen anuncios, sen minería de datos, sen xardíns privados. Non hai autoridade centralizada. + not_a_product_title: Vostede é unha persona, non un producto + real_conversation_body: Con 500 caracteres a súa disposición e soporte para contido ao por menor e avisos sobre o contido, pode expresarse vostede do xeito que queira. + real_conversation_title: Construído para conversacións reais + within_reach_body: Existen múltiples aplicativos para iOS, Android e outras plataformas grazas a un entorno API amigable para o desenvolvedor que lle permite estar ao tanto cos seus amigos en calquer lugar. + within_reach_title: Sempre en contacto + find_another_instance: Atope outra instancia + generic_description: "%{domain} é un servidor na rede" + hosted_on: Mastodon aloxado en %{domain} + learn_more: Coñeza máis + other_instances: Listado de instancias + source_code: Código fonte + status_count_after: estados + status_count_before: Quen escribeu + user_count_after: usuarias + user_count_before: Inicio de + what_is_mastodon: Qué é Mastodon? + accounts: + follow: Seguir + followers: Seguidoras + following: Seguindo + media: Medios + moved_html: "%{name} mudouse a %{new_profile_link}:" + nothing_here: Nada por aquí! + people_followed_by: Personas que segue %{name} + people_who_follow: Personas que seguen a %{name} + posts: Mensaxes + posts_with_replies: Toots e respostas + remote_follow: Seguimento remoto + reserved_username: O nome de usuaria está reservado + roles: + admin: Admin + moderator: Mod + unfollow: Deixar de seguir + admin: + account_moderation_notes: + account: Moderador + create: Crear + created_at: Data + created_msg: Nota a moderación creada con éxito! + delete: Eliminar + destroyed_msg: Nota a moderación destruída con éxito! + accounts: + are_you_sure: Está segura? + by_domain: Dominio + confirm: Confirmar + confirmed: Confirmado + demote: Degradar + disable: Deshabilitar + disable_two_factor_authentication: Deshabilitar 2FA + disabled: Deshabilitado + display_name: Mostrar nome + domain: Dominio + edit: Editar + email: E-mail + enable: Habilitar + enabled: Habilitado + feed_url: URL fonte + followers: Seguidoras + followers_url: URL das seguidoras + follows: Segue + inbox_url: URL da Caixa de entrada + ip: IP + location: + all: Todo + local: Local + remote: Remoto + title: Lugar + login_status: Estado da conexión + media_attachments: Anexos de medios + memorialize: Convertir a lembranza + moderation: + all: Todo + silenced: Acalado + suspended: Suspendido + title: Moderación + moderation_notes: Notas de moderación + most_recent_activity: Actividade máis recente + most_recent_ip: IP máis recente + not_subscribed: Non suscrita + order: + alphabetic: Alfabética + most_recent: Máis recente + title: Orde + outbox_url: URL caixa de saída + perform_full_suspension: Suspender completamente + profile_url: URL do perfil + promote: Promocionar + protocol: Protocolo + public: Público + push_subscription_expires: A suscrición PuSH caduca + redownload: Actualizar avatar + reset: Restablecer + reset_password: Restablecer contrasinal + resubscribe: Voltar a suscribir + role: Permisos + roles: + admin: Administrador + moderator: Moderador + staff: Membresía + user: Usuaria + salmon_url: URL Salmon + search: Busca + shared_inbox_url: URL da caixa de entrada compartida + show: + created_reports: Informes creados por esta conta + report: informar + targeted_reports: Informes feitos sobre esta conta + silence: Acalar + statuses: Estados + subscribe: Subscribir + title: Contas + undo_silenced: Desfacer acalar + undo_suspension: Desfacer suspensión + unsubscribe: Non subscribir + username: Nome de usuaria + web: Web + action_logs: + actions: + confirm_user: "%{name} comfirmou o enderezo de correo da usuaria %{target}" + create_custom_emoji: "%{name} subeu un novo emoji %{target}" + create_domain_block: "%{name} bloqueou o dominio %{target}" + create_email_domain_block: "%{name} engadeu a lista negra o dominio de correo %{target}" + demote_user: "%{name} degradou a usuaria %{target}" + destroy_domain_block: "%{name} desbloqueou o dominio %{target}" + destroy_email_domain_block: "%{name} meteu na lista blanca de correo o dominio %{target}" + destroy_status: "%{name} eliminou o estado de %{target}" + disable_2fa_user: "%{name} deshabilitou o requerimento 2FA para usuaria %{target}" + disable_custom_emoji: "%{name} deshabilitou emoji %{target}" + disable_user: "%{name} deshabilitou a conexión para a usuaria %{target}" + enable_custom_emoji: "%{name} habilitou emoji %{target}" + enable_user: "%{name} habilitou a conexión para a usuaria %{target}" + memorialize_account: "%{name} converteu a conta de %{target} nunha páxina para a lembranza" + promote_user: "%{name} promoveu a usuaria %{target}" + reset_password_user: "%{name} restableceu o contrasinal da usuaria %{target}" + resolve_report: "%{name} rexeitou o informe %{target}" + silence_account: "%{name} acalou a conta de %{target}" + suspend_account: "%{name} suspendeu a conta de %{target}" + unsilence_account: "%{name} deulle voz a conta de %{target}" + unsuspend_account: "%{name} activou a conta de %{target}" + update_custom_emoji: "%{name} actualizou emoji %{target}" + update_status: "%{name} actualizou un estado de %{target}" + title: Rexistro de auditoría + custom_emojis: + by_domain: Dominio + copied_msg: Creouse con éxito unha copia local dos emoji + copy: Copiar + copy_failed_msg: Non se puido facer copia local de ese emoji + created_msg: Creou o emoji con satisfactoriamente! + delete: Eliminar + destroyed_msg: Emojo destruído satisfactoriamente! + disable: Deshabilitar + disabled_msg: Deshabilitouse correctamente ese emoji + emoji: Emoji + enable: Habilitar + enabled_msg: Habilitouse correctamente ese emoji + image_hint: PNG ate 50KB + listed: Listado + new: + title: Engadir novo emoji personalizado + overwrite: Sobrescribir + shortcode: Código corto + shortcode_hint: Cando menos 2 caracteres, só caracteres alfanuméricos e subliñados + title: Emojis personalizados + unlisted: Non listado + update_failed_msg: Non se puido actualizar ese emoji + updated_msg: Actualizouse correctamente o emoji! + upload: Subir + domain_blocks: + add_new: Engadir novo + created_msg: Estase a procesar o bloqueo do dominio + destroyed_msg: Desfixose a acción de bloqueo de dominio + domain: Dominio + new: + create: Crear bloque + hint: O bloqueo do dominio non previrá a creación de entradas de contas na base de datos, pero aplicará de xeito retroactivo e automático regras específicas de moderación sobre esas contas. + severity: + desc_html: "<strong>Silenciar</strong> fará invisibles as mensaxes das contas para calquera que non os siga. <strong>Suspender</strong> eliminará todo o contido das contas, ficheiros de medios, e datos de perfil. Utilice <strong>Ningún</strong> si só quere rexeitar ficheiros de medios." + noop: Ningún + silence: Silenciar + suspend: Suspender + title: Novo bloqueo de dominio + reject_media: Rexeitar ficheiros de medios + reject_media_hint: Eliminar ficheiros de medios almacenados localmente e rexeita descargalos no futuro. Irrelevante para as suspensións + severities: + noop: Ningún + silence: Silenciar + suspend: Suspender + severity: Severidade + show: + affected_accounts: + one: Afectoulle a unha conta na base de datos + other: Afectoulle a %{count} contas na base de datos + retroactive: + silence: Non silenciar todas as contas existentes de este dominio + suspend: Non suspender todas as contas existentes de este dominio + title: Desfacer o bloqueo de dominio para %{domain} + undo: Desfacer + title: Bloqueos de domino + undo: Desfacer + email_domain_blocks: + add_new: Engadir novo + created_msg: Engadeuse correctamente o dominio de email a lista negra + delete: Eliminar + destroyed_msg: Eliminouse correctamente o dominio de e-mail da lista negra + domain: Dominio + new: + create: Engadir dominio + title: Nova entrada la lista negra de e-mail + title: Lista negra de E-mail + instances: + account_count: Contas coñecidas + domain_name: Dominio + reset: Restablecer + search: Buscar + title: Instancias coñecidas + invites: + filter: + all: Todo + available: Dispoñible + expired: Cadudado + title: Filtro + title: Convida + reports: + action_taken_by: Acción tomada por + are_you_sure: Está segura? + comment: + label: Comentario + none: Nada + delete: Eliminar + id: ID + mark_as_resolved: Marcar como resolto + nsfw: + 'false': Non agochar anexos de medios + 'true': Agochar anexos de medios + report: 'Informe #%{id}' + report_contents: Contidos + reported_account: Conta reportada + reported_by: Reportada por + resolved: Resolto + silence_account: Acalar conta + status: Estado + suspend_account: Suspender conta + target: Obxetivo + title: Informes + unresolved: Non resolto + view: Vista + settings: + bootstrap_timeline_accounts: + desc_html: Separar múltiples nomes de usuaria con vírgulas. Só funcionarán as contas locais non bloqueadas. Si baldeiro, por omisión son todos os local admin. + title: Seguimentos por omisión para novas usuarias + contact_information: + email: e-mail de traballo + username: Nome de usuaria de contacto + registrations: + closed_message: + desc_html: Mostrado na páxina de portada cando o rexistro está pechado. Pode utilizar etiquetas HTML + title: Mensaxe de rexistro pechado + deletion: + desc_html: Permitirlle a calquera que elimine a súa conta + title: Abrir o borrado da conta + min_invite_role: + disabled: Ninguén + title: Permitir convites por + open: + desc_html: Permitir que calquera poida crear unha conta + title: Abrir rexistro + show_staff_badge: + desc_html: Mostrar unha insignia de membresía nunha páxina de usuaria + title: Mostrar insigna de membresía + site_description: + desc_html: Parágrafo de presentación na páxina principal e nas meta etiquetas. Pode utilizar etiquetas HTML, en particular <code><a></code> e <code><em></code>. + title: Descrición da instancia + site_description_extended: + desc_html: Un bo lugar para o seu código de conducta, regras, guías e outras cousas que distingan a súa instancia. Pode utilizar etiquetas HTML + title: Información extendida da personalización + site_terms: + desc_html: Pode escribir a súa propia política de intimidade, termos de servizo ou aclaracións legais. Pode utilizar etiquetas HTML + title: Termos de servizo personalizados + site_title: Nome da instancia + thumbnail: + desc_html: Utilizado para vistas previsas vía OpenGraph e API. Recoméndase 1200x630px + title: Icona da instancia + timeline_preview: + desc_html: Mostrar liña de tempo pública na páxina de inicio + title: vista previa da liña temporal + title: Axustes do sitio + statuses: + back_to_account: Voltar a páxina da conta + batch: + delete: Eliminar + nsfw_off: NSFW apagado + nsfw_on: NSFW acendido + execute: Executar + failed_to_execute: Fallou a execución + media: + hide: Agochar medios + show: Mostar medios + title: Medios + no_media: Sen medios + title: Estados da conta + with_media: con medios + subscriptions: + callback_url: URL de chamada + confirmed: Confirmado + expires_in: Caduca en + last_delivery: Última entrega + title: WebSub + topic: Asunto + title: Administración + admin_mailer: + new_report: + body: "%{reporter} informou sobre %{target}" + subject: Novo informe sobre %{instance} (#%{id}) + application_mailer: + salutation: "%{name}," + settings: 'Mudar as preferencias de e-mail: %{link}' + signature: Notificacións Mastodon de %{instance} + view: 'Vista:' + applications: + created: Creouse con éxito este aplicativo + destroyed: Eliminouse con éxito o aplicativo + invalid_url: A URL proporcionada non é válida + regenerate_token: Votar a xenerar o testemuño de acceso + token_regenerated: Rexenerouse con éxito o testemuño de acceso + warning: Teña moito tino con estos datos. Nunca os comparta con ninguén! + your_token: O seu testemuño de acceso + auth: + agreement_html: Rexistrándose acorda seguir <a href="%{rules_path}">as normas da instancia</a> e <a href="%{terms_path}">os termos do servizo</a>. + change_password: Seguridade + delete_account: Eliminar conta + delete_account_html: Se desexa eliminar a súa conta, pode <a href="%{path}">facelo aquí</a>. Pediráselle confirmación. + didnt_get_confirmation: Non recibeu as instruccións de confirmación? + forgot_password: Esqueceu o contrasinal? + invalid_reset_password_token: O testemuño para restablecer o contrasinal non é válido ou caducou. Por favor solicite un novo. + login: Conectar + logout: Desconectar + migrate_account: Mover a unha conta diferente + migrate_account_html: Si desexa redirixir esta conta hacia outra diferente, pode <a href="%{path}">configuralo aquí</a>. + register: Rexistro + resend_confirmation: Voltar a enviar intruccións de confirmación + reset_password: Restablecer contrasinal + set_new_password: Establecer novo contrasinal + authorize_follow: + error: Desgraciadamente, algo fallou ao buscar a conta remota + follow: Seguir + follow_request: 'Enviou unha petición de seguimento a:' + following: 'Parabéns! Está a seguir a:' + post_follow: + close: Ou, pode pechar esta ventá. + return: Voltar ao perfil da usuaria + web: Ir a web + title: Seguir %{acct} + datetime: + distance_in_words: + about_x_hours: "%{count}h" + about_x_months: "%{count}mes" + about_x_years: "%{count}a" + almost_x_years: "%{count}a" + half_a_minute: Agora + less_than_x_minutes: "%{count}m" + less_than_x_seconds: Agora + over_x_years: "%{count}a" + x_days: "%{count}d" + x_minutes: "%{count}m" + x_months: "%{count}mes" + x_seconds: "%{count}s" + deletes: + bad_password_msg: Bo intento, hackers! Contrasinal incorrecto + confirm_password: Introduza o seu contrasinal para verificar a súa identidade + description_html: Esto eliminará de xeito <strong>permanente e irreversible</strong> o contido da súa conta e será desactivada. O seu nome de usuaria permanecerá reservado para evitar futuras confusións de identidades. + proceed: Eliminar conta + success_msg: A súa conta eliminouse correctamente + warning_html: Só se garantiza a eliminación de contido de esta instancia. O contido que foi compartido con outras instancias é probable que deixe rastros. O servidores fora de liña e servidores que se desuscribiron das súas actualizacións non actualizarán as súas bases de datos. + warning_title: Dispoñibilidade do contido espallado + errors: + '403': Non ten permiso para ver esta páxina. + '404': A páxina que está a buscar non existe. + '410': A páxina que busca xa non existe. + '422': + content: Fallou a verificación de seguridade. Está bloqueando as cookies? + title: Fallou a verficación de seguridade + '429': Acelerado + '500': + content: Sentímolo, pero algo do noso lado falloou. + title: Esta páxina non é correcta + noscript_html: Para utilizar a aplicación web de Mastodon debe habilitar JavaScript. De xeito alternativo, intente unha das <a href="https://github.com/tootsuite/documentation/blob/master/Using-Mastodon/Apps.md">apps nativas</a> para Mastodon da súa plataforma. + exports: + blocks: A bloquear + csv: CSV + follows: A seguir + mutes: Acalou + storage: Almacenamento de medios + followers: + domain: Dominio + explanation_html: Se quere asegurar a intimidade dos seus estados, debe ser consciente de quen a está a seguir. <strong>Os seus estados privados son enviados a todas as instancias onde ten seguidoras</strong>. Podería querer revisalas, e elminar seguidoras si non confía que a súa intimidade sexa respetada polos administradores ou o software de esa instancia. + followers_count: Número de seguidoras + lock_link: Bloquear a súa conta + purge: Eliminar das seguidoras + success: + one: En proceso de bloquear seguidoras de un dominio... + other: No proceso de bloquear seguidoras de %{count} dominios... + true_privacy_html: Por favor teña en conta que <strong>a verdadeira intimidade só pode ser conseguida con cifrado de extremo-a-extremo</strong>. + unlocked_warning_html: Calquera pode seguila para inmediatamente ver os seus estados privados. %{lock_link} para poder revisar e rexeitar seguidoras. + unlocked_warning_title: A súa conta non está pechada + generic: + changes_saved_msg: Cambios gardados correctamente!! + powered_by: a funcionar grazas a %{link} + save_changes: Gardar cambios + validation_errors: + one: Algo non está ben de todo! Por favor revise abaixo o erro + other: Algo aínda non está ben! Por favor revise os %{count} erros abaixo + imports: + preface: Pode importar os datos que exportou de outra instancia, tales como a lista de usuarias que está a seguir ou bloquear. + success: Os seus datos foron correctamente subidos e serán procesados ao momento + types: + blocking: Lista de bloqueo + following: Lista de seguimento + muting: Lista de usuarias acaladas + upload: Subir + in_memoriam_html: Lembranzas. + invites: + delete: Desactivar + expired: Caducou + expires_in: + '1800': 30 minutos + '21600': 6 horas + '3600': 1 hora + '43200': 12 horas + '86400': 1 día + expires_in_prompt: Nunca + generate: Xerar + max_uses: + one: 1 uso + other: "%{count} usos" + max_uses_prompt: Sen límite + prompt: Xerar e compartir ligazóns con outras para permitir acceso a esta instancia + table: + expires_at: Caduca + uses: Usos + title: Convidar xente + landing_strip_html: "<strong>%{name}</strong> é unha usuaria en %{link_to_root_path}. Pode seguilas ou interactuar con elas si ten unha conta en algún lugar do fediverso." + landing_strip_signup_html: Si non, pode <a href="%{sign_up_path}">rexistrarse aquí</a>. + lists: + errors: + limit: Acadou o número máximo de listas + media_attachments: + validations: + images_and_video: Non pode anexar un vídeo a un estado que xa contén imaxes + too_many: Non pode anexar máis de 4 ficheiros + migrations: + acct: nomeusuaria@dominio da nova conta + currently_redirecting: 'O seu perfil está listo para redirixir a:' + proceed: Gardar + updated_msg: O axuste de migración da conta actualizouse correctamente! + moderation: + title: Moderación + notification_mailer: + digest: + body: 'Aquí ten un breve sumario do que perdeu en %{instance} desde a última visita en %{since}:' + mention: "%{name} mencionouna en:" + new_followers_summary: + one: Ten unha nova seguidora! Ben! + other: Obtivo %{count} novas seguidoras! Tremendo! + subject: + one: "1 nova notificación desde a súa última visita \U0001F418" + other: "%{count} novas notificacións desde a súa última visita \U0001F418" + favourite: + body: 'O seu estado foi marcado favorito por %{name}:' + subject: "%{name} marcou favorito o seu estado" + follow: + body: "%{name} agora está a seguila!" + subject: "%{name} agora está a seguila" + follow_request: + body: "%{name} solicitou poder seguila" + subject: 'Seguidora pendente: %{name}' + mention: + body: 'Foi mencionada por %{name} en:' + subject: Vostede foi mencionada por %{name} + reblog: + body: 'O seu estado foi promocionado por %{name}:' + subject: "%{name} promocionou o seu estado" + number: + human: + decimal_units: + format: "%n%u" + units: + billion: B + million: M + quadrillion: Q + thousand: K + trillion: T + pagination: + next: Seguinte + prev: Previo + truncate: "…" + preferences: + languages: Idiomas + other: Outro + publishing: Publicando + web: Web + push_notifications: + favourite: + title: "%{name} marcou favorito o seu estado" + follow: + title: "%{name} agora está a seguila" + group: + title: "%{count} notificacións" + mention: + action_boost: Promover + action_expand: Mostar máis + action_favourite: Favorito + title: "%{name} mencionouna" + reblog: + title: "%{name} promocionou un dos seus estados" + remote_follow: + acct: Introduza o seu nomedeusuaria@dominio desde onde quere facer seguimento + missing_resource: Non se puido atopar o URL de redirecionamento requerido para a súa conta + proceed: Proceda para seguir + prompt: 'Vostede vai seguir:' + sessions: + activity: Última actividade + browser: Navegador + browsers: + alipay: Alipay + blackberry: Blackberry + chrome: Chrome + edge: Microsoft Edge + firefox: Firefox + generic: Navegador descoñecido + ie: Internet Explorer + micro_messenger: MicroMessenger + nokia: Navegador Nokia S40 Ovi + opera: Opera + phantom_js: PhantomJS + qq: Navegador QQ + safari: Safari + uc_browser: UCBrowser + weibo: Weibo + current_session: Sesión actual + description: "%{browser} en %{platform}" + explanation: Estos son os navegadores web nos que actualmente ten sesión aberta. + ip: IP + platforms: + adobe_air: Adobe Air + android: Android + blackberry: Blackberry + chrome_os: ChromeOS + firefox_os: Firefox OS + ios: iOS + linux: Linux + mac: Mac + other: plataforma descoñecida + windows: Windows + windows_mobile: Windows Mobile + windows_phone: Windows Phone + revoke: Revocar + revoke_success: A sesión revocouse con éxito + title: Sesións + settings: + authorized_apps: Apps autorizados + back: Voltar a Mastodon + delete: Eliminación da conta + development: Desenvolvemento + edit_profile: Editar perfil + export: Exportar datos + followers: Seguidoras autorizadas + import: Importar + migrate: Migrar conta + notifications: Notificacións + preferences: Preferencias + settings: Axustes + two_factor_authentication: Validar Doble Factor + your_apps: Os seus aplicativos + statuses: + open_in_web: Abrir na web + over_character_limit: Excedeu o límite de caracteres %{max} + pin_errors: + limit: Xa fixou o número máximo permitido de mensaxes + ownership: Non pode fixar a mensaxe de outra usuaria + private: As mensaxes non-públicas non poden ser fixadas + reblog: Non se poden fixar as mensaxes promovidas + show_more: Mostrar máis + title: '%{name}: "%{quote}"' + visibilities: + private: Só seguidoras + private_long: Mostrar só as seguidoras + public: Público + public_long: Visible para calquera + unlisted: Non listado + unlisted_long: Visible para calquera, pero non listado en liñas de tempo públicas + stream_entries: + click_to_show: Pulse para mostrar + pinned: Mensaxe fixada + reblogged: promocionada + sensitive_content: Contido sensible + terms: + body_html: | + <h2>Política de intimidade</h2> + + <h3 id="collect">Qué información recollemos?</h3> + + <p>Recollemos información sobre vostede cando se rexistra no noso sitio web e recollemos datos cando participa no foro lendo, escribindo e evaluando o contido compartido aquí. </p> + + <p>Cando se rexistra no noso sitio, podería solicitarselle o seu nome e enderezo de correo electrónico. Vostede podería, porén, visitar o noso sitio sin rexistrarse. O seu enderezo de correo será verificado con un correo con unha ligazón única. Si esa ligazón é visitada, saberemos que vostede controla ese enderezo de correo.</p> + + <p>Cando se rexistra e publica, almacenamos o enderezo IP desde onde publicou. Poderiamos tamén gardar rexistros do servidor que inclúan a IP de cada petición ao realizada ao servidor. </p> + + <h3 id="use">Con qué fin utilizamos a súa información?</h3> + + <p>Toda a información recollida de vostede podería ser utilizada dos seguintes xeitos:</p> + + <ul> + <li>Para individualizar a súa experiencia — a súa información axúdanos a respostar mellor as súas necesidades individuais.</li> + <li>Para mellorar o noso sitio —esforzámonos en mellorar o que ofrece o noso sitio baseándonos na información e críticas que vostede nos proporciona.</li> + <li>Para mellorar o servizo ao cliente —a súa información axúdanos a respostar máis eficientemente as súas peticións de servizo ao cliente e axuda.</li> + <li>Para enviar correos electrónicos periodicamente — O enderezo de correo que nos proporciona podería ser utilizado para enviarlle información, notificacións que solicitou sobre cambios ou asuntos ou en resposta ao ser nome de usuaria, responder a enquisas, e/ou outras peticións ou cuestións.</li> + </ul> + + <h3 id="protect">Cómo protexemos a súa información?</h3> + + <p>Implementamos varias medidas de seguridade para manter a seguiridade da súa información personal cando introduce, envía ou accede a súa información personal.</p> + + <h3 id="data-retention">Qué é a política de retención dos seus datos?</h3> + + <p>Faremos un sincero esforzo para:</p> + + <ul> + <li>Manter rexistros do sistema con enderezos IP de todas as peticións feitas a este servidor no seu nome non máis de 90 días.</li> + <li>Manter os enderezos IP asociados a usuarias rexistradas e as súas mensaxes non máis de 5 anos. </li> + </ul> + + <h3 id="cookies">Utilizamos cookies?</h3> + + <p>Si. As cookies son pequenos ficheiros que un sitio ou o seu proveedor de servizo transfire ao disco duro da súa computadora a través do navegador web (se vostede o permite). Estas cookies permiten ao sitio recoñer o seu navegador e, si ten unha conta rexistrada, asocialo coa súa conta.</p> + + <p>Utilizamos cookies para comprender e gardar as súas preferencias para futuras visitas e compilar datos agregados sobre o tráfico do sitio e interacción co sitio de tal xeito que no futuro poidamos ofrecer unha mellor experiencia de uso do sitio e ferramentas. Poderiamos contratar servizos de terceiros para axudarnos a entender mellor as nosas visitantes. Estos proveedores de servizo non teñen permiso para utilizar a información recollida no noso nome excepto para axudarnos a xestionar e mellorar o noso negocio. </p> + + <h3 id="disclose">Mostramos información a terceiros alleos?</h3> + + <p>Non vendemos, nin negociamos con, ou transmitimos de outros xeitos a axentes terceiros alleos a información que a información que a identifica personalmente. Esto non inclúe terceiros de confianza que non axudan a operar o sitio, xestionar o negocio, ou servila, así estas partes se comprometan coa confidencialidade dos datos. Poderiamos revelar a súa información cando creamos que facelo así é axeitado para cumplir coa lei, cumplir coas normas do sitio ou protexer os nosos dereitos, propiedades ou seguridade e os de outras. Porén, non se proporcionará información identificable a terceiros para publicidade, márquetin ou outros usos.</p> + + <h3 id="third-party">Ligazóns a terceiros</h3> + + <p>De xeito ocasional, a nosa discreción, poderiamos incluír ofertas de productos e servizos de terceiros no noso sitio. Estos sitios de terceiros teñen políticas de intimidade propias. Polo tanto non temos responsabilidade ou obligacións polo contido e actividades de esos sitios. Con todo, procuramos protexer a integridade do noso sitio e agradecemos calquer opinión e crítica sobre estos sitios.</p> + + <h3 id="coppa">Cumplimento coa Children's Online Privacy Protection Act</h3> + + <p>O noso sitio, productos e servizos están dirixidos as personas con 13 anos como mínimo. Si este servidor está en USA e vostede ten menos de 13 anos, a requerimento da COPPA (<a href="https://en.wikipedia.org/wiki/Children%27s_Online_Privacy_Protection_Act">Children's Online Privacy Protection Act</a>) non utilice este sitio web.</p> + + <h3 id="online">Política de intimidade só en liña</h3> + + <p>Esta política de intimidade aplícase só a información recollida no noso sitio e non a información recollida fora de liña. </p> + + <h3 id="consent">O seu consentimento</h3> + + <p>Utilizando o noso sitio, vostede acepta esta política de intimidade.</p> + + <h3 id="changes">Cambios na política de intimidade</h3> + + <p>Si decidimos cambiar a nosa política de intimidade publicaremos esos cambios en esta páxina.</p> + + <p>Este documento ten licenza CC-BY-SA. Foi actualizado o 31 de maio de 2013.</p> + + <p>Adaptado do orixinal <a href="https://github.com/discourse/discourse">Discourse privacy policy</a>.</p> + title: "%{instance} Termos do Servizo e Política de Intimidade" + themes: + default: Mastodon + time: + formats: + default: "%d %b, %Y, %H:%M" + two_factor_authentication: + code_hint: Introducir o código xerado polo seu aplicativo de autenticación para confirmar + description_html: Si habilita a <strong>autenticación de doble factor</strong>, a conexión pediralle estar en posesión do seu teléfono, que xerará testemuños para poder entrar. + disable: Deshabilitar + enable: Habilitar + enabled: A autenticación de doble-factor está habilitada + enabled_success: Habilitouse con éxito a autenticación de doble-factor + generate_recovery_codes: Xerar códigos de recuperación + instructions_html: "<strong>Escanee este código QR en Google Authenticator ou aplicativo TOTP similar no seu teléfono</strong>. Desde agora, este aplicativo xerará testemuños que vostede deberá introducir ao conectarse." + lost_recovery_codes: Os códigos de recuperación permítenlle recuperar o acceso a súa conta si perde o teléfono. Si perde os códigos de recuperación, pode restauralos aquí. Os seus códigos de recuperación anteriores serán invalidados. + manual_instructions: 'Si non pode escanear o código QR e precisa introducilo manualmente, aquí está o testemuño secreto en texto plano:' + recovery_codes: Códigos de recuperación do respaldo + recovery_codes_regenerated: Códigos de recuperación xerados correctamente + recovery_instructions_html: Si perdese o acceso ao seu teléfono, pode utilizar un dos códigos inferiores de recuperación para recuperar o acceso a súa conta. <strong>Garde os códigos en lugar seguro</strong>. Por exemplo, pode imprimilos e gardalos xunto con outros documentos importantes. + setup: Configurar + wrong_code: O código introducido non é válido! Son correctas as horas no dispositivo e o servidor? + users: + invalid_email: O enderezo de correo non é válido + invalid_otp_token: Código de doble-factor non válido + signed_in_as: 'Rexistrada como:' diff --git a/config/locales/ja.yml b/config/locales/ja.yml index b3898c1f1..44b89e859 100644 --- a/config/locales/ja.yml +++ b/config/locales/ja.yml @@ -351,7 +351,7 @@ ja: warning: このデータは気をつけて取り扱ってください。不特定多数の人と共有しないでください! your_token: アクセストークン auth: - agreement_html: 登録すると <a href="%{rules_path}">利用規約</a> と <a href="%{terms_path}">プライバシーポリシー</a> に同意したことになります。 + agreement_html: 登録すると <a href="%{rules_path}">インスタンスのルール</a> と <a href="%{terms_path}">利用規約</a> に従うことに同意したことになります。 change_password: セキュリティ delete_account: アカウントの削除 delete_account_html: アカウントを削除したい場合、<a href="%{path}">こちら</a> から手続きが行えます。削除する前に、確認画面があります。 @@ -617,6 +617,7 @@ ja: private: 非公開のトゥートを固定することはできません reblog: ブーストされたトゥートを固定することはできません show_more: もっと見る + title: '%{name}: "%{quote}"' visibilities: private: 非公開 private_long: フォロワーにのみ表示されます diff --git a/config/locales/nl.yml b/config/locales/nl.yml index dca5af57d..a0add9bfa 100644 --- a/config/locales/nl.yml +++ b/config/locales/nl.yml @@ -2,7 +2,7 @@ nl: about: about_hashtag_html: Dit zijn openbare toots die getagged zijn met <strong>#%{hashtag}</strong>. Je kunt er op reageren of iets anders mee doen als je op Mastodon (of ergens anders in de fediverse) een account hebt. - about_mastodon_html: Mastodon is een <em>vrij, gratis en open-source</em> sociaal netwerk. Een <em>gedecentraliseerd</em> alternatief voor commerciële platforms. Het voorkomt de risico's van een enkel bedrijf dat jouw communicatie monopoliseert. Kies een server die je vertrouwt — welke je ook kiest, je kunt met elke andere server communiceren. Iedereen kan een eigen Mastodon-server draaien en naadloos deelnemen in het <em>sociale netwerk</em>. + about_mastodon_html: Mastodon is een sociaal netwerk dat gebruikt maakt van open webprotocollen en vrije software. Het is net zoals e-mail gedecentraliseerd. about_this: Over deze server closed_registrations: Registreren op deze server is momenteel uitgeschakeld. contact: Contact diff --git a/config/locales/pl.yml b/config/locales/pl.yml index b2c5c8e97..8aa6d2731 100644 --- a/config/locales/pl.yml +++ b/config/locales/pl.yml @@ -116,6 +116,7 @@ pl: roles: admin: Administrator moderator: Moderator + staff: Ekipa user: Użytkownik salmon_url: Adres Salmon search: Szukaj @@ -160,7 +161,7 @@ pl: update_status: "%{name} zaktualizował wpis użytkownika %{target}" title: Dziennik działań administracyjnych custom_emojis: - by_domain: Według domeny + by_domain: Domeny copied_msg: Pomyślnie utworzono lokalną kopię emoji copy: Kopiuj copy_failed_msg: Nie udało się utworzyć lokalnej kopii emoji @@ -351,7 +352,7 @@ pl: warning: Przechowuj te dane ostrożnie. Nie udostępniaj ich nikomu! your_token: Twój token dostępu auth: - agreement_html: Rejestrując się, oświadczasz, że zapoznałeś się z <a href="%{rules_path}">naszymi zasadami użytkowania</a> i <a href="%{terms_path}">polityką prywatności</a>. + agreement_html: Rejestrując się, oświadczasz, że zapoznałeś się z <a href="%{rules_path}">informacjami o instancji</a> i <a href="%{terms_path}">zasadami korzystania z usługi</a>. change_password: Bezpieczeństwo delete_account: Usunięcie konta delete_account_html: Jeżeli chcesz usunąć konto, <a href="%{path}">przejdź tutaj</a>. Otrzymasz prośbę o potwierdzenie. @@ -432,6 +433,7 @@ pl: changes_saved_msg: Ustawienia zapisane! powered_by: uruchomione na %{link} save_changes: Zapisz zmiany + use_this: Użyj tego validation_errors: one: Coś jest wciąż nie tak! Przyjrzyj się błędowi poniżej other: Coś jest wciąż nie tak! Przejrzyj błędy (%{count}) poniżej @@ -604,7 +606,7 @@ pl: development: Tworzenie aplikacji edit_profile: Edytuj profil export: Eksportowanie danych - flavours: Motywy + flavours: Odmiany followers: Autoryzowani śledzący import: Importowanie danych keyword_mutes: Wyciszone słowa diff --git a/config/locales/pt-BR.yml b/config/locales/pt-BR.yml index 32896ab91..d4bf72da3 100644 --- a/config/locales/pt-BR.yml +++ b/config/locales/pt-BR.yml @@ -1,10 +1,10 @@ --- pt-BR: about: - about_hashtag_html: Estes são toots públicos com a hashtag <strong>#%{hashtag}</strong>. Voce pode interagir com eles se tiver uma conta em qualquer lugar no fediverso. + about_hashtag_html: Estes são toots públicos com a hashtag <strong>#%{hashtag}</strong>. Você pode interagir com eles se tiver uma conta em qualquer lugar no fediverso. about_mastodon_html: Mastodon é uma rede social baseada em protocolos abertos e software gratuito e de código aberto. É descentralizada como e-mail. about_this: Sobre - closed_registrations: Cadastros estão atualmente fechados nesta instância. No entanto! Você pode procurar uma instância diferente na qual possa criar uma conta e acessar a mesma rede por lá. + closed_registrations: Os cadastros estão atualmente fechados nesta instância. No entanto, você pode procurar uma instância diferente na qual possa criar uma conta e acessar a mesma rede por lá. contact: Contato contact_missing: Não definido contact_unavailable: N/A @@ -21,15 +21,15 @@ pt-BR: not_a_product_title: Você é uma pessoa e não um produto real_conversation_body: Com 500 caracteres à sua disposição e suporte para conteúdo granular e avisos de conteúdo, você pode se expressar da maneira que desejar. real_conversation_title: Feito para conversas reais - within_reach_body: Vários apps para iOS, Android e outras plataformas graças a um ecossistema de API amigável para desenvolvedores proporcionam que você possa se manter atualizado sobre seus amigos de qualquer lugar. - within_reach_title: Sempre a seu alcance + within_reach_body: Vários apps para iOS, Android e outras plataformas graças a um ecossistema de API amigável para desenvolvedores permitem que você possa se manter atualizado sobre seus amigos de qualquer lugar. + within_reach_title: Sempre ao seu alcance find_another_instance: Encontre outra instância generic_description: "%{domain} é um servidor na rede" hosted_on: Mastodon hospedado em %{domain} learn_more: Saiba mais other_instances: Lista de instâncias - source_code: Código fonte - status_count_after: postagens + source_code: Código-fonte + status_count_after: publicações status_count_before: Autores de user_count_after: usuários user_count_before: Casa de @@ -85,7 +85,7 @@ pt-BR: local: Local remote: Remoto title: Localização - login_status: Status de login + login_status: Situação de login media_attachments: Mídia(s) anexada(s) memorialize: Tornar um memorial moderation: @@ -96,13 +96,13 @@ pt-BR: moderation_notes: Notas de moderação most_recent_activity: Atividade mais recente most_recent_ip: IP mais recente - not_subscribed: Não inscrito + not_subscribed: Não está inscrito order: alphabetic: Alfabética most_recent: Mais recente title: Ordem - outbox_url: URL da Outbox - perform_full_suspension: Efetue suspensão total + outbox_url: URL da caixa de saída + perform_full_suspension: Aplicar suspensão total profile_url: URL do perfil promote: Promover protocol: Protocolo @@ -116,19 +116,20 @@ pt-BR: roles: admin: Administrador moderator: Moderador + staff: Equipe user: Usuário salmon_url: URL Salmon search: Pesquisar - shared_inbox_url: URL da Inbox Compartilhada + shared_inbox_url: URL da caixa de entrada compartilhada show: created_reports: Denúncias criadas por esta conta report: relatórios targeted_reports: Denúncias feitas sobre esta conta - silence: Silêncio + silence: Silenciar statuses: Postagens subscribe: Inscrever-se title: Contas - undo_silenced: Desativar silêncio + undo_silenced: Retirar silenciamento undo_suspension: Retirar suspensão unsubscribe: Desinscrever-se username: Nome de usuário @@ -160,6 +161,7 @@ pt-BR: update_status: "%{name} atualizou o estado de %{target}" title: Auditar relatório custom_emojis: + by_domain: Domínio copied_msg: Cópia local do emoji criada com sucesso copy: Copiar copy_failed_msg: Não foi possível criar uma cópia local deste emoji @@ -343,7 +345,7 @@ pt-BR: warning: Tenha cuidado com estes dados. Nunca compartilhe com alguém! your_token: Seu token de acesso auth: - agreement_html: Cadastrando-se você concorda com <a href="%{rules_path}">nossos termos de serviço</a> e <a href="%{terms_path}">política de privacidade</a>. + agreement_html: Cadastrando-se você concorda em seguir <a href="%{rules_path}">as regras da instância</a> e <a href="%{terms_path}">os nossos termos de serviço</a>. change_password: Segurança delete_account: Excluir conta delete_account_html: Se você deseja excluir a sua conta, você pode <a href="%{path}">prosseguir para cá</a>. Uma confirmação será requisitada. @@ -594,11 +596,12 @@ pt-BR: open_in_web: Abrir na web over_character_limit: limite de caracteres de %{max} excedido pin_errors: - limit: Muitos toots fixados + limit: Você já fixou o máximo de toots possíveis ownership: Toots de outras pessoas não podem ser fixados private: Toot não-público não pode ser fixado reblog: Um compartilhamento não pode ser fixado show_more: Mostrar mais + title: '%{name}: "%{quote}"' visibilities: private: Apenas seguidores private_long: Mostrar apenas para seguidores diff --git a/config/locales/pt.yml b/config/locales/pt.yml index c476bac59..c0056af4f 100644 --- a/config/locales/pt.yml +++ b/config/locales/pt.yml @@ -4,16 +4,16 @@ pt: about_hashtag_html: Estes são toots públicos marcados com <strong>#%{hashtag}</strong>. Podes interagir com eles se tiveres uma conta Mastodon. about_mastodon_html: Mastodon é uma rede social baseada em protocolos abertos da web e software livre e gratuito. É descentralizado como e-mail. about_this: Sobre esta instância - closed_registrations: Novos registos estão fechados nesta instância. + closed_registrations: Novos registos estão fechados nesta instância. No entanto! Podes procurar uma instância diferente na qual criar uma conta e obter acesso à mesma rede desde lá. contact: Contacto - contact_missing: Não definido - contact_unavailable: N/A + contact_missing: Não configurado + contact_unavailable: n.d. description_headline: O que é o %{domain}? domain_count_after: outras instâncias domain_count_before: Ligado a extended_description_html: | <h3>Um bom lugar para regras</h3> - <p>A descrição da instância ainda não foi feita.</p> + <p>A descrição estendida ainda não foi configurada.</p> features: humane_approach_body: Aprendendo com erros de outras redes sociais, Mastodon tem como objetivo fazer decisões éticas de design para combater o utilização errada de redes sociais. humane_approach_title: Uma abordagem mais humana @@ -87,6 +87,7 @@ pt: title: Local login_status: Estado de início de sessão media_attachments: Media anexa + memorialize: Converter em memorial moderation: all: Todos silenced: Silenciados @@ -100,12 +101,13 @@ pt: alphabetic: Alfabética most_recent: Mais recente title: Ordem + outbox_url: URL da caixa de saída perform_full_suspension: Fazer suspensão completa profile_url: URL do perfil promote: Promover protocol: Protocolo public: Público - push_subscription_expires: PuSH subscription expires + push_subscription_expires: A Inscrição PuSH expira redownload: Atualizar avatar reset: Restaurar reset_password: Reset palavra-passe @@ -114,8 +116,9 @@ pt: roles: admin: Administrador moderator: Moderador + staff: Equipa user: Utilizador - salmon_url: Salmon URL + salmon_url: URL Salmon search: Pesquisar shared_inbox_url: URL da caixa de entrada compartilhada show: @@ -124,9 +127,11 @@ pt: targeted_reports: Relatórios feitos sobre esta conta silence: Silêncio statuses: Status + subscribe: Inscrever-se title: Contas undo_silenced: Desfazer silenciar undo_suspension: Desfazer supensão + unsubscribe: Cancelar inscrição username: Usuário web: Web action_logs: @@ -137,6 +142,48 @@ pt: create_email_domain_block: "%{name} adicionou na lista negra o domínio de correio electrónico %{target}" demote_user: "%{name} rebaixou o utilizador %{target}" destroy_domain_block: "%{name} desbloqueou o domínio %{target}" + destroy_email_domain_block: "%{name} adicionou na lista branca o domínio de correio electrónico %{target}" + disable_2fa_user: "%{name} desactivou o requerimento de autenticação em dois passos para o utilizador %{target}" + disable_custom_emoji: "%{name} desabilitou o emoji %{target}" + disable_user: "%{name} desativou o acesso para o utilizador %{target}" + enable_custom_emoji: "%{name} habilitou o emoji %{target}" + enable_user: "%{name} ativou o acesso para o utilizador %{target}" + memorialize_account: "%{name} transformou a conta de %{target} em um memorial" + promote_user: "%{name} promoveu o utilizador %{target}" + reset_password_user: "%{name} restabeleceu a palavra-passe do utilizador %{target" + resolve_report: "%{name} recusou o relatório %{target}" + silence_account: "%{name} silenciou a conta de %{target}" + suspend_account: "%{name} suspendeu a conta de %{target}" + unsilence_account: "%{name} desativou o silêncio de %{target}" + unsuspend_account: "%{name} desativou a suspensão de %{target}" + update_custom_emoji: "%{name} atualizou o emoji %{target}" + update_status: "%{name} atualizou o estado de %{target}" + title: Registo de auditoria + custom_emojis: + by_domain: Domínio + copied_msg: Cópia local do emoji criada com sucesso + copy: Copiar + copy_failed_msg: Não foi possível criar uma cópia local deste emoji + created_msg: Emoji criado com sucesso! + delete: Apagar + destroyed_msg: Emoji destruído com sucesso! + disable: Desativar + disabled_msg: Desativado com sucesso este emoji + emoji: Emoji + enable: Ativar + enabled_msg: Ativado com sucesso este emoji + image_hint: PNG de até 50KB + listed: Listado + new: + title: Adicionar novo emoji customizado + overwrite: Sobrescrever + shortcode: Código de atalho + shortcode_hint: Pelo menos 2 caracteres, apenas caracteres alfanuméricos e underscores + title: Emojis customizados + unlisted: Não listado + update_failed_msg: Não foi possível atualizar esse emoji + updated_msg: Emoji atualizado com sucesso! + upload: Enviar domain_blocks: add_new: Adicionar novo created_msg: Bloqueio do domínio está a ser processado @@ -146,13 +193,15 @@ pt: create: Criar bloqueio hint: O bloqueio de dominio não vai previnir a criação de entradas na base de dados, mas irá retroativamente e automaticamente aplicar métodos de moderação específica nessas contas. severity: - desc_html: "<strong>Silenciar</strong> irá fazer com que os posts dessas contas sejam invisíveis para todos que não a seguem. <strong>Supender</strong> irá eliminar todo o conteúdo guardado dessa conta, mídia e informação de perfil." + desc_html: "<strong>Silenciar</strong> irá fazer com que os posts dessas contas sejam invisíveis para todos que não a seguem. <strong>Supender</strong> irá eliminar todo o conteúdo guardado dessa conta, media e informação de perfil.Usa <strong>Nenhum</strong> se apenas desejas rejeitar arquivos de media." + noop: Nenhum silence: Silenciar suspend: Suspender title: Novo bloqueio de domínio - reject_media: Rejeitar ficheiros de mídia - reject_media_hint: Remove localmente arquivos armazenados e rejeita fazer guardar novos no futuro. Irrelevante na suspensão. + reject_media: Rejeitar ficheiros de media + reject_media_hint: Remove localmente arquivos armazenados e rejeita fazer guardar novos no futuro. Irrelevante na suspensão severities: + noop: Nenhum silence: Silenciar suspend: Suspender severity: Severidade @@ -167,11 +216,32 @@ pt: undo: Anular title: Bloqueio de domínio undo: Anular + email_domain_blocks: + add_new: Adicionar novo + created_msg: Bloqueio de domínio de email criado com sucesso + delete: Eliminar + destroyed_msg: Bloqueio de domínio de email excluído com sucesso + domain: Domínio + new: + create: Adicionar domínio + title: Novo bloqueio de domínio de email + title: Bloqueio de Domínio de Email instances: account_count: Contas conhecidas domain_name: Domínio + reset: Restaurar + search: Pesquisar title: Instâncias conhecidas + invites: + filter: + all: Todos + available: Disponíveis + expired: Expirados + title: Filtro + title: Convites reports: + action_taken_by: Ação tomada por + are_you_sure: Tens a certeza? comment: label: Comentário none: Nenhum @@ -179,17 +249,20 @@ pt: id: ID mark_as_resolved: Marcar como resolvido report: 'Denúncia #%{id}' + report_contents: Conteúdos reported_account: Conta denunciada reported_by: Denúnciada por resolved: Resolvido silence_account: Conta silenciada status: Estado suspend_account: Conta suspensa - target: Target + target: Alvo title: Denúncias unresolved: Por resolver view: Ver settings: + bootstrap_timeline_accounts: + title: Seguidores predefinidos para novas contas contact_information: email: Inserir um endereço de email para tornar público username: Insira um nome de utilizador @@ -197,16 +270,49 @@ pt: closed_message: desc_html: Mostrar na página inicial quando registos estão encerrados<br/>Podes usar tags HTML title: Mensagem de registos encerrados + deletion: + desc_html: Permite a qualquer um apagar a conta + min_invite_role: + disabled: Ninguém + title: Permitir convites de open: + desc_html: Permitir que qualquer um crie uma conta title: Aceitar novos registos + show_staff_badge: + desc_html: Mostrar um crachá da equipa na página de utilizador + title: Mostrar crachá da equipa site_description: - desc_html: Mostrar como parágrafo na página inicial e usado como meta tag.<br/>Podes usar tags HTML, em particular <code><a></code> e <code><em></code>. + desc_html: Mostrar como parágrafo na página inicial e usado como meta tag.Podes usar tags HTML, em particular <code><a></code> e <code><em></code>. title: Descrição do site site_description_extended: desc_html: Mostrar na página de mais informações<br/>Podes usar tags HTML title: Página de mais informações + site_terms: + desc_html: Podes escrever a tua própria política de privacidade, termos de serviço, entre outras coisas. Podes usar tags HTML + title: Termos de serviço customizados site_title: Título do site + thumbnail: + desc_html: Usada para visualizações via OpenGraph e API. Recomenda-se 1200x630px + title: Miniatura da instância + timeline_preview: + desc_html: Exibir a linha temporal pública na página inicial + title: Visualização da linha temporal title: Preferências do site + statuses: + back_to_account: Voltar para página da conta + batch: + delete: Eliminar + nsfw_off: NSFW OFF + nsfw_on: NSFW ON + execute: Executar + failed_to_execute: Falhou ao executar + media: + hide: Esconder média + show: Mostrar média + title: Média + no_media: Não há média + title: Estado das contas + with_media: Com média subscriptions: callback_url: URL de Callback confirmed: Confirmado @@ -215,37 +321,172 @@ pt: title: WebSub topic: Tópico title: Administração + admin_mailer: + new_report: + body: "%{reporter} relatou %{target}" + subject: Novo relatório sobre %{instance} (#%{id}) application_mailer: + salutation: "%{name}," settings: 'Alterar preferências de email: %{link}' signature: notificações Mastodon do %{instance} view: 'Ver:' applications: + created: Aplicação criada com sucesso + destroyed: Aplicação eliminada com sucesso invalid_url: O URL é inválido + regenerate_token: Regenerar token de acesso + token_regenerated: Token de acesso regenerado com sucesso + warning: Cuidado com estes dados. Não partilhar com ninguém! + your_token: O teu token de acesso auth: + agreement_html: Registando-te concordas em seguir <a href="%{rules_path}">as regras da instância</a> e <a href="%{terms_path}">os nossos termos de serviço</a>. change_password: Alterar palavra-passe + delete_account: Eliminar conta + delete_account_html: Se desejas eliminar a conta, podes <a href="%{path}">continua aqui</a>. Uma confirmação será pedida. didnt_get_confirmation: Não recebeu o email de confirmação? forgot_password: Esqueceste a palavra-passe? + invalid_reset_password_token: Token de modificação da palavra-passe é inválido ou expirou. Por favor, solicita um novo. login: Entrar + logout: Sair + migrate_account: Mudar para uma conta diferente + migrate_account_html: Se desejas redirecionar esta conta para uma outra podes<a href="%{path}">configurar isso aqui</a>. register: Registar resend_confirmation: Reenviar instruções de confirmação reset_password: Criar nova palavra-passe set_new_password: Editar palavra-passe + authorize_follow: + error: Infelizmente, ocorreu um erro ao buscar a conta remota + follow: Seguir + follow_request: 'Enviaste uma solicitação de seguidor para:' + following: 'Sucesso! Agora estás a seguir a:' + post_follow: + close: Ou podes simplesmente fechar esta janela. + return: Voltar ao perfil do utilizador + title: Seguir %{acct} + datetime: + distance_in_words: + about_x_hours: "%{count}h" + about_x_months: "%{count} meses" + about_x_years: "%{count} anos" + almost_x_years: "%{count} anos" + half_a_minute: Justo agora + less_than_x_minutes: "%{count} meses" + less_than_x_seconds: Justo agora + over_x_years: "%{count} anos" + x_days: "%{count} dias" + x_minutes: "%{count} minutos" + x_months: "%{count} meses" + x_seconds: "%{count} segundos" + deletes: + bad_password_msg: Boa tentativa, hackers! Palavra-passe incorreta + confirm_password: Introduz a palavra-passe atual para verificar a tua identidade + description_html: Isto vai <strong>permanente e irreversivelmente</strong> remover conteúdo da tua conta e desativá-la. O teu nome de utilizador permanecerá reservado para prevenir futuros roubos de identidade. + proceed: Eliminar conta + success_msg: A tua conta foi eliminada com sucesso + warning_html: |- + Apenas a eliminação de conteúdo desta instância é garantido. + Conteúdo que tenha sido partilhado com outras instâncias muito provavelmente deixará pegadas. Servidores offline e servidores que se desinscreveram das tuas atualizações não atualizarão as suas bases de dados. + warning_title: Disponibilidade de conteúdo disseminado + errors: + '403': Não tens a permissão necessária para ver esta página. + '404': A página que estás a procurar não existe. + '410': A página que estás a procurar não existe mais. + '422': + content: "A verificação de segurança falhou. \nDesativaste o uso de cookies?" + title: A verificação de segurança falhou + '500': + content: Desculpe, mas algo correu mal. + title: Esta página não está correta + noscript_html: Para usar o aplicativo web do Mastodon, por favor ativa o JavaScript. Alternativamente, experimenta um dos <a href="https://github.com/tootsuite/documentation/blob/master/Using-Mastodon/Apps.md">apps nativos</a> para o Mastodon na sua plataforma. + exports: + blocks: Bloqueaste + csv: CSV + follows: Segues + mutes: Tens em silêncio + storage: Armazenamento de média + followers: + domain: Domínio + explanation_html: Se queres garantir a privacidade das tuas publicações, deves ficar atento a quem te está a seguir.<strong>As tuas publicações privadas são enviadas para todas as instâncias nas que tens seguidores</strong>. Convém revisá-las e remover seguidores se achares que a tua privacidade não será respeitada pela equipa ou software destas instâncias. + followers_count: Número de seguidores + lock_link: Bloquear a tua conta + purge: Eliminar dos seguidores + success: + one: No processo de bloqueio suave de seguidores de outro domínio... + other: No processo de bloqueio suave de seguidores de outros %{count} domínios... + true_privacy_html: Por favor leva em conta que <strong>a verdadeira privacidade só pode ser alcançada através de encriptação ponto-a-ponto</strong>. + unlocked_warning_html: Qualquer pessoa pode seguir-te e ver as tuas publicações privadas. %{lock_link} para ser capaz de revisar e rejeitar seguidores. + unlocked_warning_title: A tua conta não está bloqueada generic: - changes_saved_msg: Alteraçes guardadas! - powered_by: powered by %{link} + changes_saved_msg: Alterações guardadas! + powered_by: fornecido por %{link} save_changes: Guardar alterações validation_errors: one: Algo não está correcto. Por favor vê o erro abaixo other: Algo não está correto. Por favor vê os %{count} erros abaixo - landing_strip_html: "<strong>%{name}</strong> is a user on %{link_to_root_path}. You can follow them or interact with them if you have an account anywhere in the fediverse." + imports: + preface: Podes importar dados que tenhas exportado de outra instância, como a lista de pessoas que segues ou bloqueadas. + success: Os teus dados foram enviados com sucesso e serão processados em breve + types: + blocking: Lista de bloqueio + following: Lista de pessoas que estás a seguir + muting: Lista de utilizadores silenciados + upload: Enviar + in_memoriam_html: Em memória. + invites: + delete: Desativar + expired: Expirados + expires_in: + '1800': 30 minutos + '21600': 6 horas + '3600': 1 hora + '43200': 12 horas + '86400': 1 dia + expires_in_prompt: Nunca + generate: Gerar + max_uses: + one: 1 uso + other: "%{count} usos" + max_uses_prompt: Sem limite + prompt: Gerar e partilhar ligações com outras pessoas para permitir acesso a essa instância + table: + expires_at: Expira + uses: Usos + title: Convidar pessoas + landing_strip_html: "<strong>%{name}</strong> é um utilizador em %{link_to_root_path}. Podes segui-lo ou interagir com ele se tiveres uma conta em qualquer lugar no fediverso." landing_strip_signup_html: If you don't, you can <a href="%{sign_up_path}">sign up here</a>. + lists: + errors: + limit: Número máximo de listas alcançado + media_attachments: + validations: + images_and_video: Não é possível anexar um vídeo a uma publicação que já contém imagens + too_many: Não é possível anexar mais de 4 arquivos + migrations: + acct: username@domain da nova conta + currently_redirecting: 'O teu perfil está configurado para redirecionar para:' + proceed: Salvar + updated_msg: As configurações de migração da tua conta foram atualizadas com sucesso! + moderation: + title: Moderação notification_mailer: + digest: + body: 'Aqui tens um breve resumo do que tens perdido em %{instance} desde o último acesso em %{since}:' + mention: "%{name} mencionou-te em:" + new_followers_summary: + one: Boa! Tens um novo seguidor! + other: Tens %{count} novos seguidores! Fantástico! + subject: + one: "1 nova notificação desde o último acesso \U0001F418" + other: "%{count} novas notificações desde o último acesso \U0001F418" favourite: body: 'O teu post foi adicionado aos favoritos por %{name}:' subject: "%{name} adicionou o teu post aos favoritos" follow: body: "%{name} é teu seguidor!" subject: "%{name} começou a seguir-te" + follow_request: + body: "%{name} solicitou autorização para te seguir" + subject: 'Seguidor pendente: %{name}' mention: body: 'Foste mencionado por %{name}:' subject: "%{name} mencionou-te" @@ -267,43 +508,195 @@ pt: next: Seguinte prev: Anterior truncate: "…" + preferences: + languages: Idiomas + other: Outro + publishing: Publicação + web: Web + push_notifications: + favourite: + title: "%{name} adicionou o teu post aos favoritos" + follow: + title: "%{name} começou a seguir-te" + group: + title: "%{count} notificações" + mention: + action_boost: Partilhar + action_expand: Mostrar mais + action_favourite: Adicionar aos favoritos + title: "%{name} mencionou-te" + reblog: + title: "%{name} partilhou o teu post" remote_follow: acct: Entre seu usuário@domínio do qual quer seguir missing_resource: Não foi possível achar a URL de redirecionamento para sua conta proceed: Prossiga para seguir prompt: 'Você vai seguir:' + sessions: + activity: Última atividade + browser: Navegador + browsers: + alipay: Alipay + blackberry: Blackberry + chrome: Chrome + edge: Microsoft Edge + firefox: Firefox + generic: Navegador desconhecido + ie: Internet Explorer + micro_messenger: MicroMessenger + nokia: Navegador Nokia S40 Ovi + opera: Opera + phantom_js: PhantomJS + qq: QQ Browser + safari: Safari + uc_browser: UCBrowser + weibo: Weibo + current_session: Sessão atual + description: "%{browser} em %{platform}" + explanation: Estes são os navegadores que estão conectados com a tua conta do Mastodon. + ip: IP + platforms: + adobe_air: Adobe Air + android: Android + blackberry: Blackberry + chrome_os: ChromeOS + firefox_os: Firefox OS + ios: iOS + linux: Linux + mac: Mac + other: Plataforma desconhecida + windows: Windows + windows_mobile: Windows Mobile + windows_phone: Windows Phone + revoke: Revogar + revoke_success: Sessão revogada com sucesso + title: Sessões settings: authorized_apps: Aplicativos autorizados back: Voltar ao Mastodon + delete: Eliminação da conta + development: Desenvolvimento edit_profile: Editar perfil - export: Importar dados + export: Exportar dados + followers: Seguidores autorizados import: Importar + migrate: Migração de conta + notifications: Notificações preferences: Preferências - settings: Settings - two_factor_authentication: Autenticação Two-factor + settings: Configurações + two_factor_authentication: Autenticação em dois passos + your_apps: As tuas aplicações statuses: open_in_web: Abrir no browser over_character_limit: limite de caracter excedeu %{max} + pin_errors: + ownership: Posts de outras pessoas não podem ser fixados + private: Post não-público não pode ser fixado show_more: Mostrar mais + title: '%{name}: "%{quote}"' visibilities: private: Mostrar apenas para seguidores + private_long: Mostrar apenas para seguidores public: Público + public_long: Todos podem ver unlisted: Público, mas não mostre no timeline público + unlisted_long: Todos podem ver, porém não será postado nas timelines públicas stream_entries: click_to_show: Clique pra mostrar + pinned: Toot fixado reblogged: boosted sensitive_content: Conteúdo sensível + terms: + body_html: | + <h2>Política de privacidade</h2> + + <h3 id="collect">Quais são as informações que recolhemos?</h3> + + <p>Recolhemos informações quando te registas no nosso site e capturamos dados quando participas do fórum lendo, escrevendo e analisando o conteúdo aqui partilhado.</p> + + <p>Quando te registas no nosso site, será requisitado que você ceda seu nome e endereço de e-mail. Você pode, porém, visitar nosso site sem se cadastrar. Seu endereço de e-mail será verificado por uma mensagem contendo um link único. Se este link for visitado, saberemos que você controla este endereço de e-mail.</p> + + <p>Quando registrado e postando, nós gravamos o endereço de IP de onde a postagem se originou. Nós também podemos reter logs de serviores que incluem o endereço de IP em cada requisição para o nosso servidor.</p> + + <h3 id="use">Para que usamos essas informações?</h3> + + <p>Quaisquer das informações que coletamos podem ser usadas das seguintes formas:</p> + + <ul> + <li>Para personalizar a sua experiência — suas informações nos ajudam a nos adequar melhor às suas necessidades individuais.</li> + <li>Para melhorar nosso site — nós continuamente nos esforçamos para aprimorar nosso site baseados na informação e no feedback que recebemos de você.</li> + <li>Para aprimorar o serviço ao consumidor — suas informações nos ajudam a responder efetivamente às suas requisições e solicitações por suporte.</li> + <li>Para mandar e-mails periódicos — O endereço de e-mail que você forneceu pode ser usado para lhe enviar informações, notificações que você requisitar sobre mudanças a determinados tópicos ou menções ao seu nome de usuário, responder requisições e/ou solicitações e perguntas.</li> + </ul> + + <h3 id="protect">Como protegemos as suas informações?</h3> + + <p>Nós implementamos uma variedade de medidas de segurança para manter a segurança de suas informações pessoais quando você insere, submete ou acessa as suas informações pessoais.</p> + + <h3 id="data-retention">Qual a sua política de retenção de dados?</h3> + + <p>Faremos esforços de boa fé para:</p> + + <ul> + <li>Reter logs de servidor contendo o endereço IP de todas as requisições a este servidor por não mais que 90 dias.</li> + <li>Reter os endereços IP associados a usuários cadastrados e suas postagens por não mais que 5 anos.</li> + </ul> + + <h3 id="cookies">Nós usamos cookies?</h3> + + <p>Sim. Cookies são pequenos arquivos que um site ou o provedor de serviço transfere para o armazenamento interno de seu computador através de seu navegador (se você permitir). Estes cookies habilitam o site para reconhecer o seu navegador e, se você ter um cadastro, associá-lo a esta conta.</p> + + <p>Nós usamos cookies para entender e salvar as suas preferências para futuras visitas e compilar dados agregados sobre o tráfego do site para que possamos oferecer melhores experiências e ferramentas no futuro. Nós podemos contratar serviços de terceiros para nos auxiliar a entender melhor nossos visitantes. Estes provedores de serviço não são autoriza usar as informações coletadas em nosso nome exceto para nos ajudar a conduzir e aprimorar nosso funcionamento.</p> + + <h3 id="disclose">Nós revelamos informações para terceiros?</h3> + + <p>Nós não vendemos, tocamos ou transferimos para terceiros informações pessoais que te identificam. Isso não inclui partes em que confiamos para nos ajudar a operar nosso site, conduzir nosso funcionamento ou servir você desde que estes terceiros concordem em manter essas informações em segredo. Nós também podemos prover as suas informações para obedecer ordens judiciais, reforçar nossas políticas ou proteger nossos direitos ou de outrem, propriedades ou segurança. Entretanto, informações pessoais não identificáveis podem ser enviadas para outras partes para marketing, propaganda e outros usos.</p> + + <h3 id="third-party">Links de terceiros</h3> + + <p>Ocasionalmente, à nossa discrição, podemos icluir ou oferecer produtos ou serviços de terceiros em nosso site. Estes terceiros têm políticas de privacidade separadas e independentes. Nós, portanto, não nos responsabilizamos pelo conteúdo e atividades destes sites de terceiros. Occasionally, at our discretion, we may include or offer third party products or services on our site. Não obstante, nós procuramos proteger a integridade de nosso site e todo feedback sobre estes sites de terceiros é bem-vindo.</p> + + <h3 id="coppa">Obediência ao Ato de Proteção da Privacidade Online de Crianças</h3> + + <p>Nosso site, produtos e serviços são todos direcionados a pessoas que têm pelo menos 13 anos de idade. Se este servidor estiver nos EUA, e você tiver menos de 13 anos, pelos requerimentos da COPPA (<a href="https://en.wikipedia.org/wiki/Children%27s_Online_Privacy_Protection_Act">Children's Online Privacy Protection Act</a>) não use este site.</p> + + <h3 id="online">Política de Apenas Privacidade Online</h3> + + <p>Esta política de privacidade online se aplica somente a informações coletadas por nosso site e não a informações coletadas offline.</p> + + <h3 id="consent">Seu Consentimento</h3> + + <p>Usando o nosso site, você concorda com a nossa política de privacidade.</p> + + <h3 id="changes">Mudanças em nossa Política de Privacidade</h3> + + <p>Se decidirmos mudar a nossa política de privacidade, publicaremos as mudanças nesta página.</p> + + <p>Este documento é CC-BY-SA. A sua última atualização aconteceu em 31 de maio de 2013.</p> + + <p>Originalmente adaptado da <a href="https://github.com/discourse/discourse">política de privacidade do Discourse</a>.</p> + title: "%{instance} Termos de Serviço e Política de Privacidade" + themes: + default: Mastodon time: formats: default: "%b %d, %Y, %H:%M" two_factor_authentication: code_hint: Entre o código gerado pelo seu aplicativo para confirmar - description_html: Se você habilitar <strong>autenticação two-factor </strong>, quando logar será necessário o seu telefone que vai gerar os tokens usado. - disable: Disabilitar - enable: Habilitar - enabled_success: Autenticador Two-factor habilitador com sucesso + description_html: Se ativar a <strong>autenticação em dois passos</strong>, quando logar será necessário o seu telefone que vai gerar os tokens para validação. + disable: Desativar + enable: Ativar + enabled: A autenticação em dois passos está ativada + enabled_success: Autenticação em dois passos ativada com sucesso generate_recovery_codes: Gerar códigos para recuperar conta instructions_html: "<strong>Scaneie este código QR no seu Google Authenticator ou aplicativo similar no seu telefone</strong>. A partir de agora seu aplicativo irá gerar tokens que deverão ser digitados para você logar." lost_recovery_codes: Códigos de recuperação permite que você recupere o acesso a sua conta se você perder seu telefone. Se você perder os códigos de recuperação, você pode regera-los aqui. Seus códigos antigos serão invalidados. manual_instructions: 'Se você não puder scanear o código QR e precisa digita-los manualmente, aqui está o segredo em texto.:' + recovery_codes: Cópia de segurança dos códigos de recuperação recovery_codes_regenerated: Códigos de recuperação foram gerados com sucesso + setup: Configurar + wrong_code: O código inserido é invalido! O horário do servidor e o horário do seu aparelho estão corretos? + users: + invalid_email: O endereço de e-mail é inválido + invalid_otp_token: Código de autenticação inválido + signed_in_as: 'Registado como:' diff --git a/config/locales/ru.yml b/config/locales/ru.yml index 5eb7f256a..697a1aa27 100644 --- a/config/locales/ru.yml +++ b/config/locales/ru.yml @@ -39,6 +39,7 @@ ru: followers: Подписчики following: Подписан(а) media: Медиаконтент + moved_html: "%{name} переехал(а) на %{new_profile_link}:" nothing_here: Здесь ничего нет! people_followed_by: Люди, на которых подписан(а) %{name} people_who_follow: Подписчики %{name} @@ -59,9 +60,13 @@ ru: destroyed_msg: Заметка модератора успешно удалена! accounts: are_you_sure: Вы уверены? + by_domain: Домен confirm: Подтвердить confirmed: Подтверждено + demote: Разжаловать + disable: Отключить disable_two_factor_authentication: Отключить 2FA + disabled: Отключено display_name: Отображаемое имя domain: Домен edit: Изменить @@ -77,7 +82,9 @@ ru: local: Локальные remote: Удаленные title: Размещение + login_status: Статус аккаунта media_attachments: Мультимедийные вложения + memorialize: Превратить в Памятник moderation: all: Все silenced: Заглушенные @@ -94,6 +101,7 @@ ru: outbox_url: URL исходящих perform_full_suspension: Полная блокировка profile_url: URL профиля + promote: Повысить protocol: Протокол public: Публичный push_subscription_expires: Подписка PuSH истекает @@ -101,6 +109,12 @@ ru: reset: Сбросить reset_password: Сбросить пароль resubscribe: Переподписаться + role: Разрешения + roles: + admin: Администратор + moderator: Модератор + staff: Персонал + user: Пользователь salmon_url: Salmon URL search: Поиск shared_inbox_url: URL общих входящих @@ -117,6 +131,32 @@ ru: unsubscribe: Отписаться username: Имя пользователя web: WWW + action_logs: + actions: + confirm_user: "%{name} подтвердил(а) e-mail адрес пользователя %{target}" + create_custom_emoji: "%{name} загрузил(а) новый эмодзи %{target}" + create_domain_block: "%{name} заблокировал(а) домен %{target}" + create_email_domain_block: "%{name} добавил(а) e-mail домен %{target} в чёрный список" + demote_user: "%{name} разжаловал(а) пользователя %{target}" + destroy_domain_block: "%{name} разблокировал(а) домен %{target}" + destroy_email_domain_block: "%{name} добавил(а) e-mail домен %{target} в белый список" + destroy_status: "%{name} удалил(а) статус пользователя %{target}" + disable_2fa_user: "%{name} отключил(а) двухэтапную авторизацию у пользователя %{target}" + disable_custom_emoji: "%{name} отключил(а) эмодзи %{target}" + disable_user: "%{name} запретил(а) вход пользователя %{target}" + enable_custom_emoji: "%{name} включил(а) эмодзи %{target}" + enable_user: "%{name} включил(а) вход пользователя %{target}" + memorialize_account: "%{name} перевел(а) аккаунт пользователя %{target} в режим памятника" + promote_user: "%{name} повысил(а) пользователя %{target}" + reset_password_user: "%{name} сбросил(а) пароль пользователя %{target}" + resolve_report: "%{name} dismissed report %{target}" + silence_account: "%{name} заглушил(а) аккаунт %{target}" + suspend_account: "%{name} заморозил(а) аккаунт %{target}" + unsilence_account: "%{name} снял(а) глушение аккаунта %{target}" + unsuspend_account: "%{name} разморозил(а) аккаунт %{target}" + update_custom_emoji: "%{name} обновил(а) эмодзи %{target}" + update_status: "%{name} изменил(а) статус пользователя %{target}" + title: Журнал событий custom_emojis: copied_msg: Локальная копия эмодзи успешно создана copy: Скопироват @@ -130,11 +170,16 @@ ru: enable: Включить enabled_msg: Эмодзи успешно включено image_hint: PNG до 50KB + listed: В списке new: - title: Добавить новое эмодзи + title: Добавить новый эмодзи + overwrite: Заменить shortcode: Шорткод shortcode_hint: Как минимум 2 символа, только алфавитно-цифровые символы и подчеркивания title: Собственные эмодзи + unlisted: Не в списке + update_failed_msg: Невозможно обновить этот эмодзи + updated_msg: Эмодзи обновлён! upload: Загрузить domain_blocks: add_new: Добавить новую @@ -186,6 +231,13 @@ ru: reset: Сбросить search: Поиск title: Известные узлы + invites: + filter: + all: Все + available: Актуальные + expired: Истёкшие + title: Фильтр + title: Приглашения reports: action_taken_by: 'Действие предпринято:' are_you_sure: Вы уверены? @@ -199,6 +251,7 @@ ru: 'false': Показать мультимедийные вложения 'true': Скрыть мультимедийные вложения report: 'Жалоба #%{id}' + report_contents: Содержимое reported_account: Аккаунт нарушителя reported_by: Отправитель жалобы resolved: Разрешено @@ -210,12 +263,18 @@ ru: unresolved: Неразрешенные view: Просмотреть settings: + activity_api_enabled: + desc_html: Подсчёт количества локальных статусов, активных пользователей и новых регистраций на еженедельной основе + title: Публикация агрегированной статистики активности пользователей bootstrap_timeline_accounts: desc_html: Разделяйте имена пользователей запятыми. Сработает только для локальных незакрытых аккаунтов. По умолчанию включены все локальные администраторы. title: Подписки по умолчанию для новых пользователей contact_information: email: Введите публичный e-mail username: Введите имя пользователя + peers_api_enabled: + desc_html: Домены, которые были замечены этим узлом среди всей федерации + title: Публикация списка обнаруженных узлов registrations: closed_message: desc_html: Отображается на титульной странице, когда закрыта регистрация<br>Можно использовать HTML-теги @@ -223,9 +282,15 @@ ru: deletion: desc_html: Позволяет всем удалять собственные аккаунты title: Разрешить удаление аккаунтов + min_invite_role: + disabled: Никого + title: Разрешает приглашения от open: desc_html: Позволяет любому создавать аккаунт title: Открыть регистрацию + show_staff_badge: + desc_html: Показывать метку персонала на странице пользователя + title: Показывать метку персонала site_description: desc_html: Отображается в качестве параграфа на титульной странице и используется в качестве мета-тега.<br>Можно использовать HTML-теги, в особенности <code><a></code> и <code><em></code>. title: Описание сайта @@ -293,6 +358,8 @@ ru: invalid_reset_password_token: Токен сброса пароля неверен или устарел. Пожалуйста, запросите новый. login: Войти logout: Выйти + migrate_account: Перенести аккаунт + migrate_account_html: Если Вы хотите перенести этот аккаунт на другой, вы можете <a href="%{path}">сделать это здесь</a>. register: Зарегистрироваться resend_confirmation: Повторить отправку инструкции для подтверждения reset_password: Сбросить пароль @@ -374,12 +441,43 @@ ru: following: Подписки muting: Список глушения upload: Загрузить + in_memoriam_html: Памятник. + invites: + delete: Удалить + expired: Истекло + expires_in: + '1800': 30 минут + '21600': 6 часов + '3600': 1 час + '43200': 12 часов + '86400': 1 день + expires_in_prompt: Никогда + generate: Сгенерировать + max_uses: + one: 1 исп. + other: "%{count} исп." + max_uses_prompt: Без лимита + prompt: Генерируйте и делитесь ссылками с другими, чтобы предоставить им доступ к этому узлу. + table: + expires_at: Истекает + uses: Исп. + title: Пригласить людей landing_strip_html: "<strong>%{name}</strong> - пользователь на %{link_to_root_path}. Вы можете подписаться на него/нее и общаться с ним/ней, если у Вас есть аккаунт на любом узле общей сети." landing_strip_signup_html: Если у Вас его нет, вы можете <a href="%{sign_up_path}">зарегистрироваться здесь</a>. + lists: + errors: + limit: Вы достигли максимального числа списков media_attachments: validations: images_and_video: Нельзя добавить видео к статусу с изображениями too_many: Нельзя добавить более 4 файлов + migrations: + acct: имя@домен нового аккаунта + currently_redirecting: 'Ваш профиль будет перенаправлен на:' + proceed: Сохранить + updated_msg: Настройки миграции Вашего аккаунта обновлены! + moderation: + title: Модерация notification_mailer: digest: body: 'Кратко о пропущенном Вами на %{instance} с Вашего последнего захода %{since}:' @@ -484,6 +582,8 @@ ru: windows: Windows windows_mobile: Windows Mobile windows_phone: Windows Phone + revoke: Завершить + revoke_success: Сессия завершена успешно title: Сессии settings: authorized_apps: Авторизованные приложения @@ -494,6 +594,7 @@ ru: export: Экспорт данных followers: Авторизованные подписчики import: Импорт + migrate: Перенос аккаунта notifications: Уведомления preferences: Настройки settings: Опции @@ -503,7 +604,7 @@ ru: open_in_web: Открыть в WWW over_character_limit: превышен лимит символов (%{max}) pin_errors: - limit: Слишком много закрепленных статусов + limit: Вы закрепили максимально возможное число статусов ownership: Нельзя закрепить чужой статус private: Нельзя закрепить непубличный статус reblog: Нельзя закрепить продвинутый статус @@ -517,10 +618,52 @@ ru: unlisted_long: Показывать всем, но не отображать в публичных лентах stream_entries: click_to_show: Показать + pinned: Закреплённое сообщение reblogged: продвинул(а) sensitive_content: Чувствительный контент terms: + body_html: | + <h2>Privacy Policy</h2> + <h3 id="collect">What information do we collect?</h3> + <p>We collect information from you when you register on our site and gather data when you participate in the forum by reading, writing, and evaluating the content shared here.</p> + <p>When registering on our site, you may be asked to enter your name and e-mail address. You may, however, visit our site without registering. Your e-mail address will be verified by an email containing a unique link. If that link is visited, we know that you control the e-mail address.</p> + <p>When registered and posting, we record the IP address that the post originated from. We also may retain server logs which include the IP address of every request to our server.</p> + <h3 id="use">What do we use your information for?</h3> + <p>Any of the information we collect from you may be used in one of the following ways:</p> + <ul> + <li>To personalize your experience — your information helps us to better respond to your individual needs.</li> + <li>To improve our site — we continually strive to improve our site offerings based on the information and feedback we receive from you.</li> + <li>To improve customer service — your information helps us to more effectively respond to your customer service requests and support needs.</li> + <li>To send periodic emails — The email address you provide may be used to send you information, notifications that you request about changes to topics or in response to your user name, respond to inquiries, and/or other requests or questions.</li> + </ul> + <h3 id="protect">How do we protect your information?</h3> + <p>We implement a variety of security measures to maintain the safety of your personal information when you enter, submit, or access your personal information.</p> + <h3 id="data-retention">What is your data retention policy?</h3> + <p>We will make a good faith effort to:</p> + <ul> + <li>Retain server logs containing the IP address of all requests to this server no more than 90 days.</li> + <li>Retain the IP addresses associated with registered users and their posts no more than 5 years.</li> + </ul> + <h3 id="cookies">Do we use cookies?</h3> + <p>Yes. Cookies are small files that a site or its service provider transfers to your computer's hard drive through your Web browser (if you allow). These cookies enable the site to recognize your browser and, if you have a registered account, associate it with your registered account.</p> + <p>We use cookies to understand and save your preferences for future visits and compile aggregate data about site traffic and site interaction so that we can offer better site experiences and tools in the future. We may contract with third-party service providers to assist us in better understanding our site visitors. These service providers are not permitted to use the information collected on our behalf except to help us conduct and improve our business.</p> + <h3 id="disclose">Do we disclose any information to outside parties?</h3> + <p>We do not sell, trade, or otherwise transfer to outside parties your personally identifiable information. This does not include trusted third parties who assist us in operating our site, conducting our business, or servicing you, so long as those parties agree to keep this information confidential. We may also release your information when we believe release is appropriate to comply with the law, enforce our site policies, or protect ours or others rights, property, or safety. However, non-personally identifiable visitor information may be provided to other parties for marketing, advertising, or other uses.</p> + <h3 id="third-party">Third party links</h3> + <p>Occasionally, at our discretion, we may include or offer third party products or services on our site. These third party sites have separate and independent privacy policies. We therefore have no responsibility or liability for the content and activities of these linked sites. Nonetheless, we seek to protect the integrity of our site and welcome any feedback about these sites.</p> + <h3 id="coppa">Children's Online Privacy Protection Act Compliance</h3> + <p>Our site, products and services are all directed to people who are at least 13 years old. If this server is in the USA, and you are under the age of 13, per the requirements of COPPA (<a href="https://en.wikipedia.org/wiki/Children%27s_Online_Privacy_Protection_Act">Children's Online Privacy Protection Act</a>) do not use this site.</p> + <h3 id="online">Online Privacy Policy Only</h3> + <p>This online privacy policy applies only to information collected through our site and not to information collected offline.</p> + <h3 id="consent">Your Consent</h3> + <p>By using our site, you consent to our web site privacy policy.</p> + <h3 id="changes">Changes to our Privacy Policy</h3> + <p>If we decide to change our privacy policy, we will post those changes on this page.</p> + <p>This document is CC-BY-SA. It was last updated May 31, 2013.</p> + <p>Originally adapted from the <a href="https://github.com/discourse/discourse">Discourse privacy policy</a>.</p> title: Условия обслуживания и политика конфиденциальности %{instance} + themes: + default: Mastodon time: formats: default: "%b %d, %Y, %H:%M" diff --git a/config/locales/simple_form.ar.yml b/config/locales/simple_form.ar.yml index e4c6694e9..e3876e47b 100644 --- a/config/locales/simple_form.ar.yml +++ b/config/locales/simple_form.ar.yml @@ -7,6 +7,7 @@ ar: digest: يُرسَل بعد مضيّ مدة طويلة من خمول نشاطك يحوي على تلخيص للتبويقات التي ذُكر حسابك فيها أثناء غيابك display_name: one: <span class="name-counter">1</span> حرف متبقي + other: <span class="name-counter">%{count}</span> حرف متبقي header: PNG, GIF or JPG. على الأكثر 2 ميغابيت . سوف يتم تصغيرها إلى 700x335px locked: يتطلب منك الموافقة يدويا على كل طلب للإشتراك بحسابك و منشوراتك تعرض لمتابعيك فقط دون غيرهم note: <span class="note-counter">%{count}</span> أحرف متبقية @@ -16,6 +17,8 @@ ar: data: ملف CSV تم تصديره من خادوم مثيل آخر لماستدون sessions: otp: أدخل الرمز الثنائي من هاتفك أو استخدم أحد رموز الاسترداد. + user: + filtered_languages: سوف لن تَظهَر التبويقات المُحرَّرَة باللغات المُحدّدة أدناه على خيوطك العمومية labels: defaults: avatar: الصورة الرمزية @@ -25,6 +28,8 @@ ar: data: البيانات display_name: الاسم الذي يتم عرضه email: عنوان البريد الإلكتروني + expires_in: مدة نهاية الصلاحية + filtered_languages: اللغات المصفاة header: رأس الصفحة locale: اللغة locked: إجعل حسابك خاصًا @@ -33,17 +38,23 @@ ar: note: السيرة الذاتية otp_attempt: الرمز الثنائي password: كلمة المرور - setting_auto_play_gif: تشغيل صور جيف المتحركة تلقائي + setting_auto_play_gif: تشغيل تلقائي لِوَسائط جيف المتحركة setting_boost_modal: إظهار مربع حوار التأكيد قبل القيام بالترقية setting_default_privacy: خصوصية المنشور setting_default_sensitive: دائما تحديد الوسائط كحساسة + setting_delete_modal: إظهار مربع حوار للتأكيد قبل حذف أي تبويق setting_noindex: منع محركات البحث من فهرسة ملفي الشخصي + setting_reduce_motion: تخفيض عدد الصور في الوسائط المتحركة + setting_system_font_ui: إستخدام الخط الإفتراضي للنظام + setting_theme: سمة الموقع + setting_unfollow_modal: إظهار مربع حوار للتأكيد قبل إلغاء متابعة أي حساب severity: الشدة type: نوع الإستيراد username: اسم المستخدم interactions: must_be_follower: حظر اشعارات الأشخاص الذين لا يتبعونك must_be_following: حظر اشعارات الأشخاص الذين لا تتبعهم + must_be_following_dm: حظر التبويقات المباشرة القادمة من الحسابات التي لا تتبعها notification_emails: digest: إرسال رسائل بريد إلكتروني ملخصة favourite: إبعث بريداً إلكترونياً عندما يعجب احدهم بمنشورك diff --git a/config/locales/simple_form.fa.yml b/config/locales/simple_form.fa.yml index a19d69ff1..ddb13ae43 100644 --- a/config/locales/simple_form.fa.yml +++ b/config/locales/simple_form.fa.yml @@ -3,7 +3,7 @@ fa: simple_form: hints: defaults: - avatar: یکی از قالبهای PNG یا GIF یا JPG. بیشترین اندازه ۲ مگابایت. تصویر به اندازهٔ ۱۲۰×۱۲۰ پیکسل تبدیل خواهد شد. + avatar: یکی از قالبهای PNG یا GIF یا JPG. بیشترین اندازه ۲ مگابایت. تصویر به اندازهٔ ۱۲۰×۱۲۰ پیکسل تبدیل خواهد شد digest: پس از مدت طولانی عدم فعالیت فرستاده میشود، شامل خلاصهای از مواردی که در نبودتان از شما نام برده شده display_name: one: <span class="name-counter">1</span> حرف باقی مانده @@ -20,7 +20,7 @@ fa: sessions: otp: کد تأیید دومرحلهای را از تلفن خود وارد کنید یا یکی از کدهای بازیابی را به کار ببرید. user: - filtered_languages: زبانهای انتخابشده از فهرست عمومی نوشتههایی که میبینید حذف میشوند. + filtered_languages: زبانهای انتخابشده از فهرست عمومی نوشتههایی که میبینید حذف میشوند labels: defaults: avatar: تصویر نمایه @@ -30,10 +30,12 @@ fa: data: دادهها display_name: نمایش به نام email: نشانی ایمیل + expires_in: تاریخ انقضا filtered_languages: زبانهای فیلترشده header: تصویر زمینه locale: زبان locked: خصوصیکردن حساب + max_uses: بیشترین شمار استفاده new_password: رمز تازه note: دربارهٔ شما otp_attempt: کد ورود دومرحلهای @@ -44,6 +46,7 @@ fa: setting_default_sensitive: همیشه تصاویر را به عنوان حساس علامت بزن setting_delete_modal: پیش از پاک کردن یک نوشته پیغام تأیید نشان بده setting_noindex: درخواست از موتورهای جستجو برای لغو فهرستسازی + setting_reduce_motion: کاستن از حرکت در پویانماییها setting_system_font_ui: بهکاربردن قلم پیشفرض سیستم setting_theme: تم سایت setting_unfollow_modal: نمایش پیغام تأیید پیش از لغو پیگیری دیگران @@ -53,6 +56,7 @@ fa: interactions: must_be_follower: مسدودکردن اعلانهای همه به جز پیگیران must_be_following: مسدودکردن اعلانهای کسانی که شما پی نمیگیرید + must_be_following_dm: مسدودکردن پیغامهای خصوصی کسانی که شما پی نمیگیرید notification_emails: digest: خلاصهکردن چند اعلان در یک ایمیل favourite: وقتی کسی نوشتهٔ شما پسندید ایمیل بفرست diff --git a/config/locales/simple_form.gl.yml b/config/locales/simple_form.gl.yml index 7fa96992f..d7e5601f2 100644 --- a/config/locales/simple_form.gl.yml +++ b/config/locales/simple_form.gl.yml @@ -1,10 +1,10 @@ +--- gl: simple_form: hints: defaults: avatar: PNG, GIF ou JPG. Como moito 2MB. Será reducida ate 120x120px - digest: Enviar despois de un período longo de inactividade con un resumo das - mencións que recibeu na súa ausencia + digest: Enviar despois de un período longo de inactividade con un resumo das mencións que recibeu na súa ausencia display_name: one: <span class="name-counter">1</span> caracter restante other: <span class="name-counter">%{count}</span> caracteres restantes @@ -14,16 +14,13 @@ gl: one: <span class="note-counter">1</span> caracter restante other: <span class="note-counter">%{count}</span> caracteres restantes setting_noindex: Afecta ao seu perfil público e páxinas de estado - setting_theme: Afecta ao aspecto de Mastodon en calquer dispositivo cando - está conectada. + setting_theme: Afecta ao aspecto de Mastodon en calquer dispositivo cando está conectada. imports: data: Ficheiro CSV exportado desde outra instancia Mastodon sessions: - otp: Introduza o código de Doble-Factor desde o seu teléfono ou utilice un - dos seus códigos de recuperación. + otp: Introduza o código de Doble-Factor desde o seu teléfono ou utilice un dos seus códigos de recuperación. user: - filtered_languages: Os idiomas marcados filtraranse das liñas temporais públicas - para vostede + filtered_languages: Os idiomas marcados filtraranse das liñas temporais públicas para vostede labels: defaults: avatar: Avatar @@ -62,14 +59,13 @@ gl: must_be_following_dm: Bloquea as mensaxes directas de personas que non segue notification_emails: digest: Enviar correos con resumos - favourite: Enviar un correo cando alguén marca como favorita unha das súas - publicacións + favourite: Enviar un correo cando alguén marca como favorita unha das súas publicacións follow: Enviar un correo cando alguén a segue follow_request: Enviar un correo cando alguén solicita seguila mention: Enviar un correo cando alguén a menciona reblog: Enviar un correo cando alguén promociona a súa mensaxe 'no': Non required: - mark: '*' + mark: "*" text: requerido 'yes': Si diff --git a/config/locales/simple_form.pl.yml b/config/locales/simple_form.pl.yml index 507e46469..a97239669 100644 --- a/config/locales/simple_form.pl.yml +++ b/config/locales/simple_form.pl.yml @@ -18,7 +18,7 @@ pl: one: Pozostał <span class="name-counter">1</span> znak. other: Pozostało <span class="name-counter">%{count}</span> znaków setting_noindex: Wpływa na widoczność strony profilu i Twoich wpisów - setting_theme: Zmienia wygląd Mastodona po zalogowaniu z dowolnego urządzenia. + setting_skin: Zmienia wygląd używanej odmiany Mastodona imports: data: Plik CSV wyeksportowany z innej instancji Mastodona sessions: @@ -49,10 +49,11 @@ pl: setting_default_privacy: Widoczność wpisów setting_default_sensitive: Zawsze oznaczaj zawartość multimedialną jako wrażliwą setting_delete_modal: Pytaj o potwierdzenie przed usunięciem wpisu + setting_favourite_modal: Pytaj o potwierdzenie przed dodaniem do ulubionych setting_noindex: Nie indeksuj mojego profilu w wyszukiwarkach internetowych setting_reduce_motion: Ogranicz ruch w animacjach + setting_skin: Motyw setting_system_font_ui: Używaj domyślnej czcionki systemu - setting_theme: Motyw strony setting_unfollow_modal: Pytaj o potwierdzenie przed cofnięciem śledzenia severity: Priorytet type: Typ importu diff --git a/config/locales/simple_form.pt.yml b/config/locales/simple_form.pt.yml index a5afd02d3..9970247ab 100644 --- a/config/locales/simple_form.pt.yml +++ b/config/locales/simple_form.pt.yml @@ -11,7 +11,7 @@ pt: imports: data: Ficheiro CSV exportado de outra instância do Mastodon sessions: - otp: Insere o código o código de autenticação de dois fatores do teu telefone ou utiliza um código de recuperação de acesso. + otp: Insere o código de autenticação em dois passos do teu telefone ou utiliza um código de recuperação de acesso. labels: defaults: avatar: Imagem de Perfil @@ -26,10 +26,11 @@ pt: locked: Tornar conta privada new_password: Nova palavra-passe note: Biografia - otp_attempt: Código de autenticação de dois fatores + otp_attempt: Código de autenticação em dois passos password: Palavra-passe setting_boost_modal: Pedir confirmação antes de partilhar um post setting_default_privacy: Privacidade padrão de posts + setting_default_sensitive: Marcar sempre media como sensível setting_reduce_motion: Reduzir movimento em animações severity: Severity type: Import type @@ -41,6 +42,7 @@ pt: digest: Enviar um email da actividade nesta instância favourite: Enviar email quando alguém adiciona um post teu aos favoritos follow: Enviar email quando alguém te segue + follow_request: Enviar um email quando alguém solicitar ser o teu seguidor mention: Enviar email quando alguém te menciona reblog: Enviar email quando alguém partilhar um post teu 'no': Não diff --git a/db/migrate/20180106000232_add_index_on_statuses_for_api_v1_accounts_account_id_statuses.rb b/db/migrate/20180106000232_add_index_on_statuses_for_api_v1_accounts_account_id_statuses.rb new file mode 100644 index 000000000..401fc5e62 --- /dev/null +++ b/db/migrate/20180106000232_add_index_on_statuses_for_api_v1_accounts_account_id_statuses.rb @@ -0,0 +1,10 @@ +class AddIndexOnStatusesForApiV1AccountsAccountIdStatuses < ActiveRecord::Migration[5.1] + disable_ddl_transaction! + + def change + safety_assured do + add_index :statuses, [:account_id, :id, :visibility, :updated_at], order: { id: :desc }, algorithm: :concurrently, name: :index_statuses_20180106 + end + remove_index :statuses, name: :index_statuses_on_account_id_id + end +end diff --git a/db/schema.rb b/db/schema.rb index b480c9c46..11ca12235 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20171226094803) do +ActiveRecord::Schema.define(version: 20180106000232) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -419,7 +419,7 @@ ActiveRecord::Schema.define(version: 20171226094803) do t.bigint "application_id" t.bigint "in_reply_to_account_id" t.boolean "local_only" - t.index ["account_id", "id"], name: "index_statuses_on_account_id_id" + t.index ["account_id", "id", "visibility", "updated_at"], name: "index_statuses_20180106", order: { id: :desc } t.index ["conversation_id"], name: "index_statuses_on_conversation_id" t.index ["in_reply_to_id"], name: "index_statuses_on_in_reply_to_id" t.index ["reblog_of_id", "account_id"], name: "index_statuses_on_reblog_of_id_and_account_id" diff --git a/docker_entrypoint.sh b/docker_entrypoint.sh index e92959c8e..1af5dde64 100644 --- a/docker_entrypoint.sh +++ b/docker_entrypoint.sh @@ -11,4 +11,4 @@ echo "Updating permissions..." find /mastodon -path /mastodon/public/system -prune -o -not -user mastodon -not -group mastodon -print0 | xargs -0 chown -f mastodon:mastodon echo "Executing process..." -exec su-exec mastodon:mastodon /sbin/tini -- "$@" +LD_PRELOAD=/lib/stack-fix.so exec su-exec mastodon:mastodon /sbin/tini -- "$@" diff --git a/lib/mastodon/version.rb b/lib/mastodon/version.rb index bd23ab1d1..5936b5fcf 100644 --- a/lib/mastodon/version.rb +++ b/lib/mastodon/version.rb @@ -13,7 +13,7 @@ module Mastodon end def patch - 2 + 3 end def pre diff --git a/spec/controllers/settings/flavours_controller_spec.rb b/spec/controllers/settings/flavours_controller_spec.rb new file mode 100644 index 000000000..f89bde1f9 --- /dev/null +++ b/spec/controllers/settings/flavours_controller_spec.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true +require 'rails_helper' + +RSpec.describe Settings::FlavoursController, type: :controller do + let(:user) { Fabricate(:user) } + + before do + sign_in user, scope: :user + end + + describe 'PUT #update' do + describe 'without a user[setting_skin] parameter' do + it 'sets the selected flavour' do + put :update, params: { flavour: 'schnozzberry' } + + user.reload + + expect(user.setting_flavour).to eq 'schnozzberry' + end + end + + describe 'with a user[setting_skin] parameter' do + before do + put :update, params: { flavour: 'schnozzberry', user: { setting_skin: 'wallpaper' } } + + user.reload + end + + it 'sets the selected flavour' do + expect(user.setting_flavour).to eq 'schnozzberry' + end + + it 'sets the selected skin' do + expect(user.setting_skin).to eq 'wallpaper' + end + end + end +end diff --git a/stack-fix.c b/stack-fix.c new file mode 100644 index 000000000..09311a8f0 --- /dev/null +++ b/stack-fix.c @@ -0,0 +1,32 @@ +#include <dlfcn.h> +#include <pthread.h> +#include <stdio.h> + +// THIS IS TO AVOID A SIGFAULT WHEN RUNNING python3.6 manage.py runserver +// This should be fixed at some point by Alpine and/or Python +// Check this issue for more info +// https://github.com/docker-library/python/issues/211 +typedef int (*func_t)(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg); + +int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg) { + + pthread_attr_t local; + int used = 0, ret; + + if (!attr) { + used = 1; + pthread_attr_init(&local); + attr = &local; + } + pthread_attr_setstacksize((void*)attr, 2 * 1024 * 1024); // 2 MB + + func_t orig = (func_t)dlsym(RTLD_NEXT, "pthread_create"); + + ret = orig(thread, attr, start_routine, arg); + + if (used) { + pthread_attr_destroy(&local); + } + + return ret; +} |