Merge pull request #472 from ThibG/glitch-soc/merge

Merge upstream changes
main
ThibG 7 years ago committed by GitHub
commit 34142ab29c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -11,6 +11,7 @@ aliases:
RAILS_ENV: test RAILS_ENV: test
PARALLEL_TEST_PROCESSORS: 4 PARALLEL_TEST_PROCESSORS: 4
ALLOW_NOPAM: true ALLOW_NOPAM: true
DISABLE_SIMPLECOV: true
working_directory: ~/projects/mastodon/ working_directory: ~/projects/mastodon/
- &attach_workspace - &attach_workspace
@ -90,7 +91,7 @@ aliases:
command: ./bin/rails parallel:create parallel:load_schema parallel:prepare command: ./bin/rails parallel:create parallel:load_schema parallel:prepare
- run: - run:
name: Run Tests name: Run Tests
command: bundle exec parallel_test ./spec/ --group-by filesize --type rspec command: ./bin/retry bundle exec parallel_test ./spec/ --group-by filesize --type rspec
jobs: jobs:
install: install:
@ -150,7 +151,7 @@ jobs:
- image: circleci/node:8.11.1-stretch - image: circleci/node:8.11.1-stretch
steps: steps:
- *attach_workspace - *attach_workspace
- run: yarn test:jest - run: ./bin/retry yarn test:jest
check-i18n: check-i18n:
<<: *defaults <<: *defaults

@ -113,6 +113,8 @@ SMTP_FROM_ADDRESS=notifications@example.com
# For Keystone V3, the value for SWIFT_TENANT should be the project name # For Keystone V3, the value for SWIFT_TENANT should be the project name
# SWIFT_TENANT= # SWIFT_TENANT=
# SWIFT_PASSWORD= # SWIFT_PASSWORD=
# Some OpenStack V3 providers require PROJECT_ID (optional)
# SWIFT_PROJECT_ID=
# Keystone V2 and V3 URLs are supported. Use a V3 URL if possible to avoid # Keystone V2 and V3 URLs are supported. Use a V3 URL if possible to avoid
# issues with token rate-limiting during high load. # issues with token rate-limiting during high load.
# SWIFT_AUTH_URL= # SWIFT_AUTH_URL=

@ -1,3 +1,9 @@
---
name: Bug Report
about: Create a report to help us improve
---
[Issue text goes here]. [Issue text goes here].
* * * * * * * *

@ -0,0 +1,11 @@
---
name: Feature Request
about: Suggest an idea for this project
---
[Issue text goes here].
* * * *
- [ ] I searched or browsed the repos other issues to ensure this is not a duplicate.

@ -113,7 +113,6 @@ group :test do
gem 'microformats', '~> 4.0' gem 'microformats', '~> 4.0'
gem 'rails-controller-testing', '~> 1.0' gem 'rails-controller-testing', '~> 1.0'
gem 'rspec-sidekiq', '~> 3.0' gem 'rspec-sidekiq', '~> 3.0'
gem 'rspec-retry', '~> 0.5', require: false
gem 'simplecov', '~> 0.16', require: false gem 'simplecov', '~> 0.16', require: false
gem 'webmock', '~> 3.3' gem 'webmock', '~> 3.3'
gem 'parallel_tests', '~> 2.21' gem 'parallel_tests', '~> 2.21'

@ -503,8 +503,6 @@ GEM
rspec-expectations (~> 3.7.0) rspec-expectations (~> 3.7.0)
rspec-mocks (~> 3.7.0) rspec-mocks (~> 3.7.0)
rspec-support (~> 3.7.0) rspec-support (~> 3.7.0)
rspec-retry (0.5.7)
rspec-core (> 3.3)
rspec-sidekiq (3.0.3) rspec-sidekiq (3.0.3)
rspec-core (~> 3.0, >= 3.0.0) rspec-core (~> 3.0, >= 3.0.0)
sidekiq (>= 2.4.0) sidekiq (>= 2.4.0)
@ -729,7 +727,6 @@ DEPENDENCIES
redis-rails (~> 5.0) redis-rails (~> 5.0)
rqrcode (~> 0.10) rqrcode (~> 0.10)
rspec-rails (~> 3.7) rspec-rails (~> 3.7)
rspec-retry (~> 0.5)
rspec-sidekiq (~> 3.0) rspec-sidekiq (~> 3.0)
rubocop (~> 0.55) rubocop (~> 0.55)
ruby-progressbar (~> 1.4) ruby-progressbar (~> 1.4)

@ -3,6 +3,7 @@
module Admin module Admin
class ConfirmationsController < BaseController class ConfirmationsController < BaseController
before_action :set_user before_action :set_user
before_action :check_confirmation, only: [:resend]
def create def create
authorize @user, :confirm? authorize @user, :confirm?
@ -11,10 +12,28 @@ module Admin
redirect_to admin_accounts_path redirect_to admin_accounts_path
end end
def resend
authorize @user, :confirm?
@user.resend_confirmation_instructions
log_action :confirm, @user
flash[:notice] = I18n.t('admin.accounts.resend_confirmation.success')
redirect_to admin_accounts_path
end
private private
def set_user def set_user
@user = Account.find(params[:account_id]).user || raise(ActiveRecord::RecordNotFound) @user = Account.find(params[:account_id]).user || raise(ActiveRecord::RecordNotFound)
end end
def check_confirmation
if @user.confirmed?
flash[:error] = I18n.t('admin.accounts.resend_confirmation.already_confirmed')
redirect_to admin_accounts_path
end
end
end end
end end

@ -3,7 +3,6 @@
module Admin module Admin
class ReportedStatusesController < BaseController class ReportedStatusesController < BaseController
before_action :set_report before_action :set_report
before_action :set_status, only: [:update, :destroy]
def create def create
authorize :status, :update? authorize :status, :update?
@ -14,20 +13,6 @@ module Admin
redirect_to admin_report_path(@report) redirect_to admin_report_path(@report)
end end
def update
authorize @status, :update?
@status.update!(status_params)
log_action :update, @status
redirect_to admin_report_path(@report)
end
def destroy
authorize @status, :destroy?
RemovalWorker.perform_async(@status.id)
log_action :destroy, @status
render json: @status
end
private private
def status_params def status_params
@ -51,9 +36,5 @@ module Admin
def set_report def set_report
@report = Report.find(params[:report_id]) @report = Report.find(params[:report_id])
end end
def set_status
@status = @report.statuses.find(params[:id])
end
end end
end end

@ -5,7 +5,6 @@ module Admin
helper_method :current_params helper_method :current_params
before_action :set_account before_action :set_account
before_action :set_status, only: [:update, :destroy]
PER_PAGE = 20 PER_PAGE = 20
@ -26,40 +25,18 @@ module Admin
def create def create
authorize :status, :update? authorize :status, :update?
@form = Form::StatusBatch.new(form_status_batch_params.merge(current_account: current_account)) @form = Form::StatusBatch.new(form_status_batch_params.merge(current_account: current_account, action: action_from_button))
flash[:alert] = I18n.t('admin.statuses.failed_to_execute') unless @form.save flash[:alert] = I18n.t('admin.statuses.failed_to_execute') unless @form.save
redirect_to admin_account_statuses_path(@account.id, current_params) redirect_to admin_account_statuses_path(@account.id, current_params)
end end
def update
authorize @status, :update?
@status.update!(status_params)
log_action :update, @status
redirect_to admin_account_statuses_path(@account.id, current_params)
end
def destroy
authorize @status, :destroy?
RemovalWorker.perform_async(@status.id)
log_action :destroy, @status
render json: @status
end
private private
def status_params
params.require(:status).permit(:sensitive)
end
def form_status_batch_params def form_status_batch_params
params.require(:form_status_batch).permit(:action, status_ids: []) params.require(:form_status_batch).permit(:action, status_ids: [])
end end
def set_status
@status = @account.statuses.find(params[:id])
end
def set_account def set_account
@account = Account.find(params[:account_id]) @account = Account.find(params[:account_id])
end end
@ -72,5 +49,15 @@ module Admin
page: page > 1 && page, page: page > 1 && page,
}.select { |_, value| value.present? } }.select { |_, value| value.present? }
end end
def action_from_button
if params[:nsfw_on]
'nsfw_on'
elsif params[:nsfw_off]
'nsfw_off'
elsif params[:delete]
'delete'
end
end
end end
end end

@ -21,7 +21,7 @@ class Api::V1::Accounts::CredentialsController < Api::BaseController
private private
def account_params def account_params
params.permit(:display_name, :note, :avatar, :header, :locked, fields_attributes: [:name, :value]) params.permit(:display_name, :note, :avatar, :header, :locked, :bot, fields_attributes: [:name, :value])
end end
def user_settings_params def user_settings_params

@ -39,7 +39,7 @@ class Api::V1::Statuses::PinsController < Api::BaseController
adapter: ActivityPub::Adapter adapter: ActivityPub::Adapter
).as_json ).as_json
ActivityPub::RawDistributionWorker.perform_async(Oj.dump(json), current_account) ActivityPub::RawDistributionWorker.perform_async(Oj.dump(json), current_account.id)
end end
def distribute_remove_activity! def distribute_remove_activity!
@ -49,6 +49,6 @@ class Api::V1::Statuses::PinsController < Api::BaseController
adapter: ActivityPub::Adapter adapter: ActivityPub::Adapter
).as_json ).as_json
ActivityPub::RawDistributionWorker.perform_async(Oj.dump(json), current_account) ActivityPub::RawDistributionWorker.perform_async(Oj.dump(json), current_account.id)
end end
end end

@ -24,7 +24,7 @@ class Settings::ProfilesController < Settings::BaseController
private private
def account_params def account_params
params.require(:account).permit(:display_name, :note, :avatar, :header, :locked, fields_attributes: [:name, :value]) params.require(:account).permit(:display_name, :note, :avatar, :header, :locked, :bot, fields_attributes: [:name, :value])
end end
def set_account def set_account

@ -6,6 +6,7 @@ module SettingsHelper
ar: 'العربية', ar: 'العربية',
bg: 'Български', bg: 'Български',
ca: 'Català', ca: 'Català',
co: 'Corsu',
de: 'Deutsch', de: 'Deutsch',
el: 'Ελληνικά', el: 'Ελληνικά',
eo: 'Esperanto', eo: 'Esperanto',

@ -4,8 +4,8 @@ module StreamEntriesHelper
EMBEDDED_CONTROLLER = 'statuses' EMBEDDED_CONTROLLER = 'statuses'
EMBEDDED_ACTION = 'embed' EMBEDDED_ACTION = 'embed'
def display_name(account) def display_name(account, **options)
account.display_name.presence || account.username Formatter.instance.format_display_name(account, options)
end end
def account_description(account) def account_description(account)

@ -38,6 +38,8 @@ export default class Header extends ImmutablePureComponent {
let displayName = account.get('display_name_html'); let displayName = account.get('display_name_html');
let fields = account.get('fields'); let fields = account.get('fields');
let badge = account.get('bot') ? (<div className='roles'><div className='account-role bot'><FormattedMessage id='account.badges.bot' defaultMessage='Bot' /></div></div>) : null;
let info = ''; let info = '';
let mutingInfo = ''; let mutingInfo = '';
let actionBtn = ''; let actionBtn = '';
@ -99,38 +101,31 @@ export default class Header extends ImmutablePureComponent {
<span className='account__header__display-name' dangerouslySetInnerHTML={{ __html: displayName }} /> <span className='account__header__display-name' dangerouslySetInnerHTML={{ __html: displayName }} />
<span className='account__header__username'>@{account.get('acct')} {account.get('locked') ? <i className='fa fa-lock' /> : null}</span> <span className='account__header__username'>@{account.get('acct')} {account.get('locked') ? <i className='fa fa-lock' /> : null}</span>
{badge}
<div className='account__header__content' dangerouslySetInnerHTML={{ __html: emojify(text) }} /> <div className='account__header__content' dangerouslySetInnerHTML={{ __html: emojify(text) }} />
{fields.size > 0 && ( {fields.size > 0 && (
<table className='account__header__fields'> <div className='account__header__fields'>
<tbody>
{fields.map((pair, i) => ( {fields.map((pair, i) => (
<tr key={i}> <dl key={i}>
<th dangerouslySetInnerHTML={{ __html: pair.get('name_emojified') }} /> <dt dangerouslySetInnerHTML={{ __html: pair.get('name_emojified') }} title={pair.get('name')} />
<td dangerouslySetInnerHTML={{ __html: pair.get('value_emojified') }} /> <dd dangerouslySetInnerHTML={{ __html: pair.get('value_emojified') }} title={pair.get('value')} />
</tr> </dl>
))} ))}
</tbody> </div>
</table>
)} )}
{fields.size == 0 && metadata.length && ( {fields.size == 0 && metadata.length && (
<table className='account__header__fields'> <div className='account__header__fields'>
<tbody> {metadata.map((pair, i) => (
{(() => { <dl key={i}>
let data = []; <dt dangerouslySetInnerHTML={{ __html: emojify(pair[0]) }} title={pair[0]} />
for (let i = 0; i < metadata.length; i++) { <dd dangerouslySetInnerHTML={{ __html: emojify(pair[1]) }} title={pair[1]} />
data.push( </dl>
<tr key={i}> ))}
<th scope='row'><div dangerouslySetInnerHTML={{ __html: emojify(metadata[i][0]) }} /></th> </div>
<td><div dangerouslySetInnerHTML={{ __html: emojify(metadata[i][1]) }} /></td>
</tr>
);
}
return data;
})()}
</tbody>
</table>
) || null} ) || null}
{info} {info}

@ -509,3 +509,9 @@
margin-bottom: 0; margin-bottom: 0;
} }
} }
.account__header .roles {
margin-top: 20px;
margin-bottom: 20px;
padding: 0 15px;
}

