Merge remote-tracking branch 'personal/merge/tootsuite/master' into gs-master

th-downstream
David Yip 7 years ago
commit 19001dd3dd

@ -13,6 +13,7 @@ plugins:
- react - react
- jsx-a11y - jsx-a11y
- import - import
- promise
parserOptions: parserOptions:
sourceType: module sourceType: module
@ -157,3 +158,5 @@ rules:
- "app/javascript/**/__tests__/**" - "app/javascript/**/__tests__/**"
import/no-unresolved: error import/no-unresolved: error
import/no-webpack-loader-syntax: error import/no-webpack-loader-syntax: error
promise/catch-or-return: error

@ -2,7 +2,7 @@
module Admin module Admin
class AccountsController < BaseController class AccountsController < BaseController
before_action :set_account, only: [:show, :subscribe, :unsubscribe, :redownload, :enable, :disable, :memorialize] before_action :set_account, only: [:show, :subscribe, :unsubscribe, :redownload, :remove_avatar, :enable, :disable, :memorialize]
before_action :require_remote_account!, only: [:subscribe, :unsubscribe, :redownload] before_action :require_remote_account!, only: [:subscribe, :unsubscribe, :redownload]
before_action :require_local_account!, only: [:enable, :disable, :memorialize] before_action :require_local_account!, only: [:enable, :disable, :memorialize]
@ -60,6 +60,17 @@ module Admin
redirect_to admin_account_path(@account.id) redirect_to admin_account_path(@account.id)
end end
def remove_avatar
authorize @account, :remove_avatar?
@account.avatar = nil
@account.save!
log_action :remove_avatar, @account.user
redirect_to admin_account_path(@account.id)
end
private private
def set_account def set_account

@ -0,0 +1,49 @@
# frozen_string_literal: true
module Admin
class ReportNotesController < BaseController
before_action :set_report_note, only: [:destroy]
def create
authorize ReportNote, :create?
@report_note = current_account.report_notes.new(resource_params)
if @report_note.save
if params[:create_and_resolve]
@report_note.report.update!(action_taken: true, action_taken_by_account_id: current_account.id)
log_action :resolve, @report_note.report
redirect_to admin_reports_path, notice: I18n.t('admin.reports.resolved_msg')
else
redirect_to admin_report_path(@report_note.report_id), notice: I18n.t('admin.report_notes.created_msg')
end
else
@report = @report_note.report
@report_notes = @report.notes.latest
@form = Form::StatusBatch.new
render template: 'admin/reports/show'
end
end
def destroy
authorize @report_note, :destroy?
@report_note.destroy!
redirect_to admin_report_path(@report_note.report_id), notice: I18n.t('admin.report_notes.destroyed_msg')
end
private
def resource_params
params.require(:report_note).permit(
:content,
:report_id
)
end
def set_report_note
@report_note = ReportNote.find(params[:id])
end
end
end

@ -11,19 +11,35 @@ module Admin
def show def show
authorize @report, :show? authorize @report, :show?
@report_note = @report.notes.new
@report_notes = @report.notes.latest
@form = Form::StatusBatch.new @form = Form::StatusBatch.new
end end
def update def update
authorize @report, :update? authorize @report, :update?
process_report process_report
redirect_to admin_report_path(@report)
if @report.action_taken?
redirect_to admin_reports_path, notice: I18n.t('admin.reports.resolved_msg')
else
redirect_to admin_report_path(@report)
end
end end
private private
def process_report def process_report
case params[:outcome].to_s case params[:outcome].to_s
when 'assign_to_self'
@report.update!(assigned_account_id: current_account.id)
log_action :assigned_to_self, @report
when 'unassign'
@report.update!(assigned_account_id: nil)
log_action :unassigned, @report
when 'reopen'
@report.update!(action_taken: false, action_taken_by_account_id: nil)
log_action :reopen, @report
when 'resolve' when 'resolve'
@report.update!(action_taken_by_current_attributes) @report.update!(action_taken_by_current_attributes)
log_action :resolve, @report log_action :resolve, @report
@ -32,11 +48,13 @@ module Admin
log_action :resolve, @report log_action :resolve, @report
log_action :suspend, @report.target_account log_action :suspend, @report.target_account
resolve_all_target_account_reports resolve_all_target_account_reports
@report.reload
when 'silence' when 'silence'
@report.target_account.update!(silenced: true) @report.target_account.update!(silenced: true)
log_action :resolve, @report log_action :resolve, @report
log_action :silence, @report.target_account log_action :silence, @report.target_account
resolve_all_target_account_reports resolve_all_target_account_reports
@report.reload
else else
raise ActiveRecord::RecordNotFound raise ActiveRecord::RecordNotFound
end end

@ -40,11 +40,11 @@ class ApplicationController < ActionController::Base
end end
def require_admin! def require_admin!
redirect_to root_path unless current_user&.admin? forbidden unless current_user&.admin?
end end
def require_staff! def require_staff!
redirect_to root_path unless current_user&.staff? forbidden unless current_user&.staff?
end end
def check_suspension def check_suspension

@ -86,7 +86,7 @@ module Admin::ActionLogsHelper
opposite_verbs?(log) ? 'negative' : 'positive' opposite_verbs?(log) ? 'negative' : 'positive'
when :update, :reset_password, :disable_2fa, :memorialize when :update, :reset_password, :disable_2fa, :memorialize
'neutral' 'neutral'
when :demote, :silence, :disable, :suspend when :demote, :silence, :disable, :suspend, :remove_avatar, :reopen
'negative' 'negative'
when :destroy when :destroy
opposite_verbs?(log) ? 'positive' : 'negative' opposite_verbs?(log) ? 'positive' : 'negative'

@ -103,7 +103,7 @@ export function fetchAccount(id) {
dispatch(importFetchedAccount(response.data)); dispatch(importFetchedAccount(response.data));
})).then(() => { })).then(() => {
dispatch(fetchAccountSuccess()); dispatch(fetchAccountSuccess());
}, error => { }).catch(error => {
dispatch(fetchAccountFail(id, error)); dispatch(fetchAccountFail(id, error));
}); });
}; };

@ -1,3 +1,10 @@
import { defineMessages } from 'react-intl';
const messages = defineMessages({
unexpectedTitle: { id: 'alert.unexpected.title', defaultMessage: 'Oops!' },
unexpectedMessage: { id: 'alert.unexpected.message', defaultMessage: 'An unexpected error occurred.' },
});
export const ALERT_SHOW = 'ALERT_SHOW'; export const ALERT_SHOW = 'ALERT_SHOW';
export const ALERT_DISMISS = 'ALERT_DISMISS'; export const ALERT_DISMISS = 'ALERT_DISMISS';
export const ALERT_CLEAR = 'ALERT_CLEAR'; export const ALERT_CLEAR = 'ALERT_CLEAR';
@ -22,3 +29,21 @@ export function showAlert(title, message) {
message, message,
}; };
}; };
export function showAlertForError(error) {
if (error.response) {
const { data, status, statusText } = error.response;
let message = statusText;
let title = `${status}`;
if (data.error) {
message = data.error;
}
return showAlert(title, message);
} else {
console.error(error);
return showAlert(messages.unexpectedTitle, messages.unexpectedMessage);
}
}

@ -1,11 +1,12 @@
import api from '../api'; import api from '../api';
import { CancelToken } from 'axios'; import { CancelToken, isCancel } from 'axios';
import { throttle } from 'lodash'; import { throttle } from 'lodash';
import { search as emojiSearch } from '../features/emoji/emoji_mart_search_light'; import { search as emojiSearch } from '../features/emoji/emoji_mart_search_light';
import { tagHistory } from '../settings'; import { tagHistory } from '../settings';
import { useEmoji } from './emojis'; import { useEmoji } from './emojis';
import { importFetchedAccounts } from './importer'; import { importFetchedAccounts } from './importer';
import { updateTimeline } from './timelines'; import { updateTimeline } from './timelines';
import { showAlertForError } from './alerts';
let cancelFetchComposeSuggestionsAccounts; let cancelFetchComposeSuggestionsAccounts;
@ -291,6 +292,10 @@ const fetchComposeSuggestionsAccounts = throttle((dispatch, getState, token) =>
}).then(response => { }).then(response => {
dispatch(importFetchedAccounts(response.data)); dispatch(importFetchedAccounts(response.data));
dispatch(readyComposeSuggestionsAccounts(token, response.data)); dispatch(readyComposeSuggestionsAccounts(token, response.data));
}).catch(error => {
if (!isCancel(error)) {
dispatch(showAlertForError(error));
}
}); });
}, 200, { leading: true, trailing: true }); }, 200, { leading: true, trailing: true });

@ -1,5 +1,6 @@
import api from '../api'; import api from '../api';
import { importFetchedAccounts } from './importer'; import { importFetchedAccounts } from './importer';
import { showAlertForError } from './alerts';
export const LIST_FETCH_REQUEST = 'LIST_FETCH_REQUEST'; export const LIST_FETCH_REQUEST = 'LIST_FETCH_REQUEST';
export const LIST_FETCH_SUCCESS = 'LIST_FETCH_SUCCESS'; export const LIST_FETCH_SUCCESS = 'LIST_FETCH_SUCCESS';
@ -236,7 +237,7 @@ export const fetchListSuggestions = q => (dispatch, getState) => {
api(getState).get('/api/v1/accounts/search', { params }).then(({ data }) => { api(getState).get('/api/v1/accounts/search', { params }).then(({ data }) => {
dispatch(importFetchedAccounts(data)); dispatch(importFetchedAccounts(data));
dispatch(fetchListSuggestionsReady(q, data)); dispatch(fetchListSuggestionsReady(q, data));
}); }).catch(error => dispatch(showAlertForError(error)));
}; };
export const fetchListSuggestionsReady = (query, accounts) => ({ export const fetchListSuggestionsReady = (query, accounts) => ({

@ -116,14 +116,11 @@ export function register () {
pushNotificationsSetting.remove(me); pushNotificationsSetting.remove(me);
} }
try { return getRegistration()
getRegistration() .then(getPushSubscription)
.then(getPushSubscription) .then(unsubscribe);
.then(unsubscribe); })
} catch (e) { .catch(console.warn);
}
});
} else { } else {
console.warn('Your browser does not support Web Push Notifications.'); console.warn('Your browser does not support Web Push Notifications.');
} }
@ -143,6 +140,6 @@ export function saveSettings() {
if (me) { if (me) {
pushNotificationsSetting.set(me, data); pushNotificationsSetting.set(me, data);
} }
}); }).catch(console.warn);
}; };
} }

@ -1,5 +1,6 @@
import api from '../api'; import api from '../api';
import { debounce } from 'lodash'; import { debounce } from 'lodash';
import { showAlertForError } from './alerts';
export const SETTING_CHANGE = 'SETTING_CHANGE'; export const SETTING_CHANGE = 'SETTING_CHANGE';
export const SETTING_SAVE = 'SETTING_SAVE'; export const SETTING_SAVE = 'SETTING_SAVE';
@ -23,7 +24,9 @@ const debouncedSave = debounce((dispatch, getState) => {
const data = getState().get('settings').filter((_, path) => path !== 'saved').toJS(); const data = getState().get('settings').filter((_, path) => path !== 'saved').toJS();
api(getState).put('/api/web/settings', { data }).then(() => dispatch({ type: SETTING_SAVE })); api(getState).put('/api/web/settings', { data })
.then(() => dispatch({ type: SETTING_SAVE }))
.catch(error => dispatch(showAlertForError(error)));
}, 5000, { trailing: true }); }, 5000, { trailing: true });
export function saveSettings() { export function saveSettings() {

@ -27,6 +27,7 @@ import { initReport } from '../actions/reports';
import { openModal } from '../actions/modal'; import { openModal } from '../actions/modal';
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import { boostModal, deleteModal } from '../initial_state'; import { boostModal, deleteModal } from '../initial_state';
import { showAlertForError } from '../actions/alerts';
const messages = defineMessages({ const messages = defineMessages({
deleteConfirm: { id: 'confirmations.delete.confirm', defaultMessage: 'Delete' }, deleteConfirm: { id: 'confirmations.delete.confirm', defaultMessage: 'Delete' },
@ -83,7 +84,10 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
}, },
onEmbed (status) { onEmbed (status) {
dispatch(openModal('EMBED', { url: status.get('url') })); dispatch(openModal('EMBED', {
url: status.get('url'),
onError: error => dispatch(showAlertForError(error)),
}));
}, },
onDelete (status) { onDelete (status) {

@ -10,6 +10,7 @@ export default class EmbedModal extends ImmutablePureComponent {
static propTypes = { static propTypes = {
url: PropTypes.string.isRequired, url: PropTypes.string.isRequired,
onClose: PropTypes.func.isRequired, onClose: PropTypes.func.isRequired,
onError: PropTypes.func.isRequired,
intl: PropTypes.object.isRequired, intl: PropTypes.object.isRequired,
} }
@ -35,6 +36,8 @@ export default class EmbedModal extends ImmutablePureComponent {
iframeDocument.body.style.margin = 0; iframeDocument.body.style.margin = 0;
this.iframe.width = iframeDocument.body.scrollWidth; this.iframe.width = iframeDocument.body.scrollWidth;
this.iframe.height = iframeDocument.body.scrollHeight; this.iframe.height = iframeDocument.body.scrollHeight;
}).catch(error => {
this.props.onError(error);
}); });
} }

@ -2,7 +2,7 @@
"account.block": "حظر @{name}", "account.block": "حظر @{name}",
"account.block_domain": "إخفاء كل شيئ قادم من إسم النطاق {domain}", "account.block_domain": "إخفاء كل شيئ قادم من إسم النطاق {domain}",
"account.blocked": "محظور", "account.blocked": "محظور",
"account.direct": "Direct Message @{name}", "account.direct": "Direct message @{name}",
"account.disclaimer_full": "قد لا تعكس المعلومات أدناه الملف الشخصي الكامل للمستخدم.", "account.disclaimer_full": "قد لا تعكس المعلومات أدناه الملف الشخصي الكامل للمستخدم.",
"account.domain_blocked": "النطاق مخفي", "account.domain_blocked": "النطاق مخفي",
"account.edit_profile": "تعديل الملف الشخصي", "account.edit_profile": "تعديل الملف الشخصي",
@ -66,7 +66,7 @@
"compose_form.publish": "بوّق", "compose_form.publish": "بوّق",
"compose_form.publish_loud": "{publish}!", "compose_form.publish_loud": "{publish}!",
"compose_form.sensitive.marked": "لقد تم تحديد هذه الصورة كحساسة", "compose_form.sensitive.marked": "لقد تم تحديد هذه الصورة كحساسة",
"compose_form.sensitive.unmarked": "Media is not marked as sensitive", "compose_form.sensitive.unmarked": "لم يتم تحديد الصورة كحساسة",
"compose_form.spoiler.marked": "إنّ النص مخفي وراء تحذير", "compose_form.spoiler.marked": "إنّ النص مخفي وراء تحذير",
"compose_form.spoiler.unmarked": "النص غير مخفي", "compose_form.spoiler.unmarked": "النص غير مخفي",
"compose_form.spoiler_placeholder": "تنبيه عن المحتوى", "compose_form.spoiler_placeholder": "تنبيه عن المحتوى",
@ -221,7 +221,7 @@
"reply_indicator.cancel": "إلغاء", "reply_indicator.cancel": "إلغاء",
"report.forward": "التحويل إلى {target}", "report.forward": "التحويل إلى {target}",
"report.forward_hint": "هذا الحساب ينتمي إلى خادوم آخَر. هل تودّ إرسال نسخة مجهولة مِن التقرير إلى هنالك أيضًا ؟", "report.forward_hint": "هذا الحساب ينتمي إلى خادوم آخَر. هل تودّ إرسال نسخة مجهولة مِن التقرير إلى هنالك أيضًا ؟",
"report.hint": "The report will be sent to your instance moderators. You can provide an explanation of why you are reporting this account below:", "report.hint": "سوف يتم إرسال التقرير إلى مُشرِفي مثيل خادومكم. بإمكانك الإدلاء بشرح عن سبب الإبلاغ عن الحساب أسفله :",
"report.placeholder": "تعليقات إضافية", "report.placeholder": "تعليقات إضافية",
"report.submit": "إرسال", "report.submit": "إرسال",
"report.target": "إبلاغ", "report.target": "إبلاغ",

@ -2,7 +2,7 @@
"account.block": "Bloca @{name}", "account.block": "Bloca @{name}",
"account.block_domain": "Amaga-ho tot de {domain}", "account.block_domain": "Amaga-ho tot de {domain}",
"account.blocked": "Bloquejat", "account.blocked": "Bloquejat",
"account.direct": "Direct Message @{name}", "account.direct": "Direct message @{name}",
"account.disclaimer_full": "La informació següent pot reflectir incompleta el perfil de l'usuari.", "account.disclaimer_full": "La informació següent pot reflectir incompleta el perfil de l'usuari.",
"account.domain_blocked": "Domini ocult", "account.domain_blocked": "Domini ocult",
"account.edit_profile": "Edita el perfil", "account.edit_profile": "Edita el perfil",

@ -1,4 +1,17 @@
[ [
{
"descriptors": [
{
"defaultMessage": "Oops!",
"id": "alert.unexpected.title"
},
{
"defaultMessage": "An unexpected error occurred.",
"id": "alert.unexpected.message"
}
],
"path": "app/javascript/mastodon/actions/alerts.json"
},
{ {
"descriptors": [ "descriptors": [
{ {

@ -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": "Direct message @{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",
@ -17,8 +17,8 @@
"account.mute": "Silentigi @{name}", "account.mute": "Silentigi @{name}",
"account.mute_notifications": "Silentigi sciigojn el @{name}", "account.mute_notifications": "Silentigi sciigojn el @{name}",
"account.muted": "Silentigita", "account.muted": "Silentigita",
"account.posts": "Mesaĝoj", "account.posts": "Tootoj",
"account.posts_with_replies": "Mesaĝoj kun respondoj", "account.posts_with_replies": "Kun respondoj",
"account.report": "Signali @{name}", "account.report": "Signali @{name}",
"account.requested": "Atendo de aprobo. Alklaku por nuligi peton de sekvado", "account.requested": "Atendo de aprobo. Alklaku por nuligi peton de sekvado",
"account.share": "Diskonigi la profilon de @{name}", "account.share": "Diskonigi la profilon de @{name}",
@ -65,10 +65,10 @@
"compose_form.placeholder": "Pri kio vi pensas?", "compose_form.placeholder": "Pri kio vi pensas?",
"compose_form.publish": "Hup", "compose_form.publish": "Hup",
"compose_form.publish_loud": "{publish}!", "compose_form.publish_loud": "{publish}!",
"compose_form.sensitive.marked": "Media is marked as sensitive", "compose_form.sensitive.marked": "Aŭdovidaĵo markita tikla",
"compose_form.sensitive.unmarked": "Media is not marked as sensitive", "compose_form.sensitive.unmarked": "Aŭdovidaĵo ne markita tikla",
"compose_form.spoiler.marked": "Text is hidden behind warning", "compose_form.spoiler.marked": "Teksto kaŝita malantaŭ averto",
"compose_form.spoiler.unmarked": "Text is not hidden", "compose_form.spoiler.unmarked": "Teksto ne kaŝita",
"compose_form.spoiler_placeholder": "Skribu vian averton ĉi tie", "compose_form.spoiler_placeholder": "Skribu vian averton ĉi tie",
"confirmation_modal.cancel": "Nuligi", "confirmation_modal.cancel": "Nuligi",
"confirmations.block.confirm": "Bloki", "confirmations.block.confirm": "Bloki",
@ -260,9 +260,9 @@
"status.sensitive_warning": "Tikla enhavo", "status.sensitive_warning": "Tikla enhavo",
"status.share": "Diskonigi", "status.share": "Diskonigi",
"status.show_less": "Malgrandigi", "status.show_less": "Malgrandigi",
"status.show_less_all": "Show less for all", "status.show_less_all": "Malgrandigi ĉiujn",
"status.show_more": "Grandigi", "status.show_more": "Grandigi",
"status.show_more_all": "Show more for all", "status.show_more_all": "Grandigi ĉiujn",
"status.unmute_conversation": "Malsilentigi konversacion", "status.unmute_conversation": "Malsilentigi konversacion",
"status.unpin": "Depingli de profilo", "status.unpin": "Depingli de profilo",
"tabs_bar.federated_timeline": "Fratara tempolinio", "tabs_bar.federated_timeline": "Fratara tempolinio",

@ -1,10 +1,10 @@
{ {
"account.block": "مسدودسازی @{name}", "account.block": "مسدودسازی @{name}",
"account.block_domain": "پنهان‌سازی همه چیز از سرور {domain}", "account.block_domain": "پنهان‌سازی همه چیز از سرور {domain}",
"account.blocked": "Blocked", "account.blocked": "مسدودشده",
"account.direct": "Direct Message @{name}", "account.direct": "Direct message @{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": "پیگیران",
@ -16,9 +16,9 @@
"account.moved_to": "{name} منتقل شده است به:", "account.moved_to": "{name} منتقل شده است به:",
"account.mute": "بی‌صدا کردن @{name}", "account.mute": "بی‌صدا کردن @{name}",
"account.mute_notifications": "بی‌صداکردن اعلان‌ها از طرف @{name}", "account.mute_notifications": "بی‌صداکردن اعلان‌ها از طرف @{name}",
"account.muted": "Muted", "account.muted": "بی‌صداشده",
"account.posts": "نوشته‌ها", "account.posts": "نوشته‌ها",
"account.posts_with_replies": "Toots with replies", "account.posts_with_replies": "نوشته‌ها و پاسخ‌ها",
"account.report": "گزارش @{name}", "account.report": "گزارش @{name}",
"account.requested": "در انتظار پذیرش", "account.requested": "در انتظار پذیرش",
"account.share": "هم‌رسانی نمایهٔ @{name}", "account.share": "هم‌رسانی نمایهٔ @{name}",

@ -2,7 +2,7 @@
"account.block": "Bloquer @{name}", "account.block": "Bloquer @{name}",
"account.block_domain": "Tout masquer venant de {domain}", "account.block_domain": "Tout masquer venant de {domain}",
"account.blocked": "Bloqué", "account.blocked": "Bloqué",
"account.direct": "Direct Message @{name}", "account.direct": "Direct message @{name}",
"account.disclaimer_full": "Les données ci-dessous peuvent ne pas refléter ce profil dans sa totalité.", "account.disclaimer_full": "Les données ci-dessous peuvent ne pas refléter ce profil dans sa totalité.",
"account.domain_blocked": "Domaine caché", "account.domain_blocked": "Domaine caché",
"account.edit_profile": "Modifier le profil", "account.edit_profile": "Modifier le profil",
@ -20,7 +20,7 @@
"account.posts": "Pouets", "account.posts": "Pouets",
"account.posts_with_replies": "Pouets avec réponses", "account.posts_with_replies": "Pouets avec réponses",
"account.report": "Signaler", "account.report": "Signaler",
"account.requested": "Invitation envoyée", "account.requested": "En attente d'approbation. Cliquez pour annuler la requête",
"account.share": "Partager le profil de @{name}", "account.share": "Partager le profil de @{name}",
"account.show_reblogs": "Afficher les partages de @{name}", "account.show_reblogs": "Afficher les partages de @{name}",
"account.unblock": "Débloquer", "account.unblock": "Débloquer",
@ -88,7 +88,7 @@
"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": "Boire et manger", "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 !! (╯°□°)╯︵ ┻━┻",
@ -98,14 +98,14 @@
"emoji_button.search": "Recherche…", "emoji_button.search": "Recherche…",
"emoji_button.search_results": "Résultats de la recherche", "emoji_button.search_results": "Résultats de la recherche",
"emoji_button.symbols": "Symboles", "emoji_button.symbols": "Symboles",
"emoji_button.travel": "Lieux et voyages", "emoji_button.travel": "Lieux & Voyages",
"empty_column.community": "Le fil public local est vide. Écrivez donc quelque chose pour le remplir!", "empty_column.community": "Le fil public local est vide. Écrivez donc quelque chose pour le remplir!",
"empty_column.hashtag": "Il ny a encore aucun contenu associé à ce hashtag.", "empty_column.hashtag": "Il ny a encore aucun contenu associé à ce hashtag.",
"empty_column.home": "Vous ne suivez encore personne. Visitez {public} ou bien utilisez la recherche pour vous connecter à dautres utilisateur⋅ice⋅s.", "empty_column.home": "Vous ne suivez encore personne. Visitez {public} ou bien utilisez la recherche pour vous connecter à dautres personnes.",
"empty_column.home.public_timeline": "le fil public", "empty_column.home.public_timeline": "le fil public",
"empty_column.list": "Il n'y a rien dans cette liste pour l'instant. Dès que des personnes de cette liste publierons de nouveaux statuts, ils apparaîtront ici.", "empty_column.list": "Il n'y a rien dans cette liste pour l'instant. Dès que des personnes de cette liste publierons de nouveaux statuts, ils apparaîtront ici.",
"empty_column.notifications": "Vous navez pas encore de notification. Interagissez avec dautres utilisateur⋅ice⋅s pour débuter la conversation.", "empty_column.notifications": "Vous navez pas encore de notification. Interagissez avec dautres personnes pour débuter la conversation.",
"empty_column.public": "Il ny a rien ici! Écrivez quelque chose publiquement, ou bien suivez manuellement des utilisateur⋅ice·s dautres instances pour remplir le fil public", "empty_column.public": "Il ny a rien ici! Écrivez quelque chose publiquement, ou bien suivez manuellement des personnes dautres instances pour remplir le fil public",
"follow_request.authorize": "Accepter", "follow_request.authorize": "Accepter",
"follow_request.reject": "Rejeter", "follow_request.reject": "Rejeter",
"getting_started.appsshort": "Applications", "getting_started.appsshort": "Applications",
@ -122,9 +122,9 @@
"keyboard_shortcuts.back": "revenir en arrière", "keyboard_shortcuts.back": "revenir en arrière",
"keyboard_shortcuts.boost": "partager", "keyboard_shortcuts.boost": "partager",
"keyboard_shortcuts.column": "focaliser un statut dans l'une des colonnes", "keyboard_shortcuts.column": "focaliser un statut dans l'une des colonnes",
"keyboard_shortcuts.compose": "pour centrer la zone de redaction", "keyboard_shortcuts.compose": "pour centrer la zone de rédaction",
"keyboard_shortcuts.description": "Description", "keyboard_shortcuts.description": "Description",
"keyboard_shortcuts.down": "descendre dans la liste", "keyboard_shortcuts.down": "pour descendre dans la liste",
"keyboard_shortcuts.enter": "pour ouvrir le statut", "keyboard_shortcuts.enter": "pour ouvrir le statut",
"keyboard_shortcuts.favourite": "vers les favoris", "keyboard_shortcuts.favourite": "vers les favoris",
"keyboard_shortcuts.heading": "Raccourcis clavier", "keyboard_shortcuts.heading": "Raccourcis clavier",
@ -151,7 +151,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 cet utilisateur ?", "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.domain_blocks": "Hidden domains", "navigation_bar.domain_blocks": "Hidden domains",
@ -170,7 +170,7 @@
"notification.follow": "{name} vous suit", "notification.follow": "{name} vous suit",
"notification.mention": "{name} vous a mentionné⋅e:", "notification.mention": "{name} vous a mentionné⋅e:",
"notification.reblog": "{name} a partagé votre statut:", "notification.reblog": "{name} a partagé votre statut:",
"notifications.clear": "Nettoyer", "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 :",
@ -183,12 +183,12 @@
"notifications.column_settings.sound": "Émettre un son", "notifications.column_settings.sound": "Émettre un son",
"onboarding.done": "Effectué", "onboarding.done": "Effectué",
"onboarding.next": "Suivant", "onboarding.next": "Suivant",
"onboarding.page_five.public_timelines": "Le fil public global affiche les posts de tou⋅te⋅s les utilisateur⋅ice⋅s suivi⋅es par les membres de {domain}. Le fil public local est identique mais se limite aux utilisateur⋅ice⋅s de {domain}.", "onboarding.page_five.public_timelines": "Le fil public global affiche les messages de toutes les personnes suivies par les membres de {domain}. Le fil public local est identique mais se limite aux membres de {domain}.",
"onboarding.page_four.home": "LAccueil affiche les posts de tou⋅te·s les utilisateur⋅ice·s que vous suivez.", "onboarding.page_four.home": "LAccueil affiche les messages des personnes que vous suivez.",
"onboarding.page_four.notifications": "Les Notifications vous informent lorsque quelquun interagit avec vous.", "onboarding.page_four.notifications": "La colonne de notification vous avertit lors d'une interaction avec vous.",
"onboarding.page_one.federation": "Mastodon est un réseau social qui appartient à tou⋅te⋅s.", "onboarding.page_one.federation": "Mastodon est un réseau de serveurs indépendants qui se joignent pour former un réseau social plus vaste. Nous appelons ces serveurs des instances.",
"onboarding.page_one.full_handle": "Votre pleine maîtrise", "onboarding.page_one.full_handle": "Votre identifiant complet",
"onboarding.page_one.handle_hint": "C'est ce que vous diriez à vos amis de rechercher.", "onboarding.page_one.handle_hint": "C'est ce que vos amis devront rechercher.",
"onboarding.page_one.welcome": "Bienvenue sur Mastodon!", "onboarding.page_one.welcome": "Bienvenue sur Mastodon!",
"onboarding.page_six.admin": "Ladministrateur⋅ice de votre instance est {admin}.", "onboarding.page_six.admin": "Ladministrateur⋅ice de votre instance est {admin}.",
"onboarding.page_six.almost_done": "Nous y sommes presque…", "onboarding.page_six.almost_done": "Nous y sommes presque…",
@ -199,7 +199,7 @@
"onboarding.page_six.read_guidelines": "Sil vous plaît, noubliez pas de lire les {guidelines}!", "onboarding.page_six.read_guidelines": "Sil vous plaît, noubliez pas de lire les {guidelines}!",
"onboarding.page_six.various_app": "applications mobiles", "onboarding.page_six.various_app": "applications mobiles",
"onboarding.page_three.profile": "Modifiez votre profil pour changer votre avatar, votre description ainsi que votre nom. Vous y trouverez également dautres préférences.", "onboarding.page_three.profile": "Modifiez votre profil pour changer votre avatar, votre description ainsi que votre nom. Vous y trouverez également dautres préférences.",
"onboarding.page_three.search": "Utilisez la barre de recherche pour trouver des utilisateur⋅ice⋅s et regarder des hashtags tels que {illustration} et {introductions}. Pour trouver quelquun qui nest pas sur cette instance, utilisez son nom dutilisateur⋅ice complet.", "onboarding.page_three.search": "Utilisez la barre de recherche pour trouver des utilisateur⋅ice⋅s ou regardez des hashtags tels que {illustration} et {introductions}. Pour trouver quelquun qui nest pas sur cette instance, utilisez son identifiant complet.",
"onboarding.page_two.compose": "Écrivez depuis la colonne de composition. Vous pouvez ajouter des images, changer les réglages de confidentialité, et ajouter des avertissements de contenu (Content Warning) grâce aux icônes en dessous.", "onboarding.page_two.compose": "Écrivez depuis la colonne de composition. Vous pouvez ajouter des images, changer les réglages de confidentialité, et ajouter des avertissements de contenu (Content Warning) grâce aux icônes en dessous.",
"onboarding.skip": "Passer", "onboarding.skip": "Passer",
"privacy.change": "Ajuster la confidentialité du message", "privacy.change": "Ajuster la confidentialité du message",
@ -227,16 +227,16 @@
"report.target": "Signalement", "report.target": "Signalement",
"search.placeholder": "Rechercher", "search.placeholder": "Rechercher",
"search_popout.search_format": "Recherche avancée", "search_popout.search_format": "Recherche avancée",
"search_popout.tips.full_text": "Les textes simples retournent les pouets que vous avez écris, mis en favori, épinglés, ou ayant été mentionnés, ainsi que les noms d'utilisateurs, les noms affichés, et les hashtags correspondant.", "search_popout.tips.full_text": "Les textes simples retournent les pouets que vous avez écris, mis en favori, épinglés, ou ayant été mentionnés, ainsi que les identifiants, les noms affichés, et les hashtags des personnes et messages correspondant.",
"search_popout.tips.hashtag": "hashtag", "search_popout.tips.hashtag": "hashtag",
"search_popout.tips.status": "statuts", "search_popout.tips.status": "statuts",
"search_popout.tips.text": "Un texte simple renvoie les noms affichés, les noms dutilisateur⋅ice et les hashtags correspondants", "search_popout.tips.text": "Un texte simple renvoie les noms affichés, les identifiants et les hashtags correspondants",
"search_popout.tips.user": "utilisateur⋅ice", "search_popout.tips.user": "utilisateur⋅ice",
"search_results.accounts": "Personnes", "search_results.accounts": "Personnes",
"search_results.hashtags": "Hashtags", "search_results.hashtags": "Hashtags",
"search_results.statuses": "Pouets", "search_results.statuses": "Pouets",
"search_results.total": "{count, number} {count, plural, one {résultat} other {résultats}}", "search_results.total": "{count, number} {count, plural, one {résultat} other {résultats}}",
"standalone.public_title": "Jeter un coup dœil…", "standalone.public_title": "Un aperçu …",
"status.block": "Block @{name}", "status.block": "Block @{name}",
"status.cannot_reblog": "Cette publication ne peut être boostée", "status.cannot_reblog": "Cette publication ne peut être boostée",
"status.delete": "Effacer", "status.delete": "Effacer",

@ -27,7 +27,7 @@
"account.unblock_domain": "{domain}を表示", "account.unblock_domain": "{domain}を表示",
"account.unfollow": "フォロー解除", "account.unfollow": "フォロー解除",
"account.unmute": "@{name}さんのミュートを解除", "account.unmute": "@{name}さんのミュートを解除",
"account.unmute_notifications": "@{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": "エラー",

@ -2,7 +2,7 @@
"account.block": "@{name}을 차단", "account.block": "@{name}을 차단",
"account.block_domain": "{domain} 전체를 숨김", "account.block_domain": "{domain} 전체를 숨김",
"account.blocked": "차단 됨", "account.blocked": "차단 됨",
"account.direct": "Direct Message @{name}", "account.direct": "Direct message @{name}",
"account.disclaimer_full": "여기 있는 정보는 유저의 프로파일을 정확히 반영하지 못 할 수도 있습니다.", "account.disclaimer_full": "여기 있는 정보는 유저의 프로파일을 정확히 반영하지 못 할 수도 있습니다.",
"account.domain_blocked": "도메인 숨겨짐", "account.domain_blocked": "도메인 숨겨짐",
"account.edit_profile": "프로필 편집", "account.edit_profile": "프로필 편집",
@ -17,7 +17,7 @@
"account.mute": "@{name} 뮤트", "account.mute": "@{name} 뮤트",
"account.mute_notifications": "@{name}의 알림을 뮤트", "account.mute_notifications": "@{name}의 알림을 뮤트",
"account.muted": "뮤트 됨", "account.muted": "뮤트 됨",
"account.posts": "게시물", "account.posts": "",
"account.posts_with_replies": "툿과 답장", "account.posts_with_replies": "툿과 답장",
"account.report": "@{name} 신고", "account.report": "@{name} 신고",
"account.requested": "승인 대기 중. 클릭해서 취소하기", "account.requested": "승인 대기 중. 클릭해서 취소하기",

@ -1,10 +1,10 @@
{ {
"account.block": "Блокировать", "account.block": "Блокировать",
"account.block_domain": "Блокировать все с {domain}", "account.block_domain": "Блокировать все с {domain}",
"account.blocked": "Blocked", "account.blocked": "Заблокирован(а)",
"account.direct": "Direct Message @{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": "Подписаны",
@ -16,9 +16,9 @@
"account.moved_to": "Ищите {name} здесь:", "account.moved_to": "Ищите {name} здесь:",
"account.mute": "Заглушить", "account.mute": "Заглушить",
"account.mute_notifications": "Скрыть уведомления от @{name}", "account.mute_notifications": "Скрыть уведомления от @{name}",
"account.muted": "Muted", "account.muted": "Приглушён",
"account.posts": "Посты", "account.posts": "Посты",
"account.posts_with_replies": "Toots with replies", "account.posts_with_replies": "Посты с ответами",
"account.report": "Пожаловаться", "account.report": "Пожаловаться",
"account.requested": "Ожидает подтверждения", "account.requested": "Ожидает подтверждения",
"account.share": "Поделиться профилем @{name}", "account.share": "Поделиться профилем @{name}",
@ -29,8 +29,8 @@
"account.unmute": "Снять глушение", "account.unmute": "Снять глушение",
"account.unmute_notifications": "Показывать уведомления от @{name}", "account.unmute_notifications": "Показывать уведомления от @{name}",
"account.view_full_profile": "Показать полный профиль", "account.view_full_profile": "Показать полный профиль",
"alert.unexpected.message": "An unexpected error occurred.", "alert.unexpected.message": "Что-то пошло не так.",
"alert.unexpected.title": "Oops!", "alert.unexpected.title": "Ой!",
"boost_modal.combo": "Нажмите {combo}, чтобы пропустить это в следующий раз", "boost_modal.combo": "Нажмите {combo}, чтобы пропустить это в следующий раз",
"bundle_column_error.body": "Что-то пошло не так при загрузке этого компонента.", "bundle_column_error.body": "Что-то пошло не так при загрузке этого компонента.",
"bundle_column_error.retry": "Попробовать снова", "bundle_column_error.retry": "Попробовать снова",
@ -40,7 +40,7 @@
"bundle_modal_error.retry": "Попробовать снова", "bundle_modal_error.retry": "Попробовать снова",
"column.blocks": "Список блокировки", "column.blocks": "Список блокировки",
"column.community": "Локальная лента", "column.community": "Локальная лента",
"column.domain_blocks": "Hidden domains", "column.domain_blocks": "Скрытые домены",
"column.favourites": "Понравившееся", "column.favourites": "Понравившееся",
"column.follow_requests": "Запросы на подписку", "column.follow_requests": "Запросы на подписку",
"column.home": "Главная", "column.home": "Главная",
@ -65,10 +65,10 @@
"compose_form.placeholder": "О чем Вы думаете?", "compose_form.placeholder": "О чем Вы думаете?",
"compose_form.publish": "Трубить", "compose_form.publish": "Трубить",
"compose_form.publish_loud": "{publish}!", "compose_form.publish_loud": "{publish}!",
"compose_form.sensitive.marked": "Media is marked as sensitive", "compose_form.sensitive.marked": "Медиафайлы не отмечены как чувствительные",
"compose_form.sensitive.unmarked": "Media is not marked as sensitive", "compose_form.sensitive.unmarked": "Медиафайлы не отмечены как чувствительные",
"compose_form.spoiler.marked": "Text is hidden behind warning", "compose_form.spoiler.marked": "Текст скрыт за предупреждением",
"compose_form.spoiler.unmarked": "Text is not hidden", "compose_form.spoiler.unmarked": "Текст не скрыт",
"compose_form.spoiler_placeholder": "Напишите свое предупреждение здесь", "compose_form.spoiler_placeholder": "Напишите свое предупреждение здесь",
"confirmation_modal.cancel": "Отмена", "confirmation_modal.cancel": "Отмена",
"confirmations.block.confirm": "Заблокировать", "confirmations.block.confirm": "Заблокировать",
@ -154,7 +154,7 @@
"mute_modal.hide_notifications": "Убрать уведомления от этого пользователя?", "mute_modal.hide_notifications": "Убрать уведомления от этого пользователя?",
"navigation_bar.blocks": "Список блокировки", "navigation_bar.blocks": "Список блокировки",
"navigation_bar.community_timeline": "Локальная лента", "navigation_bar.community_timeline": "Локальная лента",
"navigation_bar.domain_blocks": "Hidden domains", "navigation_bar.domain_blocks": "Скрытые домены",
"navigation_bar.edit_profile": "Изменить профиль", "navigation_bar.edit_profile": "Изменить профиль",
"navigation_bar.favourites": "Понравившееся", "navigation_bar.favourites": "Понравившееся",
"navigation_bar.follow_requests": "Запросы на подписку", "navigation_bar.follow_requests": "Запросы на подписку",
@ -221,13 +221,13 @@
"reply_indicator.cancel": "Отмена", "reply_indicator.cancel": "Отмена",
"report.forward": "Forward to {target}", "report.forward": "Forward to {target}",
"report.forward_hint": "The account is from another server. Send an anonymized copy of the report there as well?", "report.forward_hint": "The account is from another server. Send an anonymized copy of the report there as well?",
"report.hint": "The report will be sent to your instance moderators. You can provide an explanation of why you are reporting this account below:", "report.hint": "Жалоба будет отправлена модераторам Вашего сервера. Вы также можете указать подробную причину жалобы ниже:",
"report.placeholder": "Комментарий", "report.placeholder": "Комментарий",
"report.submit": "Отправить", "report.submit": "Отправить",
"report.target": "Жалуемся на", "report.target": "Жалуемся на",
"search.placeholder": "Поиск", "search.placeholder": "Поиск",
"search_popout.search_format": "Продвинутый формат поиска", "search_popout.search_format": "Продвинутый формат поиска",
"search_popout.tips.full_text": "Simple text returns statuses you have written, favourited, boosted, or have been mentioned in, as well as matching usernames, display names, and hashtags.", "search_popout.tips.full_text": "Возвращает посты, которые Вы написали, отметили как 'избранное', продвинули или в которых были упомянуты, а также содержащие юзернейм, имя и хэштеги.",
"search_popout.tips.hashtag": "хэштег", "search_popout.tips.hashtag": "хэштег",
"search_popout.tips.status": "статус", "search_popout.tips.status": "статус",
"search_popout.tips.text": "Простой ввод текста покажет совпадающие имена пользователей, отображаемые имена и хэштеги", "search_popout.tips.text": "Простой ввод текста покажет совпадающие имена пользователей, отображаемые имена и хэштеги",

@ -2,7 +2,7 @@
"account.block": "Blokovať @{name}", "account.block": "Blokovať @{name}",
"account.block_domain": "Ukryť všetko z {domain}", "account.block_domain": "Ukryť všetko z {domain}",
"account.blocked": "Blokovaný/á", "account.blocked": "Blokovaný/á",
"account.direct": "Direct Message @{name}", "account.direct": "Direct message @{name}",
"account.disclaimer_full": "Inofrmácie nižšie nemusia byť úplným odrazom uživateľovho účtu.", "account.disclaimer_full": "Inofrmácie nižšie nemusia byť úplným odrazom uživateľovho účtu.",
"account.domain_blocked": "Doména ukrytá", "account.domain_blocked": "Doména ukrytá",
"account.edit_profile": "Upraviť profil", "account.edit_profile": "Upraviť profil",
@ -42,12 +42,12 @@
"column.community": "Lokálna časová os", "column.community": "Lokálna časová os",
"column.domain_blocks": "Hidden domains", "column.domain_blocks": "Hidden domains",
"column.favourites": "Obľúbené", "column.favourites": "Obľúbené",
"column.follow_requests": "Žiadosti o sledovaní", "column.follow_requests": "Žiadosti o sledovanie",
"column.home": "Domov", "column.home": "Domov",
"column.lists": "Zoznamy", "column.lists": "Zoznamy",
"column.mutes": "Ignorovaní užívatelia", "column.mutes": "Ignorovaní užívatelia",
"column.notifications": "Notifikácie", "column.notifications": "Notifikácie",
"column.pins": "Pripnuté toots", "column.pins": "Pripnuté tooty",
"column.public": "Federovaná časová os", "column.public": "Federovaná časová os",
"column_back_button.label": "Späť", "column_back_button.label": "Späť",
"column_header.hide_settings": "Skryť nastavenia", "column_header.hide_settings": "Skryť nastavenia",
@ -163,7 +163,7 @@
"navigation_bar.lists": "Zoznamy", "navigation_bar.lists": "Zoznamy",
"navigation_bar.logout": "Odhlásiť", "navigation_bar.logout": "Odhlásiť",
"navigation_bar.mutes": "Ignorovaní užívatelia", "navigation_bar.mutes": "Ignorovaní užívatelia",
"navigation_bar.pins": "Pripnuté toots", "navigation_bar.pins": "Pripnuté tooty",
"navigation_bar.preferences": "Voľby", "navigation_bar.preferences": "Voľby",
"navigation_bar.public_timeline": "Federovaná časová os", "navigation_bar.public_timeline": "Federovaná časová os",
"notification.favourite": "{name} sa páči tvoj status", "notification.favourite": "{name} sa páči tvoj status",

@ -1,36 +1,36 @@
{ {
"account.block": "封鎖 @{name}", "account.block": "封鎖 @{name}",
"account.block_domain": "隱藏來自 {domain} 的一切文章", "account.block_domain": "隱藏來自 {domain} 的一切文章",
"account.blocked": "Blocked", "account.blocked": "封鎖",
"account.direct": "Direct Message @{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": "關注的人",
"account.follows": "正關注", "account.follows": "正關注",
"account.follows_you": "關注你", "account.follows_you": "關注你",
"account.hide_reblogs": "Hide boosts from @{name}", "account.hide_reblogs": "隱藏 @{name} 的轉推",
"account.media": "媒體", "account.media": "媒體",
"account.mention": "提及 @{name}", "account.mention": "提及 @{name}",
"account.moved_to": "{name} has moved to:", "account.moved_to": "{name} 已經遷移到:",
"account.mute": "將 @{name} 靜音", "account.mute": "將 @{name} 靜音",
"account.mute_notifications": "Mute notifications from @{name}", "account.mute_notifications": "將來自 @{name} 的通知靜音",
"account.muted": "Muted", "account.muted": "靜音",
"account.posts": "文章", "account.posts": "文章",
"account.posts_with_replies": "Toots with replies", "account.posts_with_replies": "包含回覆的文章",
"account.report": "舉報 @{name}", "account.report": "舉報 @{name}",
"account.requested": "等候審批", "account.requested": "等候審批",
"account.share": "分享 @{name} 的個人資料", "account.share": "分享 @{name} 的個人資料",
"account.show_reblogs": "Show boosts from @{name}", "account.show_reblogs": "顯示 @{name} 的推文",
"account.unblock": "解除對 @{name} 的封鎖", "account.unblock": "解除對 @{name} 的封鎖",
"account.unblock_domain": "不再隱藏 {domain}", "account.unblock_domain": "不再隱藏 {domain}",
"account.unfollow": "取消關注", "account.unfollow": "取消關注",
"account.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": "An unexpected error occurred.", "alert.unexpected.message": "發生不可預期的錯誤。",
"alert.unexpected.title": "Oops!", "alert.unexpected.title": "噢!",
"boost_modal.combo": "如你想在下次路過這顯示,請按{combo}", "boost_modal.combo": "如你想在下次路過這顯示,請按{combo}",
"bundle_column_error.body": "加載本組件出錯。", "bundle_column_error.body": "加載本組件出錯。",
"bundle_column_error.retry": "重試", "bundle_column_error.retry": "重試",
@ -40,11 +40,11 @@
"bundle_modal_error.retry": "重試", "bundle_modal_error.retry": "重試",
"column.blocks": "封鎖用戶", "column.blocks": "封鎖用戶",
"column.community": "本站時間軸", "column.community": "本站時間軸",
"column.domain_blocks": "Hidden domains", "column.domain_blocks": "隱藏的服務站",
"column.favourites": "最愛的文章", "column.favourites": "最愛的文章",
"column.follow_requests": "關注請求", "column.follow_requests": "關注請求",
"column.home": "主頁", "column.home": "主頁",
"column.lists": "Lists", "column.lists": "列表",
"column.mutes": "靜音名單", "column.mutes": "靜音名單",
"column.notifications": "通知", "column.notifications": "通知",
"column.pins": "置頂文章", "column.pins": "置頂文章",
@ -58,25 +58,25 @@
"column_header.unpin": "取下", "column_header.unpin": "取下",
"column_subheading.navigation": "瀏覽", "column_subheading.navigation": "瀏覽",
"column_subheading.settings": "設定", "column_subheading.settings": "設定",
"compose_form.direct_message_warning": "This toot will only be visible to all the mentioned users.", "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": "你在想甚麼?",
"compose_form.publish": "發文", "compose_form.publish": "發文",
"compose_form.publish_loud": "{publish}", "compose_form.publish_loud": "{publish}",
"compose_form.sensitive.marked": "Media is marked as sensitive", "compose_form.sensitive.marked": "媒體被標示為敏感",
"compose_form.sensitive.unmarked": "Media is not marked as sensitive", "compose_form.sensitive.unmarked": "媒體沒有被標示為敏感",
"compose_form.spoiler.marked": "Text is hidden behind warning", "compose_form.spoiler.marked": "文字被警告隱藏",
"compose_form.spoiler.unmarked": "Text is not hidden", "compose_form.spoiler.unmarked": "文字沒有被隱藏",
"compose_form.spoiler_placeholder": "敏感警告訊息", "compose_form.spoiler_placeholder": "敏感警告訊息",
"confirmation_modal.cancel": "取消", "confirmation_modal.cancel": "取消",
"confirmations.block.confirm": "封鎖", "confirmations.block.confirm": "封鎖",
"confirmations.block.message": "你確定要封鎖{name}嗎?", "confirmations.block.message": "你確定要封鎖{name}嗎?",
"confirmations.delete.confirm": "刪除", "confirmations.delete.confirm": "刪除",
"confirmations.delete.message": "你確定要刪除{name}嗎?", "confirmations.delete.message": "你確定要刪除{name}嗎?",
"confirmations.delete_list.confirm": "Delete", "confirmations.delete_list.confirm": "刪除",
"confirmations.delete_list.message": "Are you sure you want to permanently delete this list?", "confirmations.delete_list.message": "你確定要永久刪除這列表嗎?",
"confirmations.domain_block.confirm": "隱藏整個網站", "confirmations.domain_block.confirm": "隱藏整個網站",
"confirmations.domain_block.message": "你真的真的確定要隱藏整個 {domain} ?多數情況下,比較推薦封鎖或靜音幾個特定目標就好。", "confirmations.domain_block.message": "你真的真的確定要隱藏整個 {domain} ?多數情況下,比較推薦封鎖或靜音幾個特定目標就好。",
"confirmations.mute.confirm": "靜音", "confirmations.mute.confirm": "靜音",
@ -86,7 +86,7 @@
"embed.instructions": "要內嵌此文章,請將以下代碼貼進你的網站。", "embed.instructions": "要內嵌此文章,請將以下代碼貼進你的網站。",
"embed.preview": "看上去會是這樣:", "embed.preview": "看上去會是這樣:",
"emoji_button.activity": "活動", "emoji_button.activity": "活動",
"emoji_button.custom": "Custom", "emoji_button.custom": "自訂",
"emoji_button.flags": "旗幟", "emoji_button.flags": "旗幟",
"emoji_button.food": "飲飲食食", "emoji_button.food": "飲飲食食",
"emoji_button.label": "加入表情符號", "emoji_button.label": "加入表情符號",
@ -94,9 +94,9 @@
"emoji_button.not_found": "No emojos!! (╯°□°)╯︵ ┻━┻", "emoji_button.not_found": "No emojos!! (╯°□°)╯︵ ┻━┻",
"emoji_button.objects": "物品", "emoji_button.objects": "物品",
"emoji_button.people": "人物", "emoji_button.people": "人物",
"emoji_button.recent": "Frequently used", "emoji_button.recent": "常用",
"emoji_button.search": "搜尋…", "emoji_button.search": "搜尋…",
"emoji_button.search_results": "Search results", "emoji_button.search_results": "搜尋結果",
"emoji_button.symbols": "符號", "emoji_button.symbols": "符號",
"emoji_button.travel": "旅遊景物", "emoji_button.travel": "旅遊景物",
"empty_column.community": "本站時間軸暫時未有內容,快文章來搶頭香啊!", "empty_column.community": "本站時間軸暫時未有內容,快文章來搶頭香啊!",
@ -119,48 +119,48 @@
"home.column_settings.show_reblogs": "顯示被轉推的文章", "home.column_settings.show_reblogs": "顯示被轉推的文章",
"home.column_settings.show_replies": "顯示回應文章", "home.column_settings.show_replies": "顯示回應文章",
"home.settings": "欄位設定", "home.settings": "欄位設定",
"keyboard_shortcuts.back": "to navigate back", "keyboard_shortcuts.back": "後退",
"keyboard_shortcuts.boost": "to boost", "keyboard_shortcuts.boost": "轉推",
"keyboard_shortcuts.column": "to focus a status in one of the columns", "keyboard_shortcuts.column": "把標示移動到其中一列",
"keyboard_shortcuts.compose": "to focus the compose textarea", "keyboard_shortcuts.compose": "把標示移動到文字輸入區",
"keyboard_shortcuts.description": "Description", "keyboard_shortcuts.description": "描述",
"keyboard_shortcuts.down": "to move down in the list", "keyboard_shortcuts.down": "在列表往下移動",
"keyboard_shortcuts.enter": "to open status", "keyboard_shortcuts.enter": "打開文章",
"keyboard_shortcuts.favourite": "to favourite", "keyboard_shortcuts.favourite": "收藏",
"keyboard_shortcuts.heading": "Keyboard Shortcuts", "keyboard_shortcuts.heading": "鍵盤快速鍵",
"keyboard_shortcuts.hotkey": "Hotkey", "keyboard_shortcuts.hotkey": "快速鍵",
"keyboard_shortcuts.legend": "to display this legend", "keyboard_shortcuts.legend": "顯示這個說明",
"keyboard_shortcuts.mention": "to mention author", "keyboard_shortcuts.mention": "提及作者",
"keyboard_shortcuts.reply": "to reply", "keyboard_shortcuts.reply": "回覆",
"keyboard_shortcuts.search": "to focus search", "keyboard_shortcuts.search": "把標示移動到搜索",
"keyboard_shortcuts.toot": "to start a brand new toot", "keyboard_shortcuts.toot": "新的推文",
"keyboard_shortcuts.unfocus": "to un-focus compose textarea/search", "keyboard_shortcuts.unfocus": "把標示移離文字輸入和搜索",
"keyboard_shortcuts.up": "to move up in the list", "keyboard_shortcuts.up": "在列表往上移動",
"lightbox.close": "關閉", "lightbox.close": "關閉",
"lightbox.next": "繼續", "lightbox.next": "繼續",
"lightbox.previous": "回退", "lightbox.previous": "回退",
"lists.account.add": "Add to list", "lists.account.add": "新增到列表",
"lists.account.remove": "Remove from list", "lists.account.remove": "從列表刪除",
"lists.delete": "Delete list", "lists.delete": "刪除列表",
"lists.edit": "Edit list", "lists.edit": "編輯列表",
"lists.new.create": "Add list", "lists.new.create": "新增列表",
"lists.new.title_placeholder": "New list title", "lists.new.title_placeholder": "新列表標題",
"lists.search": "Search among people you follow", "lists.search": "從你關注的用戶中搜索",
"lists.subheading": "Your lists", "lists.subheading": "列表",
"loading_indicator.label": "載入中...", "loading_indicator.label": "載入中...",
"media_gallery.toggle_visible": "打開或關上", "media_gallery.toggle_visible": "打開或關上",
"missing_indicator.label": "找不到內容", "missing_indicator.label": "找不到內容",
"missing_indicator.sublabel": "This resource could not be found", "missing_indicator.sublabel": "無法找到內容",
"mute_modal.hide_notifications": "Hide notifications from this user?", "mute_modal.hide_notifications": "隱藏來自這用戶的通知嗎?",
"navigation_bar.blocks": "被你封鎖的用戶", "navigation_bar.blocks": "被你封鎖的用戶",
"navigation_bar.community_timeline": "本站時間軸", "navigation_bar.community_timeline": "本站時間軸",
"navigation_bar.domain_blocks": "Hidden domains", "navigation_bar.domain_blocks": "隱藏的服務站",
"navigation_bar.edit_profile": "修改個人資料", "navigation_bar.edit_profile": "修改個人資料",
"navigation_bar.favourites": "最愛的內容", "navigation_bar.favourites": "最愛的內容",
"navigation_bar.follow_requests": "關注請求", "navigation_bar.follow_requests": "關注請求",
"navigation_bar.info": "關於本服務站", "navigation_bar.info": "關於本服務站",
"navigation_bar.keyboard_shortcuts": "Keyboard shortcuts", "navigation_bar.keyboard_shortcuts": "鍵盤快速鍵",
"navigation_bar.lists": "Lists", "navigation_bar.lists": "列表",
"navigation_bar.logout": "登出", "navigation_bar.logout": "登出",
"navigation_bar.mutes": "被你靜音的用戶", "navigation_bar.mutes": "被你靜音的用戶",
"navigation_bar.pins": "置頂文章", "navigation_bar.pins": "置頂文章",
@ -187,8 +187,8 @@
"onboarding.page_four.home": "「主頁」顯示你所關注用戶的文章", "onboarding.page_four.home": "「主頁」顯示你所關注用戶的文章",
"onboarding.page_four.notifications": "「通知」欄顯示你和其他人的互動。", "onboarding.page_four.notifications": "「通知」欄顯示你和其他人的互動。",
"onboarding.page_one.federation": "Mastodon萬象社交是由一批獨立網站組成的龐大網絡我們將這些獨立又互連網站稱為「服務站」(instance)", "onboarding.page_one.federation": "Mastodon萬象社交是由一批獨立網站組成的龐大網絡我們將這些獨立又互連網站稱為「服務站」(instance)",
"onboarding.page_one.full_handle": "Your full handle", "onboarding.page_one.full_handle": "你的帳號全名",
"onboarding.page_one.handle_hint": "This is what you would tell your friends to search for.", "onboarding.page_one.handle_hint": "朋友可以從這個帳號全名找到你",
"onboarding.page_one.welcome": "歡迎使用 Mastodon萬象社交", "onboarding.page_one.welcome": "歡迎使用 Mastodon萬象社交",
"onboarding.page_six.admin": "你服務站的管理員是{admin}", "onboarding.page_six.admin": "你服務站的管理員是{admin}",
"onboarding.page_six.almost_done": "差不多了……", "onboarding.page_six.almost_done": "差不多了……",
@ -211,33 +211,33 @@
"privacy.public.short": "公共", "privacy.public.short": "公共",
"privacy.unlisted.long": "公開,但不在公共時間軸顯示", "privacy.unlisted.long": "公開,但不在公共時間軸顯示",
"privacy.unlisted.short": "公開", "privacy.unlisted.short": "公開",
"regeneration_indicator.label": "Loading…", "regeneration_indicator.label": "載入中……",
"regeneration_indicator.sublabel": "Your home feed is being prepared!", "regeneration_indicator.sublabel": "你的主頁時間軸正在準備中!",
"relative_time.days": "{number}d", "relative_time.days": "{number}",
"relative_time.hours": "{number}h", "relative_time.hours": "{number}小時",
"relative_time.just_now": "now", "relative_time.just_now": "剛剛",
"relative_time.minutes": "{number}m", "relative_time.minutes": "{number}分鐘",
"relative_time.seconds": "{number}s", "relative_time.seconds": "{number}",
"reply_indicator.cancel": "取消", "reply_indicator.cancel": "取消",
"report.forward": "Forward to {target}", "report.forward": "轉寄到 {target}",
"report.forward_hint": "The account is from another server. Send an anonymized copy of the report there as well?", "report.forward_hint": "這個帳戶屬於其他服務站。要向該服務站發送匿名的舉報訊息嗎?",
"report.hint": "The report will be sent to your instance moderators. You can provide an explanation of why you are reporting this account below:", "report.hint": "這訊息會發送到你服務站的管理員。你可以提供舉報這個帳戶的理由:",
"report.placeholder": "額外訊息", "report.placeholder": "額外訊息",
"report.submit": "提交", "report.submit": "提交",
"report.target": "舉報", "report.target": "舉報",
"search.placeholder": "搜尋", "search.placeholder": "搜尋",
"search_popout.search_format": "Advanced search format", "search_popout.search_format": "高級搜索格式",
"search_popout.tips.full_text": "Simple text returns statuses you have written, favourited, boosted, or have been mentioned in, as well as matching usernames, display names, and hashtags.", "search_popout.tips.full_text": "輸入簡單的文字,搜索由你發放、收藏、轉推和提及你的文章,以及符合的用戶名稱,帳號名稱和標籤。",
"search_popout.tips.hashtag": "hashtag", "search_popout.tips.hashtag": "標籤",
"search_popout.tips.status": "status", "search_popout.tips.status": "文章",
"search_popout.tips.text": "Simple text returns matching display names, usernames and hashtags", "search_popout.tips.text": "輸入簡單的文字,搜索符合的用戶名稱,帳號名稱和標籤。",
"search_popout.tips.user": "user", "search_popout.tips.user": "用戶",
"search_results.accounts": "People", "search_results.accounts": "使用者",
"search_results.hashtags": "Hashtags", "search_results.hashtags": "標籤",
"search_results.statuses": "Toots", "search_results.statuses": "文章",
"search_results.total": "{count, number} 項結果", "search_results.total": "{count, number} 項結果",
"standalone.public_title": "站點一瞥…", "standalone.public_title": "站點一瞥…",
"status.block": "Block @{name}", "status.block": "封鎖 @{name}",
"status.cannot_reblog": "這篇文章無法被轉推", "status.cannot_reblog": "這篇文章無法被轉推",
"status.delete": "刪除", "status.delete": "刪除",
"status.embed": "鑲嵌", "status.embed": "鑲嵌",
@ -245,12 +245,12 @@
"status.load_more": "載入更多", "status.load_more": "載入更多",
"status.media_hidden": "隱藏媒體內容", "status.media_hidden": "隱藏媒體內容",
"status.mention": "提及 @{name}", "status.mention": "提及 @{name}",
"status.more": "More", "status.more": "更多",
"status.mute": "Mute @{name}", "status.mute": "把 @{name} 靜音",
"status.mute_conversation": "靜音對話", "status.mute_conversation": "靜音對話",
"status.open": "展開文章", "status.open": "展開文章",
"status.pin": "置頂到資料頁", "status.pin": "置頂到資料頁",
"status.pinned": "Pinned toot", "status.pinned": "置頂文章",
"status.reblog": "轉推", "status.reblog": "轉推",
"status.reblogged_by": "{name} 轉推", "status.reblogged_by": "{name} 轉推",
"status.reply": "回應", "status.reply": "回應",
@ -258,22 +258,22 @@
"status.report": "舉報 @{name}", "status.report": "舉報 @{name}",
"status.sensitive_toggle": "點擊顯示", "status.sensitive_toggle": "點擊顯示",
"status.sensitive_warning": "敏感內容", "status.sensitive_warning": "敏感內容",
"status.share": "Share", "status.share": "分享",
"status.show_less": "減少顯示", "status.show_less": "減少顯示",
"status.show_less_all": "Show less for all", "status.show_less_all": "減少顯示這類文章",
"status.show_more": "顯示更多", "status.show_more": "顯示更多",
"status.show_more_all": "Show more for all", "status.show_more_all": "顯示更多這類文章",
"status.unmute_conversation": "解禁對話", "status.unmute_conversation": "解禁對話",
"status.unpin": "解除置頂", "status.unpin": "解除置頂",
"tabs_bar.federated_timeline": "跨站", "tabs_bar.federated_timeline": "跨站",
"tabs_bar.home": "主頁", "tabs_bar.home": "主頁",
"tabs_bar.local_timeline": "本站", "tabs_bar.local_timeline": "本站",
"tabs_bar.notifications": "通知", "tabs_bar.notifications": "通知",
"ui.beforeunload": "Your draft will be lost if you leave Mastodon.", "ui.beforeunload": "如果你現在離開 Mastodon你的草稿內容將會被丟棄。",
"upload_area.title": "將檔案拖放至此上載", "upload_area.title": "將檔案拖放至此上載",
"upload_button.label": "上載媒體檔案", "upload_button.label": "上載媒體檔案",
"upload_form.description": "Describe for the visually impaired", "upload_form.description": "為視覺障礙人士添加文字說明",
"upload_form.focus": "Crop", "upload_form.focus": "裁切",
"upload_form.undo": "還原", "upload_form.undo": "還原",
"upload_progress.label": "上載中……", "upload_progress.label": "上載中……",
"video.close": "關閉影片", "video.close": "關閉影片",

@ -2,7 +2,7 @@
"account.block": "封鎖 @{name}", "account.block": "封鎖 @{name}",
"account.block_domain": "隱藏來自 {domain} 的一切貼文", "account.block_domain": "隱藏來自 {domain} 的一切貼文",
"account.blocked": "Blocked", "account.blocked": "Blocked",
"account.direct": "Direct Message @{name}", "account.direct": "Direct message @{name}",
"account.disclaimer_full": "下列資料不一定完整。", "account.disclaimer_full": "下列資料不一定完整。",
"account.domain_blocked": "Domain hidden", "account.domain_blocked": "Domain hidden",
"account.edit_profile": "編輯用者資訊", "account.edit_profile": "編輯用者資訊",
@ -103,7 +103,7 @@
"empty_column.hashtag": "這個主題標籤下什麼都沒有。", "empty_column.hashtag": "這個主題標籤下什麼都沒有。",
"empty_column.home": "你還沒關注任何人。造訪{public}或利用搜尋功能找到其他用者。", "empty_column.home": "你還沒關注任何人。造訪{public}或利用搜尋功能找到其他用者。",
"empty_column.home.public_timeline": "公開時間軸", "empty_column.home.public_timeline": "公開時間軸",
"empty_column.list": "There is nothing in this list yet.", "empty_column.list": "此份清單尚未有東西。當此清單的成員貼出了新的狀態時,它們就會出現在這裡。",
"empty_column.notifications": "還沒有任何通知。和別的使用者互動來開始對話。", "empty_column.notifications": "還沒有任何通知。和別的使用者互動來開始對話。",
"empty_column.public": "這裡什麼都沒有!公開寫些什麼,或是關注其他副本的使用者。", "empty_column.public": "這裡什麼都沒有!公開寫些什麼,或是關注其他副本的使用者。",
"follow_request.authorize": "授權", "follow_request.authorize": "授權",

@ -1,34 +1,14 @@
import { defineMessages } from 'react-intl'; import { showAlertForError } from '../actions/alerts';
import { showAlert } from '../actions/alerts';
const defaultFailSuffix = 'FAIL'; const defaultFailSuffix = 'FAIL';
const messages = defineMessages({
unexpectedTitle: { id: 'alert.unexpected.title', defaultMessage: 'Oops!' },
unexpectedMessage: { id: 'alert.unexpected.message', defaultMessage: 'An unexpected error occurred.' },
});
export default function errorsMiddleware() { export default function errorsMiddleware() {
return ({ dispatch }) => next => action => { return ({ dispatch }) => next => action => {
if (action.type && !action.skipAlert) { if (action.type && !action.skipAlert) {
const isFail = new RegExp(`${defaultFailSuffix}$`, 'g'); const isFail = new RegExp(`${defaultFailSuffix}$`, 'g');
if (action.type.match(isFail)) { if (action.type.match(isFail)) {
if (action.error.response) { dispatch(showAlertForError(action.error));
const { data, status, statusText } = action.error.response;
let message = statusText;
let title = `${status}`;
if (data.error) {
message = data.error;
}
dispatch(showAlert(title, message));
} else {
console.error(action.error);
dispatch(showAlert(messages.unexpectedTitle, messages.unexpectedMessage));
}
} }
} }

@ -265,7 +265,7 @@ export default function compose(state = initialState, action) {
.set('idempotencyKey', uuid()); .set('idempotencyKey', uuid());
case COMPOSE_DIRECT: case COMPOSE_DIRECT:
return state return state
.update('text', text => `${text}@${action.account.get('acct')} `) .update('text', text => `@${action.account.get('acct')} `)
.set('privacy', 'direct') .set('privacy', 'direct')
.set('focusDate', new Date()) .set('focusDate', new Date())
.set('idempotencyKey', uuid()); .set('idempotencyKey', uuid());

@ -4,7 +4,11 @@ import {
SEARCH_FETCH_SUCCESS, SEARCH_FETCH_SUCCESS,
SEARCH_SHOW, SEARCH_SHOW,
} from '../actions/search'; } from '../actions/search';
import { COMPOSE_MENTION, COMPOSE_REPLY } from '../actions/compose'; import {
COMPOSE_MENTION,
COMPOSE_REPLY,
COMPOSE_DIRECT,
} from '../actions/compose';
import { Map as ImmutableMap, List as ImmutableList } from 'immutable'; import { Map as ImmutableMap, List as ImmutableList } from 'immutable';
const initialState = ImmutableMap({ const initialState = ImmutableMap({
@ -29,6 +33,7 @@ export default function search(state = initialState, action) {
return state.set('hidden', false); return state.set('hidden', false);
case COMPOSE_REPLY: case COMPOSE_REPLY:
case COMPOSE_MENTION: case COMPOSE_MENTION:
case COMPOSE_DIRECT:
return state.set('hidden', true); return state.set('hidden', true);
case SEARCH_FETCH_SUCCESS: case SEARCH_FETCH_SUCCESS:
return state.set('results', ImmutableMap({ return state.set('results', ImmutableMap({

@ -9,6 +9,12 @@ const limit = 1024;
// https://webkit.org/status/#specification-service-workers // https://webkit.org/status/#specification-service-workers
const asyncCache = window.caches ? caches.open('mastodon-system') : Promise.reject(); const asyncCache = window.caches ? caches.open('mastodon-system') : Promise.reject();
function printErrorIfAvailable(error) {
if (error) {
console.warn(error);
}
}
function put(name, objects, onupdate, oncreate) { function put(name, objects, onupdate, oncreate) {
return asyncDB.then(db => new Promise((resolve, reject) => { return asyncDB.then(db => new Promise((resolve, reject) => {
const putTransaction = db.transaction(name, 'readwrite'); const putTransaction = db.transaction(name, 'readwrite');
@ -77,7 +83,9 @@ function evictAccountsByRecords(records) {
function evict(toEvict) { function evict(toEvict) {
toEvict.forEach(record => { toEvict.forEach(record => {
asyncCache.then(cache => accountAssetKeys.forEach(key => cache.delete(records[key]))); asyncCache
.then(cache => accountAssetKeys.forEach(key => cache.delete(records[key])))
.catch(printErrorIfAvailable);
accountsMovedIndex.getAll(record.id).onsuccess = ({ target }) => evict(target.result); accountsMovedIndex.getAll(record.id).onsuccess = ({ target }) => evict(target.result);
@ -90,11 +98,11 @@ function evictAccountsByRecords(records) {
} }
evict(records); evict(records);
}); }).catch(printErrorIfAvailable);
} }
export function evictStatus(id) { export function evictStatus(id) {
return evictStatuses([id]); evictStatuses([id]);
} }
export function evictStatuses(ids) { export function evictStatuses(ids) {
@ -110,7 +118,7 @@ export function evictStatuses(ids) {
idIndex.getKey(id).onsuccess = idIndex.getKey(id).onsuccess =
({ target }) => target.result && store.delete(target.result); ({ target }) => target.result && store.delete(target.result);
}); });
}); }).catch(printErrorIfAvailable);
} }
function evictStatusesByRecords(records) { function evictStatusesByRecords(records) {
@ -127,7 +135,9 @@ export function putAccounts(records) {
const oldURL = target.result[key]; const oldURL = target.result[key];
if (newURL !== oldURL) { if (newURL !== oldURL) {
asyncCache.then(cache => cache.delete(oldURL)); asyncCache
.then(cache => cache.delete(oldURL))
.catch(printErrorIfAvailable);
} }
}); });
@ -145,10 +155,14 @@ export function putAccounts(records) {
oncomplete(); oncomplete();
}).then(records => { }).then(records => {
evictAccountsByRecords(records); evictAccountsByRecords(records);
asyncCache.then(cache => cache.addAll(newURLs)); asyncCache
}); .then(cache => cache.addAll(newURLs))
.catch(printErrorIfAvailable);
}).catch(printErrorIfAvailable);
} }
export function putStatuses(records) { export function putStatuses(records) {
put('statuses', records).then(evictStatusesByRecords); put('statuses', records)
.then(evictStatusesByRecords)
.catch(printErrorIfAvailable);
} }

@ -97,6 +97,8 @@ class Account < ApplicationRecord
has_many :reports has_many :reports
has_many :targeted_reports, class_name: 'Report', foreign_key: :target_account_id has_many :targeted_reports, class_name: 'Report', foreign_key: :target_account_id
has_many :report_notes, dependent: :destroy
# Moderation notes # Moderation notes
has_many :account_moderation_notes, dependent: :destroy has_many :account_moderation_notes, dependent: :destroy
has_many :targeted_moderation_notes, class_name: 'AccountModerationNote', foreign_key: :target_account_id, dependent: :destroy has_many :targeted_moderation_notes, class_name: 'AccountModerationNote', foreign_key: :target_account_id, dependent: :destroy

@ -12,12 +12,16 @@
# account_id :integer not null # account_id :integer not null
# action_taken_by_account_id :integer # action_taken_by_account_id :integer
# target_account_id :integer not null # target_account_id :integer not null
# assigned_account_id :integer
# #
class Report < ApplicationRecord class Report < ApplicationRecord
belongs_to :account belongs_to :account
belongs_to :target_account, class_name: 'Account' belongs_to :target_account, class_name: 'Account'
belongs_to :action_taken_by_account, class_name: 'Account', optional: true belongs_to :action_taken_by_account, class_name: 'Account', optional: true
belongs_to :assigned_account, class_name: 'Account', optional: true
has_many :notes, class_name: 'ReportNote', foreign_key: :report_id, inverse_of: :report, dependent: :destroy
scope :unresolved, -> { where(action_taken: false) } scope :unresolved, -> { where(action_taken: false) }
scope :resolved, -> { where(action_taken: true) } scope :resolved, -> { where(action_taken: true) }

@ -0,0 +1,21 @@
# frozen_string_literal: true
# == Schema Information
#
# Table name: report_notes
#
# id :integer not null, primary key
# content :text not null
# report_id :integer not null
# account_id :integer not null
# created_at :datetime not null
# updated_at :datetime not null
#
class ReportNote < ApplicationRecord
belongs_to :account
belongs_to :report, inverse_of: :notes
scope :latest, -> { reorder('created_at ASC') }
validates :content, presence: true, length: { maximum: 500 }
end

@ -29,6 +29,10 @@ class AccountPolicy < ApplicationPolicy
admin? admin?
end end
def remove_avatar?
staff?
end
def subscribe? def subscribe?
admin? admin?
end end

@ -0,0 +1,17 @@
# frozen_string_literal: true
class ReportNotePolicy < ApplicationPolicy
def create?
staff?
end
def destroy?
admin? || owner?
end
private
def owner?
record.account_id == current_account&.id
end
end

@ -28,7 +28,7 @@ class ActivityPub::ProcessAccountService < BaseService
after_protocol_change! if protocol_changed? after_protocol_change! if protocol_changed?
after_key_change! if key_changed? after_key_change! if key_changed?
check_featured_collection! if @account.featured_collection_url.present? check_featured_collection! if @account&.featured_collection_url&.present?
@account @account
rescue Oj::ParseError rescue Oj::ParseError

@ -14,6 +14,14 @@
%th= t('admin.accounts.display_name') %th= t('admin.accounts.display_name')
%td= @account.display_name %td= @account.display_name
%tr
%th= t('admin.accounts.avatar')
%th
= link_to @account.avatar.url(:original) do
= image_tag @account.avatar.url(:original), alt: '', width: 40, height: 40, class: 'avatar'
- if @account.local? && @account.avatar?
= table_link_to 'trash', t('admin.accounts.remove_avatar'), remove_avatar_admin_account_path(@account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') } if can?(:remove_avatar, @account)
- if @account.local? - if @account.local?
%tr %tr
%th= t('admin.accounts.role') %th= t('admin.accounts.role')

@ -0,0 +1,11 @@
%tr
%td
%p
%strong= report_note.account.acct
on
%time.formatted{ datetime: report_note.created_at.iso8601, title: l(report_note.created_at) }
= l report_note.created_at
= table_link_to 'trash', t('admin.reports.notes.delete'), admin_report_note_path(report_note), method: :delete if can?(:destroy, report_note)
%br/
%br/
= simple_format(h(report_note.content))

@ -17,5 +17,10 @@
%span{ title: t('admin.accounts.media_attachments') } %span{ title: t('admin.accounts.media_attachments') }
= fa_icon('camera') = fa_icon('camera')
= report.media_attachments.count = report.media_attachments.count
%td
- if report.assigned_account.nil?
\-
- else
= link_to report.assigned_account.acct, admin_account_path(report.assigned_account.id)
%td %td
= table_link_to 'circle', t('admin.reports.view'), admin_report_path(report) = table_link_to 'circle', t('admin.reports.view'), admin_report_path(report)

@ -20,6 +20,7 @@
%th= t('admin.reports.reported_by') %th= t('admin.reports.reported_by')
%th= t('admin.reports.comment.label') %th= t('admin.reports.comment.label')
%th= t('admin.reports.report_contents') %th= t('admin.reports.report_contents')
%th= t('admin.reports.assigned')
%th %th
%tbody %tbody
= render @reports = render @reports

@ -1,24 +1,68 @@
- content_for :page_title do - content_for :page_title do
= t('admin.reports.report', id: @report.id) = t('admin.reports.report', id: @report.id)
%div{ style: 'overflow: hidden; margin-bottom: 20px' }
- if !@report.action_taken?
%div{ style: 'float: right' }
= link_to t('admin.reports.silence_account'), admin_report_path(@report, outcome: 'silence'), method: :put, class: 'button'
= link_to t('admin.reports.suspend_account'), admin_report_path(@report, outcome: 'suspend'), method: :put, class: 'button'
%div{ style: 'float: left' }
= link_to t('admin.reports.mark_as_resolved'), admin_report_path(@report, outcome: 'resolve'), method: :put, class: 'button'
- else
= link_to t('admin.reports.mark_as_unresolved'), admin_report_path(@report, outcome: 'reopen'), method: :put, class: 'button'
.table-wrapper
%table.table.inline-table
%tbody
%tr
%th= t('admin.reports.updated_at')
%td{colspan: 2}
%time.formatted{ datetime: @report.updated_at.iso8601 }
%tr
%th= t('admin.reports.status')
%td{colspan: 2}
- if @report.action_taken?
= t('admin.reports.resolved')
= table_link_to 'envelope-open', t('admin.reports.reopen'), admin_report_path(@report, outcome: 'reopen'), method: :put
- else
= t('admin.reports.unresolved')
- if !@report.action_taken_by_account.nil?
%tr
%th= t('admin.reports.action_taken_by')
%td= @report.action_taken_by_account.acct
- else
%tr
%th= t('admin.reports.assigned')
%td
- if @report.assigned_account.nil?
\-
- else
= link_to @report.assigned_account.acct, admin_account_path(@report.assigned_account.id)
%td{style: "text-align: right"}
- if @report.assigned_account != current_user.account
= table_link_to 'user', t('admin.reports.assign_to_self'), admin_report_path(@report, outcome: 'assign_to_self'), method: :put
- if !@report.assigned_account.nil?
= table_link_to 'trash', t('admin.reports.unassign'), admin_report_path(@report, outcome: 'unassign'), method: :put
.report-accounts .report-accounts
.report-accounts__item .report-accounts__item
%strong= t('admin.reports.reported_account') %h3= t('admin.reports.reported_account')
= render 'authorize_follows/card', account: @report.target_account, admin: true = render 'authorize_follows/card', account: @report.target_account, admin: true
= render 'admin/accounts/card', account: @report.target_account = render 'admin/accounts/card', account: @report.target_account
.report-accounts__item .report-accounts__item
%strong= t('admin.reports.reported_by') %h3= t('admin.reports.reported_by')
= render 'authorize_follows/card', account: @report.account, admin: true = render 'authorize_follows/card', account: @report.account, admin: true
= render 'admin/accounts/card', account: @report.account = render 'admin/accounts/card', account: @report.account
%p %h3= t('admin.reports.comment.label')
%strong= t('admin.reports.comment.label')
\: = simple_format(@report.comment.presence || t('admin.reports.comment.none'))
= simple_format(@report.comment.presence || t('admin.reports.comment.none'))
- unless @report.statuses.empty? - unless @report.statuses.empty?
%hr/ %hr/
%h3= t('admin.reports.statuses')
= form_for(@form, url: admin_report_reported_statuses_path(@report.id)) do |f| = form_for(@form, url: admin_report_reported_statuses_path(@report.id)) do |f|
.batch-form-box .batch-form-box
.batch-checkbox-all .batch-checkbox-all
@ -43,14 +87,20 @@
%hr/ %hr/
- if !@report.action_taken? %h3= t('admin.reports.notes.label')
%div{ style: 'overflow: hidden' }
%div{ style: 'float: right' } - if @report_notes.length > 0
= link_to t('admin.reports.silence_account'), admin_report_path(@report, outcome: 'silence'), method: :put, class: 'button' .table-wrapper
= link_to t('admin.reports.suspend_account'), admin_report_path(@report, outcome: 'suspend'), method: :put, class: 'button' %table.table
%div{ style: 'float: left' } %thead
= link_to t('admin.reports.mark_as_resolved'), admin_report_path(@report, outcome: 'resolve'), method: :put, class: 'button' %tr
- elsif !@report.action_taken_by_account.nil? %th
%p %tbody
%strong #{t('admin.reports.action_taken_by')}: = render @report_notes
= @report.action_taken_by_account.acct
= simple_form_for @report_note, url: admin_report_notes_path do |f|
= render 'shared/error_messages', object: @report_note
= f.input :content
= f.hidden_field :report_id
= f.button :button, t('admin.reports.notes.create'), type: :submit
= f.button :button, t('admin.reports.notes.create_and_resolve'), type: :submit, name: :create_and_resolve

@ -119,6 +119,7 @@ ar:
user: مستخدِم user: مستخدِم
salmon_url: عنوان رابط سالمون Salmon salmon_url: عنوان رابط سالمون Salmon
search: البحث search: البحث
shared_inbox_url: رابط الصندوق المُشترَك للبريد الوارد
show: show:
created_reports: البلاغات التي أنشأها هذا الحساب created_reports: البلاغات التي أنشأها هذا الحساب
report: التقرير report: التقرير
@ -140,14 +141,23 @@ ar:
create_email_domain_block: "%{name} قد قام بحظر نطاق البريد الإلكتروني %{target}" create_email_domain_block: "%{name} قد قام بحظر نطاق البريد الإلكتروني %{target}"
demote_user: "%{name} قد قام بإنزال الرتبة الوظيفية لـ %{target}" demote_user: "%{name} قد قام بإنزال الرتبة الوظيفية لـ %{target}"
destroy_domain_block: "%{name} قام بإلغاء الحجب عن النطاق %{target}" destroy_domain_block: "%{name} قام بإلغاء الحجب عن النطاق %{target}"
destroy_email_domain_block: قام %{name} بإضافة نطاق البريد الإلكتروني %{target} إلى اللائحة البيضاء
destroy_status: لقد قام %{name} بحذف منشور %{target}
disable_2fa_user: "%{name} لقد قام بتعطيل ميزة المصادقة بخطوتين للمستخدم %{target}" disable_2fa_user: "%{name} لقد قام بتعطيل ميزة المصادقة بخطوتين للمستخدم %{target}"
disable_custom_emoji: "%{name} قام بتعطيل الإيموجي %{target}" disable_custom_emoji: "%{name} قام بتعطيل الإيموجي %{target}"
disable_user: "%{name} لقد قام بتعطيل تسجيل الدخول للمستخدِم %{target}" disable_user: "%{name} لقد قام بتعطيل تسجيل الدخول للمستخدِم %{target}"
enable_custom_emoji: "%{name} قام بتنشيط الإيموجي %{target}" enable_custom_emoji: "%{name} قام بتنشيط الإيموجي %{target}"
enable_user: "%{name} لقد قام بتنشيط تسجيل الدخول للمستخدِم %{target}" enable_user: "%{name} لقد قام بتنشيط تسجيل الدخول للمستخدِم %{target}"
memorialize_account: لقد قام %{name} بتحويل حساب %{target} إلى صفحة تذكارية
promote_user: "%{name} قام بترقية المستخدم %{target}" promote_user: "%{name} قام بترقية المستخدم %{target}"
reset_password_user: "%{name} لقد قام بإعادة تعيين الكلمة السرية الخاصة بـ %{target}" reset_password_user: "%{name} لقد قام بإعادة تعيين الكلمة السرية الخاصة بـ %{target}"
resolve_report: قام %{name} بإلغاء التقرير المُرسَل مِن طرف %{target}
silence_account: لقد قام %{name} بكتم حساب %{target}
suspend_account: لقد قام %{name} بتعليق حساب %{target}
unsilence_account: لقد قام %{name} بإلغاء الكتم عن حساب %{target}
unsuspend_account: لقد قام %{name} بإلغاء التعليق المفروض على حساب %{target}
update_custom_emoji: "%{name} قام بتحديث الإيموجي %{target}" update_custom_emoji: "%{name} قام بتحديث الإيموجي %{target}"
update_status: لقد قام %{name} بتحديث منشور %{target}
title: سِجلّ التفتيش و المعاينة title: سِجلّ التفتيش و المعاينة
custom_emojis: custom_emojis:
by_domain: النطاق by_domain: النطاق
@ -163,35 +173,54 @@ ar:
enable: تفعيل enable: تفعيل
enabled_msg: تم تنشيط ذاك الإيموجي بنجاح enabled_msg: تم تنشيط ذاك الإيموجي بنجاح
image_hint: ملف PNG إلى غاية حجم 50 ك.ب image_hint: ملف PNG إلى غاية حجم 50 ك.ب
listed: مُدرَج
new: new:
title: إضافة إيموجي خاص جديد title: إضافة إيموجي خاص جديد
overwrite: إعادة الكتابة
shortcode: الترميز المُصَغّر shortcode: الترميز المُصَغّر
shortcode_hint: على الأقل حرفين، و فقط رموز أبجدية عددية و أسطر سفلية shortcode_hint: على الأقل حرفين، و فقط رموز أبجدية عددية و أسطر سفلية
title: الإيموجي الخاصة title: الإيموجي الخاصة
unlisted: غير مدرج
update_failed_msg: تعذرت عملية تحذيث ذاك الإيموجي update_failed_msg: تعذرت عملية تحذيث ذاك الإيموجي
updated_msg: تم تحديث الإيموجي بنجاح ! updated_msg: تم تحديث الإيموجي بنجاح !
upload: رفع upload: رفع
domain_blocks: domain_blocks:
add_new: إضافة نطاق جديد add_new: إضافة نطاق جديد
created_msg: إنّ حجب النطاق حيز التشغيل
destroyed_msg: تم إلغاء الحجب المفروض على النطاق
domain: النطاق domain: النطاق
new: new:
create: إنشاء حظر create: إنشاء حظر
severity: severity:
noop: لا شيء noop: لا شيء
silence: كتم silence: كتم
suspend: تعليق
title: حجب نطاق جديد title: حجب نطاق جديد
reject_media: رفض ملفات الوسائط reject_media: رفض ملفات الوسائط
severities: severities:
noop: لا شيء noop: لا شيء
silence: إخفاء أو كتم
suspend: تعليق
severity: الشدة
show: show:
affected_accounts:
other: هناك %{count} حسابات في قاعدة البيانات متأثرة بذلك
retroactive:
silence: إلغاء الكتم عن كافة الحسابات المتواجدة على هذا النطاق
suspend: إلغاء التعليق المفروض على كافة حسابات هذا النطاق
title: رفع حظر النطاق عن %{domain} title: رفع حظر النطاق عن %{domain}
undo: إلغاء undo: إلغاء
title: حظر النطاقات
undo: إلغاء undo: إلغاء
email_domain_blocks: email_domain_blocks:
add_new: إضافة
created_msg: لقد دخل حظر نطاق البريد الإلكتروني حيّز الخدمة
delete: حذف delete: حذف
destroyed_msg: تم حذف نطاق البريد الإلكتروني من اللائحة السوداء بنجاح
domain: النطاق domain: النطاق
new: new:
create: إضافة نطاق create: إضافة نطاق
title: إضافة نطاق بريد جديد إلى اللائحة السوداء
title: القائمة السوداء للبريد الإلكتروني title: القائمة السوداء للبريد الإلكتروني
instances: instances:
account_count: الحسابات المعروفة account_count: الحسابات المعروفة
@ -214,27 +243,52 @@ ar:
none: لا شيء none: لا شيء
delete: حذف delete: حذف
id: معرّف ID id: معرّف ID
mark_as_resolved: إعتبار التقرير كمحلول
nsfw: nsfw:
'false': الكشف عن الصور
'true': إخفاء الوسائط المرفقة 'true': إخفاء الوسائط المرفقة
report: 'التقرير #%{id}'
report_contents: المحتويات report_contents: المحتويات
reported_account: حساب مُبلّغ عنه
reported_by: أبلغ عنه من طرف reported_by: أبلغ عنه من طرف
resolved: معالجة
silence_account: كتم و إخفاء الحساب
status: الحالة status: الحالة
suspend_account: فرض تعليق على الحساب
target: الهدف
title: التقارير title: التقارير
unresolved: غير معالجة
view: عرض view: عرض
settings: settings:
activity_api_enabled:
desc_html: عدد المنشورات المحلية و المستخدمين النشطين و التسجيلات الأسبوعية الجديدة
bootstrap_timeline_accounts:
title: الإشتراكات الإفتراضية للمستخدمين الجدد
contact_information: contact_information:
email: البريد الإلكتروني المهني email: البريد الإلكتروني المهني
username: الإتصال بالمستخدِم username: الإتصال بالمستخدِم
hero:
title: الصورة الرأسية
peers_api_enabled:
desc_html: أسماء النطاقات التي إلتقى بها مثيل الخادوم على البيئة الموحَّدة فيديفرس
title: نشر عدد مثيلات الخوادم التي تم مصادفتها
registrations: registrations:
closed_message: closed_message:
title: رسالة التسجيلات المقفلة title: رسالة التسجيلات المقفلة
deletion: deletion:
desc_html: السماح لأي مستخدم إغلاق حسابه desc_html: السماح لأي مستخدم إغلاق حسابه
title: السماح بحذف الحسابات
min_invite_role:
disabled: لا أحد
open: open:
desc_html: السماح للجميع بإنشاء حساب desc_html: السماح للجميع بإنشاء حساب
title: فتح التسجيل title: فتح التسجيل
show_known_fediverse_at_about_page:
title: إظهار الفيديفرس الموحَّد في خيط المُعايَنة
site_description: site_description:
title: وصف مثيل الخادوم title: وصف مثيل الخادوم
site_description_extended:
title: الوصف المُفصّل للموقع
site_terms: site_terms:
title: شروط الخدمة المخصصة title: شروط الخدمة المخصصة
site_title: إسم مثيل الخادم site_title: إسم مثيل الخادم
@ -242,11 +296,14 @@ ar:
title: الصورة الرمزية المصغرة لمثيل الخادوم title: الصورة الرمزية المصغرة لمثيل الخادوم
timeline_preview: timeline_preview:
desc_html: عرض الخيط العمومي على صفحة الإستقبال desc_html: عرض الخيط العمومي على صفحة الإستقبال
title: مُعاينة الخيط العام
title: إعدادات الموقع title: إعدادات الموقع
statuses: statuses:
back_to_account: العودة إلى صفحة الحساب back_to_account: العودة إلى صفحة الحساب
batch: batch:
delete: حذف delete: حذف
execute: تفعيل
failed_to_execute: خطأ في التفعيل
media: media:
hide: إخفاء الوسائط hide: إخفاء الوسائط
show: إظهار الوسائط show: إظهار الوسائط
@ -256,8 +313,13 @@ ar:
subscriptions: subscriptions:
confirmed: مؤكَّد confirmed: مؤكَّد
expires_in: تنتهي مدة صلاحيتها في expires_in: تنتهي مدة صلاحيتها في
last_delivery: آخر إيداع
title: WebSub
topic: الموضوع topic: الموضوع
title: الإدارة title: الإدارة
admin_mailer:
new_report:
body: قام %{reporter} بالإبلاغ عن %{target}
application_mailer: application_mailer:
notification_preferences: تعديل خيارات البريد الإلكتروني notification_preferences: تعديل خيارات البريد الإلكتروني
salutation: "%{name}،" salutation: "%{name}،"
@ -270,6 +332,7 @@ ar:
destroyed: تم حذف التطبيق بنجاح destroyed: تم حذف التطبيق بنجاح
invalid_url: إن الرابط المقدم غير صالح invalid_url: إن الرابط المقدم غير صالح
regenerate_token: إعادة توليد رمز النفاذ regenerate_token: إعادة توليد رمز النفاذ
warning: كن حذرا مع هذه البيانات. لا تقم أبدا بمشاركتها مع الآخَرين !
your_token: رمز نفاذك your_token: رمز نفاذك
auth: auth:
agreement_html: بقبولك التسجيل فإنك تُصرِّح قبول <a href="%{rules_path}">قواعد مثيل الخادوم</a> و <a href="%{terms_path}">شروط الخدمة التي نوفرها لك</a>. agreement_html: بقبولك التسجيل فإنك تُصرِّح قبول <a href="%{rules_path}">قواعد مثيل الخادوم</a> و <a href="%{terms_path}">شروط الخدمة التي نوفرها لك</a>.
@ -283,11 +346,13 @@ ar:
logout: خروج logout: خروج
migrate_account: الإنتقال إلى حساب آخر migrate_account: الإنتقال إلى حساب آخر
migrate_account_html: إن كنت ترغب في تحويل هذا الحساب نحو حساب آخَر، يُمكِنُك <a href="%{path}">إعداده هنا</a>. migrate_account_html: إن كنت ترغب في تحويل هذا الحساب نحو حساب آخَر، يُمكِنُك <a href="%{path}">إعداده هنا</a>.
or: أو
or_log_in_with: أو قم بتسجيل الدخول بواسطة or_log_in_with: أو قم بتسجيل الدخول بواسطة
providers: providers:
cas: CAS cas: CAS
saml: SAML saml: SAML
register: إنشاء حساب register: إنشاء حساب
register_elsewhere: التسجيل على خادوم آخَر
resend_confirmation: إعادة إرسال تعليمات التأكيد resend_confirmation: إعادة إرسال تعليمات التأكيد
reset_password: إعادة تعيين كلمة المرور reset_password: إعادة تعيين كلمة المرور
security: الهوية security: الهوية
@ -296,6 +361,7 @@ ar:
error: يا للأسف، وقع هناك خطأ إثر عملية البحث عن الحساب عن بعد error: يا للأسف، وقع هناك خطأ إثر عملية البحث عن الحساب عن بعد
follow: إتبع follow: إتبع
follow_request: 'لقد قمت بإرسال طلب متابعة إلى :' follow_request: 'لقد قمت بإرسال طلب متابعة إلى :'
following: 'مرحى ! أنت الآن تتبع :'
post_follow: post_follow:
close: أو يمكنك إغلاق هذه النافذة. close: أو يمكنك إغلاق هذه النافذة.
return: العودة إلى الملف الشخصي للمستخدم return: العودة إلى الملف الشخصي للمستخدم
@ -324,18 +390,24 @@ ar:
'403': ليس لك الصلاحيات الكافية لعرض هذه الصفحة. '403': ليس لك الصلاحيات الكافية لعرض هذه الصفحة.
'404': إنّ الصفحة التي تبحث عنها لا وجود لها أصلا. '404': إنّ الصفحة التي تبحث عنها لا وجود لها أصلا.
'410': إنّ الصفحة التي تبحث عنها لم تعد موجودة. '410': إنّ الصفحة التي تبحث عنها لم تعد موجودة.
'422':
content: فشل التحقق الآمن. ربما منعتَ كعكات الكوكيز ؟
title: فشِل التحقق الآمن
'500': '500':
content: نحن متأسفون، لقد حدث خطأ ما مِن جانبنا. content: نحن متأسفون، لقد حدث خطأ ما مِن جانبنا.
title: هذه الصفحة خاطئة title: هذه الصفحة خاطئة
exports: exports:
archive_takeout: archive_takeout:
date: التاريخ
download: تنزيل نسخة لحسابك download: تنزيل نسخة لحسابك
hint_html: بإمكانك طلب نسخة كاملة لـ <strong>كافة تبويقاتك و الوسائط التي قمت بنشرها</strong>. البيانات المُصدَّرة ستكون محفوظة على شكل نسق ActivityPub و باستطاعتك قراءتها بأي برنامج يدعم هذا النسق. hint_html: بإمكانك طلب نسخة كاملة لـ <strong>كافة تبويقاتك و الوسائط التي قمت بنشرها</strong>. البيانات المُصدَّرة ستكون محفوظة على شكل نسق ActivityPub و باستطاعتك قراءتها بأي برنامج يدعم هذا النسق.
in_progress: عملية جمع نسخة لبيانات حسابك جارية … in_progress: عملية جمع نسخة لبيانات حسابك جارية …
request: طلب نسخة لحسابك request: طلب نسخة لحسابك
size: الحجم
blocks: قمت بحظر blocks: قمت بحظر
csv: CSV csv: CSV
follows: أنت تتبع follows: أنت تتبع
mutes: قُمتَ بكتم
storage: ذاكرة التخزين storage: ذاكرة التخزين
followers: followers:
domain: النطاق domain: النطاق
@ -368,9 +440,14 @@ ar:
'86400': يوم واحد '86400': يوم واحد
expires_in_prompt: أبدا expires_in_prompt: أبدا
generate: توليد generate: توليد
max_uses:
one: إستعمال واحد
other: "%{count} استخدامات"
max_uses_prompt: بلا حدود max_uses_prompt: بلا حدود
prompt: توليد و مشاركة روابط للسماح للآخَرين بالنفاذ إلى مثيل الخادوم هذا
table: table:
expires_at: تنتهي مدة صلاحيتها في expires_at: تنتهي مدة صلاحيتها في
uses: يستخدِم
title: دعوة أشخاص title: دعوة أشخاص
landing_strip_html: "<strong>%{name}</strong> هو أحد مُستخدِمي %{link_to_root_path}. بإمكانك متابعته أو التواصل معه إن كنت تملك حسابًا أيا كان على البيئة الموحَّدة فيديفرس." landing_strip_html: "<strong>%{name}</strong> هو أحد مُستخدِمي %{link_to_root_path}. بإمكانك متابعته أو التواصل معه إن كنت تملك حسابًا أيا كان على البيئة الموحَّدة فيديفرس."
landing_strip_signup_html: إن كنت لا تملك واحدا، يمكنك <a href="%{sign_up_path}">التسجيل مِن هنا</a>. landing_strip_signup_html: إن كنت لا تملك واحدا، يمكنك <a href="%{sign_up_path}">التسجيل مِن هنا</a>.
@ -433,7 +510,7 @@ ar:
next: التالي next: التالي
older: الأقدَم older: الأقدَم
prev: السابق prev: السابق
truncate: "&hellip;" truncate: و
preferences: preferences:
languages: اللغات languages: اللغات
other: إعدادات أخرى other: إعدادات أخرى

@ -2,7 +2,7 @@
zh-TW: zh-TW:
devise: devise:
confirmations: confirmations:
confirmed: 信箱驗證成功 confirmed: 您的電子郵件地址確認成功。
send_instructions: 您將會在幾分鐘內收到驗證信。 send_instructions: 您將會在幾分鐘內收到驗證信。
send_paranoid_instructions: 如果您的電子信箱已經存在於我們的資料庫,您將會在幾分鐘內收到信,確認您電子信箱的指示。 send_paranoid_instructions: 如果您的電子信箱已經存在於我們的資料庫,您將會在幾分鐘內收到信,確認您電子信箱的指示。
failure: failure:
@ -10,18 +10,39 @@ zh-TW:
inactive: 您的帳號尚未啟用。 inactive: 您的帳號尚未啟用。
invalid: 不正確的 %{authentication_keys} 或密碼。 invalid: 不正確的 %{authentication_keys} 或密碼。
last_attempt: 若您再次嘗試失敗,我們將鎖定您的帳號,以策安全。 last_attempt: 若您再次嘗試失敗,我們將鎖定您的帳號,以策安全。
locked: 您的帳號已被鎖定 locked: 您的帳號已被鎖定
not_found_in_database: 不正確的 %{authentication_keys} 或密碼。 not_found_in_database: 不正確的 %{authentication_keys} 或密碼。
timeout: 您的登入階段已經逾期,請重新登入以繼續使用。 timeout: 您的登入階段已經逾期,請重新登入以繼續使用。
unauthenticated: 您必須先登入或註冊,以繼續使用。 unauthenticated: 您必須先登入或註冊,以繼續使用。
unconfirmed: 您必須先完成信箱驗證,以繼續使用。 unconfirmed: 您必須先完成信箱驗證,以繼續使用。
mailer: mailer:
confirmation_instructions: confirmation_instructions:
action: 驗證電子郵件地址
explanation: 您已經在 %{host} 上以此電子郵件地址建立了一個帳號。您距離啟用它只剩一次點擊之遙了。如果這不是你,請忽略此電子郵件。
extra_html: 同時也請看看<a href="%{terms_path}">該實體的規則</a>與<a href="%{policy_path}">我們的服務條款</a>。
subject: 'Mastodon: 信箱驗證' subject: 'Mastodon: 信箱驗證'
title: 驗證電子郵件地址
email_changed:
explanation: 您帳號的電子郵件地址被變更為:
extra: 如果您並未變更您的電子郵件,那麼很有可能是某人取得了您帳號的存取權限。請立刻變更您的密碼,或是若您的帳號已被鎖定,請聯絡所使用實體的管理員。
subject: Mastodon 電子郵件變更
title: 新電子郵件地址
password_change: password_change:
explanation: 您帳號的密碼已變更。
extra: 如果您並未變更您的密碼,那麼很有可能是某人取得了您帳號的存取權限。請立刻變更您的密碼,或是若您的帳號已被鎖定,請聯絡所使用實體的管理員。
subject: 'Mastodon: 更改密碼' subject: 'Mastodon: 更改密碼'
title: 密碼已變更
reconfirmation_instructions:
explanation: 確認新的電子郵件地址以變更您的電子郵件。
extra: 若此次變更不是由您開啟的請忽略這個電子郵件。Mastodon 帳號的電子郵件地址在您存取上面的連結前不會變更。
subject: Mastodon%{instance} 的確認電子郵件
title: 驗證電子郵件地址
reset_password_instructions: reset_password_instructions:
action: 變更密碼
explanation: 您為您的帳號請求了一個新密碼。
extra: 若您並未請求這個,請忽略此電子郵件。您的密碼在您存取上面的連結並建立一個新的之前不會變更。
subject: 'Mastodon: 重設密碼' subject: 'Mastodon: 重設密碼'
title: 重設密碼
unlock_instructions: unlock_instructions:
subject: 'Mastodon: 帳號解鎖' subject: 'Mastodon: 帳號解鎖'
omniauth_callbacks: omniauth_callbacks:

@ -79,12 +79,17 @@ ar:
messages: messages:
access_denied: لقد رفض مالك المَورِدِ أو تصريح السيرفر طلبك. access_denied: لقد رفض مالك المَورِدِ أو تصريح السيرفر طلبك.
invalid_client: فشلت المصادقة مع العميل لأنه العميل مجهول أو لغياب المصادقة ضمن العميل أو أنّ أسلوب المصادقة غير مدعومة. invalid_client: فشلت المصادقة مع العميل لأنه العميل مجهول أو لغياب المصادقة ضمن العميل أو أنّ أسلوب المصادقة غير مدعومة.
invalid_grant: إنّ التصريح المقدَّم غير صالح، سواء انتهت مدة صلاحيته أو تم إلغاؤه أو أنه لا يتطابق مع عنوان إعادة التحويل في طلب التصريح أو أنّ هذا التصريح قد تم تقديمه لعميل آخر.
invalid_redirect_uri: إنّ عنوان إعادة التحويل غير صالح. invalid_redirect_uri: إنّ عنوان إعادة التحويل غير صالح.
invalid_request: إنّ هذا الطلب يستلزم مؤشرا أو يحمل قيمة مُعامِل غير مدعومة أو فيه خلل ما.
invalid_resource_owner: إنّ المُعرِّفات التي قدّمها صاحب المورِد غير صحيحة أو أنه لا وجود لصاحب المورِد
invalid_scope: المجال المطلوب غير صحيح أو مجهول أو مُعبَّر عنه بشكل خاطئ. invalid_scope: المجال المطلوب غير صحيح أو مجهول أو مُعبَّر عنه بشكل خاطئ.
invalid_token: invalid_token:
expired: إنتهت فترة صلاحيته رمز المصادقة expired: إنتهت فترة صلاحيته رمز المصادقة
revoked: تم إبطال رمز المصادقة revoked: تم إبطال رمز المصادقة
unknown: رمز المصادقة غير صالح unknown: رمز المصادقة غير صالح
resource_owner_authenticator_not_configured: لقد أخفقت عملية البحث عن صاحب المَورِد لغياب الضبط في Doorkeeper.configure.resource_owner_authenticator.
server_error: لقد صادفَ خادوم التصريحات ضروفا غير مواتية، الأمر الذي مَنَعه مِن مواصلة دراسة الطلب.
temporarily_unavailable: تعذر على خادم التفويض معالجة الطلب و ذلك بسبب زيادة مؤقتة في التحميل أو عملية صيانة مبرمجة على الخادم. temporarily_unavailable: تعذر على خادم التفويض معالجة الطلب و ذلك بسبب زيادة مؤقتة في التحميل أو عملية صيانة مبرمجة على الخادم.
unauthorized_client: لا يصرح للعميل بتنفيذ هذا الطلب باستخدام هذه الطريقة. unauthorized_client: لا يصرح للعميل بتنفيذ هذا الطلب باستخدام هذه الطريقة.
unsupported_grant_type: هذا النوع من منح التصريح غير معتمد في خادم الترخيص. unsupported_grant_type: هذا النوع من منح التصريح غير معتمد في خادم الترخيص.

@ -3,19 +3,19 @@ fa:
activerecord: activerecord:
attributes: attributes:
doorkeeper/application: doorkeeper/application:
name: Application name name: نام برنامه
redirect_uri: Redirect URI redirect_uri: نشانی تغییرمسیر
scopes: Scopes scopes: محدوده
website: Application website website: وبگاه برنامه
errors: errors:
models: models:
doorkeeper/application: doorkeeper/application:
attributes: attributes:
redirect_uri: redirect_uri:
fragment_present: cannot contain a fragment. fragment_present: نمی‌تواند چندتکه باشد.
invalid_uri: must be a valid URI. invalid_uri: باید یک نشانی معتبر باشد.
relative_uri: must be an absolute URI. relative_uri: باید یک نشانی مطلق باشد.
secured_uri: must be an HTTPS/SSL URI. secured_uri: باید یک نشانی HTTPS/SSL باشد.
doorkeeper: doorkeeper:
applications: applications:
buttons: buttons:

@ -35,9 +35,13 @@ id:
redirect_uri: Gunakan satu baris per URI redirect_uri: Gunakan satu baris per URI
scopes: Pisahkan scope dengan spasi. Biarkan kosong jika ingin menggunakan scope default. scopes: Pisahkan scope dengan spasi. Biarkan kosong jika ingin menggunakan scope default.
index: index:
application: Aplikasi
callback_url: URL Callback callback_url: URL Callback
delete: Hapus
name: Nama name: Nama
new: Aplikasi baru new: Aplikasi baru
scopes: Cakupan
show: Tampilkan
title: Aplikasi anda title: Aplikasi anda
new: new:
title: Aplikasi Baru title: Aplikasi Baru

@ -39,7 +39,7 @@ ru:
callback_url: Callback URL callback_url: Callback URL
delete: Удалить delete: Удалить
name: Название name: Название
new: Новое Приложение new: Новое приложение
scopes: Права scopes: Права
show: Показывать show: Показывать
title: Ваши приложения title: Ваши приложения

@ -19,7 +19,7 @@ sk:
doorkeeper: doorkeeper:
applications: applications:
buttons: buttons:
authorize: Autorizovať authorize: Overiť
cancel: Zrušiť cancel: Zrušiť
destroy: Zničiť destroy: Zničiť
edit: Upraviť edit: Upraviť
@ -54,7 +54,7 @@ sk:
title: 'Aplikácia: %{name}' title: 'Aplikácia: %{name}'
authorizations: authorizations:
buttons: buttons:
authorize: Autorizovať authorize: Overiť
deny: Zamietnuť deny: Zamietnuť
error: error:
title: Nastala chyba title: Nastala chyba

@ -5,12 +5,14 @@ zh-TW:
doorkeeper/application: doorkeeper/application:
name: 名稱 name: 名稱
redirect_uri: 重新導向 URI redirect_uri: 重新導向 URI
scopes: 範圍
website: 應用程式網頁
errors: errors:
models: models:
doorkeeper/application: doorkeeper/application:
attributes: attributes:
redirect_uri: redirect_uri:
fragment_present: URI 不可包含 "#fragment" 部份 fragment_present: 不能包含 fragment。
invalid_uri: 必需有正確的 URI. invalid_uri: 必需有正確的 URI.
relative_uri: 必需為絕對 URI. relative_uri: 必需為絕對 URI.
secured_uri: 必需使用有 HTTPS/SSL 加密的 URI. secured_uri: 必需使用有 HTTPS/SSL 加密的 URI.
@ -31,11 +33,15 @@ zh-TW:
help: help:
native_redirect_uri: 使用 %{native_redirect_uri} 作局部測試 native_redirect_uri: 使用 %{native_redirect_uri} 作局部測試
redirect_uri: 每行輸入一個 URI redirect_uri: 每行輸入一個 URI
scopes: 請用半形空格分開權限範圍 (scope)。留空表示使用預設的權限範圍 scopes: 請用半形空格分開權限範圍 (scope)。留空表示使用預設的權限範圍
index: index:
application: 應用程式
callback_url: 回傳網址 callback_url: 回傳網址
delete: 刪除
name: 名稱 name: 名稱
new: 新增應用程式 new: 新增應用程式
scopes: 範圍
show: 顯示
title: 您的應用程式 title: 您的應用程式
new: new:
title: 新增應用程式 title: 新增應用程式
@ -57,7 +63,7 @@ zh-TW:
prompt: 應用程式 %{client_name} 要求取得您帳號的部份權限 prompt: 應用程式 %{client_name} 要求取得您帳號的部份權限
title: 需要授權 title: 需要授權
show: show:
title: Copy this authorization code and paste it to the application. title: 複製此授權碼並貼上到應用程式中。
authorized_applications: authorized_applications:
buttons: buttons:
revoke: 取消授權 revoke: 取消授權
@ -77,7 +83,7 @@ zh-TW:
invalid_grant: 授權申請不正確、逾期、已被取消、與授權請求內的重新導向 URI 不符、或屬於別的客戶端程式。 invalid_grant: 授權申請不正確、逾期、已被取消、與授權請求內的重新導向 URI 不符、或屬於別的客戶端程式。
invalid_redirect_uri: 不正確的重新導向網址。 invalid_redirect_uri: 不正確的重新導向網址。
invalid_request: 請求缺少必要的參數、包含不支援的參數、或其他輸入錯誤。 invalid_request: 請求缺少必要的參數、包含不支援的參數、或其他輸入錯誤。
invalid_resource_owner: 資源擁有者的登入資訊錯誤、或無法找到該資源擁有者 invalid_resource_owner: 資源擁有者的登入資訊錯誤、或無法找到該資源擁有者
invalid_scope: 請求的權限範圍不正確、未有定義、或輸入錯誤。 invalid_scope: 請求的權限範圍不正確、未有定義、或輸入錯誤。
invalid_token: invalid_token:
expired: access token 已過期 expired: access token 已過期

@ -60,6 +60,7 @@ en:
destroyed_msg: Moderation note successfully destroyed! destroyed_msg: Moderation note successfully destroyed!
accounts: accounts:
are_you_sure: Are you sure? are_you_sure: Are you sure?
avatar: Avatar
by_domain: Domain by_domain: Domain
confirm: Confirm confirm: Confirm
confirmed: Confirmed confirmed: Confirmed
@ -108,6 +109,7 @@ en:
public: Public public: Public
push_subscription_expires: PuSH subscription expires push_subscription_expires: PuSH subscription expires
redownload: Refresh avatar redownload: Refresh avatar
remove_avatar: Remove avatar
reset: Reset reset: Reset
reset_password: Reset password reset_password: Reset password
resubscribe: Resubscribe resubscribe: Resubscribe
@ -135,6 +137,7 @@ en:
web: Web web: Web
action_logs: action_logs:
actions: actions:
assigned_to_self_report: "%{name} assigned report %{target} to themselves"
confirm_user: "%{name} confirmed e-mail address of user %{target}" confirm_user: "%{name} confirmed e-mail address of user %{target}"
create_custom_emoji: "%{name} uploaded new emoji %{target}" create_custom_emoji: "%{name} uploaded new emoji %{target}"
create_domain_block: "%{name} blocked domain %{target}" create_domain_block: "%{name} blocked domain %{target}"
@ -150,10 +153,13 @@ en:
enable_user: "%{name} enabled login for user %{target}" enable_user: "%{name} enabled login for user %{target}"
memorialize_account: "%{name} turned %{target}'s account into a memoriam page" memorialize_account: "%{name} turned %{target}'s account into a memoriam page"
promote_user: "%{name} promoted user %{target}" promote_user: "%{name} promoted user %{target}"
remove_avatar_user: "%{name} removed %{target}'s avatar"
reopen_report: "%{name} reopened report %{target}"
reset_password_user: "%{name} reset password of user %{target}" reset_password_user: "%{name} reset password of user %{target}"
resolve_report: "%{name} dismissed report %{target}" resolve_report: "%{name} resolved report %{target}"
silence_account: "%{name} silenced %{target}'s account" silence_account: "%{name} silenced %{target}'s account"
suspend_account: "%{name} suspended %{target}'s account" suspend_account: "%{name} suspended %{target}'s account"
unassigned_report: "%{name} unassigned report %{target}"
unsilence_account: "%{name} unsilenced %{target}'s account" unsilence_account: "%{name} unsilenced %{target}'s account"
unsuspend_account: "%{name} unsuspended %{target}'s account" unsuspend_account: "%{name} unsuspended %{target}'s account"
update_custom_emoji: "%{name} updated emoji %{target}" update_custom_emoji: "%{name} updated emoji %{target}"
@ -239,15 +245,26 @@ en:
expired: Expired expired: Expired
title: Filter title: Filter
title: Invites title: Invites
report_notes:
created_msg: Moderation note successfully created!
destroyed_msg: Moderation note successfully destroyed!
reports: reports:
action_taken_by: Action taken by action_taken_by: Action taken by
are_you_sure: Are you sure? are_you_sure: Are you sure?
assign_to_self: Assign to me
assigned: Assigned Moderator
comment: comment:
label: Comment label: Report Comment
none: None none: None
delete: Delete delete: Delete
id: ID id: ID
mark_as_resolved: Mark as resolved mark_as_resolved: Mark as resolved
mark_as_unresolved: Mark as unresolved
notes:
create: Add Note
create_and_resolve: Resolve with Note
delete: Delete
label: Notes
nsfw: nsfw:
'false': Unhide media attachments 'false': Unhide media attachments
'true': Hide media attachments 'true': Hide media attachments
@ -256,12 +273,16 @@ en:
reported_account: Reported account reported_account: Reported account
reported_by: Reported by reported_by: Reported by
resolved: Resolved resolved: Resolved
resolved_msg: Report successfully resolved!
silence_account: Silence account silence_account: Silence account
status: Status status: Status
statuses: Reported Toots
suspend_account: Suspend account suspend_account: Suspend account
target: Target target: Target
title: Reports title: Reports
unassign: Unassign
unresolved: Unresolved unresolved: Unresolved
updated_at: Updated
view: View view: View
settings: settings:
activity_api_enabled: activity_api_enabled:

@ -333,7 +333,7 @@ eo:
subscriptions: subscriptions:
callback_url: Revena URL callback_url: Revena URL
confirmed: Konfirmita confirmed: Konfirmita
expires_in: Eksvalidiĝas en expires_in: Eksvalidiĝas je
last_delivery: Lasta livero last_delivery: Lasta livero
title: WebSub title: WebSub
topic: Temo topic: Temo
@ -485,7 +485,7 @@ eo:
max_uses_prompt: Neniu limo max_uses_prompt: Neniu limo
prompt: Krei kaj diskonigi ligilojn al aliaj por doni aliron al ĉi tiu nodo prompt: Krei kaj diskonigi ligilojn al aliaj por doni aliron al ĉi tiu nodo
table: table:
expires_at: Eksvalidiĝas expires_at: Eksvalidiĝas je
uses: Uzoj uses: Uzoj
title: Inviti homojn title: Inviti homojn
landing_strip_html: "<strong>%{name}</strong> estas uzanto en %{link_to_root_path}. Vi povas sekvi tiun aŭ interagi kun tiu, se vi havas konton ie ajn en la fediverse." landing_strip_html: "<strong>%{name}</strong> estas uzanto en %{link_to_root_path}. Vi povas sekvi tiun aŭ interagi kun tiu, se vi havas konton ie ajn en la fediverse."
@ -636,6 +636,15 @@ eo:
two_factor_authentication: Dufaktora aŭtentigo two_factor_authentication: Dufaktora aŭtentigo
your_apps: Viaj aplikaĵoj your_apps: Viaj aplikaĵoj
statuses: statuses:
attached:
description: 'Ligita: %{attached}'
image:
one: "%{count} bildo"
other: "%{count} bildoj"
video:
one: "%{count} video"
other: "%{count} videoj"
content_warning: 'Enhava averto: %{warning}'
open_in_web: Malfermi retumile open_in_web: Malfermi retumile
over_character_limit: limo de %{max} signoj transpasita over_character_limit: limo de %{max} signoj transpasita
pin_errors: pin_errors:

@ -661,7 +661,7 @@ fr:
stream_entries: stream_entries:
click_to_show: Cliquer pour afficher click_to_show: Cliquer pour afficher
pinned: Pouet épinglé pinned: Pouet épinglé
reblogged: partagé reblogged: a partagé
sensitive_content: Contenu sensible sensitive_content: Contenu sensible
terms: terms:
body_html: | body_html: |

@ -60,6 +60,7 @@ ja:
destroyed_msg: モデレーションメモを削除しました! destroyed_msg: モデレーションメモを削除しました!
accounts: accounts:
are_you_sure: 本当に実行しますか? are_you_sure: 本当に実行しますか?
avatar: アイコン
by_domain: ドメイン by_domain: ドメイン
confirm: 確認 confirm: 確認
confirmed: 確認済み confirmed: 確認済み
@ -108,6 +109,7 @@ ja:
public: パブリック public: パブリック
push_subscription_expires: PuSH購読期限 push_subscription_expires: PuSH購読期限
redownload: アバターの更新 redownload: アバターの更新
remove_avatar: アイコンを削除
reset: リセット reset: リセット
reset_password: パスワード再設定 reset_password: パスワード再設定
resubscribe: 再講読 resubscribe: 再講読
@ -135,6 +137,7 @@ ja:
web: Web web: Web
action_logs: action_logs:
actions: actions:
assigned_to_self_report: "%{name} さんがレポート %{target} を自身の担当に割り当てました"
confirm_user: "%{name} さんが %{target} さんのメールアドレスを確認済みにしました" confirm_user: "%{name} さんが %{target} さんのメールアドレスを確認済みにしました"
create_custom_emoji: "%{name} さんがカスタム絵文字 %{target} を追加しました" create_custom_emoji: "%{name} さんがカスタム絵文字 %{target} を追加しました"
create_domain_block: "%{name} さんがドメイン %{target} をブロックしました" create_domain_block: "%{name} さんがドメイン %{target} をブロックしました"
@ -150,10 +153,13 @@ ja:
enable_user: "%{name} さんが %{target} さんのログインを有効化しました" enable_user: "%{name} さんが %{target} さんのログインを有効化しました"
memorialize_account: "%{name} さんが %{target} さんを追悼アカウントページに登録しました" memorialize_account: "%{name} さんが %{target} さんを追悼アカウントページに登録しました"
promote_user: "%{name} さんが %{target} さんを昇格しました" promote_user: "%{name} さんが %{target} さんを昇格しました"
remove_avatar_user: "%{name} さんが %{target} さんのアイコンを削除しました"
reopen_report: "%{name} さんがレポート %{target} を再び開きました"
reset_password_user: "%{name} さんが %{target} さんのパスワードをリセットしました" reset_password_user: "%{name} さんが %{target} さんのパスワードをリセットしました"
resolve_report: "%{name} さんがレポート %{target} を解決済みにしました" resolve_report: "%{name} さんがレポート %{target} を解決済みにしました"
silence_account: "%{name} さんが %{target} さんをサイレンスにしました" silence_account: "%{name} さんが %{target} さんをサイレンスにしました"
suspend_account: "%{name} さんが %{target} さんを停止しました" suspend_account: "%{name} さんが %{target} さんを停止しました"
unassigned_report: "%{name} さんがレポート %{target} の担当を外しました"
unsilence_account: "%{name} さんが %{target} さんのサイレンスを解除しました" unsilence_account: "%{name} さんが %{target} さんのサイレンスを解除しました"
unsuspend_account: "%{name} さんが %{target} さんの停止を解除しました" unsuspend_account: "%{name} さんが %{target} さんの停止を解除しました"
update_custom_emoji: "%{name} さんがカスタム絵文字 %{target} を更新しました" update_custom_emoji: "%{name} さんがカスタム絵文字 %{target} を更新しました"
@ -239,29 +245,45 @@ ja:
expired: 期限切れ expired: 期限切れ
title: フィルター title: フィルター
title: 招待 title: 招待
report_notes:
created_msg: モデレーションメモを書き込みました!
destroyed_msg: モデレーションメモを削除しました!
reports: reports:
action_taken_by: レポート処理者 action_taken_by: レポート処理者
are_you_sure: 本当に実行しますか? are_you_sure: 本当に実行しますか?
assign_to_self: 担当になる
assigned: 担当者
comment: comment:
label: コメント label: コメント
none: なし none: なし
delete: 削除 delete: 削除
id: ID id: ID
mark_as_resolved: 解決済みとしてマーク mark_as_resolved: 解決済みとしてマーク
mark_as_unresolved: 未解決として再び開く
notes:
create: 書き込む
create_and_resolve: 書き込み、解決済みにする
delete: 削除
label: メモ
nsfw: nsfw:
'false': NSFW オフ 'false': NSFW オフ
'true': NSFW オン 'true': NSFW オン
reopen: 再び開く
report: レポート#%{id} report: レポート#%{id}
report_contents: 内容 report_contents: 内容
reported_account: 報告対象アカウント reported_account: 報告対象アカウント
reported_by: 報告者 reported_by: 報告者
resolved: 解決済み resolved: 解決済み
resolved_msg: レポートを解決済みにしました!
silence_account: アカウントをサイレンス silence_account: アカウントをサイレンス
status: ステータス status: ステータス
statuses: 通報されたトゥート
suspend_account: アカウントを停止 suspend_account: アカウントを停止
target: ターゲット target: ターゲット
title: レポート title: レポート
unassign: 担当を外す
unresolved: 未解決 unresolved: 未解決
updated_at: 更新日時
view: 表示 view: 表示
settings: settings:
activity_api_enabled: activity_api_enabled:
@ -476,6 +498,7 @@ ja:
'21600': 6 時間 '21600': 6 時間
'3600': 1 時間 '3600': 1 時間
'43200': 12 時間 '43200': 12 時間
'604800': 1 週間
'86400': 1 '86400': 1
expires_in_prompt: 無期限 expires_in_prompt: 無期限
generate: 作成 generate: 作成
@ -652,8 +675,8 @@ ja:
one: "%{count} 枚の画像" one: "%{count} 枚の画像"
other: "%{count} 枚の画像" other: "%{count} 枚の画像"
video: video:
one: "%{count} の動画" one: "%{count} の動画"
other: "%{count} の動画" other: "%{count} の動画"
content_warning: '閲覧注意: %{warning}' content_warning: '閲覧注意: %{warning}'
open_in_web: Webで開く open_in_web: Webで開く
over_character_limit: 上限は %{max}文字までです over_character_limit: 上限は %{max}文字までです

@ -361,6 +361,7 @@ ko:
your_token: 액세스 토큰 your_token: 액세스 토큰
auth: auth:
agreement_html: 이 등록으로 <a href="%{rules_path}">이용규약</a> 과 <a href="%{terms_path}">약관</a>에 동의하는 것으로 간주됩니다. agreement_html: 이 등록으로 <a href="%{rules_path}">이용규약</a> 과 <a href="%{terms_path}">약관</a>에 동의하는 것으로 간주됩니다.
change_password: 패스워드
confirm_email: 확인 메일 승인 confirm_email: 확인 메일 승인
delete_account: 계정 삭제 delete_account: 계정 삭제
delete_account_html: 계정을 삭제하고 싶은 경우, <a href="%{path}">여기서</a> 삭제할 수 있습니다. 삭제 전 확인 화면이 표시됩니다. delete_account_html: 계정을 삭제하고 싶은 경우, <a href="%{path}">여기서</a> 삭제할 수 있습니다. 삭제 전 확인 화면이 표시됩니다.
@ -373,7 +374,11 @@ ko:
migrate_account_html: 이 계정을 다른 계정으로 리디렉션 하길 원하는 경우 <a href="%{path}">여기</a>에서 설정할 수 있습니다. migrate_account_html: 이 계정을 다른 계정으로 리디렉션 하길 원하는 경우 <a href="%{path}">여기</a>에서 설정할 수 있습니다.
or: 또는 or: 또는
or_log_in_with: 다른 방법으로 로그인 하려면 or_log_in_with: 다른 방법으로 로그인 하려면
providers:
cas: CAS
saml: SAML
register: 등록하기 register: 등록하기
register_elsewhere: 다른 인스턴스에서 가입
resend_confirmation: 확인 메일을 다시 보내기 resend_confirmation: 확인 메일을 다시 보내기
reset_password: 비밀번호 재설정 reset_password: 비밀번호 재설정
security: 보안 security: 보안
@ -545,7 +550,9 @@ ko:
trillion: T trillion: T
unit: '' unit: ''
pagination: pagination:
newer: 새로운 툿
next: 다음 next: 다음
older: 오래된 툿
prev: 이전 prev: 이전
truncate: "&hellip;" truncate: "&hellip;"
preferences: preferences:
@ -629,6 +636,15 @@ ko:
two_factor_authentication: 2단계 인증 two_factor_authentication: 2단계 인증
your_apps: 애플리케이션 your_apps: 애플리케이션
statuses: statuses:
attached:
description: '첨부: %{attached}'
image:
one: "%{count} 이미지"
other: "%{count} 이미지"
video:
one: "%{count} 영상"
other: "%{count} 영상"
content_warning: '열람 주의: %{warning}'
open_in_web: Web으로 열기 open_in_web: Web으로 열기
over_character_limit: 최대 %{max}자까지 입력할 수 있습니다 over_character_limit: 최대 %{max}자까지 입력할 수 있습니다
pin_errors: pin_errors:

@ -48,7 +48,7 @@ ru:
reserved_username: Имя пользователя зарезервировано reserved_username: Имя пользователя зарезервировано
roles: roles:
admin: Администратор admin: Администратор
moderator: Мод moderator: Модератор
unfollow: Отписаться unfollow: Отписаться
admin: admin:
account_moderation_notes: account_moderation_notes:
@ -217,7 +217,7 @@ ru:
title: Снять блокировку с домена %{domain} title: Снять блокировку с домена %{domain}
undo: Отменить undo: Отменить
title: Доменные блокировки title: Доменные блокировки
undo: Отемнить undo: Отменить
email_domain_blocks: email_domain_blocks:
add_new: Добавить новую add_new: Добавить новую
created_msg: Доменная блокировка еmail успешно создана created_msg: Доменная блокировка еmail успешно создана
@ -275,6 +275,9 @@ ru:
contact_information: contact_information:
email: Введите публичный e-mail email: Введите публичный e-mail
username: Введите имя пользователя username: Введите имя пользователя
hero:
desc_html: Отображается на главной странице. Рекомендуется разрешение не менее 600х100px. Если не установлено, используется изображение узла
title: Баннер узла
peers_api_enabled: peers_api_enabled:
desc_html: Домены, которые были замечены этим узлом среди всей федерации desc_html: Домены, которые были замечены этим узлом среди всей федерации
title: Публикация списка обнаруженных узлов title: Публикация списка обнаруженных узлов
@ -291,6 +294,9 @@ ru:
open: open:
desc_html: Позволяет любому создавать аккаунт desc_html: Позволяет любому создавать аккаунт
title: Открыть регистрацию title: Открыть регистрацию
show_known_fediverse_at_about_page:
desc_html: Если включено, показывает посты со всех известных узлов в предпросмотре ленты. В противном случае отображаются только локальные посты.
title: Показывать известные узлы в предпросмотре ленты
show_staff_badge: show_staff_badge:
desc_html: Показывать метку персонала на странице пользователя desc_html: Показывать метку персонала на странице пользователя
title: Показывать метку персонала title: Показывать метку персонала
@ -308,7 +314,7 @@ ru:
desc_html: Используется для предпросмотра с помощью OpenGraph и API. Рекомендуется разрешение 1200x630px desc_html: Используется для предпросмотра с помощью OpenGraph и API. Рекомендуется разрешение 1200x630px
title: Картинка узла title: Картинка узла
timeline_preview: timeline_preview:
desc_html: Показывать публичную ленту на целевой странице desc_html: Показывать публичную ленту на приветственной странице
title: Предпросмотр ленты title: Предпросмотр ленты
title: Настройки сайта title: Настройки сайта
statuses: statuses:
@ -368,13 +374,17 @@ ru:
migrate_account_html: Если Вы хотите перенести этот аккаунт на другой, вы можете <a href="%{path}">сделать это здесь</a>. migrate_account_html: Если Вы хотите перенести этот аккаунт на другой, вы можете <a href="%{path}">сделать это здесь</a>.
or: или or: или
or_log_in_with: Или войти с помощью or_log_in_with: Или войти с помощью
providers:
cas: CAS
saml: SAML
register: Зарегистрироваться register: Зарегистрироваться
register_elsewhere: Зарегистрироваться на другом сервере register_elsewhere: Зарегистрироваться на другом узле
resend_confirmation: Повторить отправку инструкции для подтверждения resend_confirmation: Повторить отправку инструкции для подтверждения
reset_password: Сбросить пароль reset_password: Сбросить пароль
security: Изменить пароль security: Безопасность
set_new_password: Задать новый пароль set_new_password: Задать новый пароль
authorize_follow: authorize_follow:
already_following: Вы уже подписаны на этот аккаунт
error: К сожалению, при поиске удаленного аккаунта возникла ошибка error: К сожалению, при поиске удаленного аккаунта возникла ошибка
follow: Подписаться follow: Подписаться
follow_request: 'Вы отправили запрос на подписку:' follow_request: 'Вы отправили запрос на подписку:'
@ -467,10 +477,13 @@ ru:
'21600': 6 часов '21600': 6 часов
'3600': 1 час '3600': 1 час
'43200': 12 часов '43200': 12 часов
'604800': 1 неделю
'86400': 1 день '86400': 1 день
expires_in_prompt: Никогда expires_in_prompt: Никогда
generate: Сгенерировать generate: Сгенерировать
max_uses: max_uses:
few: "%{count} исп."
many: "%{count} исп."
one: 1 исп. one: 1 исп.
other: "%{count} исп." other: "%{count} исп."
max_uses_prompt: Без лимита max_uses_prompt: Без лимита
@ -514,11 +527,13 @@ ru:
favourite: favourite:
body: 'Ваш статус понравился %{name}:' body: 'Ваш статус понравился %{name}:'
subject: "%{name} понравился Ваш статус" subject: "%{name} понравился Ваш статус"
title: Понравившийся статус
follow: follow:
body: "%{name} теперь подписан(а) на Вас!" body: "%{name} теперь подписан(а) на Вас!"
subject: "%{name} теперь подписан(а) на Вас" subject: "%{name} теперь подписан(а) на Вас"
title: Новый подписчик title: Новый подписчик
follow_request: follow_request:
action: Управление запросами на подписку
body: "%{name} запросил Вас о подписке" body: "%{name} запросил Вас о подписке"
subject: "%{name} хочет подписаться на Вас" subject: "%{name} хочет подписаться на Вас"
title: Новый запрос о подписке title: Новый запрос о подписке
@ -587,6 +602,7 @@ ru:
micro_messenger: MicroMessenger micro_messenger: MicroMessenger
nokia: Nokia S40 Ovi Browser nokia: Nokia S40 Ovi Browser
opera: Opera opera: Opera
otter: Otter
phantom_js: PhantomJS phantom_js: PhantomJS
qq: QQ Browser qq: QQ Browser
safari: Safari safari: Safari
@ -628,6 +644,19 @@ ru:
two_factor_authentication: Двухфакторная аутентификация two_factor_authentication: Двухфакторная аутентификация
your_apps: Ваши приложения your_apps: Ваши приложения
statuses: statuses:
attached:
description: 'Вложение: %{attached}'
image:
few: "%{count} изображения"
many: "%{count} изображений"
one: "%{count} изображение"
other: "%{count} изображений"
video:
few: "%{count} видео"
many: "%{count} видео"
one: "%{count} видео"
other: "%{count} видео"
content_warning: 'Спойлер: %{warning}'
open_in_web: Открыть в WWW open_in_web: Открыть в WWW
over_character_limit: превышен лимит символов (%{max}) over_character_limit: превышен лимит символов (%{max})
pin_errors: pin_errors:
@ -636,6 +665,7 @@ ru:
private: Нельзя закрепить непубличный статус private: Нельзя закрепить непубличный статус
reblog: Нельзя закрепить продвинутый статус reblog: Нельзя закрепить продвинутый статус
show_more: Подробнее show_more: Подробнее
title: '%{name}: "%{quote}"'
visibilities: visibilities:
private: Для подписчиков private: Для подписчиков
private_long: Показывать только подписчикам private_long: Показывать только подписчикам
@ -717,12 +747,24 @@ ru:
title: Вынос архива title: Вынос архива
welcome: welcome:
edit_profile_action: Настроить профиль edit_profile_action: Настроить профиль
edit_profile_step: Вы можете настроить свой профиль, загрузив аватар, обложку, сменив имя и много чего ещё. Если Вы хотите фильтровать подписчиков до того, как они смогут на Вас подписаться, Вы можете закрыть свой аккаунт.
explanation: Несколько советов для новичков
final_action: Начать постить final_action: Начать постить
final_step: 'Начните постить! Ваши публичные посты могут видеть другие, например, в локальной ленте или по хэштегам, даже если у Вас нет подписчиков. Вы также можете поздороваться с остальными и представиться, используя хэштек #приветствие.'
full_handle: Ваше обращение
full_handle_hint: То, что Вы хотите сообщить своим друзьям, чтобы они могли написать Вам или подписаться с другого узла.
review_preferences_action: Изменить настройки review_preferences_action: Изменить настройки
subject: Добро пожаловать на Mastodon review_preferences_step: Проверьте все настройки, например, какие письма Вы хотите получать или уровень приватности статусов по умолчанию. Если Вы не страдаете морской болезнь, можете включить автовоспроизведение GIF.
subject: Добро пожаловать в Mastodon
tip_bridge_html: Если Вы пришли из Twitter, можете поискать своих друзей в Mastodon, используя <a href="%{bridge_url}">приложение-мост</a>. Но это работает только если они тоже использовали это приложение!
tip_federated_timeline: В глобальной ленте отображается сеть Mastodon. Но в ней показаны посты только от людей, на которых подписаны Вы и Ваши соседи, поэтому лента может быть неполной.
tip_following: По умолчанию Вы подписаны на администратора(-ов) Вашего узла. Чтобы найти других интересных людей, проверьте локальную и глобальную ленты.
tip_local_timeline: В локальной ленте показаны посты от людей с %{instance}. Это Ваши непосредственные соседи!
tip_mobile_webapp: Если Ваш мобильный браузер предлагает добавить иконку Mastodon на домашний экран, то Вы можете получать push-уведомления. Прямо как полноценное приложение!
tips: Советы tips: Советы
title: Добро пожаловать на борт, %{name}! title: Добро пожаловать на борт, %{name}!
users: users:
invalid_email: Введенный e-mail неверен invalid_email: Введенный e-mail неверен
invalid_otp_token: Введен неверный код invalid_otp_token: Введен неверный код
seamless_external_login: Вы залогинены через сторонний сервис, поэтому настройки e-mail и пароля недоступны.
signed_in_as: 'Выполнен вход под именем:' signed_in_as: 'Выполнен вход под именем:'

@ -45,6 +45,7 @@ ko:
setting_default_privacy: 툿 프라이버시 setting_default_privacy: 툿 프라이버시
setting_default_sensitive: 미디어를 언제나 민감한 컨텐츠로 설정 setting_default_sensitive: 미디어를 언제나 민감한 컨텐츠로 설정
setting_delete_modal: 툿 삭제 전 확인 창을 표시 setting_delete_modal: 툿 삭제 전 확인 창을 표시
setting_display_sensitive_media: 열람주의로 설정 된 이미지도 항상 보여주기
setting_noindex: 검색엔진의 인덱싱을 거절 setting_noindex: 검색엔진의 인덱싱을 거절
setting_reduce_motion: 애니메이션 줄이기 setting_reduce_motion: 애니메이션 줄이기
setting_system_font_ui: 시스템의 초기 설정 폰트를 사용 setting_system_font_ui: 시스템의 초기 설정 폰트를 사용
@ -53,6 +54,7 @@ ko:
severity: 심각도 severity: 심각도
type: 불러오기 종류 type: 불러오기 종류
username: 유저 이름 username: 유저 이름
username_or_email: 유저네임 또는 이메일
interactions: interactions:
must_be_follower: 나를 팔로우 하지 않는 사람에게서 온 알림을 차단 must_be_follower: 나를 팔로우 하지 않는 사람에게서 온 알림을 차단
must_be_following: 내가 팔로우 하지 않는 사람에게서 온 알림을 차단 must_be_following: 내가 팔로우 하지 않는 사람에게서 온 알림을 차단

@ -38,7 +38,7 @@ ru:
filtered_languages: Фильтруемые языки filtered_languages: Фильтруемые языки
header: Заголовок header: Заголовок
locale: Язык locale: Язык
locked: Сделать аккаунт приватным locked: Сделать аккаунт закрытым
max_uses: Макс. число использований max_uses: Макс. число использований
new_password: Новый пароль new_password: Новый пароль
note: О Вас note: О Вас
@ -49,6 +49,7 @@ ru:
setting_default_privacy: Видимость постов setting_default_privacy: Видимость постов
setting_default_sensitive: Всегда отмечать медиаконтент как чувствительный setting_default_sensitive: Всегда отмечать медиаконтент как чувствительный
setting_delete_modal: Показывать диалог подтверждения перед удалением setting_delete_modal: Показывать диалог подтверждения перед удалением
setting_display_sensitive_media: Всегда показывать медиаконтент, отмеченный как чувствительный
setting_noindex: Отказаться от индексации в поисковых машинах setting_noindex: Отказаться от индексации в поисковых машинах
setting_reduce_motion: Уменьшить движение в анимации setting_reduce_motion: Уменьшить движение в анимации
setting_system_font_ui: Использовать шрифт системы по умолчанию setting_system_font_ui: Использовать шрифт системы по умолчанию
@ -57,6 +58,7 @@ ru:
severity: Строгость severity: Строгость
type: Тип импорта type: Тип импорта
username: Имя пользователя username: Имя пользователя
username_or_email: Имя пользователя или e-mail
interactions: interactions:
must_be_follower: Заблокировать уведомления не от подписчиков must_be_follower: Заблокировать уведомления не от подписчиков
must_be_following: Заблокировать уведомления от людей, на которых Вы не подписаны must_be_following: Заблокировать уведомления от людей, на которых Вы не подписаны

@ -41,6 +41,7 @@ zh-HK:
setting_default_privacy: 文章預設為 setting_default_privacy: 文章預設為
setting_default_sensitive: 預設我的內容為敏感內容 setting_default_sensitive: 預設我的內容為敏感內容
setting_delete_modal: 刪推前詢問我 setting_delete_modal: 刪推前詢問我
setting_display_sensitive_media: 預設我的媒體為敏感內容
setting_noindex: 阻止搜尋引擎檢索 setting_noindex: 阻止搜尋引擎檢索
setting_reduce_motion: 減低動畫效果 setting_reduce_motion: 減低動畫效果
setting_system_font_ui: 使用系統預設字型 setting_system_font_ui: 使用系統預設字型
@ -49,6 +50,7 @@ zh-HK:
severity: 等級 severity: 等級
type: 匯入資料類型 type: 匯入資料類型
username: 用戶名稱 username: 用戶名稱
username_or_email: 用戶名稱或電郵
interactions: interactions:
must_be_follower: 隱藏沒有關注你的用戶的通知 must_be_follower: 隱藏沒有關注你的用戶的通知
must_be_following: 隱藏你不關注的用戶的通知 must_be_following: 隱藏你不關注的用戶的通知

@ -580,7 +580,12 @@ sk:
browser: Prehliadač browser: Prehliadač
browsers: browsers:
alipay: Alipay alipay: Alipay
chrome: Google Chrome
edge: Microsoft Edge
electron: Electron
firefox: Mozilla Firefox
generic: Neznámy prehliadač generic: Neznámy prehliadač
ie: Internet Explorer
current_session: Aktuálna sezóna current_session: Aktuálna sezóna
description: "%{browser} na %{platform}" description: "%{browser} na %{platform}"
explanation: Tieto sú prehliadače ktoré sú teraz prihlásené na tvoj Mastodon účet. explanation: Tieto sú prehliadače ktoré sú teraz prihlásené na tvoj Mastodon účet.
@ -607,12 +612,22 @@ sk:
two_factor_authentication: Dvoj-faktorové overenie two_factor_authentication: Dvoj-faktorové overenie
your_apps: Tvoje aplikácie your_apps: Tvoje aplikácie
statuses: statuses:
attached:
description: 'Priložené: %{attached}'
image:
one: "%{count} obrázok"
other: "%{count} obrázkov"
video:
one: "%{count} video"
other: "%{count} videí"
content_warning: 'Varovanie o obsahu: %{warning}'
open_in_web: Otvor v okne prehliadača open_in_web: Otvor v okne prehliadača
over_character_limit: limit počtu %{max} znakov bol presiahnutý over_character_limit: limit počtu %{max} znakov bol presiahnutý
pin_errors: pin_errors:
limit: Už ste si pripli ten najvyšší možný počet príspevkov limit: Už ste si pripli ten najvyšší možný počet príspevkov
ownership: Nemožno pripnúť príspevok od niekoho iného ownership: Nemožno pripnúť príspevok od niekoho iného
private: Neverejné príspevky nemôžu byť pripnuté private: Neverejné príspevky nemôžu byť pripnuté
reblog: Pozdvihnutie sa nedá pripnúť
show_more: Ukáž viac show_more: Ukáž viac
visibilities: visibilities:
private: Iba pre sledovateľov private: Iba pre sledovateľov
@ -628,11 +643,20 @@ sk:
sensitive_content: Senzitívny obsah sensitive_content: Senzitívny obsah
terms: terms:
title: Podmienky užívania, a pravidlá o súkromí pre %{instance} title: Podmienky užívania, a pravidlá o súkromí pre %{instance}
themes:
default: Mastodon
time:
formats:
default: "%b %d, %R, %H:%M"
two_factor_authentication: two_factor_authentication:
code_hint: Pre potvrdenie teraz zadaj kód vygenerovaný pomocou tvojej overovacej aplikácie
description_html: Ak povolíš <strong> dvoj-faktorové overovanie</strong>, na prihlásenie potom budeš potrebovať svoj telefón, ktorý vygeneruje prístupové kódy, čo musíš zadať.
disable: Zakáž
enable: Povoliť enable: Povoliť
enabled: Dvoj-faktorové overovanie je povolené enabled: Dvoj-faktorové overovanie je povolené
enabled_success: Dvoj-faktorové overovanie bolo úspešne povolené enabled_success: Dvoj-faktorové overovanie bolo úspešne povolené
generate_recovery_codes: Vygeneruj zálohové kódy generate_recovery_codes: Vygeneruj zálohové kódy
instructions_html: "<strong>Naskenuj tento QR kód do Google Autentikátora, alebo do podobnej TOTP aplikácie pomocou svojho telefónu.</strong> Od tejto chvíle bude táto aplikácia pre teba generovať kódy ktoré musíš zadať aby si sa prihlásil/a."
lost_recovery_codes: Zálohové kódy ti umožnia dostať sa k svojmu účtu ak stratíš telefón. Pokiaľ si stratila svoje zálohové kódy, môžeš si ich tu znovu vygenerovať. Tvoje staré zálohové kódy budú zneplatnené. lost_recovery_codes: Zálohové kódy ti umožnia dostať sa k svojmu účtu ak stratíš telefón. Pokiaľ si stratila svoje zálohové kódy, môžeš si ich tu znovu vygenerovať. Tvoje staré zálohové kódy budú zneplatnené.
manual_instructions: 'Pokiaľ nemôžeš oskenovať daný QR kód, a potrebuješ ho zadať ručne, tu je tajomstvo v textovom formáte:' manual_instructions: 'Pokiaľ nemôžeš oskenovať daný QR kód, a potrebuješ ho zadať ručne, tu je tajomstvo v textovom formáte:'
recovery_codes: Zálohuj kódy pre obnovu recovery_codes: Zálohuj kódy pre obnovu

@ -101,7 +101,7 @@ zh-HK:
most_recent: 按時間 most_recent: 按時間
title: 排序 title: 排序
outbox_url: 寄件箱OutboxURL outbox_url: 寄件箱OutboxURL
perform_full_suspension: 實行完全 perform_full_suspension: 完全停
profile_url: 個人檔案 URL profile_url: 個人檔案 URL
promote: 升任 promote: 升任
protocol: 協議 protocol: 協議
@ -272,6 +272,9 @@ zh-HK:
contact_information: contact_information:
email: 輸入一個公開的電郵地址 email: 輸入一個公開的電郵地址
username: 輸入用戶名稱 username: 輸入用戶名稱
hero:
desc_html: 在首頁顯示。推薦最小 600x100px。如果留空就會默認為服務站縮圖。
title: 主題圖片
peers_api_enabled: peers_api_enabled:
desc_html: 現時本服務站在網絡中已發現的域名 desc_html: 現時本服務站在網絡中已發現的域名
title: 公開已知服務站的列表 title: 公開已知服務站的列表
@ -288,6 +291,9 @@ zh-HK:
open: open:
desc_html: 允許所有人建立帳戶 desc_html: 允許所有人建立帳戶
title: 開放註冊 title: 開放註冊
show_known_fediverse_at_about_page:
desc_html: 如果開啟,就會在時間軸預覽顯示跨站文章,否則就只會顯示本站文章。
title: 在時間軸預覽顯示跨站文章
show_staff_badge: show_staff_badge:
desc_html: 在個人資料頁上顯示管理人員標誌 desc_html: 在個人資料頁上顯示管理人員標誌
title: 顯示管理人員標誌 title: 顯示管理人員標誌
@ -352,6 +358,8 @@ zh-HK:
your_token: token your_token: token
auth: auth:
agreement_html: 登記即表示你同意遵守<a href="%{rules_path}">本服務站的規則</a>和<a href="%{terms_path}">使用條款</a>。 agreement_html: 登記即表示你同意遵守<a href="%{rules_path}">本服務站的規則</a>和<a href="%{terms_path}">使用條款</a>。
change_password: 密碼
confirm_email: 確認電郵
delete_account: 刪除帳戶 delete_account: 刪除帳戶
delete_account_html: 如果你想刪除你的帳戶,請<a href="%{path}">點擊這裡繼續</a>。你需要確認你的操作。 delete_account_html: 如果你想刪除你的帳戶,請<a href="%{path}">點擊這裡繼續</a>。你需要確認你的操作。
didnt_get_confirmation: 沒有收到確認指示電郵? didnt_get_confirmation: 沒有收到確認指示電郵?
@ -361,7 +369,13 @@ zh-HK:
logout: 登出 logout: 登出
migrate_account: 轉移到另一個帳號 migrate_account: 轉移到另一個帳號
migrate_account_html: 想要將這個帳號指向另一個帳號可<a href="%{path}">到這裡設定</a>。 migrate_account_html: 想要將這個帳號指向另一個帳號可<a href="%{path}">到這裡設定</a>。
or:
or_log_in_with: 或登入於
providers:
cas: CAS
saml: SAML
register: 登記 register: 登記
register_elsewhere: 在其他服務站登記
resend_confirmation: 重發確認指示電郵 resend_confirmation: 重發確認指示電郵
reset_password: 重設密碼 reset_password: 重設密碼
security: 登入資訊 security: 登入資訊
@ -411,6 +425,13 @@ zh-HK:
title: 這個頁面有問題 title: 這個頁面有問題
noscript_html: 使用 Mastodon 網頁版應用需要啟用 JavaScript。你也可以選擇適用於你的平台的 <a href="https://github.com/tootsuite/documentation/blob/master/Using-Mastodon/Apps.md">Mastodon 應用</a>。 noscript_html: 使用 Mastodon 網頁版應用需要啟用 JavaScript。你也可以選擇適用於你的平台的 <a href="https://github.com/tootsuite/documentation/blob/master/Using-Mastodon/Apps.md">Mastodon 應用</a>。
exports: exports:
archive_takeout:
date: 日期
download: 下載檔案
hint_html: 你可以下載包含你的<strong>文章和媒體</strong>的檔案。資料以 ActivityPub 格式儲存,可用於相容的軟體。
in_progress: 檔案製作中...
request: 下載檔案
size: 檔案大小
blocks: 被你封鎖的用戶 blocks: 被你封鎖的用戶
csv: CSV csv: CSV
follows: 你所關注的用戶 follows: 你所關注的用戶
@ -524,7 +545,9 @@ zh-HK:
trillion: T trillion: T
unit: '' unit: ''
pagination: pagination:
newer: 較新
next: 下一頁 next: 下一頁
older: 較舊
prev: 上一頁 prev: 上一頁
truncate: "……" truncate: "……"
preferences: preferences:
@ -606,6 +629,11 @@ zh-HK:
two_factor_authentication: 雙重認證 two_factor_authentication: 雙重認證
your_apps: 你的應用程式 your_apps: 你的應用程式
statuses: statuses:
attached:
description: 附件: %{attached}
image: "%{count} 張圖片"
video: "%{count} 段影片"
content_warning: 'Content warning: %{warning}'
open_in_web: 開啟網頁 open_in_web: 開啟網頁
over_character_limit: 超過了 %{max} 字的限制 over_character_limit: 超過了 %{max} 字的限制
pin_errors: pin_errors:
@ -670,4 +698,5 @@ zh-HK:
users: users:
invalid_email: 電郵地址格式不正確 invalid_email: 電郵地址格式不正確
invalid_otp_token: 雙重認證確認碼不正確 invalid_otp_token: 雙重認證確認碼不正確
seamless_external_login: 由於你是從外部系統登入,所以不能設定密碼和電郵。
signed_in_as: 目前登入的帳戶: signed_in_as: 目前登入的帳戶:

@ -146,6 +146,8 @@ Rails.application.routes.draw do
resources :reported_statuses, only: [:create, :update, :destroy] resources :reported_statuses, only: [:create, :update, :destroy]
end end
resources :report_notes, only: [:create, :destroy]
resources :accounts, only: [:index, :show] do resources :accounts, only: [:index, :show] do
member do member do
post :subscribe post :subscribe
@ -153,6 +155,7 @@ Rails.application.routes.draw do
post :enable post :enable
post :disable post :disable
post :redownload post :redownload
post :remove_avatar
post :memorialize post :memorialize
end end

@ -0,0 +1,5 @@
class AddAssignedAccountIdToReports < ActiveRecord::Migration[5.1]
def change
add_reference :reports, :assigned_account, null: true, default: nil, foreign_key: { on_delete: :nullify, to_table: :accounts }, index: false
end
end

@ -0,0 +1,14 @@
class CreateReportNotes < ActiveRecord::Migration[5.1]
def change
create_table :report_notes do |t|
t.text :content, null: false
t.references :report, null: false
t.references :account, null: false
t.timestamps
end
add_foreign_key :report_notes, :reports, column: :report_id, on_delete: :cascade
add_foreign_key :report_notes, :accounts, column: :account_id, on_delete: :cascade
end
end

@ -10,7 +10,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20180310000000) do ActiveRecord::Schema.define(version: 20180402040909) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "plpgsql" enable_extension "plpgsql"
@ -364,6 +364,16 @@ ActiveRecord::Schema.define(version: 20180310000000) do
t.index ["status_id", "preview_card_id"], name: "index_preview_cards_statuses_on_status_id_and_preview_card_id" t.index ["status_id", "preview_card_id"], name: "index_preview_cards_statuses_on_status_id_and_preview_card_id"
end end
create_table "report_notes", force: :cascade do |t|
t.text "content", null: false
t.bigint "report_id", null: false
t.bigint "account_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["account_id"], name: "index_report_notes_on_account_id"
t.index ["report_id"], name: "index_report_notes_on_report_id"
end
create_table "reports", force: :cascade do |t| create_table "reports", force: :cascade do |t|
t.bigint "status_ids", default: [], null: false, array: true t.bigint "status_ids", default: [], null: false, array: true
t.text "comment", default: "", null: false t.text "comment", default: "", null: false
@ -373,6 +383,7 @@ ActiveRecord::Schema.define(version: 20180310000000) do
t.bigint "account_id", null: false t.bigint "account_id", null: false
t.bigint "action_taken_by_account_id" t.bigint "action_taken_by_account_id"
t.bigint "target_account_id", null: false t.bigint "target_account_id", null: false
t.bigint "assigned_account_id"
t.index ["account_id"], name: "index_reports_on_account_id" t.index ["account_id"], name: "index_reports_on_account_id"
t.index ["target_account_id"], name: "index_reports_on_target_account_id" t.index ["target_account_id"], name: "index_reports_on_target_account_id"
end end
@ -580,7 +591,10 @@ ActiveRecord::Schema.define(version: 20180310000000) do
add_foreign_key "oauth_access_tokens", "oauth_applications", column: "application_id", name: "fk_f5fc4c1ee3", on_delete: :cascade add_foreign_key "oauth_access_tokens", "oauth_applications", column: "application_id", name: "fk_f5fc4c1ee3", on_delete: :cascade
add_foreign_key "oauth_access_tokens", "users", column: "resource_owner_id", name: "fk_e84df68546", on_delete: :cascade add_foreign_key "oauth_access_tokens", "users", column: "resource_owner_id", name: "fk_e84df68546", on_delete: :cascade
add_foreign_key "oauth_applications", "users", column: "owner_id", name: "fk_b0988c7c0a", on_delete: :cascade add_foreign_key "oauth_applications", "users", column: "owner_id", name: "fk_b0988c7c0a", on_delete: :cascade
add_foreign_key "report_notes", "accounts", on_delete: :cascade
add_foreign_key "report_notes", "reports", on_delete: :cascade
add_foreign_key "reports", "accounts", column: "action_taken_by_account_id", name: "fk_bca45b75fd", on_delete: :nullify add_foreign_key "reports", "accounts", column: "action_taken_by_account_id", name: "fk_bca45b75fd", on_delete: :nullify
add_foreign_key "reports", "accounts", column: "assigned_account_id", on_delete: :nullify
add_foreign_key "reports", "accounts", column: "target_account_id", name: "fk_eb37af34f0", on_delete: :cascade add_foreign_key "reports", "accounts", column: "target_account_id", name: "fk_eb37af34f0", on_delete: :cascade
add_foreign_key "reports", "accounts", name: "fk_4b81f7522c", on_delete: :cascade add_foreign_key "reports", "accounts", name: "fk_4b81f7522c", on_delete: :cascade
add_foreign_key "session_activations", "oauth_access_tokens", column: "access_token_id", name: "fk_957e5bda89", on_delete: :cascade add_foreign_key "session_activations", "oauth_access_tokens", column: "access_token_id", name: "fk_957e5bda89", on_delete: :cascade

@ -256,11 +256,7 @@ namespace :mastodon do
q.modify :strip q.modify :strip
end end
env['SMTP_OPENSSL_VERIFY_MODE'] = prompt.ask('SMTP OpenSSL verify mode:') do |q| env['SMTP_OPENSSL_VERIFY_MODE'] = prompt.select('SMTP OpenSSL verify mode:', %w(none peer client_once fail_if_no_peer_cert))
q.required
q.default 'peer'
q.modify :strip
end
end end
env['SMTP_FROM_ADDRESS'] = prompt.ask('E-mail address to send e-mails "from":') do |q| env['SMTP_FROM_ADDRESS'] = prompt.ask('E-mail address to send e-mails "from":') do |q|

@ -130,6 +130,7 @@
"eslint": "^4.15.0", "eslint": "^4.15.0",
"eslint-plugin-import": "^2.8.0", "eslint-plugin-import": "^2.8.0",
"eslint-plugin-jsx-a11y": "^5.1.1", "eslint-plugin-jsx-a11y": "^5.1.1",
"eslint-plugin-promise": "^3.7.0",
"eslint-plugin-react": "^7.5.1", "eslint-plugin-react": "^7.5.1",
"jest": "^21.2.1", "jest": "^21.2.1",
"raf": "^3.4.0", "raf": "^3.4.0",

@ -9,18 +9,25 @@ describe Admin::BaseController, type: :controller do
end end
end end
it 'renders admin layout' do it 'requires administrator or moderator' do
routes.draw { get 'success' => 'admin/base#success' } routes.draw { get 'success' => 'admin/base#success' }
sign_in(Fabricate(:user, admin: true)) sign_in(Fabricate(:user, admin: false, moderator: false))
get :success get :success
expect(response).to render_template layout: 'admin'
expect(response).to have_http_status(:forbidden)
end end
it 'requires administrator' do it 'renders admin layout as a moderator' do
routes.draw { get 'success' => 'admin/base#success' } routes.draw { get 'success' => 'admin/base#success' }
sign_in(Fabricate(:user, admin: false)) sign_in(Fabricate(:user, moderator: true))
get :success get :success
expect(response).to render_template layout: 'admin'
end
expect(response).to redirect_to('/') it 'renders admin layout as an admin' do
routes.draw { get 'success' => 'admin/base#success' }
sign_in(Fabricate(:user, admin: true))
get :success
expect(response).to render_template layout: 'admin'
end end
end end

@ -61,7 +61,7 @@ describe Admin::ReportsController do
report = Fabricate(:report) report = Fabricate(:report)
put :update, params: { id: report, outcome: 'resolve' } put :update, params: { id: report, outcome: 'resolve' }
expect(response).to redirect_to(admin_report_path(report)) expect(response).to redirect_to(admin_reports_path)
report.reload report.reload
expect(report.action_taken_by_account).to eq user.account expect(report.action_taken_by_account).to eq user.account
expect(report.action_taken).to eq true expect(report.action_taken).to eq true
@ -74,7 +74,7 @@ describe Admin::ReportsController do
allow(Admin::SuspensionWorker).to receive(:perform_async) allow(Admin::SuspensionWorker).to receive(:perform_async)
put :update, params: { id: report, outcome: 'suspend' } put :update, params: { id: report, outcome: 'suspend' }
expect(response).to redirect_to(admin_report_path(report)) expect(response).to redirect_to(admin_reports_path)
report.reload report.reload
expect(report.action_taken_by_account).to eq user.account expect(report.action_taken_by_account).to eq user.account
expect(report.action_taken).to eq true expect(report.action_taken).to eq true
@ -88,12 +88,46 @@ describe Admin::ReportsController do
report = Fabricate(:report) report = Fabricate(:report)
put :update, params: { id: report, outcome: 'silence' } put :update, params: { id: report, outcome: 'silence' }
expect(response).to redirect_to(admin_report_path(report)) expect(response).to redirect_to(admin_reports_path)
report.reload report.reload
expect(report.action_taken_by_account).to eq user.account expect(report.action_taken_by_account).to eq user.account
expect(report.action_taken).to eq true expect(report.action_taken).to eq true
expect(report.target_account).to be_silenced expect(report.target_account).to be_silenced
end end
end end
describe 'with an outsome of `reopen`' do
it 'reopens the report' do
report = Fabricate(:report)
put :update, params: { id: report, outcome: 'reopen' }
expect(response).to redirect_to(admin_report_path(report))
report.reload
expect(report.action_taken_by_account).to eq nil
expect(report.action_taken).to eq false
end
end
describe 'with an outsome of `assign_to_self`' do
it 'reopens the report' do
report = Fabricate(:report)
put :update, params: { id: report, outcome: 'assign_to_self' }
expect(response).to redirect_to(admin_report_path(report))
report.reload
expect(report.assigned_account).to eq user.account
end
end
describe 'with an outsome of `unassign`' do
it 'reopens the report' do
report = Fabricate(:report)
put :update, params: { id: report, outcome: 'unassign' }
expect(response).to redirect_to(admin_report_path(report))
report.reload
expect(report.assigned_account).to eq nil
end
end
end end
end end

@ -181,10 +181,48 @@ describe ApplicationController, type: :controller do
routes.draw { get 'sucesss' => 'anonymous#sucesss' } routes.draw { get 'sucesss' => 'anonymous#sucesss' }
end end
it 'redirects to root path if current user is not admin' do it 'returns a 403 if current user is not admin' do
sign_in(Fabricate(:user, admin: false)) sign_in(Fabricate(:user, admin: false))
get 'sucesss' get 'sucesss'
expect(response).to redirect_to('/') expect(response).to have_http_status(403)
end
it 'returns a 403 if current user is only a moderator' do
sign_in(Fabricate(:user, moderator: true))
get 'sucesss'
expect(response).to have_http_status(403)
end
it 'does nothing if current user is admin' do
sign_in(Fabricate(:user, admin: true))
get 'sucesss'
expect(response).to have_http_status(200)
end
end
describe 'require_staff!' do
controller do
before_action :require_staff!
def sucesss
head 200
end
end
before do
routes.draw { get 'sucesss' => 'anonymous#sucesss' }
end
it 'returns a 403 if current user is not admin or moderator' do
sign_in(Fabricate(:user, admin: false, moderator: false))
get 'sucesss'
expect(response).to have_http_status(403)
end
it 'does nothing if current user is moderator' do
sign_in(Fabricate(:user, moderator: true))
get 'sucesss'
expect(response).to have_http_status(200)
end end
it 'does nothing if current user is admin' do it 'does nothing if current user is admin' do

@ -2437,6 +2437,10 @@ eslint-plugin-jsx-a11y@^5.1.1:
emoji-regex "^6.1.0" emoji-regex "^6.1.0"
jsx-ast-utils "^1.4.0" jsx-ast-utils "^1.4.0"
eslint-plugin-promise@^3.7.0:
version "3.7.0"
resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-3.7.0.tgz#f4bde5c2c77cdd69557a8f69a24d1ad3cfc9e67e"
eslint-plugin-react@^7.5.1: eslint-plugin-react@^7.5.1:
version "7.5.1" version "7.5.1"
resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.5.1.tgz#52e56e8d80c810de158859ef07b880d2f56ee30b" resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.5.1.tgz#52e56e8d80c810de158859ef07b880d2f56ee30b"

Loading…
Cancel
Save