@ -2,7 +2,6 @@
font-size: 15px; font-size: 15px;
line-height: 20px; line-height: 20px;
overflow: hidden; overflow: hidden;
border-collapse: collapse;
margin: 20px -10px -20px; margin: 20px -10px -20px;
border-bottom: 0; border-bottom: 0;
@ -14,35 +13,36 @@
} }
} }
tr { dl {
border-top: 1px solid lighten($ui-base-color, 8%); border-top: 1px solid lighten($ui-base-color, 8%);
text-align: center; display: flex;
} }
th, td { dt,
dd {
box-sizing: border-box;
padding: 14px 20px; padding: 14px 20px;
vertical-align: middle; text-align: center;
max-height: 48px;
& > div { overflow: hidden;
max-height: 40px; white-space: nowrap;
overflow-y: auto;
white-space: pre-wrap;
text-overflow: ellipsis; text-overflow: ellipsis;
} }
}
th { dt {
color: $darker-text-color; color: $darker-text-color;
background: lighten($ui-base-color, 13%); background: lighten($ui-base-color, 13%);
max-width: 120px; width: 120px;
flex: 0 0 auto;
font-weight: 500;
a { a {
color: $primary-text-color; color: $primary-text-color;
} }
} }
td { dd {
flex: auto; flex: 1 1 auto;
color: $primary-text-color; color: $primary-text-color;
background: $ui-base-color; background: $ui-base-color;

@ -1,43 +1,56 @@
.account__header__fields { .account__header__fields {
$meta-table-border: lighten($ui-base-color, 8%); $meta-table-border: lighten($ui-base-color, 8%);
border-collapse: collapse;
padding: 0; padding: 0;
margin: 15px -15px -15px -15px; margin: 15px -15px -15px -15px;
border: 0 none; border: 0 none;
border-top: 1px solid $meta-table-border; border-top: 1px solid $meta-table-border;
border-bottom: 1px solid $meta-table-border; border-bottom: 1px solid $meta-table-border;
font-size: 14px;
line-height: 20px;
td, th { dl {
padding: 15px; display: flex;
border: 0 none;
border-bottom: 1px solid $meta-table-border; border-bottom: 1px solid $meta-table-border;
vertical-align: middle;
}
tr:last-child {
td, th {
border-bottom: 0 none;
}
} }
td { dt,
color: $ui-primary-color; dd {
box-sizing: border-box;
padding: 14px;
text-align: center; text-align: center;
width:100%; max-height: 48px;
padding-left: 0; overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
} }
th { dt {
padding-left: 15px; padding-left: 15px;
font-weight: bold; font-weight: 500;
text-align: center; text-align: center;
width: 94px; width: 120px;
color: $ui-secondary-color; flex: 0 0 auto;
color: $secondary-text-color;
background: darken($ui-base-color, 8%); background: darken($ui-base-color, 8%);
} }
dd {
flex: 1 1 auto;
color: $darker-text-color;
}
a { a {
color: $classic-highlight-color; color: $highlight-text-color;
text-decoration: none;
&:hover,
&:focus,
&:active {
text-decoration: underline;
}
}
dl:last-child {
border-bottom: 0;
} }
} }

@ -1,20 +1,29 @@
import escapeTextContentForBrowser from 'escape-html'; import escapeTextContentForBrowser from 'escape-html';
import emojify from '../../features/emoji/emoji'; import emojify from '../../features/emoji/emoji';
import { unescapeHTML } from '../../utils/html';
const domParser = new DOMParser(); const domParser = new DOMParser();
const makeEmojiMap = record => record.emojis.reduce((obj, emoji) => {
obj[`:${emoji.shortcode}:`] = emoji;
return obj;
}, {});
export function normalizeAccount(account) { export function normalizeAccount(account) {
account = { ...account }; account = { ...account };
const emojiMap = makeEmojiMap(account);
const displayName = account.display_name.length === 0 ? account.username : account.display_name; const displayName = account.display_name.length === 0 ? account.username : account.display_name;
account.display_name_html = emojify(escapeTextContentForBrowser(displayName));
account.note_emojified = emojify(account.note); account.display_name_html = emojify(escapeTextContentForBrowser(displayName), emojiMap);
account.note_emojified = emojify(account.note, emojiMap);
if (account.fields) { if (account.fields) {
account.fields = account.fields.map(pair => ({ account.fields = account.fields.map(pair => ({
...pair, ...pair,
name_emojified: emojify(escapeTextContentForBrowser(pair.name)), name_emojified: emojify(escapeTextContentForBrowser(pair.name)),
value_emojified: emojify(pair.value), value_emojified: emojify(pair.value, emojiMap),
value_plain: unescapeHTML(pair.value),
})); }));
} }
@ -42,11 +51,7 @@ export function normalizeStatus(status, normalOldStatus) {
normalStatus.hidden = normalOldStatus.get('hidden'); normalStatus.hidden = normalOldStatus.get('hidden');
} else { } else {
const searchContent = [status.spoiler_text, status.content].join('\n\n').replace(/<br\s*\/?>/g, '\n').replace(/<\/p><p>/g, '\n\n'); const searchContent = [status.spoiler_text, status.content].join('\n\n').replace(/<br\s*\/?>/g, '\n').replace(/<\/p><p>/g, '\n\n');
const emojiMap = makeEmojiMap(normalStatus);
const emojiMap = normalStatus.emojis.reduce((obj, emoji) => {
obj[`:${emoji.shortcode}:`] = emoji;
return obj;
}, {});
normalStatus.search_index = domParser.parseFromString(searchContent, 'text/html').documentElement.textContent; normalStatus.search_index = domParser.parseFromString(searchContent, 'text/html').documentElement.textContent;
normalStatus.contentHtml = emojify(normalStatus.content, emojiMap); normalStatus.contentHtml = emojify(normalStatus.content, emojiMap);

@ -8,6 +8,7 @@ import {
importFetchedStatuses, importFetchedStatuses,
} from './importer'; } from './importer';
import { defineMessages } from 'react-intl'; import { defineMessages } from 'react-intl';
import { unescapeHTML } from '../utils/html';
export const NOTIFICATIONS_UPDATE = 'NOTIFICATIONS_UPDATE'; export const NOTIFICATIONS_UPDATE = 'NOTIFICATIONS_UPDATE';
export const NOTIFICATIONS_UPDATE_NOOP = 'NOTIFICATIONS_UPDATE_NOOP'; export const NOTIFICATIONS_UPDATE_NOOP = 'NOTIFICATIONS_UPDATE_NOOP';
@ -31,13 +32,6 @@ const fetchRelatedRelationships = (dispatch, notifications) => {
} }
}; };
const unescapeHTML = (html) => {
const wrapper = document.createElement('div');
html = html.replace(/<br \/>|<br>|\n/g, ' ');
wrapper.innerHTML = html;
return wrapper.textContent;
};
export function updateNotifications(notification, intlMessages, intlLocale) { export function updateNotifications(notification, intlMessages, intlLocale) {
return (dispatch, getState) => { return (dispatch, getState) => {
const showInColumn = getState().getIn(['settings', 'notifications', 'shows', notification.type], true); const showInColumn = getState().getIn(['settings', 'notifications', 'shows', notification.type], true);

@ -43,6 +43,7 @@ class DropdownMenu extends React.PureComponent {
componentDidMount () { componentDidMount () {
document.addEventListener('click', this.handleDocumentClick, false); document.addEventListener('click', this.handleDocumentClick, false);
document.addEventListener('touchend', this.handleDocumentClick, listenerOptions); document.addEventListener('touchend', this.handleDocumentClick, listenerOptions);
if (this.focusedItem) this.focusedItem.focus();
this.setState({ mounted: true }); this.setState({ mounted: true });
} }
@ -55,6 +56,46 @@ class DropdownMenu extends React.PureComponent {
this.node = c; this.node = c;
} }
setFocusRef = c => {
this.focusedItem = c;
}
handleKeyDown = e => {
const items = Array.from(this.node.getElementsByTagName('a'));
const index = items.indexOf(e.currentTarget);
let element;
switch(e.key) {
case 'Enter':
this.handleClick(e);
break;
case 'ArrowDown':
element = items[index+1];
if (element) {
element.focus();
}
break;
case 'ArrowUp':
element = items[index-1];
if (element) {
element.focus();
}
break;
case 'Home':
element = items[0];
if (element) {
element.focus();
}
break;
case 'End':
element = items[items.length-1];
if (element) {
element.focus();
}
break;
}
}
handleClick = e => { handleClick = e => {
const i = Number(e.currentTarget.getAttribute('data-index')); const i = Number(e.currentTarget.getAttribute('data-index'));
const { action, to } = this.props.items[i]; const { action, to } = this.props.items[i];
@ -79,7 +120,7 @@ class DropdownMenu extends React.PureComponent {
return ( return (
<li className='dropdown-menu__item' key={`${text}-${i}`}> <li className='dropdown-menu__item' key={`${text}-${i}`}>
<a href={href} target='_blank' rel='noopener' role='button' tabIndex='0' autoFocus={i === 0} onClick={this.handleClick} data-index={i}> <a href={href} target='_blank' rel='noopener' role='button' tabIndex='0' ref={i === 0 ? this.setFocusRef : null} onClick={this.handleClick} onKeyDown={this.handleKeyDown} data-index={i}>
{text} {text}
</a> </a>
</li> </li>
@ -156,9 +197,6 @@ export default class Dropdown extends React.PureComponent {
handleKeyDown = e => { handleKeyDown = e => {
switch(e.key) { switch(e.key) {
case 'Enter':
this.handleClick(e);
break;
case 'Escape': case 'Escape':
this.handleClose(); this.handleClose();
break; break;

@ -35,7 +35,6 @@ export default class ScrollableList extends PureComponent {
state = { state = {
fullscreen: null, fullscreen: null,
mouseOver: false,
}; };
intersectionObserverWrapper = new IntersectionObserverWrapper(); intersectionObserverWrapper = new IntersectionObserverWrapper();
@ -72,7 +71,7 @@ export default class ScrollableList extends PureComponent {
const someItemInserted = React.Children.count(prevProps.children) > 0 && const someItemInserted = React.Children.count(prevProps.children) > 0 &&
React.Children.count(prevProps.children) < React.Children.count(this.props.children) && React.Children.count(prevProps.children) < React.Children.count(this.props.children) &&
this.getFirstChildKey(prevProps) !== this.getFirstChildKey(this.props); this.getFirstChildKey(prevProps) !== this.getFirstChildKey(this.props);
if (someItemInserted && this.node.scrollTop > 0 || (this.state.mouseOver && !prevProps.isLoading)) { if (someItemInserted && this.node.scrollTop > 0) {
return this.node.scrollHeight - this.node.scrollTop; return this.node.scrollHeight - this.node.scrollTop;
} else { } else {
return null; return null;
@ -140,14 +139,6 @@ export default class ScrollableList extends PureComponent {
this.props.onLoadMore(); this.props.onLoadMore();
} }
handleMouseEnter = () => {
this.setState({ mouseOver: true });
}
handleMouseLeave = () => {
this.setState({ mouseOver: false });
}
render () { render () {
const { children, scrollKey, trackScroll, shouldUpdateScroll, isLoading, hasMore, prepend, emptyMessage, onLoadMore } = this.props; const { children, scrollKey, trackScroll, shouldUpdateScroll, isLoading, hasMore, prepend, emptyMessage, onLoadMore } = this.props;
const { fullscreen } = this.state; const { fullscreen } = this.state;
@ -158,7 +149,7 @@ export default class ScrollableList extends PureComponent {
if (isLoading || childrenCount > 0 || !emptyMessage) { if (isLoading || childrenCount > 0 || !emptyMessage) {
scrollableArea = ( scrollableArea = (
<div className={classNames('scrollable', { fullscreen })} ref={this.setRef} onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave}> <div className={classNames('scrollable', { fullscreen })} ref={this.setRef}>
<div role='feed' className='item-list'> <div role='feed' className='item-list'>
{prepend} {prepend}

@ -206,7 +206,7 @@ export default class Status extends ImmutablePureComponent {
); );
} else { } else {
media = ( media = (
<Bundle fetchComponent={MediaGallery} loading={this.renderLoadingMediaGallery} > <Bundle fetchComponent={MediaGallery} loading={this.renderLoadingMediaGallery}>
{Component => <Component media={status.get('media_attachments')} sensitive={status.get('sensitive')} height={110} onOpenMedia={this.props.onOpenMedia} />} {Component => <Component media={status.get('media_attachments')} sensitive={status.get('sensitive')} height={110} onOpenMedia={this.props.onOpenMedia} />}
</Bundle> </Bundle>
); );

@ -1,18 +0,0 @@
import React from 'react';
import PropTypes from 'prop-types';
import Card from '../features/status/components/card';
import { fromJS } from 'immutable';
export default class CardContainer extends React.PureComponent {
static propTypes = {
locale: PropTypes.string,
card: PropTypes.array.isRequired,
};
render () {
const { card, ...props } = this.props;
return <Card card={fromJS(card)} {...props} />;
}
}

@ -0,0 +1,59 @@
import React, { Fragment } from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
import { IntlProvider, addLocaleData } from 'react-intl';
import { getLocale } from '../locales';
import Card from '../features/status/components/card';
import ModalRoot from '../components/modal_root';
import MediaModal from '../features/ui/components/media_modal';
import { fromJS } from 'immutable';
const { localeData, messages } = getLocale();
addLocaleData(localeData);
export default class CardsContainer extends React.PureComponent {
static propTypes = {
locale: PropTypes.string,
cards: PropTypes.object.isRequired,
};
state = {
media: null,
};
handleOpenCard = (media) => {
document.body.classList.add('card-standalone__body');
this.setState({ media });
}
handleCloseCard = () => {
document.body.classList.remove('card-standalone__body');
this.setState({ media: null });
}
render () {
const { locale, cards } = this.props;
return (
<IntlProvider locale={locale} messages={messages}>
<Fragment>
{[].map.call(cards, container => {
const { card, ...props } = JSON.parse(container.getAttribute('data-props'));
return ReactDOM.createPortal(
<Card card={fromJS(card)} onOpenMedia={this.handleOpenCard} {...props} />,
container,
);
})}
<ModalRoot onClose={this.handleCloseCard}>
{this.state.media && (
<MediaModal media={this.state.media} index={0} onClose={this.handleCloseCard} />
)}
</ModalRoot>
</Fragment>
</IntlProvider>
);
}
}

@ -1,4 +1,5 @@
import React from 'react'; import React, { Fragment } from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux'; import { Provider } from 'react-redux';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import configureStore from '../store/configureStore'; import configureStore from '../store/configureStore';
@ -8,6 +9,7 @@ import { getLocale } from '../locales';
import PublicTimeline from '../features/standalone/public_timeline'; import PublicTimeline from '../features/standalone/public_timeline';
import CommunityTimeline from '../features/standalone/community_timeline'; import CommunityTimeline from '../features/standalone/community_timeline';
import HashtagTimeline from '../features/standalone/hashtag_timeline'; import HashtagTimeline from '../features/standalone/hashtag_timeline';
import ModalContainer from '../features/ui/containers/modal_container';
import initialState from '../initial_state'; import initialState from '../initial_state';
const { localeData, messages } = getLocale(); const { localeData, messages } = getLocale();
@ -47,7 +49,13 @@ export default class TimelineContainer extends React.PureComponent {
return ( return (
<IntlProvider locale={locale} messages={messages}> <IntlProvider locale={locale} messages={messages}>
<Provider store={store}> <Provider store={store}>
<Fragment>
{timeline} {timeline}
{ReactDOM.createPortal(
<ModalContainer />,
document.getElementById('modal-container'),
)}
</Fragment>
</Provider> </Provider>
</IntlProvider> </IntlProvider>
); );

@ -131,6 +131,7 @@ export default class Header extends ImmutablePureComponent {
const content = { __html: account.get('note_emojified') }; const content = { __html: account.get('note_emojified') };
const displayNameHtml = { __html: account.get('display_name_html') }; const displayNameHtml = { __html: account.get('display_name_html') };
const fields = account.get('fields'); const fields = account.get('fields');
const badge = account.get('bot') ? (<div className='roles'><div className='account-role bot'><FormattedMessage id='account.badges.bot' defaultMessage='Bot' /></div></div>) : null;
return ( return (
<div className={classNames('account__header', { inactive: !!account.get('moved') })} style={{ backgroundImage: `url(${account.get('header')})` }}> <div className={classNames('account__header', { inactive: !!account.get('moved') })} style={{ backgroundImage: `url(${account.get('header')})` }}>
@ -139,19 +140,20 @@ export default class Header extends ImmutablePureComponent {
<span className='account__header__display-name' dangerouslySetInnerHTML={displayNameHtml} /> <span className='account__header__display-name' dangerouslySetInnerHTML={displayNameHtml} />
<span className='account__header__username'>@{account.get('acct')} {lockedIcon}</span> <span className='account__header__username'>@{account.get('acct')} {lockedIcon}</span>
{badge}
<div className='account__header__content' dangerouslySetInnerHTML={content} /> <div className='account__header__content' dangerouslySetInnerHTML={content} />
{fields.size > 0 && ( {fields.size > 0 && (
<table className='account__header__fields'> <div className='account__header__fields'>
<tbody>
{fields.map((pair, i) => ( {fields.map((pair, i) => (
<tr key={i}> <dl key={i}>
<th dangerouslySetInnerHTML={{ __html: pair.get('name_emojified') }} /> <dt dangerouslySetInnerHTML={{ __html: pair.get('name_emojified') }} title={pair.get('name')} />
<td dangerouslySetInnerHTML={{ __html: pair.get('value_emojified') }} /> <dd dangerouslySetInnerHTML={{ __html: pair.get('value_emojified') }} title={pair.get('value_plain')} />
</tr> </dl>
))} ))}
</tbody> </div>
</table>
)} )}
{info} {info}

@ -42,10 +42,53 @@ class PrivacyDropdownMenu extends React.PureComponent {
} }
} }
handleClick = e => { handleKeyDown = e => {
if (e.key === 'Escape') { const { items } = this.props;
const value = e.currentTarget.getAttribute('data-index');
const index = items.findIndex(item => {
return (item.value === value);
});
let element;
switch(e.key) {
case 'Escape':
this.props.onClose(); this.props.onClose();
} else if (!e.key || e.key === 'Enter') { break;
case 'Enter':
this.handleClick(e);
break;
case 'ArrowDown':
element = this.node.childNodes[index + 1];
if (element) {
element.focus();
this.props.onChange(element.getAttribute('data-index'));
}
break;
case 'ArrowUp':
element = this.node.childNodes[index - 1];
if (element) {
element.focus();
this.props.onChange(element.getAttribute('data-index'));
}
break;
case 'Home':
element = this.node.firstChild;
if (element) {
element.focus();
this.props.onChange(element.getAttribute('data-index'));
}
break;
case 'End':
element = this.node.lastChild;
if (element) {
element.focus();
this.props.onChange(element.getAttribute('data-index'));
}
break;
}
}
handleClick = e => {
const value = e.currentTarget.getAttribute('data-index'); const value = e.currentTarget.getAttribute('data-index');
e.preventDefault(); e.preventDefault();
@ -53,11 +96,11 @@ class PrivacyDropdownMenu extends React.PureComponent {
this.props.onClose(); this.props.onClose();
this.props.onChange(value); this.props.onChange(value);
} }
}
componentDidMount () { componentDidMount () {
document.addEventListener('click', this.handleDocumentClick, false); document.addEventListener('click', this.handleDocumentClick, false);
document.addEventListener('touchend', this.handleDocumentClick, listenerOptions); document.addEventListener('touchend', this.handleDocumentClick, listenerOptions);
if (this.focusedItem) this.focusedItem.focus();
this.setState({ mounted: true }); this.setState({ mounted: true });
} }
@ -70,6 +113,10 @@ class PrivacyDropdownMenu extends React.PureComponent {
this.node = c; this.node = c;
} }
setFocusRef = c => {
this.focusedItem = c;
}
render () { render () {
const { mounted } = this.state; const { mounted } = this.state;
const { style, items, value } = this.props; const { style, items, value } = this.props;
@ -80,9 +127,9 @@ class PrivacyDropdownMenu extends React.PureComponent {
// It should not be transformed when mounting because the resulting // It should not be transformed when mounting because the resulting
// size will be used to determine the coordinate of the menu by // size will be used to determine the coordinate of the menu by
// react-overlays // react-overlays
<div className='privacy-dropdown__dropdown' style={{ ...style, opacity: opacity, transform: mounted ? `scale(${scaleX}, ${scaleY})` : null }} ref={this.setRef}> <div className='privacy-dropdown__dropdown' style={{ ...style, opacity: opacity, transform: mounted ? `scale(${scaleX}, ${scaleY})` : null }} role='listbox' ref={this.setRef}>
{items.map(item => ( {items.map(item => (
<div role='button' tabIndex='0' key={item.value} data-index={item.value} onKeyDown={this.handleClick} onClick={this.handleClick} className={classNames('privacy-dropdown__option', { active: item.value === value })}> <div role='option' tabIndex='0' key={item.value} data-index={item.value} onKeyDown={this.handleKeyDown} onClick={this.handleClick} className={classNames('privacy-dropdown__option', { active: item.value === value })} aria-selected={item.value === value} ref={item.value === value ? this.setFocusRef : null}>
<div className='privacy-dropdown__option__icon'> <div className='privacy-dropdown__option__icon'>
<i className={`fa fa-fw fa-${item.icon}`} /> <i className={`fa fa-fw fa-${item.icon}`} />
</div> </div>
@ -147,9 +194,6 @@ export default class PrivacyDropdown extends React.PureComponent {
handleKeyDown = e => { handleKeyDown = e => {
switch(e.key) { switch(e.key) {
case 'Enter':
this.handleToggle(e);
break;
case 'Escape': case 'Escape':
this.handleClose(); this.handleClose();
break; break;

@ -43,12 +43,20 @@ export default class Compose extends React.PureComponent {
}; };
componentDidMount () { componentDidMount () {
const { isSearchPage } = this.props;
if (!isSearchPage) {
this.props.dispatch(mountCompose()); this.props.dispatch(mountCompose());
} }
}
componentWillUnmount () { componentWillUnmount () {
const { isSearchPage } = this.props;
if (!isSearchPage) {
this.props.dispatch(unmountCompose()); this.props.dispatch(unmountCompose());
} }
}
onFocus = () => { onFocus = () => {
this.props.dispatch(changeComposing(true)); this.props.dispatch(changeComposing(true));

@ -40,6 +40,17 @@ export default class ModalRoot extends React.PureComponent {
onClose: PropTypes.func.isRequired, onClose: PropTypes.func.isRequired,
}; };
getSnapshotBeforeUpdate () {
const visible = !!this.props.type;
return {
overflowY: visible ? 'hidden' : null,
};
}
componentDidUpdate (prevProps, prevState, { overflowY }) {
document.body.style.overflowY = overflowY;
}
renderLoading = modalId => () => { renderLoading = modalId => () => {
return ['MEDIA', 'VIDEO', 'BOOST', 'CONFIRM', 'ACTIONS'].indexOf(modalId) === -1 ? <ModalLoading /> : null; return ['MEDIA', 'VIDEO', 'BOOST', 'CONFIRM', 'ACTIONS'].indexOf(modalId) === -1 ? <ModalLoading /> : null;
} }

@ -30,7 +30,7 @@ const makeMapStateToProps = () => {
account: getAccount(state, accountId), account: getAccount(state, accountId),
comment: state.getIn(['reports', 'new', 'comment']), comment: state.getIn(['reports', 'new', 'comment']),
forward: state.getIn(['reports', 'new', 'forward']), forward: state.getIn(['reports', 'new', 'forward']),
statusIds: OrderedSet(state.getIn(['timelines', `account:${accountId}`, 'items'])).union(state.getIn(['reports', 'new', 'status_ids'])), statusIds: OrderedSet(state.getIn(['timelines', `account:${accountId}:with_replies`, 'items'])).union(state.getIn(['reports', 'new', 'status_ids'])),
}; };
}; };
@ -64,12 +64,12 @@ export default class ReportModal extends ImmutablePureComponent {
} }
componentDidMount () { componentDidMount () {
this.props.dispatch(expandAccountTimeline(this.props.account.get('id'))); this.props.dispatch(expandAccountTimeline(this.props.account.get('id'), { withReplies: true }));
} }
componentWillReceiveProps (nextProps) { componentWillReceiveProps (nextProps) {
if (this.props.account !== nextProps.account && nextProps.account) { if (this.props.account !== nextProps.account && nextProps.account) {
this.props.dispatch(expandAccountTimeline(nextProps.account.get('id'))); this.props.dispatch(expandAccountTimeline(nextProps.account.get('id'), { withReplies: true }));
} }
} }

@ -21,6 +21,8 @@ const makeGetStatusIds = () => createSelector([
} }
return statusIds.filter(id => { return statusIds.filter(id => {
if (id === null) return true;
const statusForId = statuses.get(id); const statusForId = statuses.get(id);
let showStatus = true; let showStatus = true;

@ -258,7 +258,7 @@
"status.pin": "تدبيس على الملف الشخصي", "status.pin": "تدبيس على الملف الشخصي",
"status.pinned": "تبويق مثبَّت", "status.pinned": "تبويق مثبَّت",
"status.reblog": "رَقِّي", "status.reblog": "رَقِّي",
"status.reblog_private": "Boost to original audience", "status.reblog_private": "القيام بالترقية إلى الجمهور الأصلي",
"status.reblogged_by": "{name} رقى", "status.reblogged_by": "{name} رقى",
"status.reply": "ردّ", "status.reply": "ردّ",
"status.replyAll": "رُد على الخيط", "status.replyAll": "رُد على الخيط",

@ -0,0 +1,296 @@
{
"account.block": "Bluccà @{name}",
"account.block_domain": "Piattà tuttu da {domain}",
"account.blocked": "Bluccatu",
"account.direct": "Missaghju direttu @{name}",
"account.disclaimer_full": "Information below may reflect the user's profile incompletely.",
"account.domain_blocked": "Duminiu piattatu",
"account.edit_profile": "Mudificà u prufile",
"account.follow": "Siguità",
"account.followers": "Abbunati",
"account.follows": "Abbunamenti",
"account.follows_you": "Vi seguita",
"account.hide_reblogs": "Piattà spartere da @{name}",
"account.media": "Media",
"account.mention": "Mintuvà @{name}",
"account.moved_to": "{name} hè partutu nant'à:",
"account.mute": "Piattà @{name}",
"account.mute_notifications": "Piattà nutificazione da @{name}",
"account.muted": "Piattatu",
"account.posts": "Statuti",
"account.posts_with_replies": "Statuti è risposte",
"account.report": "Palisà @{name}",
"account.requested": "In attesa d'apprubazione. Cliccate per annullà a dumanda",
"account.share": "Sparte u prufile di @{name}",
"account.show_reblogs": "Vede spartere da @{name}",
"account.unblock": "Sbluccà @{name}",
"account.unblock_domain": "Ùn piattà più {domain}",
"account.unfollow": "Ùn siguità più",
"account.unmute": "Ùn piattà più @{name}",
"account.unmute_notifications": "Ùn piattà più nutificazione da @{name}",
"account.view_full_profile": "View full profile",
"alert.unexpected.message": "Un prublemu inaspettatu hè accadutu.",
"alert.unexpected.title": "Uups!",
"boost_modal.combo": "Pudete appughjà nant'à {combo} per saltà quessa a prussima volta",
"bundle_column_error.body": "C'hè statu un prublemu caricandu st'elementu.",
"bundle_column_error.retry": "Pruvà torna",
"bundle_column_error.title": "Errore di cunnessione",
"bundle_modal_error.close": "Chjudà",
"bundle_modal_error.message": "C'hè statu un prublemu caricandu st'elementu.",
"bundle_modal_error.retry": "Pruvà torna",
"column.blocks": "Utilizatori bluccati",
"column.community": "Linea pubblica lucale",
"column.direct": "Missaghji diretti",
"column.domain_blocks": "Duminii piattati",
"column.favourites": "Favuriti",
"column.follow_requests": "Dumande d'abbunamentu",
"column.home": "Accolta",
"column.lists": "Liste",
"column.mutes": "Utilizatori piattati",
"column.notifications": "Nutificazione",
"column.pins": "Statuti puntarulati",
"column.public": "Linea pubblica glubale",
"column_back_button.label": "Ritornu",
"column_header.hide_settings": "Piattà i parametri",
"column_header.moveLeft_settings": "Spiazzà à manca",
"column_header.moveRight_settings": "Spiazzà à diritta",
"column_header.pin": "Puntarulà",
"column_header.show_settings": "Mustrà i parametri",
"column_header.unpin": "Spuntarulà",
"column_subheading.navigation": "Navigazione",
"column_subheading.settings": "Parametri",
"compose_form.direct_message_warning": "Solu l'utilizatori mintuvati puderenu vede stu statutu.",
"compose_form.hashtag_warning": "Stu statutu ùn hè \"Micca listatu\" è ùn sarà micca listatu indè e circate da hashtag. Per esse vistu in quesse, u statutu deve esse \"Pubblicu\".",
"compose_form.lock_disclaimer": "U vostru contu ùn hè micca {locked}. Tuttu u mondu pò seguitavi è vede i vostri statuti privati.",
"compose_form.lock_disclaimer.lock": "privatu",
"compose_form.placeholder": "À chè pensate?",
"compose_form.publish": "Toot",
"compose_form.publish_loud": "{publish}!",
"compose_form.sensitive.marked": "Media indicatu cum'è sensibile",
"compose_form.sensitive.unmarked": "Media micca indicatu cum'è sensibile",
"compose_form.spoiler.marked": "Testu piattatu daret'à un'avertimentu",
"compose_form.spoiler.unmarked": "Testu micca piattatu",
"compose_form.spoiler_placeholder": "Scrive u vostr'avertimentu quì",
"confirmation_modal.cancel": "Annullà",
"confirmations.block.confirm": "Bluccà",
"confirmations.block.message": "Site sicuru·a che vulete bluccà @{name}?",
"confirmations.delete.confirm": "Toglie",
"confirmations.delete.message": "Site sicuru·a che vulete supprime stu statutu?",
"confirmations.delete_list.confirm": "Toglie",
"confirmations.delete_list.message": "Site sicuru·a che vulete supprime sta lista?",
"confirmations.domain_block.confirm": "Piattà tuttu u duminiu?",
"confirmations.domain_block.message": "Site sicuru·a che vulete piattà tuttu à {domain}? Saria forse abbastanza di bluccà ò piattà alcuni conti da quallà.",
"confirmations.mute.confirm": "Piattà",
"confirmations.mute.message": "Site sicuru·a che vulete piattà @{name}?",
"confirmations.unfollow.confirm": "Disabbunassi",
"confirmations.unfollow.message": "Site sicuru·a ch'ùn vulete più siguità @{name}?",
"embed.instructions": "Integrà stu statutu à u vostru situ cù u codice quì sottu.",
"embed.preview": "Assumiglierà à qualcosa cusì:",
"emoji_button.activity": "Attività",
"emoji_button.custom": "Persunalizati",
"emoji_button.flags": "Bandere",
"emoji_button.food": "Manghjusca è Bienda",
"emoji_button.label": "Mette un'emoji",
"emoji_button.nature": "Natura",
"emoji_button.not_found": "Ùn c'hè nunda! (╯°□°)╯︵ ┻━┻",
"emoji_button.objects": "Oggetti",
"emoji_button.people": "Parsunaghji",
"emoji_button.recent": "Assai utilizati",
"emoji_button.search": "Cercà...",
"emoji_button.search_results": "Risultati di a cerca",
"emoji_button.symbols": "Simbuli",
"emoji_button.travel": "Lochi è Viaghju",
"empty_column.community": "Ùn c'hè nunda indè a linea lucale. Scrivete puru qualcosa!",
"empty_column.direct": "Ùn avete ancu nisun missaghju direttu. S'è voi mandate o ricevete unu, u vidarete quì.",
"empty_column.hashtag": "Ùn c'hè ancu nunda quì.",
"empty_column.home": "A vostr'accolta hè viota! Pudete andà nant'à {public} o pruvà a ricerca per truvà parsone da siguità.",
"empty_column.home.public_timeline": "a linea pubblica",
"empty_column.list": "Ùn c'hè ancu nunda quì. Quandu membri di sta lista manderanu novi statuti, i vidarete quì.",
"empty_column.notifications": "Ùn avete ancu nisuna nutificazione. Interact with others to start the conversation.",
"empty_column.public": "Ùn c'hè nunda quì! Scrivete qualcosa in pubblicu o seguitate utilizatori d'altre istanze per empie a linea pubblica.",
"follow_request.authorize": "Auturizà",
"follow_request.reject": "Righjittà",
"getting_started.appsshort": "Applicazione",
"getting_started.faq": "FAQ",
"getting_started.heading": "Per principià",
"getting_started.open_source_notice": "Mastodon ghjè un lugiziale liberu. Pudete cuntribuisce à u codice o a traduzione, o palisà un bug, nant'à GitHub: {github}",
"getting_started.userguide": "Guida d'utilizazione",
"home.column_settings.advanced": "Avanzati",
"home.column_settings.basic": "Bàsichi",
"home.column_settings.filter_regex": "Filtrà cù spressione regulare (regex)",
"home.column_settings.show_reblogs": "Vede e spartere",
"home.column_settings.show_replies": "Vede e risposte",
"home.settings": "Parametri di a colonna",
"keyboard_shortcuts.back": "rivultà",
"keyboard_shortcuts.boost": "sparte",
"keyboard_shortcuts.column": "fucalizà un statutu indè una colonna",
"keyboard_shortcuts.compose": "fucalizà nant'à l'area di ridazzione",
"keyboard_shortcuts.description": "Descrizzione",
"keyboard_shortcuts.down": "falà indè a lista",
"keyboard_shortcuts.enter": "apre u statutu",
"keyboard_shortcuts.favourite": "aghjunghje à i favuriti",
"keyboard_shortcuts.heading": "Accorte cù a tastera",
"keyboard_shortcuts.hotkey": "Accorta",
"keyboard_shortcuts.legend": "vede a legenda",
"keyboard_shortcuts.mention": "mintuvà l'autore",
"keyboard_shortcuts.reply": "risponde",
"keyboard_shortcuts.search": "fucalizà nant'à l'area di circata",
"keyboard_shortcuts.toggle_hidden": "vede/piattà u testu daretu à l'avertimentu CW",
"keyboard_shortcuts.toot": "scrive un novu statutu",
"keyboard_shortcuts.unfocus": "ùn fucalizà più l'area di testu",
"keyboard_shortcuts.up": "cullà indè a lista",
"lightbox.close": "Chjudà",
"lightbox.next": "Siguente",
"lightbox.previous": "Pricidente",
"lists.account.add": "Aghjunghje à a lista",
"lists.account.remove": "Toglie di a lista",
"lists.delete": "Supprime a lista",
"lists.edit": "Mudificà a lista",
"lists.new.create": "Aghjustà una lista",
"lists.new.title_placeholder": "Titulu di a lista",
"lists.search": "Circà indè i vostr'abbunamenti",
"lists.subheading": "E vo liste",
"loading_indicator.label": "Caricamentu...",
"media_gallery.toggle_visible": "Cambià a visibilità",
"missing_indicator.label": "Micca trovu",
"missing_indicator.sublabel": "Ùn era micca pussivule di truvà sta risorsa",
"mute_modal.hide_notifications": "Piattà nutificazione da st'utilizatore?",
"navigation_bar.blocks": "Utilizatori bluccati",
"navigation_bar.community_timeline": "Linea pubblica lucale",
"navigation_bar.direct": "Missaghji diretti",
"navigation_bar.domain_blocks": "Duminii piattati",
"navigation_bar.edit_profile": "Mudificà u prufile",
"navigation_bar.favourites": "Favuriti",
"navigation_bar.follow_requests": "Dumande d'abbunamentu",
"navigation_bar.info": "À prupositu di l'istanza",
"navigation_bar.keyboard_shortcuts": "Accorte cù a tastera",
"navigation_bar.lists": "Liste",
"navigation_bar.logout": "Scunnettassi",
"navigation_bar.mutes": "Utilizatori piattati",
"navigation_bar.pins": "Statuti puntarulati",
"navigation_bar.preferences": "Preferenze",
"navigation_bar.public_timeline": "Linea pubblica glubale",
"notification.favourite": "{name} hà aghjuntu u vostru statutu à i so favuriti",
"notification.follow": "{name} v'hà seguitatu",
"notification.mention": "{name} v'hà mintuvatu",
"notification.reblog": "{name} hà spartutu u vostru statutu",
"notifications.clear": "Purgà e nutificazione",
"notifications.clear_confirmation": "Site sicuru·a che vulete toglie tutte ste nutificazione?",
"notifications.column_settings.alert": "Nutificazione nant'à l'urdinatore",
"notifications.column_settings.favourite": "Favuriti:",
"notifications.column_settings.follow": "Abbunati novi:",
"notifications.column_settings.mention": "Minzione:",
"notifications.column_settings.push": "Nutificazione Push",
"notifications.column_settings.push_meta": "Quess'apparechju",
"notifications.column_settings.reblog": "Spartere:",
"notifications.column_settings.show": "Mustrà indè a colonna",
"notifications.column_settings.sound": "Sunà",
"onboarding.done": "Fatta",
"onboarding.next": "Siguente",
"onboarding.page_five.public_timelines": "A linea pubblica lucale mostra statuti pubblichi da tuttu u mondu nant'à {domain}. A linea pubblica glubale mostra ancu quelli di a ghjente seguitata da l'utilizatori di {domain}. Quesse sò una bona manera d'incuntrà nove parsone.",
"onboarding.page_four.home": "A linea d'accolta mostra i statuti di i vostr'abbunamenti.",
"onboarding.page_four.notifications": "A colonna di nutificazione mostra l'interazzione ch'altre parsone anu cù u vostru contu.",
"onboarding.page_one.federation": "Mastodon ghjè una rete di servori independenti, chjamati istanze, uniti indè una sola rete suciale.",
"onboarding.page_one.full_handle": "U vostru identificatore cumplettu",
"onboarding.page_one.handle_hint": "Quessu ghjè cio chì direte à i vostri amichi per circavi.",
"onboarding.page_one.welcome": "Benvenuti/a nant'à Mastodon!",
"onboarding.page_six.admin": "L'amministratore di a vostr'istanza hè {admin}.",
"onboarding.page_six.almost_done": "Quasgi finitu...",
"onboarding.page_six.appetoot": "Bon Appetoot!",
"onboarding.page_six.apps_available": "Ci sò {apps} dispunibule per iOS, Android è altre piattaforme.",
"onboarding.page_six.github": "Mastodon ghjè un lugiziale liberu. Pudete cuntribuisce à u codice o a traduzione, o palisà un prublemu, nant'à {github}.",
"onboarding.page_six.guidelines": "regule di a cumunità",
"onboarding.page_six.read_guidelines": "Ùn vi scurdate di leghje e {guidelines} di {domain}",
"onboarding.page_six.various_app": "applicazione pè u telefuninu",
"onboarding.page_three.profile": "Pudete mudificà u prufile per cambia u ritrattu, a descrizzione è u nome affissatu. Ci sò ancu alcun'altre preferenze.",
"onboarding.page_three.search": "Fate usu di l'area di ricerca per truvà altre persone è vede hashtag cum'è {illustration} o {introductions}. Per vede qualcunu ch'ùn hè micca nant'à st'istanza, cercate u so identificatore complettu (pare un'email).",
"onboarding.page_two.compose": "I statuti è missaghji si scrivenu indè l'area di ridazzione. Pudete caricà imagine, cambià i parametri di pubblicazione, è mette avertimenti di cuntenuti cù i buttoni quì sottu.",
"onboarding.skip": "Passà",
"privacy.change": "Mudificà a cunfidenzialità di u statutu",
"privacy.direct.long": "Mandà solu à quelli chì so mintuvati",
"privacy.direct.short": "Direttu",
"privacy.private.long": "Mustrà solu à l'abbunati",
"privacy.private.short": "Privatu",
"privacy.public.long": "Mustrà à tuttu u mondu nant'a linea pubblica",
"privacy.public.short": "Pubblicu",
"privacy.unlisted.long": "Ùn mette micca nant'a linea pubblica (ma tutt'u mondu pò vede u statutu nant'à u vostru prufile)",
"privacy.unlisted.short": "Micca listatu",
"regeneration_indicator.label": "Caricamentu…",
"regeneration_indicator.sublabel": "Priparazione di a vostra pagina d'accolta",
"relative_time.days": "{number}d",
"relative_time.hours": "{number}h",
"relative_time.just_now": "avà",
"relative_time.minutes": "{number}m",
"relative_time.seconds": "{number}s",
"reply_indicator.cancel": "Annullà",
"report.forward": "Trasferisce à {target}",
"report.forward_hint": "U contu hè nant'à un'altru servore. Vulete ancu mandà una copia anonima di u signalamentu quallà?",
"report.hint": "U signalamentu sarà mandatu à i muderatori di l'istanza. Pudete spiegà perchè avete palisatu stu contu quì sottu:",
"report.placeholder": "Altri cummenti",
"report.submit": "Mandà",
"report.target": "Signalamentu",
"search.placeholder": "Circà",
"search_popout.search_format": "Ricerca avanzata",
"search_popout.tips.full_text": "Simple text returns statuses you have written, favourited, boosted, or have been mentioned in, as well as matching usernames, display names, and hashtags.",
"search_popout.tips.hashtag": "hashtag",
"search_popout.tips.status": "statutu",
"search_popout.tips.text": "Simple text returns matching display names, usernames and hashtags",
"search_popout.tips.user": "utilizatore",
"search_results.accounts": "Ghjente",
"search_results.hashtags": "Hashtags",
"search_results.statuses": "Statuti",
"search_results.total": "{count, number} {count, plural, one {risultatu} other {risultati}}",
"standalone.public_title": "Una vista di...",
"status.block": "Bluccà @{name}",
"status.cancel_reblog_private": "Ùn sparte più",
"status.cannot_reblog": "Stu statutu ùn pò micca esse spartutu",
"status.delete": "Toglie",
"status.direct": "Mandà un missaghju @{name}",
"status.embed": "Integrà",
"status.favourite": "Aghjunghje à i favuriti",
"status.load_more": "Vede di più",
"status.media_hidden": "Media piattata",
"status.mention": "Mintuvà @{name}",
"status.more": "Più",
"status.mute": "Piattà @{name}",
"status.mute_conversation": "Piattà a cunversazione",
"status.open": "Apre stu statutu",
"status.pin": "Puntarulà à u prufile",
"status.pinned": "Statutu puntarulatu",
"status.reblog": "Sparte",
"status.reblog_private": "Sparte à l'audienza uriginale",
"status.reblogged_by": "{name} hà spartutu",
"status.reply": "Risponde",
"status.replyAll": "Risponde à tutti",
"status.report": "Palisà @{name}",
"status.sensitive_toggle": "Cliccate per vede",
"status.sensitive_warning": "Cuntinutu sensibile",
"status.share": "Sparte",
"status.show_less": "Ripiegà",
"status.show_less_all": "Ripiegà tuttu",
"status.show_more": "Slibrà",
"status.show_more_all": "Slibrà tuttu",
"status.unmute_conversation": "Ùn piattà più a cunversazione",
"status.unpin": "Spuntarulà da u prufile",
"tabs_bar.federated_timeline": "Glubale",
"tabs_bar.home": "Accolta",
"tabs_bar.local_timeline": "Lucale",
"tabs_bar.notifications": "Nutificazione",
"tabs_bar.search": "Cercà",
"ui.beforeunload": "A bruttacopia sarà persa s'ellu hè chjosu Mastodon.",
"upload_area.title": "Drag & drop per caricà un fugliale",
"upload_button.label": "Aghjunghje un media",
"upload_form.description": "Discrive per i malvistosi",
"upload_form.focus": "Riquatrà",
"upload_form.undo": "Annullà",
"upload_progress.label": "Caricamentu...",
"video.close": "Chjudà a video",
"video.exit_fullscreen": "Caccià u pienu screnu",
"video.expand": "Ingrandà a video",
"video.fullscreen": "Pienu screnu",
"video.hide": "Piattà a video",
"video.mute": "Surdina",
"video.pause": "Pausa",
"video.play": "Lettura",
"video.unmute": "Caccià a surdina"
}

@ -2,9 +2,9 @@
"account.block": "Απόκλεισε τον/την @{name}", "account.block": "Απόκλεισε τον/την @{name}",
"account.block_domain": "Απόκρυψε τα πάντα από τον/την", "account.block_domain": "Απόκρυψε τα πάντα από τον/την",
"account.blocked": "Αποκλεισμένος/η", "account.blocked": "Αποκλεισμένος/η",
"account.direct": "Απευθείας μήνυμα προς @{name}", "account.direct": "Άμεσο μήνυμα προς @{name}",
"account.disclaimer_full": "Οι παρακάτω πληροφορίες μπορει να μην αντανακλούν το προφίλ του χρήστη επαρκως.", "account.disclaimer_full": "Οι παρακάτω πληροφορίες μπορει να μην αντανακλούν το προφίλ του χρήστη επαρκως.",
"account.domain_blocked": "Domain hidden", "account.domain_blocked": "Κρυμμένος τομέας",
"account.edit_profile": "Επεξεργάσου το προφίλ", "account.edit_profile": "Επεξεργάσου το προφίλ",
"account.follow": "Ακολούθησε", "account.follow": "Ακολούθησε",
"account.followers": "Ακόλουθοι", "account.followers": "Ακόλουθοι",
@ -23,15 +23,15 @@
"account.requested": "Εκκρεμεί έγκριση. Κάνε κλικ για να ακυρώσεις το αίτημα ακολούθησης", "account.requested": "Εκκρεμεί έγκριση. Κάνε κλικ για να ακυρώσεις το αίτημα ακολούθησης",
"account.share": "Μοιράσου το προφίλ του/της @{name}", "account.share": "Μοιράσου το προφίλ του/της @{name}",
"account.show_reblogs": "Δείξε τις προωθήσεις του/της @{name}", "account.show_reblogs": "Δείξε τις προωθήσεις του/της @{name}",
"account.unblock": "Unblock @{name}", "account.unblock": "Ξεμπλόκαρε τον/την @{name}",
"account.unblock_domain": "Αποκάλυψε το {domain}", "account.unblock_domain": "Αποκάλυψε το {domain}",
"account.unfollow": "Unfollow", "account.unfollow": "Διακοπή παρακολούθησης",
"account.unmute": "Unmute @{name}", "account.unmute": "Διακοπή αποσιώπησης του/της @{name}",
"account.unmute_notifications": "Unmute notifications from @{name}", "account.unmute_notifications": "Διακοπή αποσιώπησης ειδοποιήσεων του/της @{name}",
"account.view_full_profile": "Δες το πλήρες προφίλ", "account.view_full_profile": "Δες το πλήρες προφίλ",
"alert.unexpected.message": "Προέκυψε απροσδόκητο σφάλμα.", "alert.unexpected.message": "Προέκυψε απροσδόκητο σφάλμα.",
"alert.unexpected.title": "Εεπ!", "alert.unexpected.title": "Εεπ!",
"boost_modal.combo": "You can press {combo} to skip this next time", "boost_modal.combo": "Μπορείς να πατήσεις {combo} για να το προσπεράσεις αυτό την επόμενη φορά",
"bundle_column_error.body": "Κάτι πήγε στραβά ενώ φορτωνόταν αυτό το στοιχείο.", "bundle_column_error.body": "Κάτι πήγε στραβά ενώ φορτωνόταν αυτό το στοιχείο.",
"bundle_column_error.retry": "Δοκίμασε ξανά", "bundle_column_error.retry": "Δοκίμασε ξανά",
"bundle_column_error.title": "Σφάλμα δικτύου", "bundle_column_error.title": "Σφάλμα δικτύου",
@ -41,7 +41,7 @@
"column.blocks": "Αποκλεισμένοι χρήστες", "column.blocks": "Αποκλεισμένοι χρήστες",
"column.community": "Τοπική ροή", "column.community": "Τοπική ροή",
"column.direct": "Απευθείας μηνύματα", "column.direct": "Απευθείας μηνύματα",
"column.domain_blocks": "Hidden domains", "column.domain_blocks": "Κρυμμένοι τομείς",
"column.favourites": "Αγαπημένα", "column.favourites": "Αγαπημένα",
"column.follow_requests": "Αιτήματα παρακολούθησης", "column.follow_requests": "Αιτήματα παρακολούθησης",
"column.home": "Αρχική", "column.home": "Αρχική",
@ -60,7 +60,7 @@
"column_subheading.navigation": "Πλοήγηση", "column_subheading.navigation": "Πλοήγηση",
"column_subheading.settings": "Ρυθμίσεις", "column_subheading.settings": "Ρυθμίσεις",
"compose_form.direct_message_warning": "Αυτό το τουτ θα εμφανίζεται μόνο σε όλους τους αναφερόμενους χρήστες.", "compose_form.direct_message_warning": "Αυτό το τουτ θα εμφανίζεται μόνο σε όλους τους αναφερόμενους χρήστες.",
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.", "compose_form.hashtag_warning": "Αυτό το τουτ δεν θα εμφανίζεται κάτω από καμία ταμπέλα καθώς είναι αφανές. Μόνο τα δημόσια τουτ μπορούν να αναζητηθούν ανά ταμπέλα.",
"compose_form.lock_disclaimer": "Ο λογαριασμός σου δεν είναι {locked}. Οποιοσδήποτε μπορεί να σε ακολουθήσει για να δει τις δημοσιεύσεις σας προς τους ακολούθους σας.", "compose_form.lock_disclaimer": "Ο λογαριασμός σου δεν είναι {locked}. Οποιοσδήποτε μπορεί να σε ακολουθήσει για να δει τις δημοσιεύσεις σας προς τους ακολούθους σας.",
"compose_form.lock_disclaimer.lock": "κλειδωμένος", "compose_form.lock_disclaimer.lock": "κλειδωμένος",
"compose_form.placeholder": "Τι σκέφτεσαι;", "compose_form.placeholder": "Τι σκέφτεσαι;",
@ -78,65 +78,65 @@
"confirmations.delete.message": "Σίγουρα θες να διαγράψεις αυτή την κατάσταση;", "confirmations.delete.message": "Σίγουρα θες να διαγράψεις αυτή την κατάσταση;",
"confirmations.delete_list.confirm": "Διέγραψε", "confirmations.delete_list.confirm": "Διέγραψε",
"confirmations.delete_list.message": "Σίγουρα θες να διαγράψεις οριστικά αυτή τη λίστα;", "confirmations.delete_list.message": "Σίγουρα θες να διαγράψεις οριστικά αυτή τη λίστα;",
"confirmations.domain_block.confirm": "Hide entire domain", "confirmations.domain_block.confirm": "Απόκρυψη ολόκληρου του τομέα",
"confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.", "confirmations.domain_block.message": "Σίγουρα θες να μπλοκάρεις ολόκληρο το {domain}; Συνήθως μερικά εστιασμένα μπλοκ ή αποσιωπήσεις επαρκούν και προτιμούνται.",
"confirmations.mute.confirm": "Mute", "confirmations.mute.confirm": "Αποσιώπηση",
"confirmations.mute.message": "Are you sure you want to mute {name}?", "confirmations.mute.message": "Σίγουρα θες να αποσιωπήσεις τον/την {name};",
"confirmations.unfollow.confirm": "Unfollow", "confirmations.unfollow.confirm": "Διακοπή παρακολούθησης",
"confirmations.unfollow.message": "Are you sure you want to unfollow {name}?", "confirmations.unfollow.message": "Σίγουρα θες να πάψεις να ακολουθείς τον/την {name};",
"embed.instructions": "Embed this status on your website by copying the code below.", "embed.instructions": "Ενσωματώστε αυτή την κατάσταση στην ιστοσελίδα σας αντιγράφοντας τον παρακάτω κώδικα.",
"embed.preview": "Here is what it will look like:", "embed.preview": "Ορίστε πως θα φαίνεται:",
"emoji_button.activity": "Activity", "emoji_button.activity": "Δραστηριότητα",
"emoji_button.custom": "Custom", "emoji_button.custom": "Προσαρμοσμένα",
"emoji_button.flags": "Flags", "emoji_button.flags": "Σημαίες",
"emoji_button.food": "Food & Drink", "emoji_button.food": "Φαγητά & Ποτά",
"emoji_button.label": "Insert emoji", "emoji_button.label": "Εισάγετε emoji",
"emoji_button.nature": "Nature", "emoji_button.nature": "Φύση",
"emoji_button.not_found": "No emojos!! (╯°□°)╯︵ ┻━┻", "emoji_button.not_found": "Ουδέν emojo!! (╯°□°)╯︵ ┻━┻",
"emoji_button.objects": "Objects", "emoji_button.objects": "Αντικείμενα",
"emoji_button.people": "People", "emoji_button.people": "Άνθρωποι",
"emoji_button.recent": "Frequently used", "emoji_button.recent": "Δημοφιλή",
"emoji_button.search": "Search...", "emoji_button.search": "Αναζήτηση…",
"emoji_button.search_results": "Search results", "emoji_button.search_results": "Αποτελέσματα αναζήτησης",
"emoji_button.symbols": "Symbols", "emoji_button.symbols": "Σύμβολα",
"emoji_button.travel": "Travel & Places", "emoji_button.travel": "Ταξίδια & Τοποθεσίες",
"empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!", "empty_column.community": "Η τοπική ροή είναι κενή. Γράψε κάτι δημόσιο παραμύθι ν' αρχινίσει!",
"empty_column.direct": "You don't have any direct messages yet. When you send or receive one, it will show up here.", "empty_column.direct": "Δεν έχεις απευθείας μηνύματα ακόμα. Όταν στείλεις ή λάβεις κανένα, θα εμφανιστεί εδώ.",
"empty_column.hashtag": "There is nothing in this hashtag yet.", "empty_column.hashtag": "Δεν υπάρχει ακόμα κάτι για αυτή την ταμπέλα.",
"empty_column.home": "Your home timeline is empty! Visit {public} or use search to get started and meet other users.", "empty_column.home": "Η τοπική σου ροή είναι κενή! Πήγαινε στο {public} ή κάνε αναζήτηση για να ξεκινήσεις και να γνωρίσεις άλλους χρήστες.",
"empty_column.home.public_timeline": "the public timeline", "empty_column.home.public_timeline": "η δημόσια ροή",
"empty_column.list": "There is nothing in this list yet. When members of this list post new statuses, they will appear here.", "empty_column.list": "Δεν υπάρχει τίποτα σε αυτή τη λίστα ακόμα. Όταν τα μέλη της δημοσιεύσουν νέες καταστάσεις, θα εμφανιστούν εδώ",
"empty_column.notifications": "You don't have any notifications yet. Interact with others to start the conversation.", "empty_column.notifications": "Δεν έχεις ειδοποιήσεις ακόμα. Αλληλεπίδρασε με άλλους χρήστες για να ξεκινήσεις την κουβέντα.",
"empty_column.public": "There is nothing here! Write something publicly, or manually follow users from other instances to fill it up", "empty_column.public": "Δεν υπάρχει τίποτα εδώ! Γράψε κάτι δημόσιο, ή ακολούθησε χειροκίνητα χρήστες από άλλα instances για να το γεμίσεις",
"follow_request.authorize": "Authorize", "follow_request.authorize": "Ενέκρινε",
"follow_request.reject": "Reject", "follow_request.reject": "Απέρριψε",
"getting_started.appsshort": "Apps", "getting_started.appsshort": "Εφαρμογές",
"getting_started.faq": "FAQ", "getting_started.faq": "FAQ",
"getting_started.heading": "Getting started", "getting_started.heading": "Ξεκινώντας",
"getting_started.open_source_notice": "Mastodon is open source software. You can contribute or report issues on GitHub at {github}.", "getting_started.open_source_notice": "Το Mastodon είναι ελεύθερο λογισμικό. Μπορείς να συνεισφέρεις ή να αναφέρεις ζητήματα στο GitHub στο {github}.",
"getting_started.userguide": "User Guide", "getting_started.userguide": "Οδηγός Χρηστών",
"home.column_settings.advanced": "Advanced", "home.column_settings.advanced": "Προχωρημένα",
"home.column_settings.basic": "Basic", "home.column_settings.basic": "Βασικά",
"home.column_settings.filter_regex": "Filter out by regular expressions", "home.column_settings.filter_regex": "Φιλτράρετε μέσω regular expressions",
"home.column_settings.show_reblogs": "Show boosts", "home.column_settings.show_reblogs": "Εμφάνιση προωθήσεων",
"home.column_settings.show_replies": "Show replies", "home.column_settings.show_replies": "Εμφάνιση απαντήσεων",
"home.settings": "Column settings", "home.settings": "Ρυθμίσεις στηλών",
"keyboard_shortcuts.back": "to navigate back", "keyboard_shortcuts.back": "για επιστροφή πίσω",
"keyboard_shortcuts.boost": "to boost", "keyboard_shortcuts.boost": "για προώθηση",
"keyboard_shortcuts.column": "to focus a status in one of the columns", "keyboard_shortcuts.column": "για εστίαση μιας κατάστασης σε μια από τις στήλες",
"keyboard_shortcuts.compose": "to focus the compose textarea", "keyboard_shortcuts.compose": "για εστίαση στην περιοχή κειμένου συγγραφής",
"keyboard_shortcuts.description": "Description", "keyboard_shortcuts.description": "Description",
"keyboard_shortcuts.down": "to move down in the list", "keyboard_shortcuts.down": "για κίνηση προς τα κάτω στη λίστα",
"keyboard_shortcuts.enter": "to open status", "keyboard_shortcuts.enter": "to open status",
"keyboard_shortcuts.favourite": "to favourite", "keyboard_shortcuts.favourite": "για σημείωση αγαπημένου",
"keyboard_shortcuts.heading": "Keyboard Shortcuts", "keyboard_shortcuts.heading": "Keyboard Shortcuts",
"keyboard_shortcuts.hotkey": "Hotkey", "keyboard_shortcuts.hotkey": "Συντόμευση",
"keyboard_shortcuts.legend": "to display this legend", "keyboard_shortcuts.legend": "για να εμφανίσεις αυτόν τον οδηγό",
"keyboard_shortcuts.mention": "to mention author", "keyboard_shortcuts.mention": "για να αναφέρεις το συγγραφέα",
"keyboard_shortcuts.reply": "to reply", "keyboard_shortcuts.reply": "για απάντηση",
"keyboard_shortcuts.search": "to focus search", "keyboard_shortcuts.search": "για εστίαση αναζήτησης",
"keyboard_shortcuts.toggle_hidden": "to show/hide text behind CW", "keyboard_shortcuts.toggle_hidden": "για εμφάνιση/απόκρυψη κειμένου πίσω από την προειδοποίηση",
"keyboard_shortcuts.toot": "to start a brand new toot", "keyboard_shortcuts.toot": "για δημιουργία ολοκαίνουριου τουτ",
"keyboard_shortcuts.unfocus": "to un-focus compose textarea/search", "keyboard_shortcuts.unfocus": "to un-focus compose textarea/search",
"keyboard_shortcuts.up": "to move up in the list", "keyboard_shortcuts.up": "to move up in the list",
"lightbox.close": "Close", "lightbox.close": "Close",

@ -2,7 +2,7 @@
"account.block": "Bloki @{name}", "account.block": "Bloki @{name}",
"account.block_domain": "Kaŝi ĉion de {domain}", "account.block_domain": "Kaŝi ĉion de {domain}",
"account.blocked": "Blokita", "account.blocked": "Blokita",
"account.direct": "Direct message @{name}", "account.direct": "Rekte mesaĝi @{name}",
"account.disclaimer_full": "Subaj informoj povas reflekti la profilon de la uzanto nekomplete.", "account.disclaimer_full": "Subaj informoj povas reflekti la profilon de la uzanto nekomplete.",
"account.domain_blocked": "Domajno kaŝita", "account.domain_blocked": "Domajno kaŝita",
"account.edit_profile": "Redakti profilon", "account.edit_profile": "Redakti profilon",
@ -29,8 +29,8 @@
"account.unmute": "Malsilentigi @{name}", "account.unmute": "Malsilentigi @{name}",
"account.unmute_notifications": "Malsilentigi sciigojn de @{name}", "account.unmute_notifications": "Malsilentigi sciigojn de @{name}",
"account.view_full_profile": "Vidi plenan profilon", "account.view_full_profile": "Vidi plenan profilon",
"alert.unexpected.message": "An unexpected error occurred.", "alert.unexpected.message": "Neatendita eraro okazis.",
"alert.unexpected.title": "Oops!", "alert.unexpected.title": "Ups!",
"boost_modal.combo": "Vi povas premi {combo} por preterpasi sekvafoje", "boost_modal.combo": "Vi povas premi {combo} por preterpasi sekvafoje",
"bundle_column_error.body": "Io misfunkciis en la ŝargado de ĉi tiu elemento.", "bundle_column_error.body": "Io misfunkciis en la ŝargado de ĉi tiu elemento.",
"bundle_column_error.retry": "Bonvolu reprovi", "bundle_column_error.retry": "Bonvolu reprovi",
@ -40,8 +40,8 @@
"bundle_modal_error.retry": "Bonvolu reprovi", "bundle_modal_error.retry": "Bonvolu reprovi",
"column.blocks": "Blokitaj uzantoj", "column.blocks": "Blokitaj uzantoj",
"column.community": "Loka tempolinio", "column.community": "Loka tempolinio",
"column.direct": "Direct messages", "column.direct": "Rektaj mesaĝoj",
"column.domain_blocks": "Hidden domains", "column.domain_blocks": "Kaŝitaj domajnoj",
"column.favourites": "Stelumoj", "column.favourites": "Stelumoj",
"column.follow_requests": "Petoj de sekvado", "column.follow_requests": "Petoj de sekvado",
"column.home": "Hejmo", "column.home": "Hejmo",
@ -59,7 +59,7 @@
"column_header.unpin": "Depingli", "column_header.unpin": "Depingli",
"column_subheading.navigation": "Navigado", "column_subheading.navigation": "Navigado",
"column_subheading.settings": "Agordado", "column_subheading.settings": "Agordado",
"compose_form.direct_message_warning": "This toot will only be visible to all the mentioned users.", "compose_form.direct_message_warning": "Tiu mesaĝo videblos nur por ĉiuj menciitaj uzantoj.",
"compose_form.hashtag_warning": "Ĉi tiu mesaĝo ne estos listigita per ajna kradvorto. Nur publikaj mesaĝoj estas serĉeblaj per kradvortoj.", "compose_form.hashtag_warning": "Ĉi tiu mesaĝo ne estos listigita per ajna kradvorto. Nur publikaj mesaĝoj estas serĉeblaj per kradvortoj.",
"compose_form.lock_disclaimer": "Via konta ne estas {locked}. Iu ajn povas sekvi vin por vidi viajn mesaĝojn, kiuj estas nur por sekvantoj.", "compose_form.lock_disclaimer": "Via konta ne estas {locked}. Iu ajn povas sekvi vin por vidi viajn mesaĝojn, kiuj estas nur por sekvantoj.",
"compose_form.lock_disclaimer.lock": "ŝlosita", "compose_form.lock_disclaimer.lock": "ŝlosita",
@ -101,7 +101,7 @@
"emoji_button.symbols": "Simboloj", "emoji_button.symbols": "Simboloj",
"emoji_button.travel": "Vojaĝoj kaj lokoj", "emoji_button.travel": "Vojaĝoj kaj lokoj",
"empty_column.community": "La loka tempolinio estas malplena. Skribu ion por plenigi ĝin!", "empty_column.community": "La loka tempolinio estas malplena. Skribu ion por plenigi ĝin!",
"empty_column.direct": "You don't have any direct messages yet. When you send or receive one, it will show up here.", "empty_column.direct": "Vi ankoraŭ ne havas rektan mesaĝon. Kiam vi sendos aŭ ricevos iun, ĝi aperos ĉi tie.",
"empty_column.hashtag": "Ankoraŭ estas nenio per ĉi tiu kradvorto.", "empty_column.hashtag": "Ankoraŭ estas nenio per ĉi tiu kradvorto.",
"empty_column.home": "Via hejma tempolinio estas malplena! Vizitu {public} aŭ uzu la serĉilon por renkonti aliajn uzantojn.", "empty_column.home": "Via hejma tempolinio estas malplena! Vizitu {public} aŭ uzu la serĉilon por renkonti aliajn uzantojn.",
"empty_column.home.public_timeline": "la publikan tempolinion", "empty_column.home.public_timeline": "la publikan tempolinion",
@ -135,7 +135,7 @@
"keyboard_shortcuts.mention": "por mencii la aŭtoron", "keyboard_shortcuts.mention": "por mencii la aŭtoron",
"keyboard_shortcuts.reply": "por respondi", "keyboard_shortcuts.reply": "por respondi",
"keyboard_shortcuts.search": "por fokusigi la serĉilon", "keyboard_shortcuts.search": "por fokusigi la serĉilon",
"keyboard_shortcuts.toggle_hidden": "to show/hide text behind CW", "keyboard_shortcuts.toggle_hidden": "por montri/kaŝi tekston malantaŭ enhava averto",
"keyboard_shortcuts.toot": "por komenci tute novan mesaĝon", "keyboard_shortcuts.toot": "por komenci tute novan mesaĝon",
"keyboard_shortcuts.unfocus": "por malfokusigi la tekstujon aŭ la serĉilon", "keyboard_shortcuts.unfocus": "por malfokusigi la tekstujon aŭ la serĉilon",
"keyboard_shortcuts.up": "por iri supren en la listo", "keyboard_shortcuts.up": "por iri supren en la listo",
@ -157,8 +157,8 @@
"mute_modal.hide_notifications": "Ĉu vi volas kaŝi la sciigojn el ĉi tiu uzanto?", "mute_modal.hide_notifications": "Ĉu vi volas kaŝi la sciigojn el ĉi tiu uzanto?",
"navigation_bar.blocks": "Blokitaj uzantoj", "navigation_bar.blocks": "Blokitaj uzantoj",
"navigation_bar.community_timeline": "Loka tempolinio", "navigation_bar.community_timeline": "Loka tempolinio",
"navigation_bar.direct": "Direct messages", "navigation_bar.direct": "Rektaj mesaĝoj",
"navigation_bar.domain_blocks": "Hidden domains", "navigation_bar.domain_blocks": "Kaŝitaj domajnoj",
"navigation_bar.edit_profile": "Redakti profilon", "navigation_bar.edit_profile": "Redakti profilon",
"navigation_bar.favourites": "Stelumoj", "navigation_bar.favourites": "Stelumoj",
"navigation_bar.follow_requests": "Petoj de sekvado", "navigation_bar.follow_requests": "Petoj de sekvado",
@ -242,10 +242,10 @@
"search_results.total": "{count, number} {count, plural, one {rezulto} other {rezultoj}}", "search_results.total": "{count, number} {count, plural, one {rezulto} other {rezultoj}}",
"standalone.public_title": "Enrigardo…", "standalone.public_title": "Enrigardo…",
"status.block": "Bloki @{name}", "status.block": "Bloki @{name}",
"status.cancel_reblog_private": "Unboost", "status.cancel_reblog_private": "Eksdiskonigi",
"status.cannot_reblog": "Ĉi tiu mesaĝo ne diskonigeblas", "status.cannot_reblog": "Ĉi tiu mesaĝo ne diskonigeblas",
"status.delete": "Forigi", "status.delete": "Forigi",
"status.direct": "Direct message @{name}", "status.direct": "Rekte mesaĝi @{name}",
"status.embed": "Enkorpigi", "status.embed": "Enkorpigi",
"status.favourite": "Stelumi", "status.favourite": "Stelumi",
"status.load_more": "Ŝargi pli", "status.load_more": "Ŝargi pli",
@ -258,7 +258,7 @@
"status.pin": "Alpingli profile", "status.pin": "Alpingli profile",
"status.pinned": "Alpinglita mesaĝo", "status.pinned": "Alpinglita mesaĝo",
"status.reblog": "Diskonigi", "status.reblog": "Diskonigi",
"status.reblog_private": "Boost to original audience", "status.reblog_private": "Diskonigi al la originala atentaro",
"status.reblogged_by": "{name} diskonigis", "status.reblogged_by": "{name} diskonigis",
"status.reply": "Respondi", "status.reply": "Respondi",
"status.replyAll": "Respondi al la fadeno", "status.replyAll": "Respondi al la fadeno",
@ -276,7 +276,7 @@
"tabs_bar.home": "Hejmo", "tabs_bar.home": "Hejmo",
"tabs_bar.local_timeline": "Loka tempolinio", "tabs_bar.local_timeline": "Loka tempolinio",
"tabs_bar.notifications": "Sciigoj", "tabs_bar.notifications": "Sciigoj",
"tabs_bar.search": "Search", "tabs_bar.search": "Serĉi",
"ui.beforeunload": "Via malneto perdiĝos se vi eliras de Mastodon.", "ui.beforeunload": "Via malneto perdiĝos se vi eliras de Mastodon.",
"upload_area.title": "Altreni kaj lasi por alŝuti", "upload_area.title": "Altreni kaj lasi por alŝuti",
"upload_button.label": "Aldoni aŭdovidaĵon", "upload_button.label": "Aldoni aŭdovidaĵon",

@ -13,7 +13,7 @@
"account.hide_reblogs": "Masquer les partages de @{name}", "account.hide_reblogs": "Masquer les partages de @{name}",
"account.media": "Média", "account.media": "Média",
"account.mention": "Mentionner", "account.mention": "Mentionner",
"account.moved_to": "{name} a déménagé vers :", "account.moved_to": "{name} a déménagé vers:",
"account.mute": "Masquer @{name}", "account.mute": "Masquer @{name}",
"account.mute_notifications": "Ignorer les notifications de @{name}", "account.mute_notifications": "Ignorer les notifications de @{name}",
"account.muted": "Silencé", "account.muted": "Silencé",
@ -30,7 +30,7 @@
"account.unmute_notifications": "Réactiver les notifications de @{name}", "account.unmute_notifications": "Réactiver les notifications de @{name}",
"account.view_full_profile": "Afficher le profil complet", "account.view_full_profile": "Afficher le profil complet",
"alert.unexpected.message": "Une erreur non-attendue s'est produite.", "alert.unexpected.message": "Une erreur non-attendue s'est produite.",
"alert.unexpected.title": "Oups !", "alert.unexpected.title": "Oups!",
"boost_modal.combo": "Vous pouvez appuyer sur {combo} pour pouvoir passer ceci, la prochaine fois", "boost_modal.combo": "Vous pouvez appuyer sur {combo} pour pouvoir passer ceci, la prochaine fois",
"bundle_column_error.body": "Une erreur sest produite lors du chargement de ce composant.", "bundle_column_error.body": "Une erreur sest produite lors du chargement de ce composant.",
"bundle_column_error.retry": "Réessayer", "bundle_column_error.retry": "Réessayer",
@ -77,7 +77,7 @@
"confirmations.delete.confirm": "Supprimer", "confirmations.delete.confirm": "Supprimer",
"confirmations.delete.message": "Confirmez-vous la suppression de ce pouet?", "confirmations.delete.message": "Confirmez-vous la suppression de ce pouet?",
"confirmations.delete_list.confirm": "Supprimer", "confirmations.delete_list.confirm": "Supprimer",
"confirmations.delete_list.message": "Êtes-vous sûr de vouloir supprimer définitivement cette liste ?", "confirmations.delete_list.message": "Êtes-vous sûr de vouloir supprimer définitivement cette liste?",
"confirmations.domain_block.confirm": "Masquer le domaine entier", "confirmations.domain_block.confirm": "Masquer le domaine entier",
"confirmations.domain_block.message": "Êtes-vous vraiment, vraiment sûr⋅e de vouloir bloquer {domain} en entier? Dans la plupart des cas, quelques blocages ou masquages ciblés sont suffisants et préférables.", "confirmations.domain_block.message": "Êtes-vous vraiment, vraiment sûr⋅e de vouloir bloquer {domain} en entier? Dans la plupart des cas, quelques blocages ou masquages ciblés sont suffisants et préférables.",
"confirmations.mute.confirm": "Masquer", "confirmations.mute.confirm": "Masquer",
@ -85,14 +85,14 @@
"confirmations.unfollow.confirm": "Ne plus suivre", "confirmations.unfollow.confirm": "Ne plus suivre",
"confirmations.unfollow.message": "Voulez-vous arrêter de suivre {name}?", "confirmations.unfollow.message": "Voulez-vous arrêter de suivre {name}?",
"embed.instructions": "Intégrez ce statut à votre site en copiant le code ci-dessous.", "embed.instructions": "Intégrez ce statut à votre site en copiant le code ci-dessous.",
"embed.preview": "Il apparaîtra comme cela :", "embed.preview": "Il apparaîtra comme cela:",
"emoji_button.activity": "Activités", "emoji_button.activity": "Activités",
"emoji_button.custom": "Personnalisés", "emoji_button.custom": "Personnalisés",
"emoji_button.flags": "Drapeaux", "emoji_button.flags": "Drapeaux",
"emoji_button.food": "Nourriture & Boisson", "emoji_button.food": "Nourriture & Boisson",
"emoji_button.label": "Insérer un émoji", "emoji_button.label": "Insérer un émoji",
"emoji_button.nature": "Nature", "emoji_button.nature": "Nature",
"emoji_button.not_found": "Pas d'emojis !! (╯°□°)╯︵ ┻━┻", "emoji_button.not_found": "Pas d'emojis!! (╯°□°)╯︵ ┻━┻",
"emoji_button.objects": "Objets", "emoji_button.objects": "Objets",
"emoji_button.people": "Personnages", "emoji_button.people": "Personnages",
"emoji_button.recent": "Fréquemment utilisés", "emoji_button.recent": "Fréquemment utilisés",
@ -154,7 +154,7 @@
"media_gallery.toggle_visible": "Modifier la visibilité", "media_gallery.toggle_visible": "Modifier la visibilité",
"missing_indicator.label": "Non trouvé", "missing_indicator.label": "Non trouvé",
"missing_indicator.sublabel": "Ressource introuvable", "missing_indicator.sublabel": "Ressource introuvable",
"mute_modal.hide_notifications": "Masquer les notifications de cette personne ?", "mute_modal.hide_notifications": "Masquer les notifications de cette personne?",
"navigation_bar.blocks": "Comptes bloqués", "navigation_bar.blocks": "Comptes bloqués",
"navigation_bar.community_timeline": "Fil public local", "navigation_bar.community_timeline": "Fil public local",
"navigation_bar.direct": "Messages directs", "navigation_bar.direct": "Messages directs",
@ -177,9 +177,9 @@
"notifications.clear": "Nettoyer les notifications", "notifications.clear": "Nettoyer les notifications",
"notifications.clear_confirmation": "Voulez-vous vraiment supprimer toutes vos notifications?", "notifications.clear_confirmation": "Voulez-vous vraiment supprimer toutes vos notifications?",
"notifications.column_settings.alert": "Notifications locales", "notifications.column_settings.alert": "Notifications locales",
"notifications.column_settings.favourite": "Favoris :", "notifications.column_settings.favourite": "Favoris:",
"notifications.column_settings.follow": "Nouveaux⋅elles abonné⋅e·s :", "notifications.column_settings.follow": "Nouveaux⋅elles abonné⋅e·s:",
"notifications.column_settings.mention": "Mentions :", "notifications.column_settings.mention": "Mentions:",
"notifications.column_settings.push": "Notifications push", "notifications.column_settings.push": "Notifications push",
"notifications.column_settings.push_meta": "Cet appareil", "notifications.column_settings.push_meta": "Cet appareil",
"notifications.column_settings.reblog": "Partages:", "notifications.column_settings.reblog": "Partages:",
@ -216,7 +216,7 @@
"privacy.unlisted.long": "Ne pas afficher dans les fils publics", "privacy.unlisted.long": "Ne pas afficher dans les fils publics",
"privacy.unlisted.short": "Non-listé", "privacy.unlisted.short": "Non-listé",
"regeneration_indicator.label": "Chargement…", "regeneration_indicator.label": "Chargement…",
"regeneration_indicator.sublabel": "Le flux de votre page principale est en cours de préparation !", "regeneration_indicator.sublabel": "Le flux de votre page principale est en cours de préparation!",
"relative_time.days": "{number} j", "relative_time.days": "{number} j",
"relative_time.hours": "{number} h", "relative_time.hours": "{number} h",
"relative_time.just_now": "à linstant", "relative_time.just_now": "à linstant",
@ -224,8 +224,8 @@
"relative_time.seconds": "{number} s", "relative_time.seconds": "{number} s",
"reply_indicator.cancel": "Annuler", "reply_indicator.cancel": "Annuler",
"report.forward": "Transférer à {target}", "report.forward": "Transférer à {target}",
"report.forward_hint": "Le compte provient d'un autre serveur. Envoyez également une copie anonyme du rapport ?", "report.forward_hint": "Le compte provient d'un autre serveur. Envoyez également une copie anonyme du rapport?",
"report.hint": "Le rapport sera envoyé aux modérateurs de votre instance. Vous pouvez expliquer pourquoi vous signalez ce compte ci-dessous :", "report.hint": "Le rapport sera envoyé aux modérateurs de votre instance. Vous pouvez expliquer pourquoi vous signalez ce compte ci-dessous:",
"report.placeholder": "Commentaires additionnels", "report.placeholder": "Commentaires additionnels",
"report.submit": "Envoyer", "report.submit": "Envoyer",
"report.target": "Signalement", "report.target": "Signalement",

@ -110,7 +110,7 @@
"empty_column.public": "I a pas res aquí! Escrivètz quicòm de public, o seguètz de personas dautras instàncias per garnir lo flux public", "empty_column.public": "I a pas res aquí! Escrivètz quicòm de public, o seguètz de personas dautras instàncias per garnir lo flux public",
"follow_request.authorize": "Autorizar", "follow_request.authorize": "Autorizar",
"follow_request.reject": "Regetar", "follow_request.reject": "Regetar",
"getting_started.appsshort": "Apps", "getting_started.appsshort": "Aplicacions",
"getting_started.faq": "FAQ", "getting_started.faq": "FAQ",
"getting_started.heading": "Per començar", "getting_started.heading": "Per començar",
"getting_started.open_source_notice": "Mastodon es un logicial liure. Podètz contribuir e mandar vòstres comentaris e rapòrt de bug via {github} sus GitHub.", "getting_started.open_source_notice": "Mastodon es un logicial liure. Podètz contribuir e mandar vòstres comentaris e rapòrt de bug via {github} sus GitHub.",
@ -158,7 +158,7 @@
"navigation_bar.blocks": "Personas blocadas", "navigation_bar.blocks": "Personas blocadas",
"navigation_bar.community_timeline": "Flux public local", "navigation_bar.community_timeline": "Flux public local",
"navigation_bar.direct": "Messatges dirèctes", "navigation_bar.direct": "Messatges dirèctes",
"navigation_bar.domain_blocks": "Hidden domains", "navigation_bar.domain_blocks": "Domenis amagats",
"navigation_bar.edit_profile": "Modificar lo perfil", "navigation_bar.edit_profile": "Modificar lo perfil",
"navigation_bar.favourites": "Favorits", "navigation_bar.favourites": "Favorits",
"navigation_bar.follow_requests": "Demandas dabonament", "navigation_bar.follow_requests": "Demandas dabonament",

@ -231,7 +231,7 @@
"report.target": "Nahlásenie {target}", "report.target": "Nahlásenie {target}",
"search.placeholder": "Hľadaj", "search.placeholder": "Hľadaj",
"search_popout.search_format": "Pokročilé vyhľadávanie", "search_popout.search_format": "Pokročilé vyhľadávanie",
"search_popout.tips.full_text": "Simple text returns statuses you have written, favourited, boosted, or have been mentioned in, as well as matching usernames, display names, and hashtags.", "search_popout.tips.full_text": "Jednoduchý textový výpis statusov ktoré si napísal/a, ktoré si obľúbil/a, povýšil/a, alebo aj tých, v ktorých si bol/a spomenutý/á, a potom všetky zadaniu odpovedajúce prezívky, mená a haštagy.",
"search_popout.tips.hashtag": "haštag", "search_popout.tips.hashtag": "haštag",
"search_popout.tips.status": "status", "search_popout.tips.status": "status",
"search_popout.tips.text": "Jednoduchý text vráti zhodujúce sa mená, prezývky a hashtagy", "search_popout.tips.text": "Jednoduchý text vráti zhodujúce sa mená, prezývky a hashtagy",

@ -134,7 +134,7 @@ export default function timelines(state = initialState, action) {
initialTimeline, initialTimeline,
map => map.update( map => map.update(
'items', 'items',
items => items.first() ? items : items.unshift(null) items => items.first() ? items.unshift(null) : items
) )
); );
default: default:

@ -0,0 +1,6 @@
export const unescapeHTML = (html) => {
const wrapper = document.createElement('div');
html = html.replace(/<br \/>|<br>|\n/g, ' ');
wrapper.innerHTML = html;
return wrapper.textContent;
};

@ -1,3 +1,5 @@
import EXIF from 'exif-js';
const MAX_IMAGE_DIMENSION = 1280; const MAX_IMAGE_DIMENSION = 1280;
const getImageUrl = inputFile => new Promise((resolve, reject) => { const getImageUrl = inputFile => new Promise((resolve, reject) => {
@ -28,23 +30,62 @@ const loadImage = inputFile => new Promise((resolve, reject) => {
}).catch(reject); }).catch(reject);
}); });
export default inputFile => new Promise((resolve, reject) => { const getOrientation = (img, type = 'image/png') => new Promise(resolve => {
if (!inputFile.type.match(/image.*/) || inputFile.type === 'image/gif') { if (type !== 'image/jpeg') {
resolve(inputFile); resolve(1);
return; return;
} }
loadImage(inputFile).then(img => { EXIF.getData(img, () => {
const orientation = EXIF.getTag(img, 'Orientation');
resolve(orientation);
});
});
const processImage = (img, { width, height, orientation, type = 'image/png' }) => new Promise(resolve => {
const canvas = document.createElement('canvas'); const canvas = document.createElement('canvas');
const { width, height } = img; [canvas.width, canvas.height] = orientation < 5 ? [width, height] : [height, width];
let newWidth, newHeight; const context = canvas.getContext('2d');
if (width < MAX_IMAGE_DIMENSION && height < MAX_IMAGE_DIMENSION) { switch (orientation) {
resolve(inputFile); case 2:
return; context.translate(width, 0);
break;
case 3:
context.translate(width, height);
break;
case 4:
context.translate(0, height);
break;
case 5:
context.rotate(0.5 * Math.PI);
context.translate(1, -1);
break;
case 6:
context.rotate(0.5 * Math.PI);
context.translate(0, -height);
break;
case 7:
context.rotate(0.5, Math.PI);
context.translate(width, -height);
break;
case 8:
context.rotate(-0.5, Math.PI);
context.translate(-width, 0);
break;
} }
context.drawImage(img, 0, 0, width, height);
canvas.toBlob(resolve, type);
});
const resizeImage = (img, type = 'image/png') => new Promise((resolve, reject) => {
const { width, height } = img;
let newWidth, newHeight;
if (width > height) { if (width > height) {
newHeight = height * MAX_IMAGE_DIMENSION / width; newHeight = height * MAX_IMAGE_DIMENSION / width;
newWidth = MAX_IMAGE_DIMENSION; newWidth = MAX_IMAGE_DIMENSION;
@ -56,11 +97,31 @@ export default inputFile => new Promise((resolve, reject) => {
newHeight = MAX_IMAGE_DIMENSION; newHeight = MAX_IMAGE_DIMENSION;
} }
canvas.width = newWidth; getOrientation(img, type)
canvas.height = newHeight; .then(orientation => processImage(img, {
width: newWidth,
height: newHeight,
orientation,
type,
}))
.then(resolve)
.catch(reject);
});
export default inputFile => new Promise((resolve, reject) => {
if (!inputFile.type.match(/image.*/) || inputFile.type === 'image/gif') {
resolve(inputFile);
return;
}
canvas.getContext('2d').drawImage(img, 0, 0, newWidth, newHeight); loadImage(inputFile).then(img => {
if (img.width < MAX_IMAGE_DIMENSION && img.height < MAX_IMAGE_DIMENSION) {
resolve(inputFile);
return;
}
canvas.toBlob(resolve, inputFile.type); resizeImage(img, inputFile.type)
.then(resolve)
.catch(() => resolve(inputFile));
}).catch(reject); }).catch(reject);
}); });

@ -7,7 +7,6 @@ function main() {
const { getLocale } = require('../mastodon/locales'); const { getLocale } = require('../mastodon/locales');
const { localeData } = getLocale(); const { localeData } = getLocale();
const VideoContainer = require('../mastodon/containers/video_container').default; const VideoContainer = require('../mastodon/containers/video_container').default;
const CardContainer = require('../mastodon/containers/card_container').default;
const React = require('react'); const React = require('react');
const ReactDOM = require('react-dom'); const ReactDOM = require('react-dom');
@ -57,10 +56,16 @@ function main() {
ReactDOM.render(<VideoContainer locale={locale} {...props} />, content); ReactDOM.render(<VideoContainer locale={locale} {...props} />, content);
}); });
[].forEach.call(document.querySelectorAll('[data-component="Card"]'), (content) => { const cards = document.querySelectorAll('[data-component="Card"]');
const props = JSON.parse(content.getAttribute('data-props'));
ReactDOM.render(<CardContainer locale={locale} {...props} />, content); if (cards.length > 0) {
}); import(/* webpackChunkName: "containers/cards_container" */ '../mastodon/containers/cards_container').then(({ default: CardsContainer }) => {
const content = document.createElement('div');
ReactDOM.render(<CardsContainer locale={locale} cards={cards} />, content);
document.body.appendChild(content);
}).catch(error => console.error(error));
}
const mediaGalleries = document.querySelectorAll('[data-component="MediaGallery"]'); const mediaGalleries = document.querySelectorAll('[data-component="MediaGallery"]');

@ -565,36 +565,41 @@
} }
.account__header__fields { .account__header__fields {
border-collapse: collapse;
padding: 0; padding: 0;
margin: 15px -15px -15px; margin: 15px -15px -15px;
border: 0 none; border: 0 none;
border-top: 1px solid lighten($ui-base-color, 4%); border-top: 1px solid lighten($ui-base-color, 4%);
border-bottom: 1px solid lighten($ui-base-color, 4%); border-bottom: 1px solid lighten($ui-base-color, 4%);
font-size: 14px;
line-height: 20px;
th, dl {
td { display: flex;
padding: 15px;
padding-left: 15px;
border: 0 none;
border-bottom: 1px solid lighten($ui-base-color, 4%); border-bottom: 1px solid lighten($ui-base-color, 4%);
vertical-align: middle;
} }
th { dt,
padding-left: 15px; dd {
font-weight: 500; box-sizing: border-box;
padding: 14px;
text-align: center; text-align: center;
width: 94px; max-height: 48px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
dt {
font-weight: 500;
width: 120px;
flex: 0 0 auto;
color: $secondary-text-color; color: $secondary-text-color;
background: rgba(darken($ui-base-color, 8%), 0.5); background: rgba(darken($ui-base-color, 8%), 0.5);
} }
td { dd {
flex: 1 1 auto;
color: $darker-text-color; color: $darker-text-color;
text-align: center;
width: 100%;
padding-left: 0;
} }
a { a {
@ -608,12 +613,7 @@
} }
} }
tr { dl:last-child {
&:last-child {
th,
td {
border-bottom: 0; border-bottom: 0;
} }
}
}
} }

@ -336,7 +336,8 @@
} }
} }
.simple_form.new_report_note { .simple_form.new_report_note,
.simple_form.new_account_moderation_note {
max-width: 100%; max-width: 100%;
} }

@ -4033,7 +4033,7 @@ a.status-card {
.report-modal__statuses { .report-modal__statuses {
flex: 1 1 auto; flex: 1 1 auto;
min-height: 20vh; min-height: 20vh;
max-height: 40vh; max-height: 80vh;
overflow-y: auto; overflow-y: auto;
overflow-x: hidden; overflow-x: hidden;
@ -5159,38 +5159,45 @@ noscript {
} }
} }
.account__header .roles {
margin-top: 20px;
margin-bottom: 20px;
padding: 0 15px;
}
.account__header .account__header__fields { .account__header .account__header__fields {
font-size: 14px; font-size: 14px;
line-height: 20px; line-height: 20px;
overflow: hidden; overflow: hidden;
border-collapse: collapse;
margin: 20px -10px -20px; margin: 20px -10px -20px;
border-bottom: 0; border-bottom: 0;
tr { dl {
border-top: 1px solid lighten($ui-base-color, 8%); border-top: 1px solid lighten($ui-base-color, 8%);
text-align: center; display: flex;
} }
th, dt,
td { dd {
box-sizing: border-box;
padding: 14px 20px; padding: 14px 20px;
vertical-align: middle; text-align: center;
max-height: 40px; max-height: 48px;
overflow: hidden; overflow: hidden;
white-space: nowrap; white-space: nowrap;
text-overflow: ellipsis; text-overflow: ellipsis;
} }
th { dt {
color: $darker-text-color; color: $darker-text-color;
background: darken($ui-base-color, 4%); background: darken($ui-base-color, 4%);
max-width: 120px; width: 120px;
flex: 0 0 auto;
font-weight: 500; font-weight: 500;
} }
td { dd {
flex: auto; flex: 1 1 auto;
color: $primary-text-color; color: $primary-text-color;
background: $ui-base-color; background: $ui-base-color;
} }

@ -60,6 +60,7 @@
} }
} }
.card-standalone__body,
.media-gallery-standalone__body { .media-gallery-standalone__body {
overflow: hidden; overflow: hidden;
} }

@ -87,6 +87,10 @@ code {
align-items: flex-start; align-items: flex-start;
} }
&.file .label_input {
flex-wrap: nowrap;
}
&.select .label_input { &.select .label_input {
align-items: initial; align-items: initial;
} }

@ -86,6 +86,8 @@ class ActivityPub::TagManager
end end
def local_uri?(uri) def local_uri?(uri)
return false if uri.nil?
uri = Addressable::URI.parse(uri) uri = Addressable::URI.parse(uri)
host = uri.normalized_host host = uri.normalized_host
host = "#{host}:#{uri.port}" if uri.port host = "#{host}:#{uri.port}" if uri.port
@ -99,6 +101,8 @@ class ActivityPub::TagManager
end end
def uri_to_resource(uri, klass) def uri_to_resource(uri, klass)
return if uri.nil?
if local_uri?(uri) if local_uri?(uri)
case klass.name case klass.name
when 'Account' when 'Account'

@ -67,9 +67,17 @@ class Formatter
html.html_safe # rubocop:disable Rails/OutputSafety html.html_safe # rubocop:disable Rails/OutputSafety
end end
def format_field(account, str) def format_display_name(account, **options)
html = encode(account.display_name.presence || account.username)
html = encode_custom_emojis(html, account.emojis) if options[:custom_emojify]
html.html_safe # rubocop:disable Rails/OutputSafety
end
def format_field(account, str, **options)
return reformat(str).html_safe unless account.local? # rubocop:disable Rails/OutputSafety return reformat(str).html_safe unless account.local? # rubocop:disable Rails/OutputSafety
encode_and_link_urls(str, me: true).html_safe # rubocop:disable Rails/OutputSafety html = encode_and_link_urls(str, me: true)
html = encode_custom_emojis(html, account.emojis) if options[:custom_emojify]
html.html_safe # rubocop:disable Rails/OutputSafety
end end
def linkify(text) def linkify(text)

@ -46,7 +46,8 @@ class OStatus::Activity::Creation < OStatus::Activity::Base
visibility: visibility_scope, visibility: visibility_scope,
conversation: find_or_create_conversation, conversation: find_or_create_conversation,
thread: thread? ? find_status(thread.first) || find_activitypub_status(thread.first, thread.second) : nil, thread: thread? ? find_status(thread.first) || find_activitypub_status(thread.first, thread.second) : nil,
media_attachment_ids: media_attachments.map(&:id) media_attachment_ids: media_attachments.map(&:id),
sensitive: sensitive?
) )
save_mentions(status) save_mentions(status)
@ -105,6 +106,11 @@ class OStatus::Activity::Creation < OStatus::Activity::Base
private private
def sensitive?
# OStatus-specific convention (not standard)
@xml.xpath('./xmlns:category', xmlns: OStatus::TagManager::XMLNS).any? { |category| category['term'] == 'nsfw' }
end
def find_or_create_conversation def find_or_create_conversation
uri = @xml.at_xpath('./ostatus:conversation', ostatus: OStatus::TagManager::OS_XMLNS)&.attribute('ref')&.content uri = @xml.at_xpath('./ostatus:conversation', ostatus: OStatus::TagManager::OS_XMLNS)&.attribute('ref')&.content
return if uri.nil? return if uri.nil?

@ -368,6 +368,7 @@ class OStatus::AtomSerializer
append_element(entry, 'link', nil, rel: :enclosure, type: media.file_content_type, length: media.file_file_size, href: full_asset_url(media.file.url(:original, false))) append_element(entry, 'link', nil, rel: :enclosure, type: media.file_content_type, length: media.file_file_size, href: full_asset_url(media.file.url(:original, false)))
end end
append_element(entry, 'category', nil, term: 'nsfw') if status.sensitive? && status.media_attachments.any?
append_element(entry, 'mastodon:scope', status.visibility) append_element(entry, 'mastodon:scope', status.visibility)
status.emojis.each do |emoji| status.emojis.each do |emoji|

@ -51,7 +51,7 @@ class Request
end end
def headers def headers
(@account ? @headers.merge('Signature' => signature) : @headers).without(REQUEST_TARGET) (@account ? @headers.merge('Signature' => signature) : @headers).reverse_merge('Accept-Encoding' => 'gzip').without(REQUEST_TARGET)
end end
private private
@ -100,7 +100,7 @@ class Request
end end
def http_client def http_client
@http_client ||= HTTP.timeout(:per_operation, timeout).follow(max_hops: 2) @http_client ||= HTTP.use(:auto_inflate).timeout(:per_operation, timeout).follow(max_hops: 2)
end end
def use_proxy? def use_proxy?

@ -45,6 +45,7 @@
# moved_to_account_id :bigint(8) # moved_to_account_id :bigint(8)
# featured_collection_url :string # featured_collection_url :string
# fields :jsonb # fields :jsonb
# actor_type :string
# #
class Account < ApplicationRecord class Account < ApplicationRecord
@ -76,6 +77,7 @@ class Account < ApplicationRecord
validates_with UnreservedUsernameValidator, if: -> { local? && will_save_change_to_username? } validates_with UnreservedUsernameValidator, if: -> { local? && will_save_change_to_username? }
validates :display_name, length: { maximum: 30 }, if: -> { local? && will_save_change_to_display_name? } validates :display_name, length: { maximum: 30 }, if: -> { local? && will_save_change_to_display_name? }
validate :note_length_does_not_exceed_length_limit, if: -> { local? && will_save_change_to_note? } validate :note_length_does_not_exceed_length_limit, if: -> { local? && will_save_change_to_note? }
validates :fields, length: { maximum: 4 }, if: -> { local? && will_save_change_to_fields? }
# Timelines # Timelines
has_many :stream_entries, inverse_of: :account, dependent: :destroy has_many :stream_entries, inverse_of: :account, dependent: :destroy
@ -151,6 +153,16 @@ class Account < ApplicationRecord
moved_to_account_id.present? moved_to_account_id.present?
end end
def bot?
%w(Application Service).include? actor_type
end
alias bot bot?
def bot=(val)
self.actor_type = ActiveModel::Type::Boolean.new.cast(val) ? 'Service' : 'Person'
end
def acct def acct
local? ? username : "#{username}@#{domain}" local? ? username : "#{username}@#{domain}"
end end
@ -201,10 +213,12 @@ class Account < ApplicationRecord
def fields_attributes=(attributes) def fields_attributes=(attributes)
fields = [] fields = []
if attributes.is_a?(Hash)
attributes.each_value do |attr| attributes.each_value do |attr|
next if attr[:name].blank? next if attr[:name].blank?
fields << attr fields << attr
end end
end
self[:fields] = fields self[:fields] = fields
end end
@ -272,8 +286,8 @@ class Account < ApplicationRecord
def initialize(account, attr) def initialize(account, attr)
@account = account @account = account
@name = attr['name'] @name = attr['name'].strip[0, 255]
@value = attr['value'] @value = attr['value'].strip[0, 255]
@errors = {} @errors = {}
end end
@ -398,7 +412,7 @@ class Account < ApplicationRecord
end end
def emojis def emojis
@emojis ||= CustomEmoji.from_text(note, domain) @emojis ||= CustomEmoji.from_text(emojifiable_text, domain)
end end
before_create :generate_keys before_create :generate_keys
@ -441,4 +455,8 @@ class Account < ApplicationRecord
self.domain = TagManager.instance.normalize_domain(domain) self.domain = TagManager.instance.normalize_domain(domain)
end end
def emojifiable_text
[note, display_name, fields.map(&:value)].join(' ')
end
end end

@ -41,7 +41,7 @@ class User < ApplicationRecord
include Settings::Extend include Settings::Extend
include Omniauthable include Omniauthable
ACTIVE_DURATION = 14.days ACTIVE_DURATION = 7.days
devise :two_factor_authenticatable, devise :two_factor_authenticatable,
otp_secret_encryption_key: Rails.configuration.x.otp_secret otp_secret_encryption_key: Rails.configuration.x.otp_secret

@ -37,7 +37,7 @@ class ActivityPub::ActorSerializer < ActiveModel::Serializer
end end
def type def type
'Person' object.bot? ? 'Service' : 'Person'
end end
def following def following

@ -5,7 +5,7 @@ class ActivityPub::BlockSerializer < ActiveModel::Serializer
attribute :virtual_object, key: :object attribute :virtual_object, key: :object
def id def id
[ActivityPub::TagManager.instance.uri_for(object.account), '#blocks/', object.id].join ActivityPub::TagManager.instance.uri_for(object) || [ActivityPub::TagManager.instance.uri_for(object.account), '#blocks/', object.id].join
end end
def type def type

@ -5,7 +5,7 @@ class ActivityPub::FollowSerializer < ActiveModel::Serializer
attribute :virtual_object, key: :object attribute :virtual_object, key: :object
def id def id
ActivityPub::TagManager.instance.uri_for(object) ActivityPub::TagManager.instance.uri_for(object) || [ActivityPub::TagManager.instance.uri_for(object.account), '#follows/', object.id].join
end end
def type def type

@ -3,11 +3,12 @@
class REST::AccountSerializer < ActiveModel::Serializer class REST::AccountSerializer < ActiveModel::Serializer
include RoutingHelper include RoutingHelper
attributes :id, :username, :acct, :display_name, :locked, :created_at, attributes :id, :username, :acct, :display_name, :locked, :bot, :created_at,
:note, :url, :avatar, :avatar_static, :header, :header_static, :note, :url, :avatar, :avatar_static, :header, :header_static,
:followers_count, :following_count, :statuses_count :followers_count, :following_count, :statuses_count
has_one :moved_to_account, key: :moved, serializer: REST::AccountSerializer, if: :moved_and_not_nested? has_one :moved_to_account, key: :moved, serializer: REST::AccountSerializer, if: :moved_and_not_nested?
has_many :emojis, serializer: REST::CustomEmojiSerializer
class FieldSerializer < ActiveModel::Serializer class FieldSerializer < ActiveModel::Serializer
attributes :name, :value attributes :name, :value

@ -34,6 +34,7 @@ class ActivityPub::FetchRemoteStatusService < BaseService
end end
def trustworthy_attribution?(uri, attributed_to) def trustworthy_attribution?(uri, attributed_to)
return false if uri.nil? || attributed_to.nil?
Addressable::URI.parse(uri).normalized_host.casecmp(Addressable::URI.parse(attributed_to).normalized_host).zero? Addressable::URI.parse(uri).normalized_host.casecmp(Addressable::URI.parse(attributed_to).normalized_host).zero?
end end

@ -71,6 +71,7 @@ class ActivityPub::ProcessAccountService < BaseService
@account.note = @json['summary'] || '' @account.note = @json['summary'] || ''
@account.locked = @json['manuallyApprovesFollowers'] || false @account.locked = @json['manuallyApprovesFollowers'] || false
@account.fields = property_values || {} @account.fields = property_values || {}
@account.actor_type = actor_type
end end
def set_fetchable_attributes! def set_fetchable_attributes!
@ -95,6 +96,14 @@ class ActivityPub::ProcessAccountService < BaseService
ActivityPub::SynchronizeFeaturedCollectionWorker.perform_async(@account.id) ActivityPub::SynchronizeFeaturedCollectionWorker.perform_async(@account.id)
end end
def actor_type
if @json['type'].is_a?(Array)
@json['type'].find { |type| ActivityPub::FetchRemoteAccountService::SUPPORTED_TYPES.include?(type) }
else
@json['type']
end
end
def image_url(key) def image_url(key)
value = first_of_value(@json[key]) value = first_of_value(@json[key])

@ -45,5 +45,8 @@ class ActivityPub::ProcessCollectionService < BaseService
def verify_account! def verify_account!
@account = ActivityPub::LinkedDataSignature.new(@json).verify_account! @account = ActivityPub::LinkedDataSignature.new(@json).verify_account!
rescue JSON::LD::JsonLdError => e
Rails.logger.debug "Could not verify LD-Signature for #{value_or_id(@json['actor'])}: #{e.message}"
nil
end end
end end

@ -37,7 +37,7 @@ class FanOutOnWriteService < BaseService
def deliver_to_followers(status) def deliver_to_followers(status)
Rails.logger.debug "Delivering status #{status.id} to followers" Rails.logger.debug "Delivering status #{status.id} to followers"
status.account.followers.where(domain: nil).joins(:user).where('users.current_sign_in_at > ?', 14.days.ago).select(:id).reorder(nil).find_in_batches do |followers| status.account.followers.where(domain: nil).joins(:user).where('users.current_sign_in_at > ?', User::ACTIVE_DURATION.ago).select(:id).reorder(nil).find_in_batches do |followers|
FeedInsertWorker.push_bulk(followers) do |follower| FeedInsertWorker.push_bulk(followers) do |follower|
[status.id, follower.id, :home] [status.id, follower.id, :home]
end end
@ -47,7 +47,7 @@ class FanOutOnWriteService < BaseService
def deliver_to_lists(status) def deliver_to_lists(status)
Rails.logger.debug "Delivering status #{status.id} to lists" Rails.logger.debug "Delivering status #{status.id} to lists"
status.account.lists.joins(account: :user).where('users.current_sign_in_at > ?', 14.days.ago).select(:id).reorder(nil).find_in_batches do |lists| status.account.lists.joins(account: :user).where('users.current_sign_in_at > ?', User::ACTIVE_DURATION.ago).select(:id).reorder(nil).find_in_batches do |lists|
FeedInsertWorker.push_bulk(lists) do |list| FeedInsertWorker.push_bulk(lists) do |list|
[status.id, list.id, :list] [status.id, list.id, :list]
end end

@ -27,7 +27,7 @@ class FetchLinkCardService < BaseService
end end
attach_card if @card&.persisted? attach_card if @card&.persisted?
rescue HTTP::Error, Addressable::URI::InvalidURIError => e rescue HTTP::Error, Addressable::URI::InvalidURIError, Mastodon::LengthValidationError => e
Rails.logger.debug "Error fetching link #{@url}: #{e}" Rails.logger.debug "Error fetching link #{@url}: #{e}"
nil nil
end end

@ -31,12 +31,12 @@ class PostStatusService < BaseService
sensitive: (options[:sensitive].nil? ? account.user&.setting_default_sensitive : options[:sensitive]), sensitive: (options[:sensitive].nil? ? account.user&.setting_default_sensitive : options[:sensitive]),
spoiler_text: options[:spoiler_text] || '', spoiler_text: options[:spoiler_text] || '',
visibility: options[:visibility] || account.user&.setting_default_privacy, visibility: options[:visibility] || account.user&.setting_default_privacy,
language: LanguageDetector.instance.detect(text, account), language: language_from_option(options[:language]) || LanguageDetector.instance.detect(text, account),
application: options[:application]) application: options[:application])
end end
process_mentions_service.call(status)
process_hashtags_service.call(status) process_hashtags_service.call(status)
process_mentions_service.call(status)
LinkCrawlWorker.perform_async(status.id) unless status.spoiler_text? LinkCrawlWorker.perform_async(status.id) unless status.spoiler_text?
DistributionWorker.perform_async(status.id) DistributionWorker.perform_async(status.id)
@ -68,6 +68,10 @@ class PostStatusService < BaseService
media media
end end
def language_from_option(str)
ISO_639.find(str)&.alpha2
end
def process_mentions_service def process_mentions_service
ProcessMentionsService.new ProcessMentionsService.new
end end

@ -6,7 +6,7 @@
.account__avatar{ style: "background-image: url(#{@instance_presenter.contact_account.avatar.url})" } .account__avatar{ style: "background-image: url(#{@instance_presenter.contact_account.avatar.url})" }
%span.display-name %span.display-name
%bdi %bdi
%strong.display-name__html.emojify= display_name(@instance_presenter.contact_account) %strong.display-name__html.emojify= display_name(@instance_presenter.contact_account, custom_emojify: true)
%span.display-name__account @#{@instance_presenter.contact_account.acct} %span.display-name__account @#{@instance_presenter.contact_account.acct}
- else - else
.account__display-name .account__display-name

@ -12,7 +12,7 @@
.avatar= image_tag contact.contact_account.avatar.url .avatar= image_tag contact.contact_account.avatar.url
.name .name
= link_to TagManager.instance.url_for(contact.contact_account) do = link_to TagManager.instance.url_for(contact.contact_account) do
%span.display_name.emojify= display_name(contact.contact_account) %span.display_name.emojify= display_name(contact.contact_account, custom_emojify: true)
%span.username @#{contact.contact_account.acct} %span.username @#{contact.contact_account.acct}
- else - else
.owner .owner

@ -141,3 +141,5 @@
%p %p
= link_to t('about.source_code'), @instance_presenter.source_url = link_to t('about.source_code'), @instance_presenter.source_url
= " (#{@instance_presenter.version_number})" = " (#{@instance_presenter.version_number})"
#modal-container

@ -5,7 +5,7 @@
.avatar= image_tag account.avatar.url(:original) .avatar= image_tag account.avatar.url(:original)
.name .name
= link_to TagManager.instance.url_for(account) do = link_to TagManager.instance.url_for(account) do
%span.display_name.emojify= display_name(account) %span.display_name.emojify= display_name(account, custom_emojify: true)
%span.username %span.username
@#{account.local? ? account.local_username_and_domain : account.acct} @#{account.local? ? account.local_username_and_domain : account.acct}
= fa_icon('lock') if account.locked? = fa_icon('lock') if account.locked?

@ -6,11 +6,16 @@
.card__bio .card__bio
%h1.name %h1.name
%span.p-name.emojify= display_name(account) %span.p-name.emojify= display_name(account, custom_emojify: true)
%small< %small<
%span>< @#{account.local_username_and_domain} %span>< @#{account.local_username_and_domain}
= fa_icon('lock') if account.locked? = fa_icon('lock') if account.locked?
- if Setting.show_staff_badge
- if account.bot?
.roles
.account-role.bot
= t 'accounts.roles.bot'
- elsif Setting.show_staff_badge
- if account.user_admin? - if account.user_admin?
.roles .roles
.account-role.admin .account-role.admin
@ -21,19 +26,19 @@
= t 'accounts.roles.moderator' = t 'accounts.roles.moderator'
.bio .bio
.account__header__content.p-note.emojify!=processed_bio[:text] .account__header__content.p-note.emojify!=processed_bio[:text]
- if !account.fields.empty? - if !account.fields.empty?
%table.account__header__fields .account__header__fields
%tbody
- account.fields.each do |field| - account.fields.each do |field|
%tr %dl
%th.emojify= field.name %dt.emojify{ title: field.name }= field.name
%td.emojify= Formatter.instance.format_field(account, field.value) %dd.emojify{ title: field.value }= Formatter.instance.format_field(account, field.value, custom_emojify: true)
- elsif processed_bio[:metadata].length > 0 - elsif processed_bio[:metadata].length > 0
%table.account__header__fields< .account__header__fields
- processed_bio[:metadata].each do |i| - processed_bio[:metadata].each do |i|
%tr %dl
%th.emojify>!=i[0] %dt.emojify{ title: i[0] }= i[0]
%td.emojify>!=i[1] %dd.emojify{ title: i[1] }= i[1]
.details-counters .details-counters
.counter{ class: active_nav_class(short_account_url(account)) } .counter{ class: active_nav_class(short_account_url(account)) }

@ -3,7 +3,7 @@
.moved-strip .moved-strip
.moved-strip__message .moved-strip__message
= fa_icon 'suitcase' = fa_icon 'suitcase'
= t('accounts.moved_html', name: content_tag(:strong, display_name(account), class: :emojify), new_profile_link: link_to(content_tag(:strong, safe_join(['@', content_tag(:span, moved_to_account.acct)])), TagManager.instance.url_for(moved_to_account), class: 'mention')) = t('accounts.moved_html', name: content_tag(:strong, display_name(account, custom_emojify: true), class: :emojify), new_profile_link: link_to(content_tag(:strong, safe_join(['@', content_tag(:span, moved_to_account.acct)])), TagManager.instance.url_for(moved_to_account), class: 'mention'))
.moved-strip__card .moved-strip__card
= link_to TagManager.instance.url_for(moved_to_account), class: 'detailed-status__display-name p-author h-card', target: '_blank', rel: 'noopener' do = link_to TagManager.instance.url_for(moved_to_account), class: 'detailed-status__display-name p-author h-card', target: '_blank', rel: 'noopener' do
@ -13,5 +13,5 @@
.account__avatar-overlay-overlay{ style: "background-image: url('#{account.avatar.url(:original)}')" } .account__avatar-overlay-overlay{ style: "background-image: url('#{account.avatar.url(:original)}')" }
%span.display-name %span.display-name
%strong.emojify= display_name(moved_to_account) %strong.emojify= display_name(moved_to_account, custom_emojify: true)
%span @#{moved_to_account.acct} %span @#{moved_to_account.acct}

@ -1,10 +1,7 @@
%tr .speech-bubble
%td .speech-bubble__bubble
= simple_format(h(account_moderation_note.content)) = simple_format(h(account_moderation_note.content))
%td .speech-bubble__owner
= account_moderation_note.account.acct = admin_account_link_to account_moderation_note.account
%td %time.formatted{ datetime: account_moderation_note.created_at.iso8601 }= l account_moderation_note.created_at
%time.formatted{ datetime: account_moderation_note.created_at.iso8601, title: l(account_moderation_note.created_at) } = table_link_to 'trash', t('admin.account_moderation_notes.delete'), admin_account_moderation_note_path(account_moderation_note), method: :delete if can?(:destroy, account_moderation_note)
= l account_moderation_note.created_at
%td
= link_to t('admin.account_moderation_notes.delete'), admin_account_moderation_note_path(account_moderation_note), method: :delete if can?(:destroy, account_moderation_note)

@ -2,7 +2,7 @@
= @account.acct = @account.acct
.table-wrapper .table-wrapper
%table.table %table.table.inline-table
%tbody %tbody
%tr %tr
%th= t('admin.accounts.username') %th= t('admin.accounts.username')
@ -36,13 +36,19 @@
%th= t('admin.accounts.email') %th= t('admin.accounts.email')
%td %td
= @account.user_email = @account.user_email
- if @account.user_confirmed?
= fa_icon('check')
= table_link_to 'edit', t('admin.accounts.change_email.label'), admin_account_change_email_path(@account.id) if can?(:change_email, @account.user) = table_link_to 'edit', t('admin.accounts.change_email.label'), admin_account_change_email_path(@account.id) if can?(:change_email, @account.user)
- if @account.user_unconfirmed_email.present? - if @account.user_unconfirmed_email.present?
%th= t('admin.accounts.unconfirmed_email') %th= t('admin.accounts.unconfirmed_email')
%td %td
= @account.user_unconfirmed_email = @account.user_unconfirmed_email
%tr
%th= t('admin.accounts.email_status')
%td
- if @account.user&.confirmed?
= t('admin.accounts.confirmed')
- else
= t('admin.accounts.confirming')
= table_link_to 'refresh', t('admin.accounts.resend_confirmation.send'), resend_admin_account_confirmation_path(@account.id), method: :post if can?(:confirm, @account.user)
%tr %tr
%th= t('admin.accounts.login_status') %th= t('admin.accounts.login_status')
%td %td
@ -73,17 +79,17 @@
%tr %tr
%th= t('admin.accounts.follows') %th= t('admin.accounts.follows')
%td= @account.following_count %td= number_to_human @account.following_count
%tr %tr
%th= t('admin.accounts.followers') %th= t('admin.accounts.followers')
%td= @account.followers_count %td= number_to_human @account.followers_count
%tr %tr
%th= t('admin.accounts.statuses') %th= t('admin.accounts.statuses')
%td= link_to @account.statuses_count, admin_account_statuses_path(@account.id) %td= link_to number_to_human(@account.statuses_count), admin_account_statuses_path(@account.id)
%tr %tr
%th= t('admin.accounts.media_attachments') %th= t('admin.accounts.media_attachments')
%td %td
= link_to @account.media_attachments.count, admin_account_statuses_path(@account.id, { media: true }) = link_to number_to_human(@account.media_attachments.count), admin_account_statuses_path(@account.id, { media: true })
= surround '(', ')' do = surround '(', ')' do
= number_to_human_size @account.media_attachments.sum('file_file_size') = number_to_human_size @account.media_attachments.sum('file_file_size')
%tr %tr
@ -120,11 +126,12 @@
= link_to t('admin.accounts.perform_full_suspension'), admin_account_suspension_path(@account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') }, class: 'button' if can?(:suspend, @account) = link_to t('admin.accounts.perform_full_suspension'), admin_account_suspension_path(@account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') }, class: 'button' if can?(:suspend, @account)
- if !@account.local? && @account.hub_url.present? - if !@account.local? && @account.hub_url.present?
%hr %hr.spacer/
%h3 OStatus %h3 OStatus
.table-wrapper .table-wrapper
%table.table %table.table.inline-table
%tbody %tbody
%tr %tr
%th= t('admin.accounts.feed_url') %th= t('admin.accounts.feed_url')
@ -148,11 +155,12 @@
= link_to t('admin.accounts.unsubscribe'), unsubscribe_admin_account_path(@account.id), method: :post, class: 'button negative' if can?(:unsubscribe, @account) = link_to t('admin.accounts.unsubscribe'), unsubscribe_admin_account_path(@account.id), method: :post, class: 'button negative' if can?(:unsubscribe, @account)
- if !@account.local? && @account.inbox_url.present? - if !@account.local? && @account.inbox_url.present?
%hr %hr.spacer/
%h3 ActivityPub %h3 ActivityPub
.table-wrapper .table-wrapper
%table.table %table.table.inline-table
%tbody %tbody
%tr %tr
%th= t('admin.accounts.inbox_url') %th= t('admin.accounts.inbox_url')
@ -167,24 +175,15 @@
%th= t('admin.accounts.followers_url') %th= t('admin.accounts.followers_url')
%td= link_to @account.followers_url, @account.followers_url %td= link_to @account.followers_url, @account.followers_url
%hr %hr.spacer/
%h3= t('admin.accounts.moderation_notes')
= render @moderation_notes
= simple_form_for @account_moderation_note, url: admin_account_moderation_notes_path do |f| = simple_form_for @account_moderation_note, url: admin_account_moderation_notes_path do |f|
= render 'shared/error_messages', object: @account_moderation_note = render 'shared/error_messages', object: @account_moderation_note
= f.input :content = f.input :content, placeholder: t('admin.reports.notes.placeholder'), rows: 6
= f.hidden_field :target_account_id = f.hidden_field :target_account_id
.actions .actions
= f.button :button, t('admin.account_moderation_notes.create'), type: :submit = f.button :button, t('admin.account_moderation_notes.create'), type: :submit
.table-wrapper
%table.table
%thead
%tr
%th
%th= t('admin.account_moderation_notes.account')
%th= t('admin.account_moderation_notes.created_at')
%tbody
= render @moderation_notes

@ -15,5 +15,5 @@
.account__avatar{ style: "background-image: url(#{account.avatar.url}); width: #{size}px; height: #{size}px; background-size: #{size}px #{size}px" } .account__avatar{ style: "background-image: url(#{account.avatar.url}); width: #{size}px; height: #{size}px; background-size: #{size}px #{size}px" }
%span.display-name %span.display-name
%bdi %bdi
%strong.display-name__html.emojify= display_name(account) %strong.display-name__html.emojify= display_name(account, custom_emojify: true)
%span.display-name__account @#{account.acct} %span.display-name__account @#{account.acct}

@ -7,7 +7,7 @@
%p>< %p><
%strong= Formatter.instance.format_spoiler(status) %strong= Formatter.instance.format_spoiler(status)
= Formatter.instance.format(status) = Formatter.instance.format(status, custom_emojify: true)
- unless status.media_attachments.empty? - unless status.media_attachments.empty?
- if status.media_attachments.first.video? - if status.media_attachments.first.video?

@ -1,10 +1,7 @@
- content_for :page_title do - content_for :page_title do
= t('admin.statuses.title') = t('admin.statuses.title')
\-
.back-link = "@#{@account.acct}"
= link_to admin_account_path(@account.id) do
%i.fa.fa-chevron-left.fa-fw
= t('admin.statuses.back_to_account')
.filters .filters
.filter-subset .filter-subset
@ -12,33 +9,26 @@
%ul %ul
%li= link_to t('admin.statuses.no_media'), admin_account_statuses_path(@account.id, current_params.merge(media: nil)), class: !params[:media] && 'selected' %li= link_to t('admin.statuses.no_media'), admin_account_statuses_path(@account.id, current_params.merge(media: nil)), class: !params[:media] && 'selected'
%li= link_to t('admin.statuses.with_media'), admin_account_statuses_path(@account.id, current_params.merge(media: true)), class: params[:media] && 'selected' %li= link_to t('admin.statuses.with_media'), admin_account_statuses_path(@account.id, current_params.merge(media: true)), class: params[:media] && 'selected'
.back-link{ style: 'flex: 1 1 auto; text-align: right' }
= link_to admin_account_path(@account.id) do
%i.fa.fa-chevron-left.fa-fw
= t('admin.statuses.back_to_account')
- if @statuses.empty? %hr.spacer/
.accounts-grid
= render 'accounts/nothing_here' = form_for(@form, url: admin_account_statuses_path(@account.id)) do |f|
- else
= form_for(@form, url: admin_account_statuses_path(@account.id)) do |f|
= hidden_field_tag :page, params[:page] = hidden_field_tag :page, params[:page]
= hidden_field_tag :media, params[:media] = hidden_field_tag :media, params[:media]
.batch-form-box
.batch-checkbox-all .batch-table
.batch-table__toolbar
%label.batch-table__toolbar__select.batch-checkbox-all
= check_box_tag :batch_checkbox_all, nil, false = check_box_tag :batch_checkbox_all, nil, false
= f.select :action, Form::StatusBatch::ACTION_TYPE.map{|action| [t("admin.statuses.batch.#{action}"), action]} .batch-table__toolbar__actions
= f.submit t('admin.statuses.execute'), data: { confirm: t('admin.reports.are_you_sure') }, class: 'button' = f.button safe_join([fa_icon('eye-slash'), t('admin.statuses.batch.nsfw_on')]), name: :nsfw_on, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') }
.media-spoiler-toggle-buttons = f.button safe_join([fa_icon('eye'), t('admin.statuses.batch.nsfw_off')]), name: :nsfw_off, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') }
.media-spoiler-show-button.button= t('admin.statuses.media.show') = f.button safe_join([fa_icon('trash'), t('admin.statuses.batch.delete')]), name: :delete, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') }
.media-spoiler-hide-button.button= t('admin.statuses.media.hide') .batch-table__body
- @statuses.each do |status| = render partial: 'admin/reports/status', collection: @statuses, locals: { f: f }
.account-status{ data: { id: status.id } }
.batch-checkbox
= f.check_box :status_ids, { multiple: true, include_hidden: false }, status.id
.activity-stream.activity-stream-headless
.entry= render 'stream_entries/simple_status', status: status
.account-status__actions
- unless status.media_attachments.empty?
= link_to admin_account_status_path(@account.id, status, current_params.merge(status: { sensitive: !status.sensitive })), method: :patch, class: 'icon-button nsfw-button', title: t("admin.reports.nsfw.#{!status.sensitive}") do
= fa_icon status.sensitive? ? 'eye' : 'eye-slash'
= link_to admin_account_status_path(@account.id, status), method: :delete, class: 'icon-button trash-button', title: t('admin.reports.delete'), data: { confirm: t('admin.reports.are_you_sure') }, remote: true do
= fa_icon 'trash'
= paginate @statuses = paginate @statuses

@ -2,9 +2,12 @@
= t('auth.login') = t('auth.login')
= simple_form_for(resource, as: resource_name, url: session_path(resource_name), method: :post) do |f| = simple_form_for(resource, as: resource_name, url: session_path(resource_name), method: :post) do |f|
= f.input :otp_attempt, type: :number, placeholder: t('simple_form.labels.defaults.otp_attempt'), input_html: { 'aria-label' => t('simple_form.labels.defaults.otp_attempt'), :autocomplete => 'off' }, required: true, autofocus: true, hint: t('simple_form.hints.sessions.otp') %p.hint{ style: 'margin-bottom: 25px' }= t('simple_form.hints.sessions.otp')
= f.input :otp_attempt, type: :number, placeholder: t('simple_form.labels.defaults.otp_attempt'), input_html: { 'aria-label' => t('simple_form.labels.defaults.otp_attempt'), :autocomplete => 'off' }, required: true, autofocus: true
.actions .actions
= f.button :button, t('auth.login'), type: :submit = f.button :button, t('auth.login'), type: :submit
.form-footer= render 'auth/shared/links' - if Setting.site_contact_email.present?
%p.hint.subtle-hint= t('users.otp_lost_help_html', email: mail_to(Setting.site_contact_email, nil))

@ -6,7 +6,7 @@
%span.display-name %span.display-name
- account_url = local_assigns[:admin] ? admin_account_path(account.id) : TagManager.instance.url_for(account) - account_url = local_assigns[:admin] ? admin_account_path(account.id) : TagManager.instance.url_for(account)
= link_to account_url, class: 'detailed-status__display-name p-author h-card', target: '_blank', rel: 'noopener' do = link_to account_url, class: 'detailed-status__display-name p-author h-card', target: '_blank', rel: 'noopener' do
%strong.emojify= display_name(account) %strong.emojify= display_name(account, custom_emojify: true)
%span @#{account.acct} %span @#{account.acct}
- if account.note? - if account.note?

@ -6,7 +6,7 @@
%span.display-name %span.display-name
- account_url = local_assigns[:admin] ? admin_account_path(account.id) : TagManager.instance.url_for(account) - account_url = local_assigns[:admin] ? admin_account_path(account.id) : TagManager.instance.url_for(account)
= link_to account_url, class: 'detailed-status__display-name p-author h-card', target: '_blank', rel: 'noopener' do = link_to account_url, class: 'detailed-status__display-name p-author h-card', target: '_blank', rel: 'noopener' do
%strong.emojify= display_name(account) %strong.emojify= display_name(account, custom_emojify: true)
%span @#{account.acct} %span @#{account.acct}
- if account.note? - if account.note?

@ -10,15 +10,15 @@
%td %td
%tr %tr
%th= t('exports.follows') %th= t('exports.follows')
%td= @export.total_follows %td= number_to_human @export.total_follows
%td= table_link_to 'download', t('exports.csv'), settings_exports_follows_path(format: :csv) %td= table_link_to 'download', t('exports.csv'), settings_exports_follows_path(format: :csv)
%tr %tr
%th= t('exports.blocks') %th= t('exports.blocks')
%td= @export.total_blocks %td= number_to_human @export.total_blocks
%td= table_link_to 'download', t('exports.csv'), settings_exports_blocks_path(format: :csv) %td= table_link_to 'download', t('exports.csv'), settings_exports_blocks_path(format: :csv)
%tr %tr
%th= t('exports.mutes') %th= t('exports.mutes')
%td= @export.total_mutes %td= number_to_human @export.total_mutes
%td= table_link_to 'download', t('exports.csv'), settings_exports_mutes_path(format: :csv) %td= table_link_to 'download', t('exports.csv'), settings_exports_mutes_path(format: :csv)
%p.muted-hint= t('exports.archive_takeout.hint_html') %p.muted-hint= t('exports.archive_takeout.hint_html')

@ -19,6 +19,9 @@
.fields-group .fields-group
= f.input :locked, as: :boolean, wrapper: :with_label, hint: t('simple_form.hints.defaults.locked') = f.input :locked, as: :boolean, wrapper: :with_label, hint: t('simple_form.hints.defaults.locked')
.fields-group
= f.input :bot, as: :boolean, wrapper: :with_label, hint: t('simple_form.hints.defaults.bot')
.fields-group .fields-group
.input.with_block_label .input.with_block_label
%label= t('simple_form.labels.defaults.fields') %label= t('simple_form.labels.defaults.fields')

@ -2,7 +2,7 @@
= image_tag asset_pack_path('logo.svg'), class: 'logo' = image_tag asset_pack_path('logo.svg'), class: 'logo'
%div %div
= t('landing_strip_html', name: content_tag(:span, display_name(account), class: :emojify), link_to_root_path: link_to(content_tag(:strong, site_hostname), root_path)) = t('landing_strip_html', name: content_tag(:span, display_name(account, custom_emojify: true), class: :emojify), link_to_root_path: link_to(content_tag(:strong, site_hostname), root_path))
- if open_registrations? - if open_registrations?
= t('landing_strip_signup_html', sign_up_path: new_user_registration_path) = t('landing_strip_signup_html', sign_up_path: new_user_registration_path)

@ -4,7 +4,7 @@
.avatar .avatar
= image_tag status.account.avatar.url(:original), width: 48, height: 48, alt: '', class: 'u-photo' = image_tag status.account.avatar.url(:original), width: 48, height: 48, alt: '', class: 'u-photo'
%span.display-name %span.display-name
%strong.p-name.emojify= display_name(status.account) %strong.p-name.emojify= display_name(status.account, custom_emojify: true)
%span= acct(status.account) %span= acct(status.account)
- if embedded_view? - if embedded_view?

@ -10,7 +10,7 @@
%div %div
= image_tag status.account.avatar(:original), width: 48, height: 48, alt: '', class: 'u-photo' = image_tag status.account.avatar(:original), width: 48, height: 48, alt: '', class: 'u-photo'
%span.display-name %span.display-name
%strong.p-name.emojify= display_name(status.account) %strong.p-name.emojify= display_name(status.account, custom_emojify: true)
%span= acct(status.account) %span= acct(status.account)
.status__content.p-name.emojify< .status__content.p-name.emojify<

@ -28,7 +28,7 @@
= fa_icon('retweet fw') = fa_icon('retweet fw')
%span %span
= link_to TagManager.instance.url_for(status.account), class: 'status__display-name muted' do = link_to TagManager.instance.url_for(status.account), class: 'status__display-name muted' do
%strong.emojify= display_name(status.account) %strong.emojify= display_name(status.account, custom_emojify: true)
= t('stream_entries.reblogged') = t('stream_entries.reblogged')
- elsif pinned - elsif pinned
.pre-header .pre-header

@ -33,3 +33,5 @@
%p= t 'about.about_mastodon_html' %p= t 'about.about_mastodon_html'
= render 'features' = render 'features'
#modal-container

@ -0,0 +1,46 @@
#!/bin/bash
# https://github.com/travis-ci/travis-build/blob/cbe49ea239ab37b9b38b5b44d287b7ec7a108c16/lib/travis/build/templates/header.sh#L243-L260
#
# MIT LICENSE
#
# Copyright (c) 2016 Travis CI GmbH <contact@travis-ci.org>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
retry() {
local result=0
local count=1
while [ $count -le 3 ]; do
if [ $result -ne 0 ]; then
echo -e "\n${ANSI_RED}The command \"$@\" failed. Retrying, $count of 3.${ANSI_RESET}\n" >&2
fi
"$@" && { result=0 && break; } || result=$?
count=$(($count + 1))
sleep 1
done
if [ $count -gt 3 ]; then
echo -e "\n${ANSI_RED}The command \"$@\" failed 3 times.${ANSI_RESET}\n" >&2
fi
return $result
}
retry $@

@ -41,6 +41,7 @@ module Mastodon
:ar, :ar,
:bg, :bg,
:ca, :ca,
:co,
:de, :de,
:el, :el,
:eo, :eo,

@ -62,5 +62,5 @@ ignore_unused:
- 'errors.429' - 'errors.429'
- 'admin.accounts.roles.*' - 'admin.accounts.roles.*'
- 'admin.action_logs.actions.*' - 'admin.action_logs.actions.*'
- 'themes.default' - 'themes.*'
- 'statuses.attached.*' - 'statuses.attached.*'

@ -60,6 +60,7 @@ elsif ENV['SWIFT_ENABLED'] == 'true'
fog_credentials: { fog_credentials: {
provider: 'OpenStack', provider: 'OpenStack',
openstack_username: ENV['SWIFT_USERNAME'], openstack_username: ENV['SWIFT_USERNAME'],
openstack_project_id: ENV['SWIFT_PROJECT_ID'],
openstack_project_name: ENV['SWIFT_TENANT'], openstack_project_name: ENV['SWIFT_TENANT'],
openstack_tenant: ENV['SWIFT_TENANT'], # Some OpenStack-v2 ignores project_name but needs tenant openstack_tenant: ENV['SWIFT_TENANT'], # Some OpenStack-v2 ignores project_name but needs tenant
openstack_api_key: ENV['SWIFT_PASSWORD'], openstack_api_key: ENV['SWIFT_PASSWORD'],

@ -0,0 +1,13 @@
---
co:
activerecord:
errors:
models:
account:
attributes:
username:
invalid: solu lettere, numeri è liniette basse
status:
attributes:
reblog:
taken: di u statutu esista digià

@ -4,6 +4,7 @@ ar:
about_hashtag_html: هذه هي الرسائل العامة مع الكلمات الدلالية <strong> 1#%{hashtag}</strong>. يمكنك التفاعل معهم إذا كان لديك حساب في أي مكان على الإنترنت المتحد. about_hashtag_html: هذه هي الرسائل العامة مع الكلمات الدلالية <strong> 1#%{hashtag}</strong>. يمكنك التفاعل معهم إذا كان لديك حساب في أي مكان على الإنترنت المتحد.
about_mastodon_html: ماستدون شبكة إجتماعية <em>حرة و مفتوحة المصدر</em>. هو بديل <em>لامركزي</em> لمنصات تجارية ، يمكنك من تجنب احتكار شركة واحدة للإتصالات الخاصة بك. يمكنك اختيار أي خادم تثق فيه. أيهما تختار، يمكنك التفاعل مع أي شخص آخر على الشبكة. يمكن لأي شخص تنصيب و تشغيل خادم ماستدون خاص به والمشاركة في <em>الشبكات الاجتماعية</em> بكل شفافية. about_mastodon_html: ماستدون شبكة إجتماعية <em>حرة و مفتوحة المصدر</em>. هو بديل <em>لامركزي</em> لمنصات تجارية ، يمكنك من تجنب احتكار شركة واحدة للإتصالات الخاصة بك. يمكنك اختيار أي خادم تثق فيه. أيهما تختار، يمكنك التفاعل مع أي شخص آخر على الشبكة. يمكن لأي شخص تنصيب و تشغيل خادم ماستدون خاص به والمشاركة في <em>الشبكات الاجتماعية</em> بكل شفافية.
about_this: عن مثيل الخادوم هذا about_this: عن مثيل الخادوم هذا
administered_by: 'يديره :'
closed_registrations: التسجيلات في مثيل الخادوم هذا مُغلقة حاليًا. closed_registrations: التسجيلات في مثيل الخادوم هذا مُغلقة حاليًا.
contact: للتواصل معنا contact: للتواصل معنا
contact_missing: غير محدد contact_missing: غير محدد
@ -52,17 +53,24 @@ ar:
unfollow: إلغاء المتابعة unfollow: إلغاء المتابعة
admin: admin:
account_moderation_notes: account_moderation_notes:
account: مُشرِف
create: إنشاء create: إنشاء
created_at: التاريخ
created_msg: تم إنشاء ملاحظة الإشراف بنجاح ! created_msg: تم إنشاء ملاحظة الإشراف بنجاح !
delete: حذف delete: حذف
destroyed_msg: تم تدمير ملاحظة الإشراف بنجاح ! destroyed_msg: تم تدمير ملاحظة الإشراف بنجاح !
accounts: accounts:
are_you_sure: متأكد ؟ are_you_sure: متأكد ؟
avatar: الصورة الرمزية
by_domain: النطاق by_domain: النطاق
change_email:
changed_msg: تم تعديل عنوان البريد الإلكتروني الخاص بالحساب بنجاح !
current_email: عنوان البريد الإلكتروني الحالي
label: تعديل عنوان البريد الإلكتروني
new_email: عنوان البريد الإلكتروني الجديد
submit: تعديل عنوان البريد الإلكتروني
title: تعديل عنوان البريد الإلكتروني الخاص بـ %{username}
confirm: تأكيد confirm: تأكيد
confirmed: مؤكَّد confirmed: مؤكَّد
confirming: التأكد
demote: إنزال الرُتبة الوظيفية demote: إنزال الرُتبة الوظيفية
disable: تعطيل disable: تعطيل
disable_two_factor_authentication: تعطيل 2FA disable_two_factor_authentication: تعطيل 2FA
@ -71,6 +79,7 @@ ar:
domain: النطاق domain: النطاق
edit: تعديل edit: تعديل
email: البريد الإلكتروني email: البريد الإلكتروني
email_status: حالة البريد الإلكتروني
enable: تفعيل enable: تفعيل
enabled: مفعَّل enabled: مفعَّل
feed_url: عنوان رابط التغذية feed_url: عنوان رابط التغذية
@ -108,6 +117,11 @@ ar:
public: عمومي public: عمومي
push_subscription_expires: انتهاء الاشتراك ”PuSH“ push_subscription_expires: انتهاء الاشتراك ”PuSH“
redownload: تحديث الصورة الرمزية redownload: تحديث الصورة الرمزية
remove_avatar: حذف الصورة الرمزية
resend_confirmation:
already_confirmed: هذا المستخدم مؤكد بالفعل
send: أعد إرسال رسالة البريد الالكتروني الخاصة بالتأكيد
success: تم إرسال رسالة التأكيد بنجاح!
reset: إعادة التعيين reset: إعادة التعيين
reset_password: إعادة ضبط كلمة السر reset_password: إعادة ضبط كلمة السر
resubscribe: اشترك مرة أخرى resubscribe: اشترك مرة أخرى
@ -241,12 +255,8 @@ ar:
are_you_sure: هل أنت متأكد ؟ are_you_sure: هل أنت متأكد ؟
comment: comment:
none: لا شيء none: لا شيء
delete: حذف
id: معرّف ID id: معرّف ID
mark_as_resolved: إعتبار التقرير كمحلول mark_as_resolved: إعتبار التقرير كمحلول
nsfw:
'false': الكشف عن الصور
'true': إخفاء الوسائط المرفقة
report: 'التقرير #%{id}' report: 'التقرير #%{id}'
report_contents: المحتويات report_contents: المحتويات
reported_account: حساب مُبلّغ عنه reported_account: حساب مُبلّغ عنه
@ -305,11 +315,8 @@ ar:
back_to_account: العودة إلى صفحة الحساب back_to_account: العودة إلى صفحة الحساب
batch: batch:
delete: حذف delete: حذف
execute: تفعيل
failed_to_execute: خطأ في التفعيل failed_to_execute: خطأ في التفعيل
media: media:
hide: إخفاء الوسائط
show: إظهار الوسائط
title: الوسائط title: الوسائط
title: منشورات الحساب title: منشورات الحساب
with_media: بالوسائط with_media: بالوسائط

@ -53,9 +53,7 @@ ca:
unfollow: Deixa de seguir unfollow: Deixa de seguir
admin: admin:
account_moderation_notes: account_moderation_notes:
account: Moderador
create: Crea create: Crea
created_at: Data
created_msg: La nota de moderació s'ha creat correctament! created_msg: La nota de moderació s'ha creat correctament!
delete: Suprimeix delete: Suprimeix
destroyed_msg: Nota de moderació destruïda amb èxit! destroyed_msg: Nota de moderació destruïda amb èxit!
@ -72,6 +70,7 @@ ca:
title: Canviar adreça de correu de %{username} title: Canviar adreça de correu de %{username}
confirm: Confirma confirm: Confirma
confirmed: Confirmat confirmed: Confirmat
confirming: Confirmando
demote: Degrada demote: Degrada
disable: Inhabilita disable: Inhabilita
disable_two_factor_authentication: Desactiva 2FA disable_two_factor_authentication: Desactiva 2FA
@ -80,6 +79,7 @@ ca:
domain: Domini domain: Domini
edit: Edita edit: Edita
email: Correu electrònic email: Correu electrònic
email_status: Estado del correo electrónico
enable: Habilita enable: Habilita
enabled: Habilitat enabled: Habilitat
feed_url: URL del canal feed_url: URL del canal
@ -118,6 +118,10 @@ ca:
push_subscription_expires: La subscripció PuSH expira push_subscription_expires: La subscripció PuSH expira
redownload: Actualitza l'avatar redownload: Actualitza l'avatar
remove_avatar: Eliminar avatar remove_avatar: Eliminar avatar
resend_confirmation:
already_confirmed: Este usuario ya está confirmado
send: Reenviar el correo electrónico de confirmación
success: "¡Correo electrónico de confirmación enviado con éxito!"
reset: Reinicialitza reset: Reinicialitza
reset_password: Restableix la contrasenya reset_password: Restableix la contrasenya
resubscribe: Torna a subscriure resubscribe: Torna a subscriure
@ -269,7 +273,6 @@ ca:
comment: comment:
none: Cap none: Cap
created_at: Reportat created_at: Reportat
delete: Suprimeix
id: ID id: ID
mark_as_resolved: Marca com a resolt mark_as_resolved: Marca com a resolt
mark_as_unresolved: Marcar sense resoldre mark_as_unresolved: Marcar sense resoldre
@ -279,9 +282,6 @@ ca:
create_and_unresolve: Reobrir amb nota create_and_unresolve: Reobrir amb nota
delete: Esborrar delete: Esborrar
placeholder: Descriu les accions que s'han pres o qualsevol altra actualització d'aquest informe… placeholder: Descriu les accions que s'han pres o qualsevol altra actualització d'aquest informe…
nsfw:
'false': Mostra els fitxers multimèdia adjunts
'true': Amaga els fitxers multimèdia adjunts
reopen: Reobrir informe reopen: Reobrir informe
report: 'Informe #%{id}' report: 'Informe #%{id}'
report_contents: Contingut report_contents: Contingut
@ -356,11 +356,8 @@ ca:
delete: Suprimeix delete: Suprimeix
nsfw_off: Marcar com a no sensible nsfw_off: Marcar com a no sensible
nsfw_on: Marcar com a sensible nsfw_on: Marcar com a sensible
execute: Executa
failed_to_execute: No s'ha pogut executar failed_to_execute: No s'ha pogut executar
media: media:
hide: Amaga el contingut multimèdia
show: Mostra el contingut multimèdia
title: Contingut multimèdia title: Contingut multimèdia
no_media: Sense contingut multimèdia no_media: Sense contingut multimèdia
title: Estats del compte title: Estats del compte
@ -376,6 +373,7 @@ ca:
admin_mailer: admin_mailer:
new_report: new_report:
body: "%{reporter} ha informat de %{target}" body: "%{reporter} ha informat de %{target}"
body_remote: Algú des de el domini %{domain} ha informat sobre %{target}
subject: Informe nou per a %{instance} (#%{id}) subject: Informe nou per a %{instance} (#%{id})
application_mailer: application_mailer:
notification_preferences: Canvia les preferències de correu notification_preferences: Canvia les preferències de correu

@ -0,0 +1,831 @@
---
co:
about:
about_hashtag_html: Quessi sò statuti pubblichi taggati cù <strong>#%{hashtag}</strong>. Pudete interagisce cù elli sì voi avete un contu in qualche parte di u <em>fediverse</em>.
about_mastodon_html: Mastodon ghjè una rete suciale custruita incù prutucolli web aperti è lugiziali liberi. Hè decentralizatu cumu le-mail.
about_this: À prupositu
administered_by: 'Amministratu da:'
closed_registrations: Pè avà, larregistramenti sò chjosi nantà stistanza. Mà pudete truvà unaltristanza per fà un contu è avè accessu à listessa reta da quallà!
contact: Cuntattu
contact_missing: Mancante
contact_unavailable: Micca dispunibule
description_headline: Quale hè %{domain} ?
domain_count_after: altre istanze
domain_count_before: Cunnettati à
extended_description_html: |
<h3>Una bona piazza per e regule</h3>
<p>A descrizzione stesa ùn hè micca stata riempiuta.</p>
features:
humane_approach_body: Mastodon hà amparatu da i sbagli di laltre rete suciale, è prova à fà scelte di cuncezzione più etiche per luttà contrà labusu di i media suciali.
humane_approach_title: Una mentalità più umana
not_a_product_body: Mastodon ùn hè micca una rete cummerciale. Micca pubblicità, micca pruspizzione di dati, micca ambienti chjosi, è micca auturità centrale.
not_a_product_title: Site una parsona, micca un pruduttu
real_conversation_body: Cù 500 caratteri dispunibuli, diffusione persunalizata di u cuntinutu è avertimenti per media sensibili, pudete cumunicà cumè voi vulete.
real_conversation_title: Fattu per una vera cunversazione
within_reach_body: Parechje app per iOS, Android è altre piattaforme, create cù un sistemu dAPI accessibile à i prugrammatori, vi permettenu davè accessu à i vostri amichi senza prublemi.
within_reach_title: Sempre accessibile
generic_description: "%{domain} hè un servore di a rete"
hosted_on: Mastodon allughjatu nantà %{domain}
learn_more: Amparà di più
other_instances: Lista di listanze
source_code: Codice di fonte
status_count_after: statuti
status_count_before: chì anu pubblicatu
user_count_after: parsone quì
user_count_before: Ci sò
what_is_mastodon: Quale hè Mastodon?
accounts:
follow: Siguità
followers: Abbunati
following: Abbunamenti
media: Media
moved_html: "%{name} hà cambiatu di contu, avà hè nantà %{new_profile_link}:"
nothing_here: Ùn chè nunda quì!
people_followed_by: Seguitati da %{name}
people_who_follow: Seguitanu %{name}
posts: Statuti
posts_with_replies: Statuti è risposte
remote_follow: Siguità daltrò
reserved_username: Stu cugnome hè riservatu
roles:
admin: Amministratore
moderator: Muderatore
unfollow: Ùn siguità più
admin:
account_moderation_notes:
create: Creà
created_msg: Nota di muderazione creata!
delete: Toglie
destroyed_msg: Nota di muderazione sguassata!
accounts:
are_you_sure: Site sicuru·a?
avatar: Ritrattu di prufile
by_domain: Duminiu
change_email:
changed_msg: Email di u contu cambiatu!
current_email: Email attuale
label: Mudificà lEmail
new_email: Novu Email
submit: Cambià Email
title: Mudificà lEmail di %{username}
confirm: Cunfirmà
confirmed: Cunfirmata
demote: Ritrugradà
disable: Disattivà
disable_two_factor_authentication: Disattivà lidentificazione à 2 fattori
disabled: Disattivatu
display_name: Nome pubblicu
domain: Duminiu
edit: Mudificà
email: E-mail
enable: Attivà
enabled: Attivatu
feed_url: URL di u flussu
followers: Abbunati
followers_url: URL di labbunati
follows: Abbunamenti
inbox_url: URL di linbox
ip: IP
location:
all: Tutti
local: Lucale
remote: Daltrò
title: Lucalizazione
login_status: Statutu di cunnessione
media_attachments: Media aghjunti
memorialize: Trasfurmà in mimuriale
moderation:
all: Tutti
silenced: Silenzati
suspended: Suspesi
title: Muderazione
moderation_notes: Note di muderazione
most_recent_activity: Attività più ricente
most_recent_ip: IP più ricente
not_subscribed: Micca abbunatu
order:
alphabetic: Alfabeticu
most_recent: Più ricente
title: Urdine
outbox_url: URL di loutbox
perform_full_suspension: Fà una suspensione cumpleta
profile_url: URL di u prufile
promote: Prumove
protocol: Prutucollu
public: Pubblicu
push_subscription_expires: Spirata di labbunamentu PuSH
redownload: Mette à ghjornu i ritratti
remove_avatar: Toglie lavatar
reset: Reset
reset_password: Riinizializà a chjave daccessu
resubscribe: Riabbunassi
role: Auturizazione
roles:
admin: Amministratore
moderator: Muderatore
staff: Squadra
user: Utilizatore
salmon_url: URL di Salmon
search: Cercà
shared_inbox_url: URL di linbox spartuta
show:
created_reports: Signalamenti creati da stu contu
report: Signalamentu
targeted_reports: Signalamenti creati contrà stu contu
silence: Silenzà
statuses: Statuti
subscribe: Abbunassi
title: Conti
unconfirmed_email: E-mail micca cunfirmatu
undo_silenced: Ùn silenzà più
undo_suspension: Ùn suspende più
unsubscribe: Disabbunassi
username: Cugnome
web: Web
action_logs:
actions:
assigned_to_self_report: "%{name} shè assignatu u signalamentu %{target}"
change_email_user: "%{name} hà cambiatu lindirizzu e-mail di %{target}"
confirm_user: "%{name} hà cunfirmatu lindirizzu e-mail di %{target}"
create_custom_emoji: "%{name} hà caricatu una novemoji %{target}"
create_domain_block: "%{name} hà bluccatu u duminiu %{target}"
create_email_domain_block: "%{name} hà messu u duminiu e-mail %{target} nanta lista nera"
demote_user: "%{name} hà ritrugradatu lutilizatore %{target}"
destroy_domain_block: "%{name} hà sbluccatu u duminiu %{target}"
destroy_email_domain_block: "%{name} hà messu u duminiu e-mail %{target} nanta lista bianca"
destroy_status: "%{name} hà toltu u statutu di %{target}"
disable_2fa_user: "%{name} hà disattivatu lidentificazione à dui fattori per %{target}"
disable_custom_emoji: "%{name} hà disattivatu lemoji %{target}"
disable_user: "%{name} hà disattivatu a cunnessione per %{target}"
enable_custom_emoji: "%{name} hà attivatu lemoji %{target}"
enable_user: "%{name} hà attivatu a cunnessione per %{target}"
memorialize_account: "%{name} hà trasfurmatu u contu di %{target} in una pagina mimuriale"
promote_user: "%{name} hà prumossu %{target}"
remove_avatar_user: "%{name} hà toltu u ritrattu di %{target}"
reopen_report: "%{name} hà riapertu u signalamentu %{target}"
reset_password_user: "%{name} hà riinizializatu a chjave daccessu di %{target}"
resolve_report: "%{name} hà chjosu u signalamentu %{target}"
silence_account: "%{name} hà silenzatu u contu di %{target}"
suspend_account: "%{name} hà suspesu u contu di %{target}"
unassigned_report: "%{name} hà disassignatu u signalamentu %{target}"
unsilence_account: "%{name} hà fattu che u contu di %{target} ùn hè più silenzatu"
unsuspend_account: "%{name} hà fattu che u contu di %{target} ùn hè più suspesu"
update_custom_emoji: "%{name} hà messu à ghjornu lemoji %{target}"
update_status: "%{name} hà cambiatu u statutu di %{target}"
title: Ghjurnale daudit
custom_emojis:
by_domain: Duminiu
copied_msg: Copia lucale di lemoji creata!
copy: Cupià
copy_failed_msg: Ùn shè micca pussutu creà una copia di lemoji
created_msg: Lemoji hè stata creata!
delete: Toglie
destroyed_msg: Lemoji hè stata tolta!
disable: Disattivà
disabled_msg: Lemoji hè stata disattivata!
emoji: Emoji
enable: Attivà
enabled_msg: Lemoji hè stata attivata!
image_hint: PNG di 50Ko o menu
listed: Listata
new:
title: Aghjustà una novemoji
overwrite: Soprascrive
shortcode: Accorta
shortcode_hint: 2 caratteri o più, solu lettere, numeri è liniette basse
title: Emoji parsunalizate
unlisted: Micca listata
update_failed_msg: Ùn shè micca pussutu mette à ghjornu lemoji
updated_msg: Lemoji hè stata messa à ghjornu!
upload: Caricà
domain_blocks:
add_new: Aghjustà
created_msg: U blucchime di u duminiu hè attivu
destroyed_msg: U blucchime di u duminiu ùn hè più attivu
domain: Duminiu
new:
create: Creà un blucchime
hint: U blucchime di duminiu ùn impedirà micca a creazione di conti indè a database, mà metudi di muderazione specifiche saranu applicati.
severity:
desc_html: Cù<strong>Silenzà</strong>, solu labbunati di u contu viderenu i so missaghji. <strong>Suspende</strong> sguassarà tutti i cuntenuti è dati di u contu. Utilizate <strong>Nisuna</strong> sè voi vulete solu righjittà fugliali media.
noop: Nisuna
silence: Silenzà
suspend: Suspende
title: Novu blucchime di duminiu
reject_media: Righjittà i fugliali media
reject_media_hint: Sguassa tutti i media caricati è ricusa caricamenti futuri. Inutile per una suspensione
severities:
noop: Nisuna
silence: Silenzà
suspend: Suspende
severity: Severità
show:
affected_accounts:
one: Un contu tuccatu indè a database
other: "%{count} conti tuccati indè a database"
retroactive:
silence: Ùn silenzà più i conti nantà stu duminiu
suspend: Ùn suspende più i conti nantà stu duminiu
title: Ùn bluccà più u duminiu %{domain}
undo: Annullà
title: Blucchimi di duminiu
undo: Annullà
email_domain_blocks:
add_new: Aghjustà
created_msg: U blucchime di u duminiu de-mail hè attivu
delete: Toglie
destroyed_msg: U blucchime di u duminiu de-mail ùn hè più attivu
domain: Duminiu
new:
create: Creà un blucchime
title: Nova iscrizzione nanta lista nera e-mail
title: Lista nera e-mail
instances:
account_count: Conti cunnisciuti
domain_name: Duminiu
reset: Riinizializà
search: Cercà
title: Istanze cunnisciute
invites:
filter:
all: Tuttu
available: Dispunibuli
expired: Spirati
title: Filtrà
title: Invitazione
report_notes:
created_msg: Nota di signalamentu creata!
destroyed_msg: Nota di signalamentu sguassata!
reports:
account:
note: nota
report: palisà
action_taken_by: Intervenzione di
are_you_sure: Site sicuru·a?
assign_to_self: Assignallu à mè
assigned: Muderatore assignatu
comment:
none: Nisunu
created_at: Palisatu
id: ID
mark_as_resolved: Indicà cumè chjosu
mark_as_unresolved: Indicà cumè sempre apertu
notes:
create: Aghjunghje una nota
create_and_resolve: Chjude cù una nota
create_and_unresolve: Riapre cù una nota
delete: Toglie
placeholder: Per parlà di lazzione piglate, o altre messe à ghjornu nantà u signalamentu…
reopen: Riapre u signalamentu
report: 'Signalamente #%{id}'
report_contents: Cuntenuti
reported_account: Contu palisatu
reported_by: Palisatu da
resolved: Scioltu è chjosu
resolved_msg: Signalamentu scioltu!
silence_account: Silenzà u contu
status: Statutu
suspend_account: Suspende u contu
target: Oggettu
title: Signalamenti
unassign: Disassignà
unresolved: Micca sciolti
updated_at: Messi à ghjornu
view: Vede
settings:
activity_api_enabled:
desc_html: Numeri di statuti creati quì, utilizatori attivi, è arregistramenti novi tutte e settimane
title: Pubblicà statistiche nantà lattività di lutilizatori
bootstrap_timeline_accounts:
desc_html: Cugnomi separati cù virgule. Solu pussibule cù conti lucali è pubblichi. Quandu a lista hè viota, tutti lamministratori lucali saranu selezziunati.
title: Abbunamenti predefiniti per lutilizatori novi
contact_information:
email: E-mail prufissiunale
username: Identificatore di cuntattu
hero:
desc_html: Affissatu nanta pagina daccolta. Ricumandemu almenu 600x100px. Sellu ùn hè micca definiti, a vignetta di listanza sarà usata
title: Ritrattu di cuprendula
peers_api_enabled:
desc_html: Indirizzi stistanza hà vistu indè u fediverse
title: Pubblicà a lista distanza cunnisciute
registrations:
closed_message:
desc_html: Affissatu nanta pagina daccolta quandu larregistramenti sò chjosi. Pudete fà usu di u furmattu HTML
title: Missaghju per larregistramenti chjosi
deletion:
desc_html: Auturizà tuttu u mondu di sguassà u so propiu contu
title: Auturizà à sguassà i conti
min_invite_role:
disabled: Nisunu
title: Auturizà linvitazione da
open:
desc_html: Auturizà tuttu u mondu à creà un contu quì
title: Apre larregistramenti
show_known_fediverse_at_about_page:
desc_html: Quandu ghjè selezziunatu, statuti di tuttu listanze cunnisciute saranu affissati indè a vista di e linee. Altrimente soli i statuti lucali saranu mustrati.
title: Vedde tuttu u fediverse cunnisciutu nanta vista di e linee
show_staff_badge:
desc_html: Mustrerà un badge Squadra nantà un prufile dutilizatore
title: Mustrà un badge staff
site_description:
desc_html: Paragrafu di prisentazione nanta pagina daccolta è i marchi meta. Pudete fà usu di marchi HTML, in particulare <code>&lt;a&gt;</code> è <code>&lt;em&gt;</code>.
title: Discrizzione di listanza
site_description_extended:
desc_html: Una bona piazza per e regule, infurmazione è altre cose chì lutilizatori duverìanu sapè. Pudete fà usu di marchi HTML
title: Discrizzione stesa di u situ
site_terms:
desc_html: Quì pudete scrive e vostre regule di cunfidenzialità, cundizione dusu o altre menzione legale. Pudete fà usu di marchi HTML
title: Termini persunalizati
site_title: Nome di listanza
thumbnail:
desc_html: Utilizatu per viste cù OpenGraph è lAPI. Ricumandemu 1200x630px
title: Vignetta di listanza
timeline_preview:
desc_html: Vede a linea pubblica nanta pagina daccolta
title: Vista di e linee
title: Parametri di u situ
statuses:
back_to_account: Ritornu à a pagina di u contu
batch:
delete: Toglie
nsfw_off: Indicà cumè micca sensibile
nsfw_on: Indicà cumè sensibile
failed_to_execute: Esecuzione impussibule
media:
title: Media
no_media: Nisun media
title: Statutu di u contu
with_media: Cù media
subscriptions:
callback_url: URL di richjama
confirmed: Cunfirmatu
expires_in: Spira in
last_delivery: Ultima arricata
title: WebSub
topic: Sughjettu
title: Amministrazione
admin_mailer:
new_report:
body: "%{reporter} hà palisatu %{target}"
body_remote: Qualchunu da %{domain} hà palisatu %{target}
subject: Novu signalamentu nantà %{instance} (#%{id})
application_mailer:
notification_preferences: Cambià e priferenze e-mail
salutation: "%{name},"
settings: 'Cambià e priferenze e-mail: %{link}'
view: 'Vede:'
view_profile: Vede u prufile
view_status: Vede u statutu
applications:
created: Applicazione creata
destroyed: Applicazione sguassata
invalid_url: LURL chè stata pruvista ùn hè valida
regenerate_token: Regenerate access token
token_regenerated: Access token successfully regenerated
warning: Be very careful with this data. Never share it with anyone!
your_token: Rigenerà a fiscia daccessu
auth:
agreement_html: Arregistrassi vole dì chì site daccunsentu per siguità <a href="%{rules_path}">e regule di listanza</a> è <a href="%{terms_path}">e cundizione dusu</a>.
change_password: Chjave daccessu
confirm_email: Cunfirmà le-mail
delete_account: Sguassà u contu
delete_account_html: Sè voi vulete toglie u vostru contu <a href="%{path}">ghjè quì</a>. Duverete cunfirmà a vostra scelta.
didnt_get_confirmation: Ùn avete micca ricevutu listruzione di cunfirmazione?
forgot_password: Chjave scurdata?
invalid_reset_password_token: Password reset token is invalid or expired. Please request a new one.
login: Cunnettassi
logout: Scunnettassi
migrate_account: Cambià di contu
migrate_account_html: Sè voi vulete riindirizà stu contu versu unaltru, <a href="%{path}">ghjè pussibule quì</a>.
or: o
or_log_in_with: O cunnettatevi cù
providers:
cas: CAS
saml: SAML
register: Arregistrassi
register_elsewhere: Arregistrassi altrò
resend_confirmation: Rimandà listruzzioni di cunfirmazione
reset_password: Cambià a chjave daccessu
security: Sicurità
set_new_password: Creà una nova chjave daccessu
authorize_follow:
already_following: You are already following this account
error: Peccatu, chè statu un prublemu ricercandu u contu.
follow: Siguità
follow_request: 'Avete dumandatu di siguità:'
following: 'Eccu! Avà seguitate:'
post_follow:
close: Or, you can just close this window.
return: Rivultà à u prufile di lutilizatore
web: Andà à linterfaccia web
title: Siguità %{acct}
datetime:
distance_in_words:
about_x_hours: "%{count}h"
about_x_months: "%{count}mo"
about_x_years: "%{count}y"
almost_x_years: "%{count}y"
half_a_minute: Avà
less_than_x_minutes: "%{count}m"
less_than_x_seconds: Avà
over_x_years: "%{count}y"
x_days: "%{count}d"
x_minutes: "%{count}m"
x_months: "%{count}mo"
x_seconds: "%{count}s"
deletes:
bad_password_msg: È nò! Sta chjave ùn hè curretta
confirm_password: Entrate a vostra chjave daccessu attuale per verificà a vostra identità
description_html: U contu sarà deattivatu è u cuntenutu sarà sguassatu di manera <strong>permanente è irreversibile</strong>. Ùn sarà micca pussibule piglià stu cugnome torna per evità limpusture.
proceed: Sguassà u contu
success_msg: U vostru contu hè statu sguassatu
warning_html: Pudete esse sicuru·a solu chì u cuntenutu sarà sguassatu di stistanza. Sellu hè statu spartutu in altrò, sarà forse sempre quallà.
warning_title: Dispunibilità di i cuntenuti sparsi
errors:
'403': Ùn site micca auturizatu·a à vede sta pagina.
'404': Sta pagina ùn esiste micca.
'410': Sta pagina ùn esiste più.
'422':
content: Chè statu un prublemu cù a verificazione di sicurità. Forse bluccate cookies?
title: Fiascu di verificazione
'429': Limitatu dopà troppu richieste
'500':
content: Scusate, mà chè statu un prublemu cù u nostru servore.
title: Sta pagina ùn hè curretta
noscript_html: Mastodon nantà u web hà bisognu di JavaScript per funziunà. Pudete ancu pruvà <a href="https://github.com/tootsuite/documentation/blob/master/Using-Mastodon/Apps.md">lapplicazione native</a> per a vostra piattaforma.
exports:
archive_takeout:
date: Data
download: Scaricà larchiviu
hint_html: Pudete dumandà unarchiviu di i vostri <strong>statuti è media caricati</strong>. I dati saranu in u furmattu ActivityPub è pudarenu esse letti da tutti i lugiziali chì u supportanu.
in_progress: Cumpilazione di larchiviu...
request: Dumandà u vostrarchiviu
size: Pesu
blocks: Bluccate
csv: CSV
follows: Seguitate
mutes: Piattate
storage: I vostri media
followers:
domain: Duminiu
explanation_html: Per assicuravi di a cunfidenzialità di i vostri statuti, duvete avè primura di quale vi seguita. <strong>I vostri statuti privati sò mandati à tutte listanze induve avete abbunati</strong>. Pensate à u vostru livellu di cunfidenza in i so amministratori.
followers_count: Numeru dabbunati
lock_link: Rendete u contu privatu
purge: Toglie di a lista dabbunati
success:
one: Suppressione di labbunati dun duminiu...
other: Suppressione di labbunati da %{count} duminii...
true_privacy_html: Ùn vi scurdate chì <strong>una vera cunfidenzialità pò solu esse ottenuta cù crittografia da un capu à laltru</strong>.
unlocked_warning_html: Tuttu u mondu pò seguitavi è vede i vostri statuti privati. %{lock_link} per pudè cunfirmà o righjittà abbunamenti.
unlocked_warning_title: U vostru contu hè pubblicu
generic:
changes_saved_msg: Cambiamenti salvati!
powered_by: mossu da %{link}
save_changes: Salvà e mudificazione
validation_errors:
one: Qualcosa ùn và bè! Verificate un prublemu quì sottu.
other: Qualcosa ùn và bè! Verificate %{count} prublemi quì sottu.
imports:
preface: Pudete impurtà certi dati cumu e persone chì seguitate o bluccate nantà u vostru contu nantà stistanza à partesi di fugliali creati nantà unaltristanza.
success: I vostri dati sò stati impurtati è saranu trattati da quì à pocu.
types:
blocking: Persone chì bluccate
following: Persone chì seguitate
muting: Persone chì piattate
upload: Impurtà
in_memoriam_html: In mimoria.
invites:
delete: Disattivà
expired: Spirata
expires_in:
'1800': 30 minuti
'21600': 6 ore
'3600': 1 ora
'43200': 12 ore
'604800': 1 settimana
'86400': 1 ghjornu
expires_in_prompt: Mai
generate: Creà
max_uses:
one: 1 usu
other: "%{count} usi"
max_uses_prompt: Micca limita
prompt: Create è spartete ligami cù altre parsone per dà accessu à listanza
table:
expires_at: Spira
uses: Utiliza
title: Invità ghjente
landing_strip_html: "<strong>%{name}</strong> hè nantà %{link_to_root_path}. Pudete seguitallu·a o cumunicà cù ellu·a cù un contu in qualche parte di u fediverse."
landing_strip_signup_html: Pudete ancu <a href="%{sign_up_path}">arrigistravi quì</a>.
lists:
errors:
limit: Ùn pudete più creà altre liste.
media_attachments:
validations:
images_and_video: Ùn si pò micca aghjunghje un filmettu à un statutu chì hà digià ritratti
too_many: Ùn si pò micca aghjunghje più di 4 fugliali
migrations:
acct: cugnome@duminiu di u novu contu
currently_redirecting: "U vostru prufile riindiriza tuttu versu à:"
proceed: Salvà
updated_msg: I paramettri di migrazione sò stati messi à ghjornu!
moderation:
title: Muderazione
notification_mailer:
digest:
action: Vede tutte e nutificazione
body: Eccu cio chavete mancatu dapoi à a vostrultima visita u %{since}
mention: "%{name} vhà mintuvatu·a in:"
new_followers_summary:
one: Avete ancu unabbunatu novu!
other: Avete ancu %{count} abbunati novi!
subject:
one: "Una nutificazione nova dapoi à a vostrultima visita \U0001F418"
other: "%{count} nutificazione nove dapoi à a vostrultima visita \U0001F418"
title: Dapoi lultima volta…
favourite:
body: "%{name} hà aghjuntu u vostru statutu à i so favuriti :"
subject: "%{name} hà messu u vostru post in i so favuriti"
title: Novu favuritu
follow:
body: "%{name} shè abbunatu à u vostru contu !"
subject: "%{name} vi seguita"
title: Abbunatu novu
follow_request:
action: Vede e dumande dabbunamentu
body: "%{name} vole abbunassi à u vostru contu"
subject: 'Dumanda dabbunamentu: %{name}'
title: Nova dumanda dabbunamentu
mention:
action: Risposta
body: "%{name} vhà mintuvatu·a indè :"
subject: "%{name} vhà mintuvatu·a"
title: Nova menzione
reblog:
body: 'U vostru statutu hè statu spartutu da %{name}:'
subject: "%{name} hà spartutu u vostru statutu"
title: Nova spartera
number:
human:
decimal_units:
format: "%n%u"
units:
billion: G
million: M
quadrillion: P
thousand: K
trillion: T
unit: ''
pagination:
newer: Più ricente
next: Dopu
older: Più vechju
prev: Nanzu
truncate: "&hellip;"
preferences:
languages: Lingue
other: Altre
publishing: Pubblicazione
web: Web
push_notifications:
favourite:
title: "%{name} hà aghjuntu u vostru statutu à i so favuriti"
follow:
title: "%{name} vi seguita"
group:
title: "%{count} nutificazioni"
mention:
action_boost: Sparte
action_expand: Vede di più
action_favourite: Aghjunghje à i favuriti
title: "%{name} vhà mintuvatu·a"
reblog:
title: "%{name} hà spartutu u vostru statutu"
remote_follow:
acct: Entrate u vostru cugnome@istanza da induve vulete siguità stu contu.
missing_resource: Ùn avemu pussutu à truvà lindirizzu di ridirezzione
proceed: Cuntinuà per siguità
prompt: 'Avete da siguità:'
remote_unfollow:
error: Errore
title: Titulu
unfollowed: Disabbunatu
sessions:
activity: Ultima attività
browser: Navigatore
browsers:
alipay: Alipay
blackberry: Blackberry
chrome: Chrome
edge: Microsoft Edge
electron: Electron
firefox: Firefox
generic: Navigatore scunnisciutu
ie: Internet Explorer
micro_messenger: MicroMessenger
nokia: Nokia S40 Ovi Browser
opera: Opera
otter: Otter
phantom_js: PhantomJS
qq: QQ Browser
safari: Safari
uc_browser: UCBrowser
weibo: Weibo
current_session: Sessione attuale
description: "%{browser} nantà %{platform}"
explanation: Quessi sò i navigatori cunnettati à u vostru contu 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: piattaforma scunnisciuta
windows: Windows
windows_mobile: Windows Mobile
windows_phone: Windows Phone
revoke: Rivucà
revoke_success: Sessione rivucata
title: Sessioni
settings:
authorized_apps: Applicazione auturizate
back: Ritornu nantà Mastodon
delete: Suppressione di u contu
development: Sviluppu
edit_profile: Mudificà u prufile
export: Spurtazione dinfurmazione
followers: Abbunati auturizati
import: Impurtazione
migrate: Migrazione di u contu
notifications: Nutificazione
preferences: Priferenze
settings: Parametri
two_factor_authentication: Identificazione à dui fattori
your_apps: E vostre applicazione
statuses:
attached:
description: 'Aghjuntu: %{attached}'
image:
one: "%{count} ritrattu"
other: "%{count} ritratti"
video:
one: "%{count} filmettu"
other: "%{count} filmetti"
content_warning: 'Avertimentu: %{warning}'
disallowed_hashtags:
one: 'cuntene lhashtag disattivatu: %{tags}'
other: 'cuntene lhashtag disattivati: %{tags}'
open_in_web: Apre nantà u web
over_character_limit: Site soprà a limita di %{max} caratteri
pin_errors:
limit: Avete digià puntarulatu u numeru massimale di statuti
ownership: Pudete puntarulà solu unu di i vostri propii statuti
private: Ùn pudete micca puntarulà un statutu chùn hè micca pubblicu
reblog: Ùn pudete micca puntarulà una spartera
show_more: Vede di più
title: '%{name}: "%{quote}"'
visibilities:
private: Solu per labbunati
private_long: Mustrà solu à labbunati
public: Pubblicu
public_long: Tuttu u mondu pò vede
unlisted: Micca listatu
unlisted_long: Tuttu u mondu pò vede, mà micca indè e linee pubbliche
stream_entries:
click_to_show: Cliccà per vede
pinned: Statutu puntarulatu
reblogged: spartutu
sensitive_content: Cuntenutu sensibile
terms:
body_html: |
<h2>Privacy Policy</h2>
<h3 id="collect">What information do we collect?</h3>
<ul>
<li><em>Basic account information</em>: If you register on this server, you may be asked to enter a username, an e-mail address and a password. You may also enter additional profile information such as a display name and biography, and upload a profile picture and header image. The username, display name, biography, profile picture and header image are always listed publicly.</li>
<li><em>Posts, following and other public information</em>: The list of people you follow is listed publicly, the same is true for your followers. When you submit a message, the date and time is stored as well as the application you submitted the message from. Messages may contain media attachments, such as pictures and videos. Public and unlisted posts are available publicly. When you feature a post on your profile, that is also publicly available information. Your posts are delivered to your followers, in some cases it means they are delivered to different servers and copies are stored there. When you delete posts, this is likewise delivered to your followers. The action of reblogging or favouriting another post is always public.</li>
<li><em>Direct and followers-only posts</em>: All posts are stored and processed on the server. Followers-only posts are delivered to your followers and users who are mentioned in them, and direct posts are delivered only to users mentioned in them. In some cases it means they are delivered to different servers and copies are stored there. We make a good faith effort to limit the access to those posts only to authorized persons, but other servers may fail to do so. Therefore its important to review servers your followers belong to. You may toggle an option to approve and reject new followers manually in the settings. <em>Please keep in mind that the operators of the server and any receiving server may view such messages</em>, and that recipients may screenshot, copy or otherwise re-share them. <em>Do not share any dangerous information over Mastodon.</em></li>
<li><em>IPs and other metadata</em>: When you log in, we record the IP address you log in from, as well as the name of your browser application. All the logged in sessions are available for your review and revocation in the settings. The latest IP address used is stored for up to 12 months. We also may retain server logs which include the IP address of every request to our server.</li>
</ul>
<hr class="spacer" />
<h3 id="use">What do we use your information for?</h3>
<p>Any of the information we collect from you may be used in the following ways:</p>
<ul>
<li>To provide the core functionality of Mastodon. You can only interact with other peoples content and post your own content when you are logged in. For example, you may follow other people to view their combined posts in your own personalized home timeline.</li>
<li>To aid moderation of the community, for example comparing your IP address with other known ones to determine ban evasion or other violations.</li>
<li>The email address you provide may be used to send you information, notifications about other people interacting with your content or sending you messages, and to respond to inquiries, and/or other requests or questions.</li>
</ul>
<hr class="spacer" />
<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. Among other things, your browser session, as well as the traffic between your applications and the API, are secured with SSL, and your password is hashed using a strong one-way algorithm. You may enable two-factor authentication to further secure access to your account.</p>
<hr class="spacer" />
<h3 id="data-retention">What is our 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, in so far as such logs are kept, no more than 90 days.</li>
<li>Retain the IP addresses associated with registered users no more than 12 months.</li>
</ul>
<p>You can request and download an archive of your content, including your posts, media attachments, profile picture, and header image.</p>
<p>You may irreversibly delete your account at any time.</p>
<hr class="spacer"/>
<h3 id="cookies">Do we use cookies?</h3>
<p>Yes. Cookies are small files that a site or its service provider transfers to your computers 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.</p>
<hr class="spacer" />
<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.</p>
<p>Your public content may be downloaded by other servers in the network. Your public and followers-only posts are delivered to the servers where your followers reside, and direct messages are delivered to the servers of the recipients, in so far as those followers or recipients reside on a different server than this.</p>
<p>When you authorize an application to use your account, depending on the scope of permissions you approve, it may access your public profile information, your following list, your followers, your lists, all your posts, and your favourites. Applications can never access your e-mail address or password.</p>
<hr class="spacer" />
<h3 id="coppa">Childrens 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">Childrens Online Privacy Protection Act</a>) do not use this site.</p>
<hr class="spacer" />
<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 March 7, 2018.</p>
<p>Originally adapted from the <a href="https://github.com/discourse/discourse">Discourse privacy policy</a>.</p>
title: Termini dusu è di cunfidenzialità per %{instance}
themes:
contrast: Cuntrastu altu
default: Mastodon
time:
formats:
default: "%d %b %Y, %H:%M"
two_factor_authentication:
code_hint: Entrate u codice generatu da lapplicazione per cunfirmà
description_html: Sella hè attivata <strong>lidentificazione à dui fattori</strong>, duvete avè u vostru telefuninu pè ottene un codice di cunnezzione.
disable: Disattivà
enable: Attivà
enabled: Identificazione à dui fattori attivata
enabled_success: Lidentificazione à dui fattori hè stata attivata.
generate_recovery_codes: Creà codici di ricuperazione
instructions_html: "<strong>Scanate stu QR code cù Google Authenticator, Authy o qualcosa cusì nantà u vostru telefuninu</strong>. Stapplicazione hà da creà codici da entrà ogni volta chì vi cunnettate."
lost_recovery_codes: I codici di ricuperazione à usu unicu vi permettenu di sempre avè accessu à u vostru contu sè voi avete persu u vostru telefuninu. Selli sò ancu persi, pudete creà codici novi quì. I vechji codici ùn marchjeranu più.
manual_instructions: Sellu ùn hè micca pussibule scanà u QR code, pudete entre sta chjave sicreta:
recovery_codes: Codici di ricuperazione
recovery_codes_regenerated: Codici di ricuperazione ricreati
recovery_instructions_html: Pudete fà usu di i codici quì sottu per sempre avè accessu à u vostru contu sellu hè statu persu u vostru telefuninu. <strong>Guardateli in una piazza sicura</strong>. Per esempiu, stampati è cunservati cù altri ducumenti impurtanti.
setup: Installà
wrong_code: U codice ùn hè micca currettu! Site sicuru che lora di u telefuninu è di u servore sò esatte?
user_mailer:
backup_ready:
explanation: Avete dumandatu unarchiviu cumpletu di u vostru contu Mastodon. Avà hè prontu per scaricà!
subject: U vostru archiviu hè prontu à scaricà
title: Archiviu prontu
welcome:
edit_profile_action: Cunfigurazione di u prufile
edit_profile_step: Pudete persunalizà u vostru prufile cù un ritrattu di prufile o di cuprendula, un nome pubblicu persunalizatu, etc. Pudete ancu rende u contu privatu per duvè cunfirmà ogni dumanda dabbunamentu.
explanation: Eccu alcune idee per principià
final_action: Principià à pustà
final_step: 'Andemu! Ancu senza abbunati i vostri missaghji pubblichi puderanu esse visti da altre persone, per esempiu nanta linea lucale è lhashtag. Pudete ancu prisintavi nantà u hashtag #introductions!'
full_handle: U vostru identificatore cumplettu
full_handle_hint: Quessu ghjè cio chì direte à i vostri amichi per circavi, abbunassi à u vostru contu da altrò, o mandà missaghji.
review_preferences_action: Mudificà e priferenze
review_preferences_step: Quì pudete adattà u cumpurtamentu di Mastodon à e vostre priferenze, cumè lemail che vulete riceve, u nivellu di cunfidenzialità predefinitu di i vostri statuti, o u cumpurtamentu di i GIF animati.
subject: Benvenutu·a nantà Mastodon
tip_bridge_html: Sè voi venite di Twitter, pudete truvà i vostri amichi da quallà chì sò nantà Mastodon cù a <a href="%{bridge_url}">bridge app</a>. Mà ùn marchja chè selli lanu ancu usata!
tip_federated_timeline: A linea pubblica glubale mostra i statuti da altre istanze nanta rete Mastodon, mà ùn hè micca cumpleta perchè ci sò soli i conti à quelli sò abbunati membri di a vostristanza.
tip_following: Site digià abbunatu·a à lamministratori di u vostru servore. Per truvà daltre parsone da siguità, pudete pruvà e linee pubbliche.
tip_local_timeline: A linea pubblica lucale ghjè una vista crunulogica di i statuti di a ghjente nantà %{instance}.
tip_mobile_webapp: Pudete aghjunghje Mastodon à a pagina daccolta di u vostru navigatore di telefuninu per riceve nutificazione, cumun applicazione.
tips: Cunsiglii
title: Benvenutu·a, %{name}!
users:
invalid_email: Lindirizzu e-mail ùn hè currettu.
invalid_otp_token: U codice didentificazione ùn hè currettu.
seamless_external_login: Site cunnettatu·a dapoi un serviziu esternu, allora i parametri di chjave daccessu è dindirizzu e-mail ùn so micca dispunibili.
signed_in_as: 'Cunnettatu·a cumè:'

@ -53,9 +53,7 @@ de:
unfollow: Entfolgen unfollow: Entfolgen
admin: admin:
account_moderation_notes: account_moderation_notes:
account: Moderator*in
create: Erstellen create: Erstellen
created_at: Datum
created_msg: Moderationsnotiz erfolgreich erstellt! created_msg: Moderationsnotiz erfolgreich erstellt!
delete: Löschen delete: Löschen
destroyed_msg: Moderationsnotiz erfolgreich gelöscht! destroyed_msg: Moderationsnotiz erfolgreich gelöscht!
@ -72,6 +70,7 @@ de:
title: E-Mail-Adresse für %{username} ändern title: E-Mail-Adresse für %{username} ändern
confirm: Bestätigen confirm: Bestätigen
confirmed: Bestätigt confirmed: Bestätigt
confirming: Bestätigung
demote: Degradieren demote: Degradieren
disable: Ausschalten disable: Ausschalten
disable_two_factor_authentication: 2FA abschalten disable_two_factor_authentication: 2FA abschalten
@ -80,6 +79,7 @@ de:
domain: Domain domain: Domain
edit: Bearbeiten edit: Bearbeiten
email: E-Mail email: E-Mail
email_status: E-Mail-Status
enable: Freischalten enable: Freischalten
enabled: Freigegeben enabled: Freigegeben
feed_url: Feed-URL feed_url: Feed-URL
@ -118,6 +118,10 @@ de:
push_subscription_expires: PuSH-Abonnement läuft aus push_subscription_expires: PuSH-Abonnement läuft aus
redownload: Avatar neu laden redownload: Avatar neu laden
remove_avatar: Profilbild entfernen remove_avatar: Profilbild entfernen
resend_confirmation:
already_confirmed: Dieser Benutzer wurde bereits bestätigt
send: Bestätigungsmail erneut senden
success: Bestätigungs-E-Mail erfolgreich gesendet!
reset: Zurücksetzen reset: Zurücksetzen
reset_password: Passwort zurücksetzen reset_password: Passwort zurücksetzen
resubscribe: Wieder abonnieren resubscribe: Wieder abonnieren
@ -269,7 +273,6 @@ de:
comment: comment:
none: Kein none: Kein
created_at: Gemeldet created_at: Gemeldet
delete: Löschen
id: ID id: ID
mark_as_resolved: Als gelöst markieren mark_as_resolved: Als gelöst markieren
mark_as_unresolved: Als ungelöst markieren mark_as_unresolved: Als ungelöst markieren
@ -279,9 +282,6 @@ de:
create_and_unresolve: Mit Kommentar wieder öffnen create_and_unresolve: Mit Kommentar wieder öffnen
delete: Löschen delete: Löschen
placeholder: Beschreibe, welche Maßnahmen ergriffen wurden oder andere Neuigkeiten zu dieser Meldung… placeholder: Beschreibe, welche Maßnahmen ergriffen wurden oder andere Neuigkeiten zu dieser Meldung…
nsfw:
'false': Medienanhänge wieder anzeigen
'true': Medienanhänge verbergen
reopen: Meldung wieder öffnen reopen: Meldung wieder öffnen
report: 'Meldung #%{id}' report: 'Meldung #%{id}'
report_contents: Inhalt report_contents: Inhalt
@ -356,11 +356,8 @@ de:
delete: Löschen delete: Löschen
nsfw_off: Als nicht heikel markieren nsfw_off: Als nicht heikel markieren
nsfw_on: Als heikel markieren nsfw_on: Als heikel markieren
execute: Ausführen
failed_to_execute: Ausführen fehlgeschlagen failed_to_execute: Ausführen fehlgeschlagen
media: media:
hide: Medien verbergen
show: Medien anzeigen
title: Medien title: Medien
no_media: Keine Medien no_media: Keine Medien
title: Beiträge des Kontos title: Beiträge des Kontos

@ -0,0 +1,82 @@
---
co:
devise:
confirmations:
confirmed: U vostru indirizzu email hè statu cunfirmatu.
send_instructions: Avete da riceve unemail cù listruzzione di cunfirmazione in qualchì minuta. Pensate à verificà u cartulare di spam sellu ùn chè nunda.
send_paranoid_instructions: Sellu esiste u vostru indirizzu email in a database, avete da riceve listruzzione pè cunfirmà u vostru contu in qualchì minuta. Pensate à verificà u cartulare di spam sellu ùn chè nunda.
failure:
already_authenticated: Site digià cunnettatu·a.
inactive: U vostru contu ùn hè ancu attivatu.
invalid: L %{authentication_keys} o a chjave daccessu ùn sò curretti.
last_attempt: Avete unultimu tintativu nanzu chì u vostru contu sia chjosu.
locked: U vostru contu hè chjosu.
not_found_in_database: L %{authentication_keys} o a chjave daccessu ùn sò curretti.
timeout: A vostra sezzione hè spirata. Ricunnettatevi pè cuntinuà.
unauthenticated: Cunnettatevi o arregistratevi pè cuntinuà.
unconfirmed: Duvete cunfirmà u vostru contu pè cuntinuà.
mailer:
confirmation_instructions:
action: Verificà lindirizzu email
explanation: Avete creatu un contu nantà %{host} cù stindirizzu email. Pudete attivallu cù un clic, o ignurà quessu missaghji sellu un era micca voi.
extra_html: Pensate à leghje <a href="%{terms_path}">e regule di listanza</a> è <a href="%{policy_path}">i termini dusu</a>.
subject: 'Mastodon: Istruzzione di cunfirmazione per %{instance}'
title: Verificà lindirizzu email
email_changed:
explanation: 'Lindirizzu email di u vostru contu hè stata cambiata per:'
extra: Sellu un era micca voi chavete cambiatu u vostru email, qualchunaltru hà accessu à u vostru contu. Duvete cambià a vostra chjave daccessu o cuntattà lamministratore di listanza sellu ùn hè più pussibule di cunnettavi.
subject: 'Mastodon: Email cambiatu'
title: Novu indirizzu email
password_change:
explanation: A chjave daccessu per u vostru contu hè stata cambiata.
extra: Sellu un era micca voi chavete cambiatu a vostra chjave daccessu, qualchunaltru hà accessu à u vostru contu. Duvete cambià a vostra chjave daccessu o cuntattà lamministratore di listanza sellu ùn hè più pussibule di cunnettavi.
subject: 'Mastodon: Chjave daccessu cambiata'
title: Chjave cambiata
reconfirmation_instructions:
explanation: Cunfirmà u novu indirizzu per cambià lemail.
extra: Sellu ùn era micca voi, ignurate stu missaghju. Lemail ùn cambiarà micca sè voi ùn cliccate micca u ligame.
subject: 'Mastodon: Cunfirmà lemail per %{instance}'
title: Verificà indirizzu email
reset_password_instructions:
action: Cambià a chjave daccessu
explanation: Avete dumandatu una nova chjave daccessu per u vostru contu.
extra: Sellu ùn era micca voi, ignurate stu missaghju. A chjave daccessu ùn cambiarà micca sè voi ùn cliccate micca u ligame.
subject: 'Mastodon: Cambià a chjave daccessu'
title: Cambià a chjave
unlock_instructions:
subject: 'Mastodon: Riapre u contu'
omniauth_callbacks:
failure: Ùn pudemu micca cunnettavi da %{kind} perchè "%{reason}".
success: Vi site cunnettatu·a da %{kind}.
passwords:
no_token: Ùn pudete micca vede sta pagina senza vene dun e-mail di cambiamentu di chjave daccessu. Sè voi venite quì dapoi ste-mail, assicuratevi chavete utilizatu lindirizzu URL cumpletu.
send_instructions: Avete da riceve listruzzione di cambiamentu di a chjave daccessu in qualchì minuta.
send_paranoid_instructions: Sellu esiste u vostre-mail in a database, avete da riceve un ligame di reinizialisazione.
updated: A vostra chjave daccessu hè stata cambiata, è site cunnettatu·a.
updated_not_active: A vostra chjave daccessu hè stata cambiata.
registrations:
destroyed: U vostru contu hè statu sguassatu. Avvedeci!
signed_up: Benvinutu! Site cunnettatu·a.
signed_up_but_inactive: Site arregistratu·a, mà ùn pudete micca cunnettavi perchè u vostru contu deve esse attivatu.
signed_up_but_locked: Site arregistratu·a, mà ùn pudete micca cunnettavi perchè u vostru contu hè chjosu.
signed_up_but_unconfirmed: Un missaghju cù un ligame di cunfirmazione hè statu mandatu à u vostru indirizzu e-mail. Aprite stu ligame pè attivà u vostru contu. Pensate à verificà u cartulare di spam sellu ùn chè nunda.
update_needs_confirmation: U vostru contu hè statu messu à ghjornu mà duvemu verificà u vostru novu e-mail. Un missaghju cù un ligame di cunfirmazione hè statu mandatu. Pensate à verificà u cartulare di spam sellu ùn chè nunda.
updated: U vostru contu hè statu messu à ghjornu.
sessions:
already_signed_out: Scunnettatu·a.
signed_in: Cunnettatu·a.
signed_out: Scunnettatu·a.
unlocks:
send_instructions: Avete da riceve une-mail cù listruzzione pè riapre u vostru contu in qualchì minuta.
send_paranoid_instructions: Sellu esiste u vostru contu, avete da riceve une-mail dù listruzzione pè riapre u vostru contu.
unlocked: U vostru contu hè statu riapertu, pudete cunnettavi pè cuntinuà.
errors:
messages:
already_confirmed: hè digià cunfirmatu, pudete pruvà à cunnettà vi
confirmation_period_expired: deve esse cunfirmatu nanzà %{period}, duvete fà unaltra dumanda
expired: hè spiratu, duvete fà unaltra dumanda
not_found: ùn hè micca statu trovu
not_locked: ùn era micca chjosu
not_saved:
one: Un prublemu hà impeditu a cunservazione di stu (sta) %{resource}
other: "%{count} prublemi anu impeditu a cunservazione di stu (sta) %{resource} :"

@ -0,0 +1,119 @@
---
co:
activerecord:
attributes:
doorkeeper/application:
name: Nome di lapplicazione
redirect_uri: URI di ridirezzione
scopes: Scopi
website: Situ di lapplicazione
errors:
models:
doorkeeper/application:
attributes:
redirect_uri:
fragment_present: ùn pò cuntene un pezzu.
invalid_uri: duve esse unURI curretta.
relative_uri: duve esse unURI assoluta.
secured_uri: duve esse unURL HTTPS/SSL.
doorkeeper:
applications:
buttons:
authorize: Appruvà
cancel: Sguassà
destroy: Strughje
edit: Mudificà
submit: Mandà
confirmations:
destroy: Site sicuru·a?
edit:
title: Mudificà lapplicazione
form:
error: Uups! Vinvitemu à verificà u vostru formulariu per vede selli ùn ci sò sbaglii.
help:
native_redirect_uri: Utilizate %{native_redirect_uri} pè e prove lucale
redirect_uri: Utilizzate una linea per ogni URI
scopes: Separate i scopi cù spazii. Lasciate viotu per utilizzà i scopi predefiniti.
index:
application: Applicazione
callback_url: URL di richjama
delete: Toglie
name: Nome
new: Applicazione nova
scopes: Scopi
show: Vede
title: E vostre applicazione
new:
title: Applicazione nova
show:
actions: Azzioni
application_id: Chjave di u clientu
callback_urls: URL di richjama
scopes: Scopi
secret: Sicretu di u clientu
title: 'Applicazione : %{name}'
authorizations:
buttons:
authorize: Appruvà
deny: Ricusà
error:
title: Chè statu un prublemu
new:
able_to: Stapplicazione puderà
prompt: Parmette %{client_name} dutilizzà u vostru contu?
title: Permessu riquestu
show:
title: Codice dauturizazione da cupià indè lapplicazione
authorized_applications:
buttons:
revoke: Sguassà
confirmations:
revoke: Site sicuru·a?
index:
application: Applicazione
created_at: Auturizata u
date_format: "%d-%m-%Y %H:%M:%S"
scopes: Scopi
title: E vostre applicazione auturizate
errors:
messages:
access_denied: U pruprietariu di a risorsa o u servore dautitinficazione hà ricusatu a dumanda.
credential_flow_not_configured: U flussu di lidentificazione di u pruprietariu di a risorsa hà fiascatu perchè Doorkeeper.configure.resource_owner_from_credentials ùn hè micca cunfiguratu.
invalid_client: Lautintificazione di u cliente hà fiascatu perchè u cliente ùn hè micca cunnisciutu, lidentificazione di u cliente ùn hè cumpresa, o u modu didentificazione ùn marchja micca.
invalid_grant: Laccunsentu dauturizazione furnitu ùn hè currettu, hè spiratu, sguassatu, ùn và micca cù lindirizzu di ridirezzione usatu in a dumanda dauturizazione, o hè statu emessu per unaltru cliente.
invalid_redirect_uri: LURI di ridirezzione ùn hè curretta.
invalid_request: Ci manca un parametru riquestu indè a dumanda, cuntene un parametru chùn esiste micca, o altru sbagliu di forma.
invalid_resource_owner: Lidintificanti di u pruprietariu di a risorsa ùn sò curretti, o u pruprietariu ùn pò micca esse trovu.
invalid_scope: U scopu dumandatu ùn hè currettu, hè scunnisciutu, o altru sbagliu di forma.
invalid_token:
expired: A marca daccessu hè spirata
revoked: A marca daccessu hè stata rivucata
unknown: A marca daccessu ùn hè curretta
resource_owner_authenticator_not_configured: Ùn chè micca pussutu ricercà u pruprietariu di a risorsa perchè Doorkeeper.configure.resource_owner_authenticator ùn hè micca cunfiguratu.
server_error: Chè statu un prublemu cù u servore dauturizazione.
temporarily_unavailable: U servore dauturizazione ùn pò micca trattà a dumanda avà perchè hè sopraccaricatu o in mantenimentu.
unauthorized_client: U cliente ùn pò micca fà sta dumanda cusì.
unsupported_grant_type: Stu tippu daccunsentu ùn marchja micca nantà stu servore dauturizazione.
unsupported_response_type: Sta risposta ùn marchja micca nantà stu servore dauturizazione.
flash:
applications:
create:
notice: Applicazione creata.
destroy:
notice: Applicazione sguassata.
update:
notice: Applicazione messa à ghjornu.
authorized_applications:
destroy:
notice: Applicazione sguassata.
layouts:
admin:
nav:
applications: Applicazione
oauth2_provider: Furnitore OAuth2
application:
title: Auturizazione OAuth riquestata.
scopes:
follow: bluccà, sbluccà, è reghje labbunamenti
read: leghje linfurmazione di u vostru contu
write: mandà missaghji per voi

@ -33,14 +33,14 @@ sk:
help: help:
native_redirect_uri: Použite %{native_redirect_uri} pre lokálne testy native_redirect_uri: Použite %{native_redirect_uri} pre lokálne testy
redirect_uri: Iba jedna URI na riadok redirect_uri: Iba jedna URI na riadok
scopes: Rozsahy oddeľujte medzerami. Nechajte prázdne pre štandardné rozsahy. scopes: Oprávnenia oddeľujte medzerami. Nechajte prázdne pre štandardné oprávnenia.
index: index:
application: Aplikácia application: Aplikácia
callback_url: Návratová URL callback_url: Návratová URL
delete: Zmazať delete: Zmazať
name: Názov name: Názov
new: Nová aplikácia new: Nová aplikácia
scopes: Rozsahy scopes: Oprávnenia
show: Ukázať show: Ukázať
title: Vaše aplikácie title: Vaše aplikácie
new: new:
@ -49,7 +49,7 @@ sk:
actions: Akcie actions: Akcie
application_id: Kľúč klienta application_id: Kľúč klienta
callback_urls: Návratové URL adresy callback_urls: Návratové URL adresy
scopes: Rozsahy scopes: Oprávnenia
secret: Tajné slovo klienta secret: Tajné slovo klienta
title: 'Aplikácia: %{name}' title: 'Aplikácia: %{name}'
authorizations: authorizations:
@ -73,7 +73,7 @@ sk:
application: Aplikácia application: Aplikácia
created_at: Autorizované created_at: Autorizované
date_format: "%Y-%m-%d %H:%M:%S" date_format: "%Y-%m-%d %H:%M:%S"
scopes: Rozsahy scopes: Oprávnenia
title: Vaše autorizované aplikácie title: Vaše autorizované aplikácie
errors: errors:
messages: messages:

@ -1,12 +1,15 @@
--- ---
el: el:
about: about:
about_hashtag_html: Αυτά είναι δημόσια τουτ σημειωμένα με <strong>#%{hashtag}</strong>. Μπορείς να αλληλεπιδράσεις με αυτά αν έχεις λογαριασμό οπουδήποτε στο fediverse.
about_mastodon_html: Το Mastodon είναι ένα κοινωνικό δίκτυο που βασίζεται σε ανοιχτά δικτυακά πρωτόκολλα και ελεύθερο λογισμικό ανοιχτού κώδικα. Είναι αποκεντρωμένο όπως το e-mail. about_mastodon_html: Το Mastodon είναι ένα κοινωνικό δίκτυο που βασίζεται σε ανοιχτά δικτυακά πρωτόκολλα και ελεύθερο λογισμικό ανοιχτού κώδικα. Είναι αποκεντρωμένο όπως το e-mail.
about_this: Σχετικά about_this: Σχετικά
administered_by: 'Διαχειρίζεται από:' administered_by: 'Διαχειρίζεται από:'
closed_registrations: Αυτή τη στιγμή οι εγγραφές σε αυτό τον διακομιστή είναι κλειστές. Αλλά! Μπορείς να βρεις έναν άλλο διακομιστή για να ανοίξεις λογαριασμό και να έχεις πρόσβαση από εκεί στο ίδιο ακριβώς δίκτυο. closed_registrations: Αυτή τη στιγμή οι εγγραφές σε αυτό τον διακομιστή είναι κλειστές. Αλλά! Μπορείς να βρεις έναν άλλο διακομιστή για να ανοίξεις λογαριασμό και να έχεις πρόσβαση από εκεί στο ίδιο ακριβώς δίκτυο.
contact: Επικοινωνία contact: Επικοινωνία
contact_missing: Δεν έχει οριστεί contact_missing: Δεν έχει οριστεί
contact_unavailable: Μ
description_headline: Τι είναι το %{domain};
domain_count_after: άλλοι διακομιστές domain_count_after: άλλοι διακομιστές
domain_count_before: Συνδέεται με domain_count_before: Συνδέεται με
extended_description_html: | extended_description_html: |
@ -15,9 +18,12 @@ el:
features: features:
humane_approach_body: Μαθαίνοντας από τις αποτυχίες άλλων δικτύων, το Mastodon στοχεύει να κάνει σχεδιαστικά ηθικές επιλογές για να καταπολεμήσει την κακόβουλη χρήση των κοινωνικών δικτύων. humane_approach_body: Μαθαίνοντας από τις αποτυχίες άλλων δικτύων, το Mastodon στοχεύει να κάνει σχεδιαστικά ηθικές επιλογές για να καταπολεμήσει την κακόβουλη χρήση των κοινωνικών δικτύων.
humane_approach_title: Μια πιο ανθρώπινη προσέγγιση humane_approach_title: Μια πιο ανθρώπινη προσέγγιση
not_a_product_body: Το Mastodon δεν είναι εμπορικό δίκτυο. Χωρίς διαφημίσεις, χωρίς εξόρυξη δεδομένων, χωρίς φραγμένες περιοχές. Δεν έχει κεντρική αρχή.
not_a_product_title: Είσαι άτομο, όχι προϊόν not_a_product_title: Είσαι άτομο, όχι προϊόν
real_conversation_body: Με 500 χαρακτήρες στη διάθεσή σου και υποστήριξη για λεπτομερή έλεγχο και προειδοποιήσεις πολυμέσων, μπορείς να εκφραστείς με τον τρόπο που θέλεις.
real_conversation_title: Φτιαγμένο για αληθινή συζήτηση real_conversation_title: Φτιαγμένο για αληθινή συζήτηση
within_reach_body: Οι πολλαπλές εφαρμογές για το iOS, το Android και τις υπόλοιπες πλατφόρμες, χάρη σε ένα φιλικό προς τους προγραμματιστές οικοσύστημα API, σου επιτρέπουν να κρατάς επαφή με τους φίλους και τις φίλες σου οπουδήποτε. within_reach_body: Οι πολλαπλές εφαρμογές για το iOS, το Android και τις υπόλοιπες πλατφόρμες, χάρη σε ένα φιλικό προς τους προγραμματιστές οικοσύστημα API, σου επιτρέπουν να κρατάς επαφή με τους φίλους και τις φίλες σου οπουδήποτε.
within_reach_title: Πάντα προσβάσιμο
generic_description: "%{domain} είναι ένας εξυπηρετητής στο δίκτυο" generic_description: "%{domain} είναι ένας εξυπηρετητής στο δίκτυο"
hosted_on: Το Mastodon φιλοξενείται στο %{domain} hosted_on: Το Mastodon φιλοξενείται στο %{domain}
learn_more: Μάθε περισσότερα learn_more: Μάθε περισσότερα
@ -26,6 +32,7 @@ el:
status_count_after: καταστάσεις status_count_after: καταστάσεις
status_count_before: Ποιός συνέγραψε status_count_before: Ποιός συνέγραψε
user_count_after: χρήστες user_count_after: χρήστες
user_count_before: Σπίτι
what_is_mastodon: Τι είναι το Mastodon; what_is_mastodon: Τι είναι το Mastodon;
accounts: accounts:
follow: Ακολούθησε follow: Ακολούθησε
@ -38,3 +45,163 @@ el:
people_who_follow: Χρήστες που ακολουθούν τον/την %{name} people_who_follow: Χρήστες που ακολουθούν τον/την %{name}
posts: Τουτ posts: Τουτ
posts_with_replies: Τουτ και απαντήσεις posts_with_replies: Τουτ και απαντήσεις
remote_follow: Απομακρυσμένη παρακολούθηση
reserved_username: Το όνομα χρήστη είναι κατειλημμένο
roles:
admin: Διαχειριστής
moderator: Μεσολαβητής
unfollow: Διακοπή παρακολούθησης
admin:
account_moderation_notes:
create: Δημιουργία
created_msg: Επιτυχής δημιουργία σημειώματος μεσολάβησης!
delete: Διαγραφή
destroyed_msg: Επιτυχής καταστροφή σημειώματος μεσολάβησης!
accounts:
are_you_sure: Σίγουρα;
avatar: Αβατάρ
by_domain: Τομέας
change_email:
changed_msg: Επιτυχής αλλαγή email λογαριασμού!
current_email: Τρέχον email
label: Αλλαγή email
new_email: Νέο email
submit: Αλλαγή email
title: Αλλαγή email για %{username}
confirm: Επιβεβαίωση
confirmed: Επιβεβαιώθηκε
demote: Υποβίβαση
disable: Απενεργοποίηση
disable_two_factor_authentication: Απενεργοποίηση 2FA
disabled: Απενεργοποιημένο
display_name: Όνομα εμφάνισης
domain: Τομέας
edit: Αλλαγή
email: Email
enable: Ενεργοποίηση
enabled: Ενεργοποιημένο
feed_url: URL ροής
followers: Ακόλουθοι
followers_url: URL ακολούθων
follows: Ακολουθεί
inbox_url: URL εισερχομένων
ip: IP
location:
all: Όλα
local: Τοπικά
remote: Απομακρυσμένα
title: Τοποθεσία
login_status: Κατάσταση εισόδου
media_attachments: Συνημμένα πολυμέσα
memorialize: Μετατροπή σε νεκρολογία
moderation:
all: Όλα
silenced: Αποσιωπημένα
suspended: Σε αναστολή
title: Μεσολάβηση
moderation_notes: Σημειώσεις μεσολάβησης
most_recent_activity: Πιο πρόσφατη δραστηριότητα
most_recent_ip: Πιο πρόσφατη IP
not_subscribed: Άνευ εγγραφής
order:
alphabetic: Αλφαβητικά
most_recent: Πιο πρόσφατα
title: Ταξινόμηση
outbox_url: URL εξερχομένων
perform_full_suspension: Πλήρης αναστολή
profile_url: URL προφίλ
promote: Προβίβασε
protocol: Πρωτόκολλο
public: Δημόσιο
push_subscription_expires: Η εγγραφή PuSH λήγει
redownload: Ανανέωση αβατάρ
remove_avatar: Απομακρυσμένο αβατάρ
reset: Επαναφορά
reset_password: Επαναφορά συνθηματικού
resubscribe: Επανεγγραφή
role: Δικαιώματα
roles:
admin: Διαχειριστής
moderator: Μεσολαβητής
staff: Προσωπικό
user: Χρήστης
salmon_url: URL Salmon
search: Αναζήτηση
shared_inbox_url: URL κοινόχρηστων εισερχομένων
show:
created_reports: Αναφορές από αυτόν το λογαριασμό
report: ανάφερε
targeted_reports: Αναφορές για αυτόν το λογαριασμό
silence: Αποσιώπησε
statuses: Καταστάσεις
subscribe: Εγγραφή
title: Λογαριασμοί
unconfirmed_email: Ανεπιβεβαίωτο email
undo_silenced: Αναίρεση αποσιώπησης
undo_suspension: Αναίρεση παύσης
unsubscribe: Κατάργηση εγγραφής
username: Όνομα χρήστη
web: Διαδίκτυο
action_logs:
actions:
assigned_to_self_report: Ο/Η %{name} ανάθεσε την αναφορά %{target} στον εαυτό του/της
change_email_user: Ο/Η %{name} άλλαξε τη διεύθυνση email του χρήστη %{target}
confirm_user: Ο/Η %{name} επιβεβαίωσε τη διεύθυνση email του χρήστη %{target}
create_custom_emoji: Ο/Η %{name} ανέβασε νέο emoji %{target}
create_domain_block: Ο/Η %{name} μπλόκαρε τον τομέα %{target}
create_email_domain_block: Ο/Η %{name} έβαλε τον τομέα email %{target} σε μαύρη λίστα
demote_user: Ο/Η %{name} υποβίβασε το χρήστη %{target}
destroy_domain_block: Ο/Η %{name} ξεμπλόκαρε τον τομέα %{target}
destroy_email_domain_block: Ο/Η %{name} έβαλε τον τομέα email %{target} σε λευκή λίστα
destroy_status: Ο/Η %{name} αφαίρεσε την κατάσταση του/της %{target}
disable_2fa_user: Ο/Η %{name} απενεργοποίησε την απαίτηση δύο παραγόντων για το χρήστη %{target}
disable_custom_emoji: Ο/Η %{name} απενεργοποίησε το emoji %{target}
disable_user: Ο/Η %{name} απενεργοποίησε την είσοδο για το χρήστη %{target}
enable_custom_emoji: Ο/Η %{name} ενεργοποίησε το emoji %{target}
enable_user: Ο/Η %{name} ενεργοποίησε την είσοδο του χρήστη %{target}
memorialize_account: Ο/Η %{name} μετέτρεψε το λογαριασμό του/της %{target} σε σελίδα νεκρολογίας
promote_user: Ο/Η %{name} προβίβασε το χρήστη %{target}
remove_avatar_user: Ο/Η %{name} αφαίρεσε το αβατάρ του/της %{target}
reopen_report: Ο/Η %{name} ξανάνοιξε την αναφορά %{target}
reset_password_user: Ο/Η %{name} επανέφερε το συνθηματικό του χρήστη %{target}
resolve_report: Ο/Η %{name} επέλυσε την αναφορά %{target}
silence_account: Ο/Η %{name} αποσιώπησε το λογαριασμό του/της %{target}
suspend_account: Ο/Η %{name} έπαυσε το λογαριασμό του/της %{target}
unassigned_report: Ο/Η %{name} αποδέσμευσε την αναφορά %{target}
unsilence_account: Ο/Η %{name} ήρε την αποσιώπηση του λογαριασμού του/της %{target}
unsuspend_account: Ο/Η %{name} ήρε την παύση του λογαριασμού του χρήστη %{target}
update_custom_emoji: Ο/Η %{name} ενημέρωσε το emoji %{target}
update_status: Ο/Η %{name} ενημέρωσε την κατάσταση του/της %{target}
title: Αρχείο ελέγχου
custom_emojis:
by_domain: Τομέας
copied_msg: Επιτυχής δημιουργία τοπικού αντίγραφου του emoji
copy: Αντιγραφή
copy_failed_msg: Αδυναμία δημιουργίας τοπικού αντίγραφου αυτού του emoji
created_msg: Επιτυχής δημιουργία του emoji!
delete: Διαγραφή
destroyed_msg: Επιτυχής καταστροφή του emojo!
disable: Απενεργοποίηση
disabled_msg: Επιτυχής απενεργοποίηση αυτού του emoji
emoji: Emoji
enable: Ενεργοποίηση
enabled_msg: Επιτυχής ενεργοποίηση αυτού του emoji
image_hint: PNG έως 50KB
listed: Αναφερθέντα
new:
title: Προσθήκη νέου προσαρμοσμένου emoji
overwrite: Αντικατάσταση
shortcode: Σύντομος κωδικός
shortcode_hint: Τουλάχιστον 2 χαρακτήρες, μόνο αλφαριθμητικοί και κάτω παύλες
title: Προσαρμοσμένα emoji
update_failed_msg: Αδυναμία ενημέρωσης του emoji
updated_msg: Επιτυχής ενημέρωση του Emoji!
upload: Ανέβασμα
domain_blocks:
add_new: Προσθήκη νέου
created_msg: Ο αποκλεισμός τομέα είναι υπό επεξεργασία
destroyed_msg: Ο αποκλεισμός τομέα άρθηκε
domain: Τομέας
new:
create: Δημιουργία αποκλεισμού
hint: Ο αποκλεισμός τομέα δεν θα αποτρέψει νέες καταχωρίσεις λογαριασμών στην βάση δεδομένων, αλλά θα εφαρμόσει αναδρομικά και αυτόματα συγκεκριμένες πολιτικές μεσολάβησης σε αυτούς τους λογαριασμούς.

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

Loading…
Cancel
Save