diff --git a/app/javascript/mastodon/features/domain_blocks/index.js b/app/javascript/mastodon/features/domain_blocks/index.js
index 7c075f5a5c..16e200b31e 100644
--- a/app/javascript/mastodon/features/domain_blocks/index.js
+++ b/app/javascript/mastodon/features/domain_blocks/index.js
@@ -33,6 +33,7 @@ class Blocks extends ImmutablePureComponent {
hasMore: PropTypes.bool,
domains: ImmutablePropTypes.orderedSet,
intl: PropTypes.object.isRequired,
+ multiColumn: PropTypes.bool,
};
componentWillMount () {
@@ -44,7 +45,7 @@ class Blocks extends ImmutablePureComponent {
}, 300, { leading: true });
render () {
- const { intl, domains, shouldUpdateScroll, hasMore } = this.props;
+ const { intl, domains, shouldUpdateScroll, hasMore, multiColumn } = this.props;
if (!domains) {
return (
@@ -65,6 +66,7 @@ class Blocks extends ImmutablePureComponent {
hasMore={hasMore}
shouldUpdateScroll={shouldUpdateScroll}
emptyMessage={emptyMessage}
+ bindToDocument={!multiColumn}
>
{domains.map(domain =>
diff --git a/app/javascript/mastodon/features/favourited_statuses/index.js b/app/javascript/mastodon/features/favourited_statuses/index.js
index fa9401b90e..8c7b238696 100644
--- a/app/javascript/mastodon/features/favourited_statuses/index.js
+++ b/app/javascript/mastodon/features/favourited_statuses/index.js
@@ -95,6 +95,7 @@ class Favourites extends ImmutablePureComponent {
onLoadMore={this.handleLoadMore}
shouldUpdateScroll={shouldUpdateScroll}
emptyMessage={emptyMessage}
+ bindToDocument={!multiColumn}
/>
);
diff --git a/app/javascript/mastodon/features/favourites/index.js b/app/javascript/mastodon/features/favourites/index.js
index d1ac229a27..464f7aeb0a 100644
--- a/app/javascript/mastodon/features/favourites/index.js
+++ b/app/javascript/mastodon/features/favourites/index.js
@@ -23,6 +23,7 @@ class Favourites extends ImmutablePureComponent {
dispatch: PropTypes.func.isRequired,
shouldUpdateScroll: PropTypes.func,
accountIds: ImmutablePropTypes.list,
+ multiColumn: PropTypes.bool,
};
componentWillMount () {
@@ -36,7 +37,7 @@ class Favourites extends ImmutablePureComponent {
}
render () {
- const { shouldUpdateScroll, accountIds } = this.props;
+ const { shouldUpdateScroll, accountIds, multiColumn } = this.props;
if (!accountIds) {
return (
@@ -56,6 +57,7 @@ class Favourites extends ImmutablePureComponent {
scrollKey='favourites'
shouldUpdateScroll={shouldUpdateScroll}
emptyMessage={emptyMessage}
+ bindToDocument={!multiColumn}
>
{accountIds.map(id =>
diff --git a/app/javascript/mastodon/features/follow_requests/index.js b/app/javascript/mastodon/features/follow_requests/index.js
index 44624cb406..570cf57c8a 100644
--- a/app/javascript/mastodon/features/follow_requests/index.js
+++ b/app/javascript/mastodon/features/follow_requests/index.js
@@ -32,6 +32,7 @@ class FollowRequests extends ImmutablePureComponent {
hasMore: PropTypes.bool,
accountIds: ImmutablePropTypes.list,
intl: PropTypes.object.isRequired,
+ multiColumn: PropTypes.bool,
};
componentWillMount () {
@@ -43,7 +44,7 @@ class FollowRequests extends ImmutablePureComponent {
}, 300, { leading: true });
render () {
- const { intl, shouldUpdateScroll, accountIds, hasMore } = this.props;
+ const { intl, shouldUpdateScroll, accountIds, hasMore, multiColumn } = this.props;
if (!accountIds) {
return (
@@ -64,6 +65,7 @@ class FollowRequests extends ImmutablePureComponent {
hasMore={hasMore}
shouldUpdateScroll={shouldUpdateScroll}
emptyMessage={emptyMessage}
+ bindToDocument={!multiColumn}
>
{accountIds.map(id =>
diff --git a/app/javascript/mastodon/features/followers/index.js b/app/javascript/mastodon/features/followers/index.js
index e3387e1be8..dce05bdc62 100644
--- a/app/javascript/mastodon/features/followers/index.js
+++ b/app/javascript/mastodon/features/followers/index.js
@@ -36,6 +36,7 @@ class Followers extends ImmutablePureComponent {
hasMore: PropTypes.bool,
blockedBy: PropTypes.bool,
isAccount: PropTypes.bool,
+ multiColumn: PropTypes.bool,
};
componentWillMount () {
@@ -55,7 +56,7 @@ class Followers extends ImmutablePureComponent {
}, 300, { leading: true });
render () {
- const { shouldUpdateScroll, accountIds, hasMore, blockedBy, isAccount } = this.props;
+ const { shouldUpdateScroll, accountIds, hasMore, blockedBy, isAccount, multiColumn } = this.props;
if (!isAccount) {
return (
@@ -87,6 +88,7 @@ class Followers extends ImmutablePureComponent {
prepend={}
alwaysPrepend
emptyMessage={emptyMessage}
+ bindToDocument={!multiColumn}
>
{blockedBy ? [] : accountIds.map(id =>
diff --git a/app/javascript/mastodon/features/following/index.js b/app/javascript/mastodon/features/following/index.js
index 3bf89fb2ba..d9f2ef0790 100644
--- a/app/javascript/mastodon/features/following/index.js
+++ b/app/javascript/mastodon/features/following/index.js
@@ -36,6 +36,7 @@ class Following extends ImmutablePureComponent {
hasMore: PropTypes.bool,
blockedBy: PropTypes.bool,
isAccount: PropTypes.bool,
+ multiColumn: PropTypes.bool,
};
componentWillMount () {
@@ -55,7 +56,7 @@ class Following extends ImmutablePureComponent {
}, 300, { leading: true });
render () {
- const { shouldUpdateScroll, accountIds, hasMore, blockedBy, isAccount } = this.props;
+ const { shouldUpdateScroll, accountIds, hasMore, blockedBy, isAccount, multiColumn } = this.props;
if (!isAccount) {
return (
@@ -87,6 +88,7 @@ class Following extends ImmutablePureComponent {
prepend={}
alwaysPrepend
emptyMessage={emptyMessage}
+ bindToDocument={!multiColumn}
>
{blockedBy ? [] : accountIds.map(id =>
diff --git a/app/javascript/mastodon/features/hashtag_timeline/index.js b/app/javascript/mastodon/features/hashtag_timeline/index.js
index 0d3c97a648..c50f6a79ae 100644
--- a/app/javascript/mastodon/features/hashtag_timeline/index.js
+++ b/app/javascript/mastodon/features/hashtag_timeline/index.js
@@ -157,6 +157,7 @@ class HashtagTimeline extends React.PureComponent {
onLoadMore={this.handleLoadMore}
emptyMessage={}
shouldUpdateScroll={shouldUpdateScroll}
+ bindToDocument={!multiColumn}
/>
);
diff --git a/app/javascript/mastodon/features/home_timeline/index.js b/app/javascript/mastodon/features/home_timeline/index.js
index 097f91c16c..bf8ff117bb 100644
--- a/app/javascript/mastodon/features/home_timeline/index.js
+++ b/app/javascript/mastodon/features/home_timeline/index.js
@@ -119,6 +119,7 @@ class HomeTimeline extends React.PureComponent {
timelineId='home'
emptyMessage={ }} />}
shouldUpdateScroll={shouldUpdateScroll}
+ bindToDocument={!multiColumn}
/>
);
diff --git a/app/javascript/mastodon/features/list_timeline/index.js b/app/javascript/mastodon/features/list_timeline/index.js
index 0db6d22282..844c93db1e 100644
--- a/app/javascript/mastodon/features/list_timeline/index.js
+++ b/app/javascript/mastodon/features/list_timeline/index.js
@@ -184,6 +184,7 @@ class ListTimeline extends React.PureComponent {
onLoadMore={this.handleLoadMore}
emptyMessage={}
shouldUpdateScroll={shouldUpdateScroll}
+ bindToDocument={!multiColumn}
/>
);
diff --git a/app/javascript/mastodon/features/lists/index.js b/app/javascript/mastodon/features/lists/index.js
index 015e21b687..a06e0b934f 100644
--- a/app/javascript/mastodon/features/lists/index.js
+++ b/app/javascript/mastodon/features/lists/index.js
@@ -40,6 +40,7 @@ class Lists extends ImmutablePureComponent {
dispatch: PropTypes.func.isRequired,
lists: ImmutablePropTypes.list,
intl: PropTypes.object.isRequired,
+ multiColumn: PropTypes.bool,
};
componentWillMount () {
@@ -47,7 +48,7 @@ class Lists extends ImmutablePureComponent {
}
render () {
- const { intl, shouldUpdateScroll, lists } = this.props;
+ const { intl, shouldUpdateScroll, lists, multiColumn } = this.props;
if (!lists) {
return (
@@ -70,6 +71,7 @@ class Lists extends ImmutablePureComponent {
shouldUpdateScroll={shouldUpdateScroll}
emptyMessage={emptyMessage}
prepend={}
+ bindToDocument={!multiColumn}
>
{lists.map(list =>
diff --git a/app/javascript/mastodon/features/mutes/index.js b/app/javascript/mastodon/features/mutes/index.js
index 4ed29a1ce6..57d8b9915f 100644
--- a/app/javascript/mastodon/features/mutes/index.js
+++ b/app/javascript/mastodon/features/mutes/index.js
@@ -32,6 +32,7 @@ class Mutes extends ImmutablePureComponent {
hasMore: PropTypes.bool,
accountIds: ImmutablePropTypes.list,
intl: PropTypes.object.isRequired,
+ multiColumn: PropTypes.bool,
};
componentWillMount () {
@@ -43,7 +44,7 @@ class Mutes extends ImmutablePureComponent {
}, 300, { leading: true });
render () {
- const { intl, shouldUpdateScroll, hasMore, accountIds } = this.props;
+ const { intl, shouldUpdateScroll, hasMore, accountIds, multiColumn } = this.props;
if (!accountIds) {
return (
@@ -64,6 +65,7 @@ class Mutes extends ImmutablePureComponent {
hasMore={hasMore}
shouldUpdateScroll={shouldUpdateScroll}
emptyMessage={emptyMessage}
+ bindToDocument={!multiColumn}
>
{accountIds.map(id =>
diff --git a/app/javascript/mastodon/features/notifications/index.js b/app/javascript/mastodon/features/notifications/index.js
index df4ad6f2aa..e708c4fcf1 100644
--- a/app/javascript/mastodon/features/notifications/index.js
+++ b/app/javascript/mastodon/features/notifications/index.js
@@ -191,6 +191,7 @@ class Notifications extends React.PureComponent {
onScrollToTop={this.handleScrollToTop}
onScroll={this.handleScroll}
shouldUpdateScroll={shouldUpdateScroll}
+ bindToDocument={!multiColumn}
>
{scrollableContent}
diff --git a/app/javascript/mastodon/features/pinned_statuses/index.js b/app/javascript/mastodon/features/pinned_statuses/index.js
index 98cdbda3c4..64ebfc7ae5 100644
--- a/app/javascript/mastodon/features/pinned_statuses/index.js
+++ b/app/javascript/mastodon/features/pinned_statuses/index.js
@@ -28,6 +28,7 @@ class PinnedStatuses extends ImmutablePureComponent {
statusIds: ImmutablePropTypes.list.isRequired,
intl: PropTypes.object.isRequired,
hasMore: PropTypes.bool.isRequired,
+ multiColumn: PropTypes.bool,
};
componentWillMount () {
@@ -43,7 +44,7 @@ class PinnedStatuses extends ImmutablePureComponent {
}
render () {
- const { intl, shouldUpdateScroll, statusIds, hasMore } = this.props;
+ const { intl, shouldUpdateScroll, statusIds, hasMore, multiColumn } = this.props;
return (
@@ -53,6 +54,7 @@ class PinnedStatuses extends ImmutablePureComponent {
scrollKey='pinned_statuses'
hasMore={hasMore}
shouldUpdateScroll={shouldUpdateScroll}
+ bindToDocument={!multiColumn}
/>
);
diff --git a/app/javascript/mastodon/features/public_timeline/index.js b/app/javascript/mastodon/features/public_timeline/index.js
index 2b7d9c56f9..1edb303b84 100644
--- a/app/javascript/mastodon/features/public_timeline/index.js
+++ b/app/javascript/mastodon/features/public_timeline/index.js
@@ -126,6 +126,7 @@ class PublicTimeline extends React.PureComponent {
scrollKey={`public_timeline-${columnId}`}
emptyMessage={}
shouldUpdateScroll={shouldUpdateScroll}
+ bindToDocument={!multiColumn}
/>
);
diff --git a/app/javascript/mastodon/features/reblogs/index.js b/app/javascript/mastodon/features/reblogs/index.js
index c05d21c740..26f93ad1b2 100644
--- a/app/javascript/mastodon/features/reblogs/index.js
+++ b/app/javascript/mastodon/features/reblogs/index.js
@@ -23,6 +23,7 @@ class Reblogs extends ImmutablePureComponent {
dispatch: PropTypes.func.isRequired,
shouldUpdateScroll: PropTypes.func,
accountIds: ImmutablePropTypes.list,
+ multiColumn: PropTypes.bool,
};
componentWillMount () {
@@ -36,7 +37,7 @@ class Reblogs extends ImmutablePureComponent {
}
render () {
- const { shouldUpdateScroll, accountIds } = this.props;
+ const { shouldUpdateScroll, accountIds, multiColumn } = this.props;
if (!accountIds) {
return (
@@ -56,6 +57,7 @@ class Reblogs extends ImmutablePureComponent {
scrollKey='reblogs'
shouldUpdateScroll={shouldUpdateScroll}
emptyMessage={emptyMessage}
+ bindToDocument={!multiColumn}
>
{accountIds.map(id =>
diff --git a/app/javascript/mastodon/features/ui/components/modal_root.js b/app/javascript/mastodon/features/ui/components/modal_root.js
index cc2ab6c8ce..06f9e1bc4d 100644
--- a/app/javascript/mastodon/features/ui/components/modal_root.js
+++ b/app/javascript/mastodon/features/ui/components/modal_root.js
@@ -32,6 +32,28 @@ const MODAL_COMPONENTS = {
'LIST_ADDER':ListAdder,
};
+let cachedScrollbarWidth = null;
+
+export const getScrollbarWidth = () => {
+ if (cachedScrollbarWidth !== null) {
+ return cachedScrollbarWidth;
+ }
+
+ const outer = document.createElement('div');
+ outer.style.visibility = 'hidden';
+ outer.style.overflow = 'scroll';
+ document.body.appendChild(outer);
+
+ const inner = document.createElement('div');
+ outer.appendChild(inner);
+
+ const scrollbarWidth = outer.offsetWidth - inner.offsetWidth;
+ cachedScrollbarWidth = scrollbarWidth;
+ outer.parentNode.removeChild(outer);
+
+ return scrollbarWidth;
+};
+
export default class ModalRoot extends React.PureComponent {
static propTypes = {
@@ -47,8 +69,10 @@ export default class ModalRoot extends React.PureComponent {
componentDidUpdate (prevProps, prevState, { visible }) {
if (visible) {
document.body.classList.add('with-modals--active');
+ document.documentElement.style.marginRight = `${getScrollbarWidth()}px`;
} else {
document.body.classList.remove('with-modals--active');
+ document.documentElement.style.marginRight = 0;
}
}
diff --git a/app/javascript/mastodon/features/ui/index.js b/app/javascript/mastodon/features/ui/index.js
index 791133afd3..d1a3dc9495 100644
--- a/app/javascript/mastodon/features/ui/index.js
+++ b/app/javascript/mastodon/features/ui/index.js
@@ -110,12 +110,25 @@ class SwitchingColumnsArea extends React.PureComponent {
componentWillMount () {
window.addEventListener('resize', this.handleResize, { passive: true });
+
+ if (this.state.mobile || forceSingleColumn) {
+ document.body.classList.toggle('layout-single-column', true);
+ document.body.classList.toggle('layout-multiple-columns', false);
+ } else {
+ document.body.classList.toggle('layout-single-column', false);
+ document.body.classList.toggle('layout-multiple-columns', true);
+ }
}
- componentDidUpdate (prevProps) {
+ componentDidUpdate (prevProps, prevState) {
if (![this.props.location.pathname, '/'].includes(prevProps.location.pathname)) {
this.node.handleChildrenContentChange();
}
+
+ if (prevState.mobile !== this.state.mobile && !forceSingleColumn) {
+ document.body.classList.toggle('layout-single-column', this.state.mobile);
+ document.body.classList.toggle('layout-multiple-columns', !this.state.mobile);
+ }
}
componentWillUnmount () {
diff --git a/app/javascript/mastodon/locales/ar.json b/app/javascript/mastodon/locales/ar.json
index d05c61f986..d62ee90c2c 100644
--- a/app/javascript/mastodon/locales/ar.json
+++ b/app/javascript/mastodon/locales/ar.json
@@ -156,6 +156,7 @@
"home.column_settings.basic": "أساسية",
"home.column_settings.show_reblogs": "عرض الترقيات",
"home.column_settings.show_replies": "عرض الردود",
+ "home.column_settings.update_live": "Update in real-time",
"intervals.full.days": "{number, plural, one {# يوم} other {# أيام}}",
"intervals.full.hours": "{number, plural, one {# ساعة} other {# ساعات}}",
"intervals.full.minutes": "{number, plural, one {# دقيقة} other {# دقائق}}",
@@ -221,6 +222,7 @@
"lists.new.title_placeholder": "عنوان القائمة الجديدة",
"lists.search": "إبحث في قائمة الحسابات التي تُتابِعها",
"lists.subheading": "قوائمك",
+ "load_pending": "{count, plural, one {# new item} other {# new items}}",
"loading_indicator.label": "تحميل...",
"media_gallery.toggle_visible": "عرض / إخفاء",
"missing_indicator.label": "تعذر العثور عليه",
@@ -314,6 +316,7 @@
"search_results.accounts": "أشخاص",
"search_results.hashtags": "الوُسوم",
"search_results.statuses": "التبويقات",
+ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.",
"search_results.total": "{count, number} {count, plural, one {result} و {results}}",
"status.admin_account": "افتح الواجهة الإدارية لـ @{name}",
"status.admin_status": "افتح هذا المنشور على واجهة الإشراف",
diff --git a/app/javascript/mastodon/locales/ast.json b/app/javascript/mastodon/locales/ast.json
index b911848ee0..3ae4e5e5e4 100644
--- a/app/javascript/mastodon/locales/ast.json
+++ b/app/javascript/mastodon/locales/ast.json
@@ -64,7 +64,7 @@
"column_header.show_settings": "Show settings",
"column_header.unpin": "Desfixar",
"column_subheading.settings": "Axustes",
- "community.column_settings.media_only": "Media Only",
+ "community.column_settings.media_only": "Media only",
"compose_form.direct_message_warning": "Esti toot namái va unviase a los usuarios mentaos.",
"compose_form.direct_message_warning_learn_more": "Learn more",
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
@@ -156,6 +156,7 @@
"home.column_settings.basic": "Basic",
"home.column_settings.show_reblogs": "Amosar toots compartíos",
"home.column_settings.show_replies": "Amosar rempuestes",
+ "home.column_settings.update_live": "Update in real-time",
"intervals.full.days": "{number, plural, one {# day} other {# days}}",
"intervals.full.hours": "{number, plural, one {# hour} other {# hours}}",
"intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}",
@@ -221,6 +222,7 @@
"lists.new.title_placeholder": "Títulu nuevu de la llista",
"lists.search": "Guetar ente la xente que sigues",
"lists.subheading": "Les tos llistes",
+ "load_pending": "{count, plural, one {# new item} other {# new items}}",
"loading_indicator.label": "Cargando...",
"media_gallery.toggle_visible": "Toggle visibility",
"missing_indicator.label": "Nun s'alcontró",
@@ -314,6 +316,7 @@
"search_results.accounts": "Xente",
"search_results.hashtags": "Etiquetes",
"search_results.statuses": "Toots",
+ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.",
"search_results.total": "{count, number} {count, plural, one {result} other {results}}",
"status.admin_account": "Open moderation interface for @{name}",
"status.admin_status": "Open this status in the moderation interface",
diff --git a/app/javascript/mastodon/locales/bg.json b/app/javascript/mastodon/locales/bg.json
index 783f9eb688..4c97fe1fc0 100644
--- a/app/javascript/mastodon/locales/bg.json
+++ b/app/javascript/mastodon/locales/bg.json
@@ -64,7 +64,7 @@
"column_header.show_settings": "Show settings",
"column_header.unpin": "Unpin",
"column_subheading.settings": "Settings",
- "community.column_settings.media_only": "Media Only",
+ "community.column_settings.media_only": "Media only",
"compose_form.direct_message_warning": "This toot will only be visible to all the mentioned users.",
"compose_form.direct_message_warning_learn_more": "Learn more",
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
@@ -156,6 +156,7 @@
"home.column_settings.basic": "Basic",
"home.column_settings.show_reblogs": "Show boosts",
"home.column_settings.show_replies": "Show replies",
+ "home.column_settings.update_live": "Update in real-time",
"intervals.full.days": "{number, plural, one {# day} other {# days}}",
"intervals.full.hours": "{number, plural, one {# hour} other {# hours}}",
"intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}",
@@ -221,6 +222,7 @@
"lists.new.title_placeholder": "New list title",
"lists.search": "Search among people you follow",
"lists.subheading": "Your lists",
+ "load_pending": "{count, plural, one {# new item} other {# new items}}",
"loading_indicator.label": "Зареждане...",
"media_gallery.toggle_visible": "Toggle visibility",
"missing_indicator.label": "Not found",
@@ -314,6 +316,7 @@
"search_results.accounts": "People",
"search_results.hashtags": "Hashtags",
"search_results.statuses": "Toots",
+ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.",
"search_results.total": "{count, number} {count, plural, one {result} other {results}}",
"status.admin_account": "Open moderation interface for @{name}",
"status.admin_status": "Open this status in the moderation interface",
diff --git a/app/javascript/mastodon/locales/bn.json b/app/javascript/mastodon/locales/bn.json
index 5b7162ec12..358f994f30 100644
--- a/app/javascript/mastodon/locales/bn.json
+++ b/app/javascript/mastodon/locales/bn.json
@@ -1,13 +1,13 @@
{
"account.add_or_remove_from_list": "তালিকাতে আরো যুক্ত বা মুছে ফেলুন",
"account.badges.bot": "রোবট",
- "account.block": "@{name} বন্ধ করুন",
+ "account.block": "@{name} কে বন্ধ করুন",
"account.block_domain": "{domain} থেকে সব সরিয়ে ফেলুন",
"account.blocked": "বন্ধ করা হয়েছে",
- "account.direct": "@{name}কে সরকারি লিখুন",
+ "account.direct": "@{name} এর কাছে সরকারি লেখা পাঠাতে",
"account.domain_blocked": "ওয়েবসাইট সরিয়ে ফেলা হয়েছে",
- "account.edit_profile": "নিজের পাতা সম্পাদনা করুন",
- "account.endorse": "নিজের পাতায় দেখান",
+ "account.edit_profile": "নিজের পাতা সম্পাদনা করতে",
+ "account.endorse": "আপনার নিজের পাতায় দেখাতে",
"account.follow": "অনুসরণ করুন",
"account.followers": "অনুসরণকারক",
"account.followers.empty": "এই ব্যবহারকারীকে কেও এখনো অনুসরণ করে না।",
@@ -18,21 +18,21 @@
"account.link_verified_on": "এই লিংকের মালিকানা চেক করা হয়েছে {date} তারিকে",
"account.locked_info": "এই নিবন্ধনের গোপনীয়তার ক্ষেত্র তালা দেওয়া আছে। নিবন্ধনকারী অনুসরণ করার অনুমতি যাদেরকে দেবেন, শুধু তারাই অনুসরণ করতে পারবেন।",
"account.media": "ছবি বা ভিডিও",
- "account.mention": "@{name} কে উল্লেখ করুন",
+ "account.mention": "@{name} কে উল্লেখ করতে",
"account.moved_to": "{name} চলে গেছে এখানে:",
- "account.mute": "@{name}র কার্যক্রম সরিয়ে ফেলুন",
+ "account.mute": "@{name} সব কার্যক্রম আপনার সময়রেখা থেকে সরিয়ে ফেলতে",
"account.mute_notifications": "@{name}র প্রজ্ঞাপন আপনার কাছ থেকে সরিয়ে ফেলুন",
"account.muted": "সরানো আছে",
"account.posts": "টুট",
"account.posts_with_replies": "টুট এবং মতামত",
- "account.report": "@{name}কে রিপোর্ট করে দিন",
+ "account.report": "@{name} কে রিপোর্ট করতে",
"account.requested": "অনুমতির অপেক্ষায় আছে। অনুসরণ করার অনুরোধ বাতিল করতে এখানে ক্লিক করুন",
"account.share": "@{name}র পাতা অন্যদের দেখান",
"account.show_reblogs": "@{name}র সমর্থনগুলো দেখুন",
"account.unblock": "@{name}র কার্যকলাপ আবার দেখুন",
"account.unblock_domain": "{domain}থেকে আবার দেখুন",
- "account.unendorse": "নিজের পাতায় এটা দেখতে চান না",
- "account.unfollow": "অনুসরণ বন্ধ করুন",
+ "account.unendorse": "আপনার নিজের পাতায় এটা না দেখাতে",
+ "account.unfollow": "অনুসরণ না করতে",
"account.unmute": "@{name}র কার্যকলাপ আবার দেখুন",
"account.unmute_notifications": "@{name}র প্রজ্ঞাপন দেওয়ার অনুমতি দিন",
"alert.unexpected.message": "অপ্রত্যাশিত একটি সমস্যা হয়েছে।",
@@ -42,7 +42,7 @@
"bundle_column_error.retry": "আবার চেষ্টা করুন",
"bundle_column_error.title": "নেটওয়ার্কের সমস্যা হচ্ছে",
"bundle_modal_error.close": "বন্ধ করুন",
- "bundle_modal_error.message": "এই অংশটি দেখতে যেয়ে কোনো সমস্যা হয়েছে।",
+ "bundle_modal_error.message": "এই অংশটি দেখাতে যেয়ে কোনো সমস্যা হয়েছে।",
"bundle_modal_error.retry": "আবার চেষ্টা করুন",
"column.blocks": "যাদের বন্ধ করে রাখা হয়েছে",
"column.community": "স্থানীয় সময়সারি",
@@ -77,12 +77,12 @@
"compose_form.poll.remove_option": "এই বিকল্পটি মুছে ফেলুন",
"compose_form.publish": "টুট",
"compose_form.publish_loud": "{publish}!",
- "compose_form.sensitive.hide": "Mark media as sensitive",
+ "compose_form.sensitive.hide": "এই ছবি বা ভিডিওটি সংবেদনশীল হিসেবে চিহ্নিত করতে",
"compose_form.sensitive.marked": "এই ছবি বা ভিডিওটি সংবেদনশীল হিসেবে চিহ্নিত করা হয়েছে",
"compose_form.sensitive.unmarked": "এই ছবি বা ভিডিওটি সংবেদনশীল হিসেবে চিহ্নিত করা হয়নি",
"compose_form.spoiler.marked": "লেখাটি সাবধানতার পেছনে লুকানো আছে",
"compose_form.spoiler.unmarked": "লেখাটি লুকানো নেই",
- "compose_form.spoiler_placeholder": "আপনার সাবধানতা এখানে লিখুন",
+ "compose_form.spoiler_placeholder": "আপনার লেখা দেখার সাবধানবাণী লিখুন",
"confirmation_modal.cancel": "বাতিল করুন",
"confirmations.block.block_and_report": "বন্ধ করুন এবং রিপোর্ট করুন",
"confirmations.block.confirm": "বন্ধ করুন",
@@ -99,7 +99,7 @@
"confirmations.redraft.message": "আপনি কি নিশ্চিত এটি মুছে ফেলে এবং আবার সম্পাদন করতে চান ? এটাতে যা পছন্দিত, সমর্থন বা মতামত আছে সেগুলো নতুন লেখার সাথে যুক্ত থাকবে না।",
"confirmations.reply.confirm": "মতামত",
"confirmations.reply.message": "এখন মতামত লিখতে গেলে আপনার এখন যেটা লিখছেন সেটা মুছে যাবে। আপনি নি নিশ্চিত এটা করতে চান ?",
- "confirmations.unfollow.confirm": "অনুসরণ বন্ধ করুন",
+ "confirmations.unfollow.confirm": "অনুসরণ করা বাতিল করতে",
"confirmations.unfollow.message": "আপনি কি নিশ্চিত {name} কে আর অনুসরণ করতে চান না ?",
"embed.instructions": "এই লেখাটি আপনার ওয়েবসাইটে যুক্ত করতে নিচের কোডটি বেবহার করুন।",
"embed.preview": "সেটা দেখতে এরকম হবে:",
@@ -137,11 +137,11 @@
"follow_request.authorize": "অনুমতি দিন",
"follow_request.reject": "প্রত্যাখ্যান করুন",
"getting_started.developers": "তৈরিকারকদের জন্য",
- "getting_started.directory": "নিজস্ব পাতার তালিকা",
+ "getting_started.directory": "নিজস্ব-পাতাগুলির তালিকা",
"getting_started.documentation": "নথিপত্র",
"getting_started.heading": "শুরু করা",
"getting_started.invite": "অন্যদের আমন্ত্রণ করুন",
- "getting_started.open_source_notice": "মাস্টাডন একটি মুক্ত সফটওয়্যার। আপনি তৈরিতে সাহায্য করতে পারেন অথবা সমস্যা রিপোর্ট করতে পারেন গিটহাবে {github}।",
+ "getting_started.open_source_notice": "মাস্টাডন একটি মুক্ত সফটওয়্যার। তৈরিতে সাহায্য করতে বা কোনো সমস্যা সম্পর্কে জানাতে আমাদের গিটহাবে যেতে পারেন {github}।",
"getting_started.security": "নিরাপত্তা",
"getting_started.terms": "ব্যবহারের নিয়মাবলী",
"hashtag.column_header.tag_mode.all": "এবং {additional}",
@@ -152,10 +152,11 @@
"hashtag.column_settings.tag_mode.all": "এগুলো সব",
"hashtag.column_settings.tag_mode.any": "এর ভেতরে যেকোনোটা",
"hashtag.column_settings.tag_mode.none": "এগুলোর একটাও না",
- "hashtag.column_settings.tag_toggle": "আরো ট্যাগ এই কলামে যুক্ত করুন",
+ "hashtag.column_settings.tag_toggle": "আরো ট্যাগ এই কলামে যুক্ত করতে",
"home.column_settings.basic": "সাধারণ",
"home.column_settings.show_reblogs": "সমর্থনগুলো দেখান",
"home.column_settings.show_replies": "মতামত দেখান",
+ "home.column_settings.update_live": "Update in real-time",
"intervals.full.days": "{number, plural, one {# day} other {# days}}",
"intervals.full.hours": "{number, plural, one {# ঘটা} other {# ঘটা}}",
"intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}",
@@ -195,7 +196,7 @@
"keyboard_shortcuts.local": "স্থানীয় সময়রেখাতে যেতে",
"keyboard_shortcuts.mention": "লেখককে উল্লেখ করতে",
"keyboard_shortcuts.muted": "বন্ধ করা ব্যবহারকারীদের তালিকা খুলতে",
- "keyboard_shortcuts.my_profile": "নিজের পাতা দেখতে",
+ "keyboard_shortcuts.my_profile": "আপনার নিজের পাতা দেখতে",
"keyboard_shortcuts.notifications": "প্রজ্ঞাপনের কলাম খুলতে",
"keyboard_shortcuts.pinned": "পিন দেওয়া টুটের তালিকা খুলতে",
"keyboard_shortcuts.profile": "লেখকের পাতা দেখতে",
@@ -204,14 +205,14 @@
"keyboard_shortcuts.search": "খোঁজার অংশে ফোকাস করতে",
"keyboard_shortcuts.start": "\"প্রথম শুরুর\" কলাম বের করতে",
"keyboard_shortcuts.toggle_hidden": "CW লেখা দেখতে বা লুকাতে",
- "keyboard_shortcuts.toggle_sensitivity": "to show/hide media",
+ "keyboard_shortcuts.toggle_sensitivity": "ভিডিও/ছবি দেখতে বা বন্ধ করতে",
"keyboard_shortcuts.toot": "নতুন একটা টুট লেখা শুরু করতে",
"keyboard_shortcuts.unfocus": "লেখা বা খোঁজার জায়গায় ফোকাস না করতে",
"keyboard_shortcuts.up": "তালিকার উপরের দিকে যেতে",
"lightbox.close": "বন্ধ",
"lightbox.next": "পরবর্তী",
"lightbox.previous": "পূর্ববর্তী",
- "lightbox.view_context": "View context",
+ "lightbox.view_context": "প্রসঙ্গটি দেখতে",
"lists.account.add": "তালিকাতে যুক্ত করতে",
"lists.account.remove": "তালিকা থেকে বাদ দিতে",
"lists.delete": "তালিকা মুছে ফেলতে",
@@ -221,6 +222,7 @@
"lists.new.title_placeholder": "তালিকার নতুন শিরোনাম দিতে",
"lists.search": "যাদের অনুসরণ করেন তাদের ভেতরে খুঁজুন",
"lists.subheading": "আপনার তালিকা",
+ "load_pending": "{count, plural, one {# new item} other {# new items}}",
"loading_indicator.label": "আসছে...",
"media_gallery.toggle_visible": "দৃশ্যতার অবস্থা বদলান",
"missing_indicator.label": "খুঁজে পাওয়া যায়নি",
@@ -230,14 +232,14 @@
"navigation_bar.blocks": "বন্ধ করা ব্যবহারকারী",
"navigation_bar.community_timeline": "স্থানীয় সময়রেখা",
"navigation_bar.compose": "নতুন টুট লিখুন",
- "navigation_bar.direct": "সরাসরি লেখা",
+ "navigation_bar.direct": "সরাসরি লেখাগুলি",
"navigation_bar.discover": "ঘুরে দেখুন",
"navigation_bar.domain_blocks": "বন্ধ করা ওয়েবসাইট",
- "navigation_bar.edit_profile": "নিজের পাতা সম্পাদনা করুন",
+ "navigation_bar.edit_profile": "নিজের পাতা সম্পাদনা করতে",
"navigation_bar.favourites": "পছন্দের",
"navigation_bar.filters": "বন্ধ করা শব্দ",
"navigation_bar.follow_requests": "অনুসরণের অনুরোধগুলি",
- "navigation_bar.follows_and_followers": "Follows and followers",
+ "navigation_bar.follows_and_followers": "যাদেরকে অনুসরণ করেন এবং যারা তাকে অনুসরণ করে",
"navigation_bar.info": "এই সার্ভার সম্পর্কে",
"navigation_bar.keyboard_shortcuts": "হটকীগুলি",
"navigation_bar.lists": "তালিকাগুলো",
@@ -246,7 +248,7 @@
"navigation_bar.personal": "নিজস্ব",
"navigation_bar.pins": "পিন দেওয়া টুট",
"navigation_bar.preferences": "পছন্দসমূহ",
- "navigation_bar.profile_directory": "Profile directory",
+ "navigation_bar.profile_directory": "নিজস্ব পাতার তালিকা",
"navigation_bar.public_timeline": "যুক্তবিশ্বের সময়রেখা",
"navigation_bar.security": "নিরাপত্তা",
"notification.favourite": "{name} আপনার কার্যক্রম পছন্দ করেছেন",
@@ -256,18 +258,18 @@
"notification.reblog": "{name} আপনার কার্যক্রমে সমর্থন দেখিয়েছেন",
"notifications.clear": "প্রজ্ঞাপনগুলো মুছে ফেলতে",
"notifications.clear_confirmation": "আপনি কি নির্চিত প্রজ্ঞাপনগুলো মুছে ফেলতে চান ?",
- "notifications.column_settings.alert": "কম্পিউটারে প্রজ্ঞাপন",
+ "notifications.column_settings.alert": "কম্পিউটারে প্রজ্ঞাপনগুলি",
"notifications.column_settings.favourite": "পছন্দের:",
- "notifications.column_settings.filter_bar.advanced": "সব শ্রেণীগুলো দেখতে",
- "notifications.column_settings.filter_bar.category": "দ্রুত ছাঁকনি বার",
- "notifications.column_settings.filter_bar.show": "দেখতে",
+ "notifications.column_settings.filter_bar.advanced": "সব শ্রেণীগুলো দেখানো",
+ "notifications.column_settings.filter_bar.category": "সংক্ষিপ্ত ছাঁকনি অংশ",
+ "notifications.column_settings.filter_bar.show": "দেখানো",
"notifications.column_settings.follow": "নতুন অনুসরণকারীরা:",
"notifications.column_settings.mention": "প্রজ্ঞাপনগুলো:",
"notifications.column_settings.poll": "নির্বাচনের ফলাফল:",
- "notifications.column_settings.push": "পুশ প্রজ্ঞাপন",
+ "notifications.column_settings.push": "পুশ প্রজ্ঞাপনগুলি",
"notifications.column_settings.reblog": "সমর্থনগুলো:",
- "notifications.column_settings.show": "কলামে দেখান",
- "notifications.column_settings.sound": "শব্দ বাজাতে",
+ "notifications.column_settings.show": "কলামে দেখানো",
+ "notifications.column_settings.sound": "শব্দ বাজানো",
"notifications.filter.all": "সব",
"notifications.filter.boosts": "সমর্থনগুলো",
"notifications.filter.favourites": "পছন্দের গুলো",
@@ -276,7 +278,7 @@
"notifications.filter.polls": "নির্বাচনের ফলাফল",
"notifications.group": "{count} প্রজ্ঞাপন",
"poll.closed": "বন্ধ",
- "poll.refresh": "আবার সতেজ করতে",
+ "poll.refresh": "বদলেছে কিনা দেখতে",
"poll.total_votes": "{count, plural, one {# ভোট} other {# ভোট}}",
"poll.vote": "ভোট",
"poll_button.add_poll": "একটা নির্বাচন যোগ করতে",
@@ -314,6 +316,7 @@
"search_results.accounts": "মানুষ",
"search_results.hashtags": "হ্যাশট্যাগগুলি",
"search_results.statuses": "টুট",
+ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.",
"search_results.total": "{count, number} {count, plural, one {ফলাফল} other {ফলাফল}}",
"status.admin_account": "@{name} র জন্য পরিচালনার ইন্টারফেসে ঢুকুন",
"status.admin_status": "যায় লেখাটি পরিচালনার ইন্টারফেসে খুলুন",
@@ -323,7 +326,7 @@
"status.copy": "লেখাটির লিংক কপি করতে",
"status.delete": "মুছে ফেলতে",
"status.detailed_status": "বিস্তারিত কথোপকথনের হিসেবে দেখতে",
- "status.direct": "@{name} কে সরাসরি পাঠান",
+ "status.direct": "@{name} কে সরাসরি লেখা পাঠাতে",
"status.embed": "এমবেড করতে",
"status.favourite": "পছন্দের করতে",
"status.filtered": "ছাঁকনিদিত",
@@ -344,7 +347,7 @@
"status.redraft": "মুছে আবার নতুন করে লিখতে",
"status.reply": "মতামত জানাতে",
"status.replyAll": "লেখাযুক্ত সবার কাছে মতামত জানাতে",
- "status.report": "@{name}কে রিপোর্ট করতে",
+ "status.report": "@{name} কে রিপোর্ট করতে",
"status.sensitive_warning": "সংবেদনশীল কিছু",
"status.share": "অন্যদের জানান",
"status.show_less": "কম দেখতে",
@@ -354,7 +357,7 @@
"status.show_thread": "আলোচনা দেখতে",
"status.unmute_conversation": "আলোচনার প্রজ্ঞাপন চালু করতে",
"status.unpin": "নিজের পাতা থেকে পিন করে রাখাটির পিন খুলতে",
- "suggestions.dismiss": "সাহায্যের জন্য পরামর্শগুলো সরাতে",
+ "suggestions.dismiss": "সাহায্যের পরামর্শগুলো সরাতে",
"suggestions.header": "আপনি হয়তোবা এগুলোতে আগ্রহী হতে পারেন…",
"tabs_bar.federated_timeline": "যুক্তবিশ্ব",
"tabs_bar.home": "বাড়ি",
@@ -369,7 +372,7 @@
"trends.count_by_accounts": "{count} {rawCount, plural, one {person} other {people}} কথা বলছে",
"ui.beforeunload": "যে পর্যন্ত এটা লেখা হয়েছে, মাস্টাডন থেকে চলে গেলে এটা মুছে যাবে।",
"upload_area.title": "টেনে এখানে ছেড়ে দিলে এখানে যুক্ত করা যাবে",
- "upload_button.label": "ছবি বা ভিডিও যুক্ত করতে (এসব ধরণের JPEG, PNG, GIF, WebM, MP4, MOV)",
+ "upload_button.label": "ছবি বা ভিডিও যুক্ত করতে (এসব ধরণের: JPEG, PNG, GIF, WebM, MP4, MOV)",
"upload_error.limit": "যা যুক্ত করতে চাচ্ছেন সেটি বেশি বড়, এখানকার সর্বাধিকের মেমোরির উপরে চলে গেছে।",
"upload_error.poll": "নির্বাচনক্ষেত্রে কোনো ফাইল যুক্ত করা যাবেনা।",
"upload_form.description": "যারা দেখতে পায়না তাদের জন্য এটা বর্ণনা করতে",
diff --git a/app/javascript/mastodon/locales/ca.json b/app/javascript/mastodon/locales/ca.json
index bb73b2a419..09f8838e9c 100644
--- a/app/javascript/mastodon/locales/ca.json
+++ b/app/javascript/mastodon/locales/ca.json
@@ -156,6 +156,7 @@
"home.column_settings.basic": "Bàsic",
"home.column_settings.show_reblogs": "Mostrar impulsos",
"home.column_settings.show_replies": "Mostrar respostes",
+ "home.column_settings.update_live": "Update in real-time",
"intervals.full.days": "{number, plural, one {# dia} other {# dies}}",
"intervals.full.hours": "{number, plural, one {# hora} other {# hores}}",
"intervals.full.minutes": "{number, plural, one {# minut} other {# minuts}}",
@@ -221,6 +222,7 @@
"lists.new.title_placeholder": "Nova llista",
"lists.search": "Cercar entre les persones que segueixes",
"lists.subheading": "Les teves llistes",
+ "load_pending": "{count, plural, one {# new item} other {# new items}}",
"loading_indicator.label": "Carregant...",
"media_gallery.toggle_visible": "Alternar visibilitat",
"missing_indicator.label": "No trobat",
@@ -314,6 +316,7 @@
"search_results.accounts": "Gent",
"search_results.hashtags": "Etiquetes",
"search_results.statuses": "Toots",
+ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.",
"search_results.total": "{count, number} {count, plural, one {resultat} other {resultats}}",
"status.admin_account": "Obre l'interfície de moderació per a @{name}",
"status.admin_status": "Obre aquest toot a la interfície de moderació",
diff --git a/app/javascript/mastodon/locales/co.json b/app/javascript/mastodon/locales/co.json
index fb8ffdd510..7a1ff863b0 100644
--- a/app/javascript/mastodon/locales/co.json
+++ b/app/javascript/mastodon/locales/co.json
@@ -156,6 +156,7 @@
"home.column_settings.basic": "Bàsichi",
"home.column_settings.show_reblogs": "Vede e spartere",
"home.column_settings.show_replies": "Vede e risposte",
+ "home.column_settings.update_live": "Update in real-time",
"intervals.full.days": "{number, plural, one {# ghjornu} other {# ghjorni}}",
"intervals.full.hours": "{number, plural, one {# ora} other {# ore}}",
"intervals.full.minutes": "{number, plural, one {# minuta} other {# minute}}",
@@ -221,6 +222,7 @@
"lists.new.title_placeholder": "Titulu di a lista",
"lists.search": "Circà indè i vostr'abbunamenti",
"lists.subheading": "E vo liste",
+ "load_pending": "{count, plural, one {# new item} other {# new items}}",
"loading_indicator.label": "Caricamentu...",
"media_gallery.toggle_visible": "Cambià a visibilità",
"missing_indicator.label": "Micca trovu",
@@ -314,6 +316,7 @@
"search_results.accounts": "Ghjente",
"search_results.hashtags": "Hashtag",
"search_results.statuses": "Statuti",
+ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.",
"search_results.total": "{count, number} {count, plural, one {risultatu} other {risultati}}",
"status.admin_account": "Apre l'interfaccia di muderazione per @{name}",
"status.admin_status": "Apre stu statutu in l'interfaccia di muderazione",
diff --git a/app/javascript/mastodon/locales/cs.json b/app/javascript/mastodon/locales/cs.json
index f10a3f38b7..020fd35b03 100644
--- a/app/javascript/mastodon/locales/cs.json
+++ b/app/javascript/mastodon/locales/cs.json
@@ -156,6 +156,7 @@
"home.column_settings.basic": "Základní",
"home.column_settings.show_reblogs": "Zobrazit boosty",
"home.column_settings.show_replies": "Zobrazit odpovědi",
+ "home.column_settings.update_live": "Update in real-time",
"intervals.full.days": "{number, plural, one {# den} few {# dny} many {# dne} other {# dní}}",
"intervals.full.hours": "{number, plural, one {# hodina} few {# hodiny} many {# hodiny} other {# hodin}}",
"intervals.full.minutes": "{number, plural, one {# minuta} few {# minuty} many {# minuty} other {# minut}}",
@@ -221,6 +222,7 @@
"lists.new.title_placeholder": "Název nového seznamu",
"lists.search": "Hledejte mezi lidmi, které sledujete",
"lists.subheading": "Vaše seznamy",
+ "load_pending": "{count, plural, one {# new item} other {# new items}}",
"loading_indicator.label": "Načítám…",
"media_gallery.toggle_visible": "Přepínat viditelnost",
"missing_indicator.label": "Nenalezeno",
@@ -314,6 +316,7 @@
"search_results.accounts": "Lidé",
"search_results.hashtags": "Hashtagy",
"search_results.statuses": "Tooty",
+ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.",
"search_results.total": "{count, number} {count, plural, one {výsledek} few {výsledky} many {výsledku} other {výsledků}}",
"status.admin_account": "Otevřít moderátorské rozhraní pro uživatele @{name}",
"status.admin_status": "Otevřít tento toot v moderátorském rozhraní",
diff --git a/app/javascript/mastodon/locales/cy.json b/app/javascript/mastodon/locales/cy.json
index 4ce5d7ad97..9de3efda8c 100644
--- a/app/javascript/mastodon/locales/cy.json
+++ b/app/javascript/mastodon/locales/cy.json
@@ -156,6 +156,7 @@
"home.column_settings.basic": "Syml",
"home.column_settings.show_reblogs": "Dangos bŵstiau",
"home.column_settings.show_replies": "Dangos ymatebion",
+ "home.column_settings.update_live": "Update in real-time",
"intervals.full.days": "{number, plural, one {# ddydd} other {# o ddyddiau}}",
"intervals.full.hours": "{number, plural, one {# awr} other {# o oriau}}",
"intervals.full.minutes": "{number, plural, one {# funud} other {# o funudau}}",
@@ -221,6 +222,7 @@
"lists.new.title_placeholder": "Teitl rhestr newydd",
"lists.search": "Chwilio ymysg pobl yr ydych yn ei ddilyn",
"lists.subheading": "Eich rhestrau",
+ "load_pending": "{count, plural, one {# new item} other {# new items}}",
"loading_indicator.label": "Llwytho...",
"media_gallery.toggle_visible": "Toglo gwelededd",
"missing_indicator.label": "Heb ei ganfod",
@@ -314,6 +316,7 @@
"search_results.accounts": "Pobl",
"search_results.hashtags": "Hanshnodau",
"search_results.statuses": "Tŵtiau",
+ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.",
"search_results.total": "{count, number} {count, plural, one {result} other {results}}",
"status.admin_account": "Agor rhyngwyneb goruwchwylio ar gyfer @{name}",
"status.admin_status": "Agor y tŵt yn y rhyngwyneb goruwchwylio",
diff --git a/app/javascript/mastodon/locales/da.json b/app/javascript/mastodon/locales/da.json
index ba8ba7a28e..17080c41e3 100644
--- a/app/javascript/mastodon/locales/da.json
+++ b/app/javascript/mastodon/locales/da.json
@@ -156,6 +156,7 @@
"home.column_settings.basic": "Grundlæggende",
"home.column_settings.show_reblogs": "Vis fremhævelser",
"home.column_settings.show_replies": "Vis svar",
+ "home.column_settings.update_live": "Update in real-time",
"intervals.full.days": "{number, plural, one {# day} other {# days}}",
"intervals.full.hours": "{number, plural, one {# hour} other {# hours}}",
"intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}",
@@ -221,6 +222,7 @@
"lists.new.title_placeholder": "Ny liste titel",
"lists.search": "Søg iblandt folk du følger",
"lists.subheading": "Dine lister",
+ "load_pending": "{count, plural, one {# new item} other {# new items}}",
"loading_indicator.label": "Indlæser...",
"media_gallery.toggle_visible": "Ændre synlighed",
"missing_indicator.label": "Ikke fundet",
@@ -314,6 +316,7 @@
"search_results.accounts": "Folk",
"search_results.hashtags": "Emnetags",
"search_results.statuses": "Trut",
+ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.",
"search_results.total": "{count, number} {count, plural, et {result} andre {results}}",
"status.admin_account": "Open moderation interface for @{name}",
"status.admin_status": "Open this status in the moderation interface",
diff --git a/app/javascript/mastodon/locales/de.json b/app/javascript/mastodon/locales/de.json
index ac8bc9b9f7..4ae785270e 100644
--- a/app/javascript/mastodon/locales/de.json
+++ b/app/javascript/mastodon/locales/de.json
@@ -156,6 +156,7 @@
"home.column_settings.basic": "Einfach",
"home.column_settings.show_reblogs": "Geteilte Beiträge anzeigen",
"home.column_settings.show_replies": "Antworten anzeigen",
+ "home.column_settings.update_live": "Update in real-time",
"intervals.full.days": "{number, plural, one {# Tag} other {# Tage}}",
"intervals.full.hours": "{number, plural, one {# Stunde} other {# Stunden}}",
"intervals.full.minutes": "{number, plural, one {# Minute} other {# Minuten}}",
@@ -221,6 +222,7 @@
"lists.new.title_placeholder": "Neuer Titel der Liste",
"lists.search": "Suche nach Leuten denen du folgst",
"lists.subheading": "Deine Listen",
+ "load_pending": "{count, plural, one {# new item} other {# new items}}",
"loading_indicator.label": "Wird geladen …",
"media_gallery.toggle_visible": "Sichtbarkeit umschalten",
"missing_indicator.label": "Nicht gefunden",
@@ -314,6 +316,7 @@
"search_results.accounts": "Personen",
"search_results.hashtags": "Hashtags",
"search_results.statuses": "Beiträge",
+ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.",
"search_results.total": "{count, number} {count, plural, one {Ergebnis} other {Ergebnisse}}",
"status.admin_account": "Öffne Moderationsoberfläche für @{name}",
"status.admin_status": "Öffne Beitrag in der Moderationsoberfläche",
diff --git a/app/javascript/mastodon/locales/defaultMessages.json b/app/javascript/mastodon/locales/defaultMessages.json
index 076aca2b16..8c8c89115c 100644
--- a/app/javascript/mastodon/locales/defaultMessages.json
+++ b/app/javascript/mastodon/locales/defaultMessages.json
@@ -158,6 +158,15 @@
],
"path": "app/javascript/mastodon/components/load_more.json"
},
+ {
+ "descriptors": [
+ {
+ "defaultMessage": "{count, plural, one {# new item} other {# new items}}",
+ "id": "load_pending"
+ }
+ ],
+ "path": "app/javascript/mastodon/components/load_pending.json"
+ },
{
"descriptors": [
{
@@ -735,7 +744,7 @@
{
"descriptors": [
{
- "defaultMessage": "Media Only",
+ "defaultMessage": "Media only",
"id": "community.column_settings.media_only"
}
],
@@ -1004,6 +1013,10 @@
"defaultMessage": "Toots",
"id": "search_results.statuses"
},
+ {
+ "defaultMessage": "Searching toots by their content is not enabled on this Mastodon server.",
+ "id": "search_results.statuses_fts_disabled"
+ },
{
"defaultMessage": "Hashtags",
"id": "search_results.hashtags"
@@ -1412,10 +1425,6 @@
},
{
"descriptors": [
- {
- "defaultMessage": "Basic",
- "id": "home.column_settings.basic"
- },
{
"defaultMessage": "Show boosts",
"id": "home.column_settings.show_reblogs"
@@ -1797,6 +1806,14 @@
"defaultMessage": "Push notifications",
"id": "notifications.column_settings.push"
},
+ {
+ "defaultMessage": "Basic",
+ "id": "home.column_settings.basic"
+ },
+ {
+ "defaultMessage": "Update in real-time",
+ "id": "home.column_settings.update_live"
+ },
{
"defaultMessage": "Quick filter bar",
"id": "notifications.column_settings.filter_bar.category"
diff --git a/app/javascript/mastodon/locales/el.json b/app/javascript/mastodon/locales/el.json
index e118e427b0..df85c025ff 100644
--- a/app/javascript/mastodon/locales/el.json
+++ b/app/javascript/mastodon/locales/el.json
@@ -156,6 +156,7 @@
"home.column_settings.basic": "Βασικά",
"home.column_settings.show_reblogs": "Εμφάνιση προωθήσεων",
"home.column_settings.show_replies": "Εμφάνιση απαντήσεων",
+ "home.column_settings.update_live": "Update in real-time",
"intervals.full.days": "{number, plural, one {# μέρα} other {# μέρες}}",
"intervals.full.hours": "{number, plural, one {# ώρα} other {# ώρες}}",
"intervals.full.minutes": "{number, plural, one {# λεπτό} other {# λεπτά}}",
@@ -221,6 +222,7 @@
"lists.new.title_placeholder": "Τίτλος νέας λίστα",
"lists.search": "Αναζήτησε μεταξύ των ανθρώπων που ακουλουθείς",
"lists.subheading": "Οι λίστες σου",
+ "load_pending": "{count, plural, one {# new item} other {# new items}}",
"loading_indicator.label": "Φορτώνει...",
"media_gallery.toggle_visible": "Εναλλαγή ορατότητας",
"missing_indicator.label": "Δε βρέθηκε",
@@ -314,6 +316,7 @@
"search_results.accounts": "Άνθρωποι",
"search_results.hashtags": "Ταμπέλες",
"search_results.statuses": "Τουτ",
+ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.",
"search_results.total": "{count, number} {count, plural, zero {αποτελέσματα} one {αποτέλεσμα} other {αποτελέσματα}}",
"status.admin_account": "Άνοιγμα λειτουργίας διαμεσολάβησης για τον/την @{name}",
"status.admin_status": "Άνοιγμα αυτής της δημοσίευσης στη λειτουργία διαμεσολάβησης",
diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json
index a75c417996..7bed985307 100644
--- a/app/javascript/mastodon/locales/en.json
+++ b/app/javascript/mastodon/locales/en.json
@@ -160,6 +160,7 @@
"home.column_settings.basic": "Basic",
"home.column_settings.show_reblogs": "Show boosts",
"home.column_settings.show_replies": "Show replies",
+ "home.column_settings.update_live": "Update in real-time",
"intervals.full.days": "{number, plural, one {# day} other {# days}}",
"intervals.full.hours": "{number, plural, one {# hour} other {# hours}}",
"intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}",
@@ -225,6 +226,7 @@
"lists.new.title_placeholder": "New list title",
"lists.search": "Search among people you follow",
"lists.subheading": "Your lists",
+ "load_pending": "{count, plural, one {# new item} other {# new items}}",
"loading_indicator.label": "Loading...",
"media_gallery.toggle_visible": "Toggle visibility",
"missing_indicator.label": "Not found",
@@ -319,6 +321,7 @@
"search_results.accounts": "People",
"search_results.hashtags": "Hashtags",
"search_results.statuses": "Toots",
+ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.",
"search_results.total": "{count, number} {count, plural, one {result} other {results}}",
"status.admin_account": "Open moderation interface for @{name}",
"status.admin_status": "Open this status in the moderation interface",
diff --git a/app/javascript/mastodon/locales/eo.json b/app/javascript/mastodon/locales/eo.json
index 897cb63530..ddc6942521 100644
--- a/app/javascript/mastodon/locales/eo.json
+++ b/app/javascript/mastodon/locales/eo.json
@@ -156,6 +156,7 @@
"home.column_settings.basic": "Bazaj agordoj",
"home.column_settings.show_reblogs": "Montri diskonigojn",
"home.column_settings.show_replies": "Montri respondojn",
+ "home.column_settings.update_live": "Update in real-time",
"intervals.full.days": "{number, plural, one {# tago} other {# tagoj}}",
"intervals.full.hours": "{number, plural, one {# horo} other {# horoj}}",
"intervals.full.minutes": "{number, plural, one {# minuto} other {# minutoj}}",
@@ -221,6 +222,7 @@
"lists.new.title_placeholder": "Titolo de la nova listo",
"lists.search": "Serĉi inter la homoj, kiujn vi sekvas",
"lists.subheading": "Viaj listoj",
+ "load_pending": "{count, plural, one {# new item} other {# new items}}",
"loading_indicator.label": "Ŝargado…",
"media_gallery.toggle_visible": "Baskuligi videblecon",
"missing_indicator.label": "Ne trovita",
@@ -314,6 +316,7 @@
"search_results.accounts": "Homoj",
"search_results.hashtags": "Kradvortoj",
"search_results.statuses": "Mesaĝoj",
+ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.",
"search_results.total": "{count, number} {count, plural, one {rezulto} other {rezultoj}}",
"status.admin_account": "Malfermi la kontrolan interfacon por @{name}",
"status.admin_status": "Malfermi ĉi tiun mesaĝon en la kontrola interfaco",
diff --git a/app/javascript/mastodon/locales/es.json b/app/javascript/mastodon/locales/es.json
index 8fe50ace58..dc42bc7efe 100644
--- a/app/javascript/mastodon/locales/es.json
+++ b/app/javascript/mastodon/locales/es.json
@@ -98,7 +98,7 @@
"confirmations.redraft.confirm": "Borrar y volver a borrador",
"confirmations.redraft.message": "Estás seguro de que quieres borrar este estado y volverlo a borrador? Perderás todas las respuestas, impulsos y favoritos asociados a él, y las respuestas a la publicación original quedarán huérfanos.",
"confirmations.reply.confirm": "Responder",
- "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?",
+ "confirmations.reply.message": "Responder sobrescribirá el mensaje que estás escribiendo. ¿Estás seguro de que deseas continuar?",
"confirmations.unfollow.confirm": "Dejar de seguir",
"confirmations.unfollow.message": "¿Estás seguro de que quieres dejar de seguir a {name}?",
"embed.instructions": "Añade este toot a tu sitio web con el siguiente código.",
@@ -149,33 +149,34 @@
"hashtag.column_header.tag_mode.none": "sin {additional}",
"hashtag.column_settings.select.no_options_message": "No se encontraron sugerencias",
"hashtag.column_settings.select.placeholder": "Introduzca hashtags…",
- "hashtag.column_settings.tag_mode.all": "All of these",
+ "hashtag.column_settings.tag_mode.all": "Cualquiera de estos",
"hashtag.column_settings.tag_mode.any": "Cualquiera de estos",
"hashtag.column_settings.tag_mode.none": "Ninguno de estos",
"hashtag.column_settings.tag_toggle": "Include additional tags in this column",
"home.column_settings.basic": "Básico",
"home.column_settings.show_reblogs": "Mostrar retoots",
"home.column_settings.show_replies": "Mostrar respuestas",
- "intervals.full.days": "{number, plural, one {# day} other {# days}}",
- "intervals.full.hours": "{number, plural, one {# hour} other {# hours}}",
- "intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}",
+ "home.column_settings.update_live": "Update in real-time",
+ "intervals.full.days": "{number, plural, one {# día} other {# días}}",
+ "intervals.full.hours": "{number, plural, one {# hora} other {# horas}}",
+ "intervals.full.minutes": "{number, plural, one {# minuto} other {# minutos}}",
"introduction.federation.action": "Siguiente",
"introduction.federation.federated.headline": "Federado",
- "introduction.federation.federated.text": "Public posts from other servers of the fediverse will appear in the federated timeline.",
+ "introduction.federation.federated.text": "Los mensajes públicos de otros servidores del fediverso aparecerán en la cronología federada.",
"introduction.federation.home.headline": "Inicio",
- "introduction.federation.home.text": "Posts from people you follow will appear in your home feed. You can follow anyone on any server!",
+ "introduction.federation.home.text": "Los posts de personas que sigues aparecerán en tu cronología. ¡Puedes seguir a cualquiera en cualquier servidor!",
"introduction.federation.local.headline": "Local",
- "introduction.federation.local.text": "Public posts from people on the same server as you will appear in the local timeline.",
+ "introduction.federation.local.text": "Los posts públicos de personas en el mismo servidor que aparecerán en la cronología local.",
"introduction.interactions.action": "¡Terminar tutorial!",
"introduction.interactions.favourite.headline": "Favorito",
- "introduction.interactions.favourite.text": "You can save a toot for later, and let the author know that you liked it, by favouriting it.",
- "introduction.interactions.reblog.headline": "Boost",
- "introduction.interactions.reblog.text": "You can share other people's toots with your followers by boosting them.",
+ "introduction.interactions.favourite.text": "Puedes guardar un toot para más tarde, y hacer saber al autor que te gustó, dándole a favorito.",
+ "introduction.interactions.reblog.headline": "Retootear",
+ "introduction.interactions.reblog.text": "Puedes compartir los toots de otras personas con tus seguidores retooteando los mismos.",
"introduction.interactions.reply.headline": "Responder",
- "introduction.interactions.reply.text": "You can reply to other people's and your own toots, which will chain them together in a conversation.",
+ "introduction.interactions.reply.text": "Puedes responder a tus propios toots y los de otras personas, que se encadenarán juntos en una conversación.",
"introduction.welcome.action": "¡Vamos!",
"introduction.welcome.headline": "Primeros pasos",
- "introduction.welcome.text": "Welcome to the fediverse! In a few moments, you'll be able to broadcast messages and talk to your friends across a wide variety of servers. But this server, {domain}, is special—it hosts your profile, so remember its name.",
+ "introduction.welcome.text": "¡Bienvenido al fediverso! En unos momentos, podrás transmitir mensajes y hablar con tus amigos a través de una amplia variedad de servidores. Pero este servidor, {domain}, es especial, alberga tu perfil, así que recuerda su nombre.",
"keyboard_shortcuts.back": "volver atrás",
"keyboard_shortcuts.blocked": "abrir una lista de usuarios bloqueados",
"keyboard_shortcuts.boost": "retootear",
@@ -184,7 +185,7 @@
"keyboard_shortcuts.description": "Descripción",
"keyboard_shortcuts.direct": "abrir la columna de mensajes directos",
"keyboard_shortcuts.down": "mover hacia abajo en la lista",
- "keyboard_shortcuts.enter": "to open status",
+ "keyboard_shortcuts.enter": "abrir estado",
"keyboard_shortcuts.favourite": "añadir a favoritos",
"keyboard_shortcuts.favourites": "abrir la lista de favoritos",
"keyboard_shortcuts.federated": "abrir el timeline federado",
@@ -204,7 +205,7 @@
"keyboard_shortcuts.search": "para poner el foco en la búsqueda",
"keyboard_shortcuts.start": "abrir la columna \"comenzar\"",
"keyboard_shortcuts.toggle_hidden": "mostrar/ocultar texto tras aviso de contenido (CW)",
- "keyboard_shortcuts.toggle_sensitivity": "to show/hide media",
+ "keyboard_shortcuts.toggle_sensitivity": "mostrar/ocultar medios",
"keyboard_shortcuts.toot": "para comenzar un nuevo toot",
"keyboard_shortcuts.unfocus": "para retirar el foco de la caja de redacción/búsqueda",
"keyboard_shortcuts.up": "para ir hacia arriba en la lista",
@@ -216,11 +217,12 @@
"lists.account.remove": "Quitar de lista",
"lists.delete": "Borrar lista",
"lists.edit": "Editar lista",
- "lists.edit.submit": "Change title",
+ "lists.edit.submit": "Cambiar título",
"lists.new.create": "Añadir lista",
"lists.new.title_placeholder": "Título de la nueva lista",
"lists.search": "Buscar entre la gente a la que sigues",
"lists.subheading": "Tus listas",
+ "load_pending": "{count, plural, one {# new item} other {# new items}}",
"loading_indicator.label": "Cargando…",
"media_gallery.toggle_visible": "Cambiar visibilidad",
"missing_indicator.label": "No encontrado",
@@ -237,7 +239,7 @@
"navigation_bar.favourites": "Favoritos",
"navigation_bar.filters": "Palabras silenciadas",
"navigation_bar.follow_requests": "Solicitudes para seguirte",
- "navigation_bar.follows_and_followers": "Follows and followers",
+ "navigation_bar.follows_and_followers": "Siguiendo y seguidores",
"navigation_bar.info": "Información adicional",
"navigation_bar.keyboard_shortcuts": "Atajos",
"navigation_bar.lists": "Listas",
@@ -246,41 +248,41 @@
"navigation_bar.personal": "Personal",
"navigation_bar.pins": "Toots fijados",
"navigation_bar.preferences": "Preferencias",
- "navigation_bar.profile_directory": "Profile directory",
+ "navigation_bar.profile_directory": "Directorio de perfiles",
"navigation_bar.public_timeline": "Historia federada",
"navigation_bar.security": "Seguridad",
"notification.favourite": "{name} marcó tu estado como favorito",
"notification.follow": "{name} te empezó a seguir",
"notification.mention": "{name} te ha mencionado",
- "notification.poll": "A poll you have voted in has ended",
+ "notification.poll": "Una encuesta en la que has votado ha terminado",
"notification.reblog": "{name} ha retooteado tu estado",
"notifications.clear": "Limpiar notificaciones",
"notifications.clear_confirmation": "¿Seguro que quieres limpiar permanentemente todas tus notificaciones?",
"notifications.column_settings.alert": "Notificaciones de escritorio",
"notifications.column_settings.favourite": "Favoritos:",
- "notifications.column_settings.filter_bar.advanced": "Display all categories",
- "notifications.column_settings.filter_bar.category": "Quick filter bar",
- "notifications.column_settings.filter_bar.show": "Show",
+ "notifications.column_settings.filter_bar.advanced": "Mostrar todas las categorías",
+ "notifications.column_settings.filter_bar.category": "Barra de filtrado rápido",
+ "notifications.column_settings.filter_bar.show": "Mostrar",
"notifications.column_settings.follow": "Nuevos seguidores:",
"notifications.column_settings.mention": "Menciones:",
- "notifications.column_settings.poll": "Poll results:",
+ "notifications.column_settings.poll": "Resultados de la votación:",
"notifications.column_settings.push": "Notificaciones push",
"notifications.column_settings.reblog": "Retoots:",
"notifications.column_settings.show": "Mostrar en columna",
"notifications.column_settings.sound": "Reproducir sonido",
- "notifications.filter.all": "All",
- "notifications.filter.boosts": "Boosts",
- "notifications.filter.favourites": "Favourites",
- "notifications.filter.follows": "Follows",
- "notifications.filter.mentions": "Mentions",
- "notifications.filter.polls": "Poll results",
+ "notifications.filter.all": "Todos",
+ "notifications.filter.boosts": "Retoots",
+ "notifications.filter.favourites": "Favoritos",
+ "notifications.filter.follows": "Seguidores",
+ "notifications.filter.mentions": "Menciones",
+ "notifications.filter.polls": "Resultados de la votación",
"notifications.group": "{count} notificaciones",
- "poll.closed": "Closed",
- "poll.refresh": "Refresh",
- "poll.total_votes": "{count, plural, one {# vote} other {# votes}}",
- "poll.vote": "Vote",
- "poll_button.add_poll": "Add a poll",
- "poll_button.remove_poll": "Remove poll",
+ "poll.closed": "Cerrada",
+ "poll.refresh": "Actualizar",
+ "poll.total_votes": "{count, plural, one {# voto} other {# votos}}",
+ "poll.vote": "Votar",
+ "poll_button.add_poll": "Añadir una encuesta",
+ "poll_button.remove_poll": "Eliminar encuesta",
"privacy.change": "Ajustar privacidad",
"privacy.direct.long": "Sólo mostrar a los usuarios mencionados",
"privacy.direct.short": "Directo",
@@ -289,7 +291,7 @@
"privacy.public.long": "Mostrar en la historia federada",
"privacy.public.short": "Público",
"privacy.unlisted.long": "No mostrar en la historia federada",
- "privacy.unlisted.short": "Sin federar",
+ "privacy.unlisted.short": "No listado",
"regeneration_indicator.label": "Cargando…",
"regeneration_indicator.sublabel": "¡Tu historia de inicio se está preparando!",
"relative_time.days": "{number}d",
@@ -308,19 +310,20 @@
"search_popout.search_format": "Formato de búsqueda avanzada",
"search_popout.tips.full_text": "Búsquedas de texto recuperan posts que has escrito, marcado como favoritos, retooteado o en los que has sido mencionado, así como usuarios, nombres y hashtags.",
"search_popout.tips.hashtag": "etiqueta",
- "search_popout.tips.status": "status",
+ "search_popout.tips.status": "estado",
"search_popout.tips.text": "El texto simple devuelve correspondencias de nombre, usuario y hashtag",
"search_popout.tips.user": "usuario",
"search_results.accounts": "Gente",
"search_results.hashtags": "Etiquetas",
"search_results.statuses": "Toots",
+ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.",
"search_results.total": "{count, number} {count, plural, one {resultado} other {resultados}}",
- "status.admin_account": "Open moderation interface for @{name}",
- "status.admin_status": "Open this status in the moderation interface",
- "status.block": "Block @{name}",
+ "status.admin_account": "Abrir interfaz de moderación para @{name}",
+ "status.admin_status": "Abrir este estado en la interfaz de moderación",
+ "status.block": "Bloquear a @{name}",
"status.cancel_reblog_private": "Des-impulsar",
"status.cannot_reblog": "Este toot no puede retootearse",
- "status.copy": "Copy link to status",
+ "status.copy": "Copiar enlace al estado",
"status.delete": "Borrar",
"status.detailed_status": "Vista de conversación detallada",
"status.direct": "Mensaje directo a @{name}",
@@ -336,7 +339,7 @@
"status.open": "Expandir estado",
"status.pin": "Fijar",
"status.pinned": "Toot fijado",
- "status.read_more": "Read more",
+ "status.read_more": "Leer más",
"status.reblog": "Retootear",
"status.reblog_private": "Implusar a la audiencia original",
"status.reblogged_by": "Retooteado por {name}",
@@ -351,27 +354,27 @@
"status.show_less_all": "Mostrar menos para todo",
"status.show_more": "Mostrar más",
"status.show_more_all": "Mostrar más para todo",
- "status.show_thread": "Show thread",
+ "status.show_thread": "Ver hilo",
"status.unmute_conversation": "Dejar de silenciar conversación",
"status.unpin": "Dejar de fijar",
- "suggestions.dismiss": "Dismiss suggestion",
- "suggestions.header": "You might be interested in…",
+ "suggestions.dismiss": "Descartar sugerencia",
+ "suggestions.header": "Es posible que te interese…",
"tabs_bar.federated_timeline": "Federado",
"tabs_bar.home": "Inicio",
"tabs_bar.local_timeline": "Local",
"tabs_bar.notifications": "Notificaciones",
"tabs_bar.search": "Buscar",
- "time_remaining.days": "{number, plural, one {# day} other {# days}} left",
- "time_remaining.hours": "{number, plural, one {# hour} other {# hours}} left",
- "time_remaining.minutes": "{number, plural, one {# minute} other {# minutes}} left",
- "time_remaining.moments": "Moments remaining",
- "time_remaining.seconds": "{number, plural, one {# second} other {# seconds}} left",
- "trends.count_by_accounts": "{count} {rawCount, plural, one {person} other {people}} talking",
+ "time_remaining.days": "{number, plural, one {# día restante} other {# días restantes}}",
+ "time_remaining.hours": "{number, plural, one {# hora restante} other {# horas restantes}}",
+ "time_remaining.minutes": "{number, plural, one {# minuto restante} other {# minutos restantes}}",
+ "time_remaining.moments": "Momentos restantes",
+ "time_remaining.seconds": "{number, plural, one {# segundo restante} other {# segundos restantes}}",
+ "trends.count_by_accounts": "{count} {rawCount, plural, one {persona} other {personas}} hablando",
"ui.beforeunload": "Tu borrador se perderá si sales de Mastodon.",
"upload_area.title": "Arrastra y suelta para subir",
"upload_button.label": "Subir multimedia (JPEG, PNG, GIF, WebM, MP4, MOV)",
- "upload_error.limit": "File upload limit exceeded.",
- "upload_error.poll": "File upload not allowed with polls.",
+ "upload_error.limit": "Límite de subida de archivos excedido.",
+ "upload_error.poll": "Subida de archivos no permitida con encuestas.",
"upload_form.description": "Describir para los usuarios con dificultad visual",
"upload_form.focus": "Recortar",
"upload_form.undo": "Borrar",
diff --git a/app/javascript/mastodon/locales/eu.json b/app/javascript/mastodon/locales/eu.json
index 3e91012b35..0c078840a9 100644
--- a/app/javascript/mastodon/locales/eu.json
+++ b/app/javascript/mastodon/locales/eu.json
@@ -156,6 +156,7 @@
"home.column_settings.basic": "Oinarrizkoa",
"home.column_settings.show_reblogs": "Erakutsi bultzadak",
"home.column_settings.show_replies": "Erakutsi erantzunak",
+ "home.column_settings.update_live": "Update in real-time",
"intervals.full.days": "{number, plural, one {egun #} other {# egun}}",
"intervals.full.hours": "{number, plural, one {ordu #} other {# ordu}}",
"intervals.full.minutes": "{number, plural, one {minutu #} other {# minutu}}",
@@ -221,6 +222,7 @@
"lists.new.title_placeholder": "Zerrenda berriaren izena",
"lists.search": "Bilatu jarraitzen dituzun pertsonen artean",
"lists.subheading": "Zure zerrendak",
+ "load_pending": "{count, plural, one {# new item} other {# new items}}",
"loading_indicator.label": "Kargatzen...",
"media_gallery.toggle_visible": "Txandakatu ikusgaitasuna",
"missing_indicator.label": "Ez aurkitua",
@@ -314,6 +316,7 @@
"search_results.accounts": "Jendea",
"search_results.hashtags": "Traolak",
"search_results.statuses": "Toot-ak",
+ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.",
"search_results.total": "{count, number} {count, plural, one {emaitza} other {emaitzak}}",
"status.admin_account": "Ireki @{name} erabiltzailearen moderazio interfazea",
"status.admin_status": "Ireki mezu hau moderazio interfazean",
diff --git a/app/javascript/mastodon/locales/fa.json b/app/javascript/mastodon/locales/fa.json
index 68d231ce95..41143bcc88 100644
--- a/app/javascript/mastodon/locales/fa.json
+++ b/app/javascript/mastodon/locales/fa.json
@@ -156,6 +156,7 @@
"home.column_settings.basic": "اصلی",
"home.column_settings.show_reblogs": "نمایش بازبوقها",
"home.column_settings.show_replies": "نمایش پاسخها",
+ "home.column_settings.update_live": "Update in real-time",
"intervals.full.days": "{number, plural, one {# روز} other {# روز}}",
"intervals.full.hours": "{number, plural, one {# ساعت} other {# ساعت}}",
"intervals.full.minutes": "{number, plural, one {# دقیقه} other {# دقیقه}}",
@@ -221,6 +222,7 @@
"lists.new.title_placeholder": "نام فهرست تازه",
"lists.search": "بین کسانی که پی میگیرید بگردید",
"lists.subheading": "فهرستهای شما",
+ "load_pending": "{count, plural, one {# new item} other {# new items}}",
"loading_indicator.label": "بارگیری...",
"media_gallery.toggle_visible": "تغییر پیدایی",
"missing_indicator.label": "پیدا نشد",
@@ -314,6 +316,7 @@
"search_results.accounts": "افراد",
"search_results.hashtags": "هشتگها",
"search_results.statuses": "بوقها",
+ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.",
"search_results.total": "{count, number} {count, plural, one {نتیجه} other {نتیجه}}",
"status.admin_account": "محیط مدیریت مربوط به @{name} را باز کن",
"status.admin_status": "این نوشته را در محیط مدیریت باز کن",
diff --git a/app/javascript/mastodon/locales/fi.json b/app/javascript/mastodon/locales/fi.json
index 342a15bfb0..05495d5d74 100644
--- a/app/javascript/mastodon/locales/fi.json
+++ b/app/javascript/mastodon/locales/fi.json
@@ -156,6 +156,7 @@
"home.column_settings.basic": "Perusasetukset",
"home.column_settings.show_reblogs": "Näytä buustaukset",
"home.column_settings.show_replies": "Näytä vastaukset",
+ "home.column_settings.update_live": "Update in real-time",
"intervals.full.days": "Päivä päiviä",
"intervals.full.hours": "Tunti tunteja",
"intervals.full.minutes": "Minuuti minuuteja",
@@ -221,6 +222,7 @@
"lists.new.title_placeholder": "Uuden listan nimi",
"lists.search": "Etsi seuraamistasi henkilöistä",
"lists.subheading": "Omat listat",
+ "load_pending": "{count, plural, one {# new item} other {# new items}}",
"loading_indicator.label": "Ladataan...",
"media_gallery.toggle_visible": "Säädä näkyvyyttä",
"missing_indicator.label": "Ei löytynyt",
@@ -314,6 +316,7 @@
"search_results.accounts": "Ihmiset",
"search_results.hashtags": "Hashtagit",
"search_results.statuses": "Tuuttaukset",
+ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.",
"search_results.total": "{count, number} {count, plural, one {result} other {results}}",
"status.admin_account": "Open moderation interface for @{name}",
"status.admin_status": "Open this status in the moderation interface",
diff --git a/app/javascript/mastodon/locales/fr.json b/app/javascript/mastodon/locales/fr.json
index 06bb70e028..f4db2e7a1a 100644
--- a/app/javascript/mastodon/locales/fr.json
+++ b/app/javascript/mastodon/locales/fr.json
@@ -156,6 +156,7 @@
"home.column_settings.basic": "Basique",
"home.column_settings.show_reblogs": "Afficher les partages",
"home.column_settings.show_replies": "Afficher les réponses",
+ "home.column_settings.update_live": "Update in real-time",
"intervals.full.days": "{number, plural, one {# jour} other {# jours}}",
"intervals.full.hours": "{number, plural, one {# heure} other {# heures}}",
"intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}",
@@ -221,6 +222,7 @@
"lists.new.title_placeholder": "Titre de la nouvelle liste",
"lists.search": "Rechercher parmi les gens que vous suivez",
"lists.subheading": "Vos listes",
+ "load_pending": "{count, plural, one {# new item} other {# new items}}",
"loading_indicator.label": "Chargement…",
"media_gallery.toggle_visible": "Modifier la visibilité",
"missing_indicator.label": "Non trouvé",
@@ -314,6 +316,7 @@
"search_results.accounts": "Comptes",
"search_results.hashtags": "Hashtags",
"search_results.statuses": "Pouets",
+ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.",
"search_results.total": "{count, number} {count, plural, one {résultat} other {résultats}}",
"status.admin_account": "Ouvrir l'interface de modération pour @{name}",
"status.admin_status": "Ouvrir ce statut dans l'interface de modération",
diff --git a/app/javascript/mastodon/locales/gl.json b/app/javascript/mastodon/locales/gl.json
index 9b19d6f113..2605f61f8a 100644
--- a/app/javascript/mastodon/locales/gl.json
+++ b/app/javascript/mastodon/locales/gl.json
@@ -156,6 +156,7 @@
"home.column_settings.basic": "Básico",
"home.column_settings.show_reblogs": "Mostrar repeticións",
"home.column_settings.show_replies": "Mostrar respostas",
+ "home.column_settings.update_live": "Update in real-time",
"intervals.full.days": "{number, plural,one {# día} other {# días}}",
"intervals.full.hours": "{number, plural, one {# hora} other {# horas}}",
"intervals.full.minutes": "{number, plural, one {# minuto} other {# minutos}}",
@@ -221,6 +222,7 @@
"lists.new.title_placeholder": "Novo título da lista",
"lists.search": "Procurar entre a xente que segues",
"lists.subheading": "As túas listas",
+ "load_pending": "{count, plural, one {# new item} other {# new items}}",
"loading_indicator.label": "Cargando...",
"media_gallery.toggle_visible": "Ocultar",
"missing_indicator.label": "Non atopado",
@@ -314,6 +316,7 @@
"search_results.accounts": "Xente",
"search_results.hashtags": "Etiquetas",
"search_results.statuses": "Toots",
+ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.",
"search_results.total": "{count, number} {count,plural,one {result} outros {results}}",
"status.admin_account": "Abrir interface de moderación para @{name}",
"status.admin_status": "Abrir este estado na interface de moderación",
@@ -369,7 +372,7 @@
"trends.count_by_accounts": "{count} {rawCount, plural, one {person} outras {people}} conversando",
"ui.beforeunload": "O borrador perderase se sae de Mastodon.",
"upload_area.title": "Arrastre e solte para subir",
- "upload_button.label": "Engadir medios (JPEG, PNG, GIF, WebM, MP4, MOV)",
+ "upload_button.label": "Engadir medios ({formats})",
"upload_error.limit": "Excedeu o límite de subida de ficheiros.",
"upload_error.poll": "Non se poden subir ficheiros nas sondaxes.",
"upload_form.description": "Describa para deficientes visuais",
diff --git a/app/javascript/mastodon/locales/he.json b/app/javascript/mastodon/locales/he.json
index 248be3c7b5..99bb87a5f1 100644
--- a/app/javascript/mastodon/locales/he.json
+++ b/app/javascript/mastodon/locales/he.json
@@ -64,7 +64,7 @@
"column_header.show_settings": "הצגת העדפות",
"column_header.unpin": "שחרור קיבוע",
"column_subheading.settings": "אפשרויות",
- "community.column_settings.media_only": "Media Only",
+ "community.column_settings.media_only": "Media only",
"compose_form.direct_message_warning": "This toot will only be visible to all the mentioned users.",
"compose_form.direct_message_warning_learn_more": "Learn more",
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
@@ -156,6 +156,7 @@
"home.column_settings.basic": "למתחילים",
"home.column_settings.show_reblogs": "הצגת הדהודים",
"home.column_settings.show_replies": "הצגת תגובות",
+ "home.column_settings.update_live": "Update in real-time",
"intervals.full.days": "{number, plural, one {# day} other {# days}}",
"intervals.full.hours": "{number, plural, one {# hour} other {# hours}}",
"intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}",
@@ -221,6 +222,7 @@
"lists.new.title_placeholder": "New list title",
"lists.search": "Search among people you follow",
"lists.subheading": "Your lists",
+ "load_pending": "{count, plural, one {# new item} other {# new items}}",
"loading_indicator.label": "טוען...",
"media_gallery.toggle_visible": "נראה\\בלתי נראה",
"missing_indicator.label": "לא נמצא",
@@ -314,6 +316,7 @@
"search_results.accounts": "People",
"search_results.hashtags": "Hashtags",
"search_results.statuses": "Toots",
+ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.",
"search_results.total": "{count, number} {count, plural, one {תוצאה} other {תוצאות}}",
"status.admin_account": "Open moderation interface for @{name}",
"status.admin_status": "Open this status in the moderation interface",
diff --git a/app/javascript/mastodon/locales/hi.json b/app/javascript/mastodon/locales/hi.json
index ac58514d42..d4d9e5f64b 100644
--- a/app/javascript/mastodon/locales/hi.json
+++ b/app/javascript/mastodon/locales/hi.json
@@ -156,6 +156,7 @@
"home.column_settings.basic": "Basic",
"home.column_settings.show_reblogs": "Show boosts",
"home.column_settings.show_replies": "Show replies",
+ "home.column_settings.update_live": "Update in real-time",
"intervals.full.days": "{number, plural, one {# day} other {# days}}",
"intervals.full.hours": "{number, plural, one {# hour} other {# hours}}",
"intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}",
@@ -221,6 +222,7 @@
"lists.new.title_placeholder": "New list title",
"lists.search": "Search among people you follow",
"lists.subheading": "Your lists",
+ "load_pending": "{count, plural, one {# new item} other {# new items}}",
"loading_indicator.label": "Loading...",
"media_gallery.toggle_visible": "Toggle visibility",
"missing_indicator.label": "Not found",
@@ -314,6 +316,7 @@
"search_results.accounts": "People",
"search_results.hashtags": "Hashtags",
"search_results.statuses": "Toots",
+ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.",
"search_results.total": "{count, number} {count, plural, one {result} other {results}}",
"status.admin_account": "Open moderation interface for @{name}",
"status.admin_status": "Open this status in the moderation interface",
diff --git a/app/javascript/mastodon/locales/hr.json b/app/javascript/mastodon/locales/hr.json
index 6f9b5343af..273b70d079 100644
--- a/app/javascript/mastodon/locales/hr.json
+++ b/app/javascript/mastodon/locales/hr.json
@@ -64,7 +64,7 @@
"column_header.show_settings": "Show settings",
"column_header.unpin": "Unpin",
"column_subheading.settings": "Postavke",
- "community.column_settings.media_only": "Media Only",
+ "community.column_settings.media_only": "Media only",
"compose_form.direct_message_warning": "This toot will only be visible to all the mentioned users.",
"compose_form.direct_message_warning_learn_more": "Learn more",
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
@@ -156,6 +156,7 @@
"home.column_settings.basic": "Osnovno",
"home.column_settings.show_reblogs": "Pokaži boostove",
"home.column_settings.show_replies": "Pokaži odgovore",
+ "home.column_settings.update_live": "Update in real-time",
"intervals.full.days": "{number, plural, one {# day} other {# days}}",
"intervals.full.hours": "{number, plural, one {# hour} other {# hours}}",
"intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}",
@@ -221,6 +222,7 @@
"lists.new.title_placeholder": "New list title",
"lists.search": "Search among people you follow",
"lists.subheading": "Your lists",
+ "load_pending": "{count, plural, one {# new item} other {# new items}}",
"loading_indicator.label": "Učitavam...",
"media_gallery.toggle_visible": "Preklopi vidljivost",
"missing_indicator.label": "Nije nađen",
@@ -314,6 +316,7 @@
"search_results.accounts": "People",
"search_results.hashtags": "Hashtags",
"search_results.statuses": "Toots",
+ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.",
"search_results.total": "{count, number} {count, plural, one {result} other {results}}",
"status.admin_account": "Open moderation interface for @{name}",
"status.admin_status": "Open this status in the moderation interface",
diff --git a/app/javascript/mastodon/locales/hu.json b/app/javascript/mastodon/locales/hu.json
index 1c3b63d7d2..38d30efe43 100644
--- a/app/javascript/mastodon/locales/hu.json
+++ b/app/javascript/mastodon/locales/hu.json
@@ -156,6 +156,7 @@
"home.column_settings.basic": "Alapértelmezések",
"home.column_settings.show_reblogs": "Megtolások mutatása",
"home.column_settings.show_replies": "Válaszok mutatása",
+ "home.column_settings.update_live": "Update in real-time",
"intervals.full.days": "{number, plural, one {# nap} other {# nap}}",
"intervals.full.hours": "{number, plural, one {# óra} other {# óra}}",
"intervals.full.minutes": "{number, plural, one {# perc} other {# perc}}",
@@ -221,6 +222,7 @@
"lists.new.title_placeholder": "Új lista címe",
"lists.search": "Keresés a követett személyek között",
"lists.subheading": "Listáid",
+ "load_pending": "{count, plural, one {# new item} other {# new items}}",
"loading_indicator.label": "Betöltés...",
"media_gallery.toggle_visible": "Láthatóság állítása",
"missing_indicator.label": "Nincs találat",
@@ -314,6 +316,7 @@
"search_results.accounts": "Emberek",
"search_results.hashtags": "Hashtagek",
"search_results.statuses": "Tülkök",
+ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.",
"search_results.total": "{count, number} {count, plural, one {találat} other {találat}}",
"status.admin_account": "Moderáció megnyitása @{name} felhasználóhoz",
"status.admin_status": "Tülk megnyitása moderációra",
diff --git a/app/javascript/mastodon/locales/hy.json b/app/javascript/mastodon/locales/hy.json
index b2dc16a484..801d34380a 100644
--- a/app/javascript/mastodon/locales/hy.json
+++ b/app/javascript/mastodon/locales/hy.json
@@ -64,7 +64,7 @@
"column_header.show_settings": "Ցուցադրել կարգավորումները",
"column_header.unpin": "Հանել",
"column_subheading.settings": "Կարգավորումներ",
- "community.column_settings.media_only": "Media Only",
+ "community.column_settings.media_only": "Media only",
"compose_form.direct_message_warning": "This toot will only be visible to all the mentioned users.",
"compose_form.direct_message_warning_learn_more": "Learn more",
"compose_form.hashtag_warning": "Այս թութը չի հաշվառվի որեւէ պիտակի տակ, քանզի այն ծածուկ է։ Միայն հրապարակային թթերը հնարավոր է որոնել պիտակներով։",
@@ -156,6 +156,7 @@
"home.column_settings.basic": "Հիմնական",
"home.column_settings.show_reblogs": "Ցուցադրել տարածածները",
"home.column_settings.show_replies": "Ցուցադրել պատասխանները",
+ "home.column_settings.update_live": "Update in real-time",
"intervals.full.days": "{number, plural, one {# day} other {# days}}",
"intervals.full.hours": "{number, plural, one {# hour} other {# hours}}",
"intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}",
@@ -221,6 +222,7 @@
"lists.new.title_placeholder": "Նոր ցանկի վերնագիր",
"lists.search": "Փնտրել քո հետեւած մարդկանց մեջ",
"lists.subheading": "Քո ցանկերը",
+ "load_pending": "{count, plural, one {# new item} other {# new items}}",
"loading_indicator.label": "Բեռնվում է…",
"media_gallery.toggle_visible": "Ցուցադրել/թաքցնել",
"missing_indicator.label": "Չգտնվեց",
@@ -314,6 +316,7 @@
"search_results.accounts": "People",
"search_results.hashtags": "Hashtags",
"search_results.statuses": "Toots",
+ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.",
"search_results.total": "{count, number} {count, plural, one {արդյունք} other {արդյունք}}",
"status.admin_account": "Open moderation interface for @{name}",
"status.admin_status": "Open this status in the moderation interface",
diff --git a/app/javascript/mastodon/locales/id.json b/app/javascript/mastodon/locales/id.json
index 07ce0eb985..daa87f9557 100644
--- a/app/javascript/mastodon/locales/id.json
+++ b/app/javascript/mastodon/locales/id.json
@@ -1,5 +1,5 @@
{
- "account.add_or_remove_from_list": "Add or Remove from lists",
+ "account.add_or_remove_from_list": "Tambah atau Hapus dari daftar",
"account.badges.bot": "Bot",
"account.block": "Blokir @{name}",
"account.block_domain": "Sembunyikan segalanya dari {domain}",
@@ -7,23 +7,23 @@
"account.direct": "Direct Message @{name}",
"account.domain_blocked": "Domain disembunyikan",
"account.edit_profile": "Ubah profil",
- "account.endorse": "Feature on profile",
+ "account.endorse": "Tampilkan di profil",
"account.follow": "Ikuti",
"account.followers": "Pengikut",
- "account.followers.empty": "No one follows this user yet.",
+ "account.followers.empty": "Tidak ada satupun yang mengkuti pengguna ini saat ini.",
"account.follows": "Mengikuti",
- "account.follows.empty": "This user doesn't follow anyone yet.",
+ "account.follows.empty": "Pengguna ini belum mengikuti siapapun.",
"account.follows_you": "Mengikuti anda",
"account.hide_reblogs": "Sembunyikan boosts dari @{name}",
- "account.link_verified_on": "Ownership of this link was checked on {date}",
- "account.locked_info": "This account privacy status is set to locked. The owner manually reviews who can follow them.",
+ "account.link_verified_on": "Kepemilikan tautan ini telah dicek pada {date}",
+ "account.locked_info": "Status privasi akun ini disetel untuk dikunci. Pemilik secara manual meninjau siapa yang dapat mengikuti mereka.",
"account.media": "Media",
"account.mention": "Balasan @{name}",
"account.moved_to": "{name} telah pindah ke:",
"account.mute": "Bisukan @{name}",
"account.mute_notifications": "Sembunyikan notifikasi dari @{name}",
"account.muted": "Dibisukan",
- "account.posts": "Toots",
+ "account.posts": "Toot",
"account.posts_with_replies": "Postingan dengan balasan",
"account.report": "Laporkan @{name}",
"account.requested": "Menunggu persetujuan. Klik untuk membatalkan permintaan",
@@ -31,23 +31,23 @@
"account.show_reblogs": "Tampilkan boost dari @{name}",
"account.unblock": "Hapus blokir @{name}",
"account.unblock_domain": "Tampilkan {domain}",
- "account.unendorse": "Don't feature on profile",
+ "account.unendorse": "Jangan tampilkan di profil",
"account.unfollow": "Berhenti mengikuti",
"account.unmute": "Berhenti membisukan @{name}",
"account.unmute_notifications": "Munculkan notifikasi dari @{name}",
- "alert.unexpected.message": "An unexpected error occurred.",
+ "alert.unexpected.message": "Terjadi kesalahan yang tidak terduga.",
"alert.unexpected.title": "Oops!",
"boost_modal.combo": "Anda dapat menekan {combo} untuk melewati ini",
"bundle_column_error.body": "Kesalahan terjadi saat memuat komponen ini.",
"bundle_column_error.retry": "Coba lagi",
- "bundle_column_error.title": "Network error",
+ "bundle_column_error.title": "Kesalahan jaringan",
"bundle_modal_error.close": "Tutup",
"bundle_modal_error.message": "Kesalahan terjadi saat memuat komponen ini.",
"bundle_modal_error.retry": "Coba lagi",
"column.blocks": "Pengguna diblokir",
"column.community": "Linimasa Lokal",
- "column.direct": "Direct messages",
- "column.domain_blocks": "Hidden domains",
+ "column.direct": "Pesan langsung",
+ "column.domain_blocks": "Topik tersembunyi",
"column.favourites": "Favorit",
"column.follow_requests": "Permintaan mengikuti",
"column.home": "Beranda",
@@ -64,41 +64,41 @@
"column_header.show_settings": "Tampilkan pengaturan",
"column_header.unpin": "Lepaskan",
"column_subheading.settings": "Pengaturan",
- "community.column_settings.media_only": "Media Only",
+ "community.column_settings.media_only": "Hanya media",
"compose_form.direct_message_warning": "This toot will only be visible to all the mentioned users.",
- "compose_form.direct_message_warning_learn_more": "Learn more",
+ "compose_form.direct_message_warning_learn_more": "Pelajari selengkapnya",
"compose_form.hashtag_warning": "Toot ini tidak akan ada dalam daftar tagar manapun karena telah di set sebagai tidak terdaftar. Hanya postingan publik yang bisa dicari dengan tagar.",
"compose_form.lock_disclaimer": "Akun anda tidak {locked}. Semua orang dapat mengikuti anda untuk melihat postingan khusus untuk pengikut anda.",
"compose_form.lock_disclaimer.lock": "terkunci",
"compose_form.placeholder": "Apa yang ada di pikiran anda?",
- "compose_form.poll.add_option": "Add a choice",
- "compose_form.poll.duration": "Poll duration",
- "compose_form.poll.option_placeholder": "Choice {number}",
- "compose_form.poll.remove_option": "Remove this choice",
+ "compose_form.poll.add_option": "Tambahkan pilihan",
+ "compose_form.poll.duration": "Durasi jajak pendapat",
+ "compose_form.poll.option_placeholder": "Pilihan {number}",
+ "compose_form.poll.remove_option": "Hapus opsi ini",
"compose_form.publish": "Toot",
"compose_form.publish_loud": "{publish}!",
- "compose_form.sensitive.hide": "Mark media as sensitive",
+ "compose_form.sensitive.hide": "Tandai sebagai media sensitif",
"compose_form.sensitive.marked": "Sumber ini telah ditandai sebagai sumber sensitif.",
"compose_form.sensitive.unmarked": "Sumber ini tidak ditandai sebagai sumber sensitif",
"compose_form.spoiler.marked": "Teks disembunyikan dibalik peringatan",
"compose_form.spoiler.unmarked": "Teks tidak tersembunyi",
"compose_form.spoiler_placeholder": "Peringatan konten",
"confirmation_modal.cancel": "Batal",
- "confirmations.block.block_and_report": "Block & Report",
+ "confirmations.block.block_and_report": "Blokir & Laporkan",
"confirmations.block.confirm": "Blokir",
"confirmations.block.message": "Apa anda yakin ingin memblokir {name}?",
"confirmations.delete.confirm": "Hapus",
"confirmations.delete.message": "Apa anda yakin untuk menghapus status ini?",
- "confirmations.delete_list.confirm": "Delete",
+ "confirmations.delete_list.confirm": "Hapus",
"confirmations.delete_list.message": "Apakah anda yakin untuk menghapus daftar ini secara permanen?",
"confirmations.domain_block.confirm": "Sembunyikan keseluruhan domain",
"confirmations.domain_block.message": "Apakah anda benar benar yakin untuk memblokir keseluruhan {domain}? Dalam kasus tertentu beberapa pemblokiran atau penyembunyian lebih baik.",
"confirmations.mute.confirm": "Bisukan",
"confirmations.mute.message": "Apa anda yakin ingin membisukan {name}?",
- "confirmations.redraft.confirm": "Delete & redraft",
+ "confirmations.redraft.confirm": "Hapus dan konsep ulang",
"confirmations.redraft.message": "Are you sure you want to delete this status and re-draft it? You will lose all replies, boosts and favourites to it.",
- "confirmations.reply.confirm": "Reply",
- "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?",
+ "confirmations.reply.confirm": "Balas",
+ "confirmations.reply.message": "Membalas sekarang akan menimpa pesan yang sedang Anda buat. Anda yakin ingin melanjutkan?",
"confirmations.unfollow.confirm": "Berhenti mengikuti",
"confirmations.unfollow.message": "Apakah anda ingin berhenti mengikuti {name}?",
"embed.instructions": "Sematkan status ini di website anda dengan menyalin kode di bawah ini.",
@@ -117,38 +117,38 @@
"emoji_button.search_results": "Hasil pencarian",
"emoji_button.symbols": "Simbol",
"emoji_button.travel": "Tempat Wisata",
- "empty_column.account_timeline": "No toots here!",
- "empty_column.account_unavailable": "Profile unavailable",
- "empty_column.blocks": "You haven't blocked any users yet.",
+ "empty_column.account_timeline": "Tidak ada toot di sini!",
+ "empty_column.account_unavailable": "Profil tidak tersedia",
+ "empty_column.blocks": "Anda belum memblokir siapapun.",
"empty_column.community": "Linimasa lokal masih kosong. Tulis sesuatu secara publik dan buat roda berputar!",
- "empty_column.direct": "You don't have any direct messages yet. When you send or receive one, it will show up here.",
- "empty_column.domain_blocks": "There are no hidden domains yet.",
- "empty_column.favourited_statuses": "You don't have any favourite toots yet. When you favourite one, it will show up here.",
- "empty_column.favourites": "No one has favourited this toot yet. When someone does, they will show up here.",
- "empty_column.follow_requests": "You don't have any follow requests yet. When you receive one, it will show up here.",
+ "empty_column.direct": "Anda belum memiliki pesan langsung. Ketika Anda mengirim atau menerimanya, maka akan muncul di sini.",
+ "empty_column.domain_blocks": "Tidak ada topik tersembunyi.",
+ "empty_column.favourited_statuses": "Anda belum memiliki toot favorit. Ketika Anda mengirim atau menerimanya, maka akan muncul di sini.",
+ "empty_column.favourites": "Tidak ada seorangpun yang memfavoritkan toot ini. Ketika seseorang melakukannya, maka akan muncul disini.",
+ "empty_column.follow_requests": "Anda belum memiliki permintaan mengikuti. Ketika Anda menerimanya, maka akan muncul disini.",
"empty_column.hashtag": "Tidak ada apapun dalam hashtag ini.",
"empty_column.home": "Linimasa anda kosong! Kunjungi {public} atau gunakan pencarian untuk memulai dan bertemu pengguna lain.",
"empty_column.home.public_timeline": "linimasa publik",
"empty_column.list": "Tidak ada postingan di list ini. Ketika anggota dari list ini memposting status baru, status tersebut akan tampil disini.",
- "empty_column.lists": "You don't have any lists yet. When you create one, it will show up here.",
- "empty_column.mutes": "You haven't muted any users yet.",
+ "empty_column.lists": "Anda belum memiliki daftar. Ketika Anda membuatnya, maka akan muncul disini.",
+ "empty_column.mutes": "Anda belum membisukan siapapun.",
"empty_column.notifications": "Anda tidak memiliki notifikasi apapun. Berinteraksi dengan orang lain untuk memulai percakapan.",
"empty_column.public": "Tidak ada apapun disini! Tulis sesuatu, atau ikuti pengguna lain dari server lain untuk mengisi ini",
"follow_request.authorize": "Izinkan",
"follow_request.reject": "Tolak",
- "getting_started.developers": "Developers",
- "getting_started.directory": "Profile directory",
- "getting_started.documentation": "Documentation",
+ "getting_started.developers": "Pengembang",
+ "getting_started.directory": "Direktori profil",
+ "getting_started.documentation": "Dokumentasi",
"getting_started.heading": "Mulai",
- "getting_started.invite": "Invite people",
+ "getting_started.invite": "Undang orang",
"getting_started.open_source_notice": "Mastodon adalah perangkat lunak yang bersifat terbuka. Anda dapat berkontribusi atau melaporkan permasalahan/bug di Github {github}.",
- "getting_started.security": "Security",
- "getting_started.terms": "Terms of service",
- "hashtag.column_header.tag_mode.all": "and {additional}",
- "hashtag.column_header.tag_mode.any": "or {additional}",
- "hashtag.column_header.tag_mode.none": "without {additional}",
- "hashtag.column_settings.select.no_options_message": "No suggestions found",
- "hashtag.column_settings.select.placeholder": "Enter hashtags…",
+ "getting_started.security": "Keamanan",
+ "getting_started.terms": "Ketentuan layanan",
+ "hashtag.column_header.tag_mode.all": "dan {additional}",
+ "hashtag.column_header.tag_mode.any": "atau {additional}",
+ "hashtag.column_header.tag_mode.none": "tanpa {additional}",
+ "hashtag.column_settings.select.no_options_message": "Tidak ada saran yang ditemukan",
+ "hashtag.column_settings.select.placeholder": "Masukkan tagar…",
"hashtag.column_settings.tag_mode.all": "All of these",
"hashtag.column_settings.tag_mode.any": "Any of these",
"hashtag.column_settings.tag_mode.none": "None of these",
@@ -156,6 +156,7 @@
"home.column_settings.basic": "Dasar",
"home.column_settings.show_reblogs": "Tampilkan boost",
"home.column_settings.show_replies": "Tampilkan balasan",
+ "home.column_settings.update_live": "Update in real-time",
"intervals.full.days": "{number, plural, one {# day} other {# days}}",
"intervals.full.hours": "{number, plural, one {# hour} other {# hours}}",
"intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}",
@@ -221,6 +222,7 @@
"lists.new.title_placeholder": "New list title",
"lists.search": "Search among people you follow",
"lists.subheading": "Your lists",
+ "load_pending": "{count, plural, one {# new item} other {# new items}}",
"loading_indicator.label": "Tunggu sebentar...",
"media_gallery.toggle_visible": "Tampil/Sembunyikan",
"missing_indicator.label": "Tidak ditemukan",
@@ -314,6 +316,7 @@
"search_results.accounts": "People",
"search_results.hashtags": "Hashtags",
"search_results.statuses": "Toots",
+ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.",
"search_results.total": "{count, number} {count, plural, one {hasil} other {hasil}}",
"status.admin_account": "Open moderation interface for @{name}",
"status.admin_status": "Open this status in the moderation interface",
diff --git a/app/javascript/mastodon/locales/io.json b/app/javascript/mastodon/locales/io.json
index c3f8707d13..864d499955 100644
--- a/app/javascript/mastodon/locales/io.json
+++ b/app/javascript/mastodon/locales/io.json
@@ -64,7 +64,7 @@
"column_header.show_settings": "Show settings",
"column_header.unpin": "Unpin",
"column_subheading.settings": "Settings",
- "community.column_settings.media_only": "Media Only",
+ "community.column_settings.media_only": "Media only",
"compose_form.direct_message_warning": "This toot will only be visible to all the mentioned users.",
"compose_form.direct_message_warning_learn_more": "Learn more",
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
@@ -156,6 +156,7 @@
"home.column_settings.basic": "Simpla",
"home.column_settings.show_reblogs": "Montrar repeti",
"home.column_settings.show_replies": "Montrar respondi",
+ "home.column_settings.update_live": "Update in real-time",
"intervals.full.days": "{number, plural, one {# day} other {# days}}",
"intervals.full.hours": "{number, plural, one {# hour} other {# hours}}",
"intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}",
@@ -221,6 +222,7 @@
"lists.new.title_placeholder": "New list title",
"lists.search": "Search among people you follow",
"lists.subheading": "Your lists",
+ "load_pending": "{count, plural, one {# new item} other {# new items}}",
"loading_indicator.label": "Kargante...",
"media_gallery.toggle_visible": "Chanjar videbleso",
"missing_indicator.label": "Ne trovita",
@@ -314,6 +316,7 @@
"search_results.accounts": "People",
"search_results.hashtags": "Hashtags",
"search_results.statuses": "Toots",
+ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.",
"search_results.total": "{count, number} {count, plural, one {rezulto} other {rezulti}}",
"status.admin_account": "Open moderation interface for @{name}",
"status.admin_status": "Open this status in the moderation interface",
diff --git a/app/javascript/mastodon/locales/it.json b/app/javascript/mastodon/locales/it.json
index f7e2e43538..7925cef8c1 100644
--- a/app/javascript/mastodon/locales/it.json
+++ b/app/javascript/mastodon/locales/it.json
@@ -4,7 +4,7 @@
"account.block": "Blocca @{name}",
"account.block_domain": "Nascondi tutto da {domain}",
"account.blocked": "Bloccato",
- "account.direct": "Invia messaggio diretto a @{name}",
+ "account.direct": "Invia messaggio privato a @{name}",
"account.domain_blocked": "Dominio nascosto",
"account.edit_profile": "Modifica profilo",
"account.endorse": "Metti in evidenza sul profilo",
@@ -121,7 +121,7 @@
"empty_column.account_unavailable": "Profilo non disponibile",
"empty_column.blocks": "Non hai ancora bloccato nessun utente.",
"empty_column.community": "La timeline locale è vuota. Condividi qualcosa pubblicamente per dare inizio alla festa!",
- "empty_column.direct": "Non hai ancora nessun messaggio diretto. Quando ne manderai o riceverai qualcuno, apparirà qui.",
+ "empty_column.direct": "Non hai ancora nessun messaggio privato. Quando ne manderai o riceverai qualcuno, apparirà qui.",
"empty_column.domain_blocks": "Non vi sono domini nascosti.",
"empty_column.favourited_statuses": "Non hai ancora segnato nessun toot come apprezzato. Quando lo farai, comparirà qui.",
"empty_column.favourites": "Nessuno ha ancora segnato questo toot come apprezzato. Quando qualcuno lo farà, apparirà qui.",
@@ -156,6 +156,7 @@
"home.column_settings.basic": "Semplice",
"home.column_settings.show_reblogs": "Mostra post condivisi",
"home.column_settings.show_replies": "Mostra risposte",
+ "home.column_settings.update_live": "Update in real-time",
"intervals.full.days": "{number, plural, one {# giorno} other {# giorni}}",
"intervals.full.hours": "{number, plural, one {# ora} other {# ore}}",
"intervals.full.minutes": "{number, plural, one {# minuto} other {# minuti}}",
@@ -221,6 +222,7 @@
"lists.new.title_placeholder": "Titolo della nuova lista",
"lists.search": "Cerca tra le persone che segui",
"lists.subheading": "Le tue liste",
+ "load_pending": "{count, plural, one {# new item} other {# new items}}",
"loading_indicator.label": "Caricamento...",
"media_gallery.toggle_visible": "Imposta visibilità",
"missing_indicator.label": "Non trovato",
@@ -283,7 +285,7 @@
"poll_button.remove_poll": "Rimuovi sondaggio",
"privacy.change": "Modifica privacy del post",
"privacy.direct.long": "Invia solo a utenti menzionati",
- "privacy.direct.short": "Diretto",
+ "privacy.direct.short": "Diretto in privato",
"privacy.private.long": "Invia solo ai seguaci",
"privacy.private.short": "Privato",
"privacy.public.long": "Invia alla timeline pubblica",
@@ -314,6 +316,7 @@
"search_results.accounts": "Gente",
"search_results.hashtags": "Hashtag",
"search_results.statuses": "Toot",
+ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.",
"search_results.total": "{count} {count, plural, one {risultato} other {risultati}}",
"status.admin_account": "Apri interfaccia di moderazione per @{name}",
"status.admin_status": "Apri questo status nell'interfaccia di moderazione",
@@ -323,7 +326,7 @@
"status.copy": "Copia link allo status",
"status.delete": "Elimina",
"status.detailed_status": "Vista conversazione dettagliata",
- "status.direct": "Messaggio diretto @{name}",
+ "status.direct": "Messaggio privato @{name}",
"status.embed": "Incorpora",
"status.favourite": "Apprezzato",
"status.filtered": "Filtrato",
diff --git a/app/javascript/mastodon/locales/ja.json b/app/javascript/mastodon/locales/ja.json
index 6dadf7c602..3c6d718350 100644
--- a/app/javascript/mastodon/locales/ja.json
+++ b/app/javascript/mastodon/locales/ja.json
@@ -160,6 +160,7 @@
"home.column_settings.basic": "基本設定",
"home.column_settings.show_reblogs": "ブースト表示",
"home.column_settings.show_replies": "返信表示",
+ "home.column_settings.update_live": "Update in real-time",
"intervals.full.days": "{number}日",
"intervals.full.hours": "{number}時間",
"intervals.full.minutes": "{number}分",
@@ -225,6 +226,7 @@
"lists.new.title_placeholder": "新規リスト名",
"lists.search": "フォローしている人の中から検索",
"lists.subheading": "あなたのリスト",
+ "load_pending": "{count, plural, one {# new item} other {# new items}}",
"loading_indicator.label": "読み込み中...",
"media_gallery.toggle_visible": "表示切り替え",
"missing_indicator.label": "見つかりません",
@@ -319,6 +321,7 @@
"search_results.accounts": "人々",
"search_results.hashtags": "ハッシュタグ",
"search_results.statuses": "トゥート",
+ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.",
"search_results.total": "{count, number}件の結果",
"status.admin_account": "@{name} のモデレーション画面を開く",
"status.admin_status": "このトゥートをモデレーション画面で開く",
diff --git a/app/javascript/mastodon/locales/ka.json b/app/javascript/mastodon/locales/ka.json
index ff7059aea2..a785434761 100644
--- a/app/javascript/mastodon/locales/ka.json
+++ b/app/javascript/mastodon/locales/ka.json
@@ -156,6 +156,7 @@
"home.column_settings.basic": "ძირითადი",
"home.column_settings.show_reblogs": "ბუსტების ჩვენება",
"home.column_settings.show_replies": "პასუხების ჩვენება",
+ "home.column_settings.update_live": "Update in real-time",
"intervals.full.days": "{number, plural, one {# day} other {# days}}",
"intervals.full.hours": "{number, plural, one {# hour} other {# hours}}",
"intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}",
@@ -221,6 +222,7 @@
"lists.new.title_placeholder": "ახალი სიის სათაური",
"lists.search": "ძებნა ადამიანებს შორის რომელთაც მიჰყვებით",
"lists.subheading": "თქვენი სიები",
+ "load_pending": "{count, plural, one {# new item} other {# new items}}",
"loading_indicator.label": "იტვირთება...",
"media_gallery.toggle_visible": "ხილვადობის ჩართვა",
"missing_indicator.label": "არაა ნაპოვნი",
@@ -314,6 +316,7 @@
"search_results.accounts": "ხალხი",
"search_results.hashtags": "ჰეშტეგები",
"search_results.statuses": "ტუტები",
+ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.",
"search_results.total": "{count, number} {count, plural, one {result} other {results}}",
"status.admin_account": "Open moderation interface for @{name}",
"status.admin_status": "Open this status in the moderation interface",
diff --git a/app/javascript/mastodon/locales/kk.json b/app/javascript/mastodon/locales/kk.json
index b9bd7cac31..9514d68a9d 100644
--- a/app/javascript/mastodon/locales/kk.json
+++ b/app/javascript/mastodon/locales/kk.json
@@ -156,6 +156,7 @@
"home.column_settings.basic": "Негізгі",
"home.column_settings.show_reblogs": "Бөлісулерді көрсету",
"home.column_settings.show_replies": "Жауаптарды көрсету",
+ "home.column_settings.update_live": "Update in real-time",
"intervals.full.days": "{number, plural, one {# күн} other {# күн}}",
"intervals.full.hours": "{number, plural, one {# сағат} other {# сағат}}",
"intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}",
@@ -221,6 +222,7 @@
"lists.new.title_placeholder": "Жаңа тізім аты",
"lists.search": "Сіз іздеген адамдар арасында іздеу",
"lists.subheading": "Тізімдеріңіз",
+ "load_pending": "{count, plural, one {# new item} other {# new items}}",
"loading_indicator.label": "Жүктеу...",
"media_gallery.toggle_visible": "Көрінуді қосу",
"missing_indicator.label": "Табылмады",
@@ -314,6 +316,7 @@
"search_results.accounts": "Адамдар",
"search_results.hashtags": "Хэштегтер",
"search_results.statuses": "Жазбалар",
+ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.",
"search_results.total": "{count, number} {count, plural, one {result} other {results}}",
"status.admin_account": "@{name} үшін модерация интерфейсін аш",
"status.admin_status": "Бұл жазбаны модерация интерфейсінде аш",
diff --git a/app/javascript/mastodon/locales/ko.json b/app/javascript/mastodon/locales/ko.json
index 656a36bce2..e716319387 100644
--- a/app/javascript/mastodon/locales/ko.json
+++ b/app/javascript/mastodon/locales/ko.json
@@ -156,6 +156,7 @@
"home.column_settings.basic": "기본 설정",
"home.column_settings.show_reblogs": "부스트 표시",
"home.column_settings.show_replies": "답글 표시",
+ "home.column_settings.update_live": "Update in real-time",
"intervals.full.days": "{number} 일",
"intervals.full.hours": "{number} 시간",
"intervals.full.minutes": "{number} 분",
@@ -221,6 +222,7 @@
"lists.new.title_placeholder": "새 리스트의 이름",
"lists.search": "팔로우 중인 사람들 중에서 찾기",
"lists.subheading": "당신의 리스트",
+ "load_pending": "{count, plural, one {# new item} other {# new items}}",
"loading_indicator.label": "불러오는 중...",
"media_gallery.toggle_visible": "표시 전환",
"missing_indicator.label": "찾을 수 없습니다",
@@ -314,6 +316,7 @@
"search_results.accounts": "사람",
"search_results.hashtags": "해시태그",
"search_results.statuses": "툿",
+ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.",
"search_results.total": "{count, number}건의 결과",
"status.admin_account": "@{name}에 대한 모더레이션 인터페이스 열기",
"status.admin_status": "모더레이션 인터페이스에서 이 게시물 열기",
@@ -326,7 +329,7 @@
"status.direct": "@{name}에게 다이렉트 메시지",
"status.embed": "공유하기",
"status.favourite": "즐겨찾기",
- "status.filtered": "필터링 됨",
+ "status.filtered": "필터로 걸러짐",
"status.load_more": "더 보기",
"status.media_hidden": "미디어 숨겨짐",
"status.mention": "답장",
diff --git a/app/javascript/mastodon/locales/lt.json b/app/javascript/mastodon/locales/lt.json
index ac58514d42..919129cc57 100644
--- a/app/javascript/mastodon/locales/lt.json
+++ b/app/javascript/mastodon/locales/lt.json
@@ -64,7 +64,7 @@
"column_header.show_settings": "Show settings",
"column_header.unpin": "Unpin",
"column_subheading.settings": "Settings",
- "community.column_settings.media_only": "Media Only",
+ "community.column_settings.media_only": "Media only",
"compose_form.direct_message_warning": "This toot will only be sent to all the mentioned users.",
"compose_form.direct_message_warning_learn_more": "Learn more",
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
@@ -156,6 +156,7 @@
"home.column_settings.basic": "Basic",
"home.column_settings.show_reblogs": "Show boosts",
"home.column_settings.show_replies": "Show replies",
+ "home.column_settings.update_live": "Update in real-time",
"intervals.full.days": "{number, plural, one {# day} other {# days}}",
"intervals.full.hours": "{number, plural, one {# hour} other {# hours}}",
"intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}",
@@ -221,6 +222,7 @@
"lists.new.title_placeholder": "New list title",
"lists.search": "Search among people you follow",
"lists.subheading": "Your lists",
+ "load_pending": "{count, plural, one {# new item} other {# new items}}",
"loading_indicator.label": "Loading...",
"media_gallery.toggle_visible": "Toggle visibility",
"missing_indicator.label": "Not found",
@@ -314,6 +316,7 @@
"search_results.accounts": "People",
"search_results.hashtags": "Hashtags",
"search_results.statuses": "Toots",
+ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.",
"search_results.total": "{count, number} {count, plural, one {result} other {results}}",
"status.admin_account": "Open moderation interface for @{name}",
"status.admin_status": "Open this status in the moderation interface",
@@ -369,7 +372,7 @@
"trends.count_by_accounts": "{count} {rawCount, plural, one {person} other {people}} talking",
"ui.beforeunload": "Your draft will be lost if you leave Mastodon.",
"upload_area.title": "Drag & drop to upload",
- "upload_button.label": "Add media (JPEG, PNG, GIF, WebM, MP4, MOV)",
+ "upload_button.label": "Add media ({formats})",
"upload_error.limit": "File upload limit exceeded.",
"upload_error.poll": "File upload not allowed with polls.",
"upload_form.description": "Describe for the visually impaired",
diff --git a/app/javascript/mastodon/locales/lv.json b/app/javascript/mastodon/locales/lv.json
index 647e23a691..5328f15c5a 100644
--- a/app/javascript/mastodon/locales/lv.json
+++ b/app/javascript/mastodon/locales/lv.json
@@ -156,6 +156,7 @@
"home.column_settings.basic": "Basic",
"home.column_settings.show_reblogs": "Show boosts",
"home.column_settings.show_replies": "Show replies",
+ "home.column_settings.update_live": "Update in real-time",
"intervals.full.days": "{number, plural, one {# day} other {# days}}",
"intervals.full.hours": "{number, plural, one {# hour} other {# hours}}",
"intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}",
@@ -221,6 +222,7 @@
"lists.new.title_placeholder": "New list title",
"lists.search": "Search among people you follow",
"lists.subheading": "Your lists",
+ "load_pending": "{count, plural, one {# new item} other {# new items}}",
"loading_indicator.label": "Loading...",
"media_gallery.toggle_visible": "Toggle visibility",
"missing_indicator.label": "Not found",
@@ -314,6 +316,7 @@
"search_results.accounts": "People",
"search_results.hashtags": "Hashtags",
"search_results.statuses": "Toots",
+ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.",
"search_results.total": "{count, number} {count, plural, one {result} other {results}}",
"status.admin_account": "Open moderation interface for @{name}",
"status.admin_status": "Open this status in the moderation interface",
@@ -369,7 +372,7 @@
"trends.count_by_accounts": "{count} {rawCount, plural, one {person} other {people}} talking",
"ui.beforeunload": "Your draft will be lost if you leave Mastodon.",
"upload_area.title": "Drag & drop to upload",
- "upload_button.label": "Add media (JPEG, PNG, GIF, WebM, MP4, MOV)",
+ "upload_button.label": "Add media ({formats})",
"upload_error.limit": "File upload limit exceeded.",
"upload_error.poll": "File upload not allowed with polls.",
"upload_form.description": "Describe for the visually impaired",
diff --git a/app/javascript/mastodon/locales/ms.json b/app/javascript/mastodon/locales/ms.json
index d7c5099636..ad72b32331 100644
--- a/app/javascript/mastodon/locales/ms.json
+++ b/app/javascript/mastodon/locales/ms.json
@@ -64,7 +64,7 @@
"column_header.show_settings": "Show settings",
"column_header.unpin": "Unpin",
"column_subheading.settings": "Settings",
- "community.column_settings.media_only": "Media Only",
+ "community.column_settings.media_only": "Media only",
"compose_form.direct_message_warning": "This toot will only be sent to all the mentioned users.",
"compose_form.direct_message_warning_learn_more": "Learn more",
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
@@ -156,6 +156,7 @@
"home.column_settings.basic": "Basic",
"home.column_settings.show_reblogs": "Show boosts",
"home.column_settings.show_replies": "Show replies",
+ "home.column_settings.update_live": "Update in real-time",
"intervals.full.days": "{number, plural, one {# day} other {# days}}",
"intervals.full.hours": "{number, plural, one {# hour} other {# hours}}",
"intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}",
@@ -221,6 +222,7 @@
"lists.new.title_placeholder": "New list title",
"lists.search": "Search among people you follow",
"lists.subheading": "Your lists",
+ "load_pending": "{count, plural, one {# new item} other {# new items}}",
"loading_indicator.label": "Loading...",
"media_gallery.toggle_visible": "Toggle visibility",
"missing_indicator.label": "Not found",
@@ -314,6 +316,7 @@
"search_results.accounts": "People",
"search_results.hashtags": "Hashtags",
"search_results.statuses": "Toots",
+ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.",
"search_results.total": "{count, number} {count, plural, one {result} other {results}}",
"status.admin_account": "Open moderation interface for @{name}",
"status.admin_status": "Open this status in the moderation interface",
@@ -369,7 +372,7 @@
"trends.count_by_accounts": "{count} {rawCount, plural, one {person} other {people}} talking",
"ui.beforeunload": "Your draft will be lost if you leave Mastodon.",
"upload_area.title": "Drag & drop to upload",
- "upload_button.label": "Add media (JPEG, PNG, GIF, WebM, MP4, MOV)",
+ "upload_button.label": "Add media ({formats})",
"upload_error.limit": "File upload limit exceeded.",
"upload_error.poll": "File upload not allowed with polls.",
"upload_form.description": "Describe for the visually impaired",
diff --git a/app/javascript/mastodon/locales/nl.json b/app/javascript/mastodon/locales/nl.json
index f6504f4bb8..d7f428193c 100644
--- a/app/javascript/mastodon/locales/nl.json
+++ b/app/javascript/mastodon/locales/nl.json
@@ -156,6 +156,7 @@
"home.column_settings.basic": "Algemeen",
"home.column_settings.show_reblogs": "Boosts tonen",
"home.column_settings.show_replies": "Reacties tonen",
+ "home.column_settings.update_live": "Update in real-time",
"intervals.full.days": "{number, plural, one {# dag} other {# dagen}}",
"intervals.full.hours": "{number, plural, one {# uur} other {# uur}}",
"intervals.full.minutes": "{number, plural, one {# minuut} other {# minuten}}",
@@ -221,6 +222,7 @@
"lists.new.title_placeholder": "Naam nieuwe lijst",
"lists.search": "Zoek naar mensen die je volgt",
"lists.subheading": "Jouw lijsten",
+ "load_pending": "{count, plural, one {# new item} other {# new items}}",
"loading_indicator.label": "Laden…",
"media_gallery.toggle_visible": "Media wel/niet tonen",
"missing_indicator.label": "Niet gevonden",
@@ -314,6 +316,7 @@
"search_results.accounts": "Gebruikers",
"search_results.hashtags": "Hashtags",
"search_results.statuses": "Toots",
+ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.",
"search_results.total": "{count, number} {count, plural, one {resultaat} other {resultaten}}",
"status.admin_account": "Moderatie-omgeving van @{name} openen",
"status.admin_status": "Deze toot in de moderatie-omgeving openen",
diff --git a/app/javascript/mastodon/locales/no.json b/app/javascript/mastodon/locales/no.json
index 2ba8236e27..ea722a01e7 100644
--- a/app/javascript/mastodon/locales/no.json
+++ b/app/javascript/mastodon/locales/no.json
@@ -64,7 +64,7 @@
"column_header.show_settings": "Vis innstillinger",
"column_header.unpin": "Løsne",
"column_subheading.settings": "Innstillinger",
- "community.column_settings.media_only": "Media Only",
+ "community.column_settings.media_only": "Media only",
"compose_form.direct_message_warning": "This toot will only be visible to all the mentioned users.",
"compose_form.direct_message_warning_learn_more": "Learn more",
"compose_form.hashtag_warning": "Denne tuten blir ikke listet under noen emneknagger da den er ulistet. Kun offentlige tuter kan søktes etter med emneknagg.",
@@ -156,6 +156,7 @@
"home.column_settings.basic": "Enkel",
"home.column_settings.show_reblogs": "Vis fremhevinger",
"home.column_settings.show_replies": "Vis svar",
+ "home.column_settings.update_live": "Update in real-time",
"intervals.full.days": "{number, plural, one {# day} other {# days}}",
"intervals.full.hours": "{number, plural, one {# hour} other {# hours}}",
"intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}",
@@ -221,6 +222,7 @@
"lists.new.title_placeholder": "Ny listetittel",
"lists.search": "Søk blant personer du følger",
"lists.subheading": "Dine lister",
+ "load_pending": "{count, plural, one {# new item} other {# new items}}",
"loading_indicator.label": "Laster...",
"media_gallery.toggle_visible": "Veksle synlighet",
"missing_indicator.label": "Ikke funnet",
@@ -314,6 +316,7 @@
"search_results.accounts": "People",
"search_results.hashtags": "Hashtags",
"search_results.statuses": "Toots",
+ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.",
"search_results.total": "{count, number} {count, plural, one {resultat} other {resultater}}",
"status.admin_account": "Open moderation interface for @{name}",
"status.admin_status": "Open this status in the moderation interface",
diff --git a/app/javascript/mastodon/locales/oc.json b/app/javascript/mastodon/locales/oc.json
index 3178f200de..34804da208 100644
--- a/app/javascript/mastodon/locales/oc.json
+++ b/app/javascript/mastodon/locales/oc.json
@@ -77,7 +77,7 @@
"compose_form.poll.remove_option": "Levar aquesta opcion",
"compose_form.publish": "Tut",
"compose_form.publish_loud": "{publish} !",
- "compose_form.sensitive.hide": "Mark media as sensitive",
+ "compose_form.sensitive.hide": "Marcar coma sensible",
"compose_form.sensitive.marked": "Lo mèdia es marcat coma sensible",
"compose_form.sensitive.unmarked": "Lo mèdia es pas marcat coma sensible",
"compose_form.spoiler.marked": "Lo tèxte es rescondut jos l’avertiment",
@@ -156,6 +156,7 @@
"home.column_settings.basic": "Basic",
"home.column_settings.show_reblogs": "Mostrar los partatges",
"home.column_settings.show_replies": "Mostrar las responsas",
+ "home.column_settings.update_live": "Update in real-time",
"intervals.full.days": "{number, plural, one {# jorn} other {# jorns}}",
"intervals.full.hours": "{number, plural, one {# ora} other {# oras}}",
"intervals.full.minutes": "{number, plural, one {# minuta} other {# minutas}}",
@@ -204,14 +205,14 @@
"keyboard_shortcuts.search": "anar a la recèrca",
"keyboard_shortcuts.start": "dobrir la colomna « Per començar »",
"keyboard_shortcuts.toggle_hidden": "mostrar/amagar lo tèxte dels avertiments",
- "keyboard_shortcuts.toggle_sensitivity": "to show/hide media",
+ "keyboard_shortcuts.toggle_sensitivity": "per mostrar/rescondre los mèdias",
"keyboard_shortcuts.toot": "començar un estatut tot novèl",
"keyboard_shortcuts.unfocus": "quitar lo camp tèxte/de recèrca",
"keyboard_shortcuts.up": "far montar dins la lista",
"lightbox.close": "Tampar",
"lightbox.next": "Seguent",
"lightbox.previous": "Precedent",
- "lightbox.view_context": "View context",
+ "lightbox.view_context": "Veire lo contèxt",
"lists.account.add": "Ajustar a la lista",
"lists.account.remove": "Levar de la lista",
"lists.delete": "Suprimir la lista",
@@ -221,6 +222,7 @@
"lists.new.title_placeholder": "Títol de la nòva lista",
"lists.search": "Cercar demest lo monde que seguètz",
"lists.subheading": "Vòstras listas",
+ "load_pending": "{count, plural, one {# new item} other {# new items}}",
"loading_indicator.label": "Cargament…",
"media_gallery.toggle_visible": "Modificar la visibilitat",
"missing_indicator.label": "Pas trobat",
@@ -237,7 +239,7 @@
"navigation_bar.favourites": "Favorits",
"navigation_bar.filters": "Mots ignorats",
"navigation_bar.follow_requests": "Demandas d’abonament",
- "navigation_bar.follows_and_followers": "Follows and followers",
+ "navigation_bar.follows_and_followers": "Abonament e seguidors",
"navigation_bar.info": "Tocant aqueste servidor",
"navigation_bar.keyboard_shortcuts": "Acorchis clavièr",
"navigation_bar.lists": "Listas",
@@ -246,7 +248,7 @@
"navigation_bar.personal": "Personal",
"navigation_bar.pins": "Tuts penjats",
"navigation_bar.preferences": "Preferéncias",
- "navigation_bar.profile_directory": "Profile directory",
+ "navigation_bar.profile_directory": "Annuari de perfils",
"navigation_bar.public_timeline": "Flux public global",
"navigation_bar.security": "Seguretat",
"notification.favourite": "{name} a ajustat a sos favorits",
@@ -314,6 +316,7 @@
"search_results.accounts": "Gents",
"search_results.hashtags": "Etiquetas",
"search_results.statuses": "Tuts",
+ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.",
"search_results.total": "{count, number} {count, plural, one {resultat} other {resultats}}",
"status.admin_account": "Dobrir l’interfàcia de moderacion per @{name}",
"status.admin_status": "Dobrir aqueste estatut dins l’interfàcia de moderacion",
diff --git a/app/javascript/mastodon/locales/pl.json b/app/javascript/mastodon/locales/pl.json
index d101c21aac..d96ceb0645 100644
--- a/app/javascript/mastodon/locales/pl.json
+++ b/app/javascript/mastodon/locales/pl.json
@@ -160,6 +160,7 @@
"home.column_settings.basic": "Podstawowe",
"home.column_settings.show_reblogs": "Pokazuj podbicia",
"home.column_settings.show_replies": "Pokazuj odpowiedzi",
+ "home.column_settings.update_live": "Update in real-time",
"intervals.full.days": "{number, plural, one {# dzień} few {# dni} many {# dni} other {# dni}}",
"intervals.full.hours": "{number, plural, one {# godzina} few {# godziny} many {# godzin} other {# godzin}}",
"intervals.full.minutes": "{number, plural, one {# minuta} few {# minuty} many {# minut} other {# minut}}",
@@ -225,6 +226,7 @@
"lists.new.title_placeholder": "Wprowadź tytuł listy",
"lists.search": "Szukaj wśród osób które śledzisz",
"lists.subheading": "Twoje listy",
+ "load_pending": "{count, plural, one {# new item} other {# new items}}",
"loading_indicator.label": "Ładowanie…",
"media_gallery.toggle_visible": "Przełącz widoczność",
"missing_indicator.label": "Nie znaleziono",
@@ -319,6 +321,7 @@
"search_results.accounts": "Ludzie",
"search_results.hashtags": "Hashtagi",
"search_results.statuses": "Wpisy",
+ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.",
"search_results.total": "{count, number} {count, plural, one {wynik} few {wyniki} many {wyników} more {wyników}}",
"status.admin_account": "Otwórz interfejs moderacyjny dla @{name}",
"status.admin_status": "Otwórz ten wpis w interfejsie moderacyjnym",
diff --git a/app/javascript/mastodon/locales/pt-BR.json b/app/javascript/mastodon/locales/pt-BR.json
index dca087af95..1fb700874c 100644
--- a/app/javascript/mastodon/locales/pt-BR.json
+++ b/app/javascript/mastodon/locales/pt-BR.json
@@ -36,7 +36,7 @@
"account.unmute": "Não silenciar @{name}",
"account.unmute_notifications": "Retirar silêncio das notificações vindas de @{name}",
"alert.unexpected.message": "Um erro inesperado ocorreu.",
- "alert.unexpected.title": "Oops!",
+ "alert.unexpected.title": "Eita!",
"boost_modal.combo": "Você pode pressionar {combo} para ignorar este diálogo na próxima vez",
"bundle_column_error.body": "Algo de errado aconteceu enquanto este componente era carregado.",
"bundle_column_error.retry": "Tente novamente",
@@ -77,7 +77,7 @@
"compose_form.poll.remove_option": "Remover essa opção",
"compose_form.publish": "Publicar",
"compose_form.publish_loud": "{publish}!",
- "compose_form.sensitive.hide": "Mark media as sensitive",
+ "compose_form.sensitive.hide": "Marcar mídia como sensível",
"compose_form.sensitive.marked": "Mídia está marcada como sensível",
"compose_form.sensitive.unmarked": "Mídia não está marcada como sensível",
"compose_form.spoiler.marked": "O texto está escondido por um aviso de conteúdo",
@@ -89,7 +89,7 @@
"confirmations.block.message": "Você tem certeza de que quer bloquear {name}?",
"confirmations.delete.confirm": "Excluir",
"confirmations.delete.message": "Você tem certeza de que quer excluir esta postagem?",
- "confirmations.delete_list.confirm": "Delete",
+ "confirmations.delete_list.confirm": "Excluir",
"confirmations.delete_list.message": "Você tem certeza que quer deletar permanentemente a lista?",
"confirmations.domain_block.confirm": "Esconder o domínio inteiro",
"confirmations.domain_block.message": "Você quer mesmo bloquear {domain} inteiro? Na maioria dos casos, silenciar ou bloquear alguns usuários é o suficiente e o recomendado. Você não vai ver conteúdo desse domínio em nenhuma das timelines públicas ou nas suas notificações. Seus seguidores desse domínio serão removidos.",
@@ -156,13 +156,14 @@
"home.column_settings.basic": "Básico",
"home.column_settings.show_reblogs": "Mostrar compartilhamentos",
"home.column_settings.show_replies": "Mostrar as respostas",
+ "home.column_settings.update_live": "Update in real-time",
"intervals.full.days": "{number, plural, one {# dia} other {# dias}}",
"intervals.full.hours": "{number, plural, one {# hora} other {# horas}}",
- "intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}",
+ "intervals.full.minutes": "{number, plural, one {# minuto} other {# minutos}}",
"introduction.federation.action": "Próximo",
- "introduction.federation.federated.headline": "Federated",
+ "introduction.federation.federated.headline": "Global",
"introduction.federation.federated.text": "Posts públicos de outros servidores do fediverso vão aparecer na timeline global.",
- "introduction.federation.home.headline": "Home",
+ "introduction.federation.home.headline": "Início",
"introduction.federation.home.text": "Posts de pessoas que você segue vão aparecer na sua página inicial. Você pode seguir pessoas de qualquer servidor!",
"introduction.federation.local.headline": "Local",
"introduction.federation.local.text": "Posts públicos de pessoas no mesmo servidor que você vão aparecer na timeline local.",
@@ -204,23 +205,24 @@
"keyboard_shortcuts.search": "para focar a pesquisa",
"keyboard_shortcuts.start": "para abrir a coluna \"primeiros passos\"",
"keyboard_shortcuts.toggle_hidden": "mostrar/esconder o texto com aviso de conteúdo",
- "keyboard_shortcuts.toggle_sensitivity": "to show/hide media",
+ "keyboard_shortcuts.toggle_sensitivity": "mostrar/esconder mídia",
"keyboard_shortcuts.toot": "para compor um novo toot",
"keyboard_shortcuts.unfocus": "para remover o foco da área de composição/pesquisa",
"keyboard_shortcuts.up": "para mover para cima na lista",
"lightbox.close": "Fechar",
"lightbox.next": "Próximo",
"lightbox.previous": "Anterior",
- "lightbox.view_context": "View context",
+ "lightbox.view_context": "Ver contexto",
"lists.account.add": "Adicionar a listas",
"lists.account.remove": "Remover da lista",
- "lists.delete": "Delete list",
+ "lists.delete": "Excluir lista",
"lists.edit": "Editar lista",
"lists.edit.submit": "Mudar o título",
"lists.new.create": "Adicionar lista",
"lists.new.title_placeholder": "Novo título da lista",
"lists.search": "Procurar entre as pessoas que você segue",
"lists.subheading": "Suas listas",
+ "load_pending": "{count, plural, one {# new item} other {# new items}}",
"loading_indicator.label": "Carregando...",
"media_gallery.toggle_visible": "Esconder/Mostrar",
"missing_indicator.label": "Não encontrado",
@@ -237,7 +239,7 @@
"navigation_bar.favourites": "Favoritos",
"navigation_bar.filters": "Palavras silenciadas",
"navigation_bar.follow_requests": "Seguidores pendentes",
- "navigation_bar.follows_and_followers": "Follows and followers",
+ "navigation_bar.follows_and_followers": "Seguindo e seguidores",
"navigation_bar.info": "Mais informações",
"navigation_bar.keyboard_shortcuts": "Atalhos de teclado",
"navigation_bar.lists": "Listas",
@@ -246,7 +248,7 @@
"navigation_bar.personal": "Pessoal",
"navigation_bar.pins": "Postagens fixadas",
"navigation_bar.preferences": "Preferências",
- "navigation_bar.profile_directory": "Profile directory",
+ "navigation_bar.profile_directory": "Diretório de perfis",
"navigation_bar.public_timeline": "Global",
"navigation_bar.security": "Segurança",
"notification.favourite": "{name} adicionou a sua postagem aos favoritos",
@@ -314,6 +316,7 @@
"search_results.accounts": "Pessoas",
"search_results.hashtags": "Hashtags",
"search_results.statuses": "Toots",
+ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.",
"search_results.total": "{count, number} {count, plural, one {resultado} other {resultados}}",
"status.admin_account": "Abrir interface de moderação para @{name}",
"status.admin_status": "Abrir esse status na interface de moderação",
diff --git a/app/javascript/mastodon/locales/pt.json b/app/javascript/mastodon/locales/pt.json
index 157090c55f..c6ea3f8479 100644
--- a/app/javascript/mastodon/locales/pt.json
+++ b/app/javascript/mastodon/locales/pt.json
@@ -17,7 +17,7 @@
"account.hide_reblogs": "Esconder partilhas de @{name}",
"account.link_verified_on": "A posse deste link foi verificada em {date}",
"account.locked_info": "O estatuto de privacidade desta conta é fechado. O dono revê manualmente que a pode seguir.",
- "account.media": "Media",
+ "account.media": "Média",
"account.mention": "Mencionar @{name}",
"account.moved_to": "{name} mudou a sua conta para:",
"account.mute": "Silenciar @{name}",
@@ -49,50 +49,50 @@
"column.direct": "Mensagens directas",
"column.domain_blocks": "Domínios escondidos",
"column.favourites": "Favoritos",
- "column.follow_requests": "Seguidores Pendentes",
+ "column.follow_requests": "Seguidores pendentes",
"column.home": "Início",
"column.lists": "Listas",
"column.mutes": "Utilizadores silenciados",
"column.notifications": "Notificações",
"column.pins": "Publicações fixas",
- "column.public": "Cronologia federativa",
+ "column.public": "Cronologia federada",
"column_back_button.label": "Voltar",
- "column_header.hide_settings": "Esconder preferências",
+ "column_header.hide_settings": "Esconder configurações",
"column_header.moveLeft_settings": "Mover coluna para a esquerda",
"column_header.moveRight_settings": "Mover coluna para a direita",
"column_header.pin": "Fixar",
- "column_header.show_settings": "Mostrar preferências",
+ "column_header.show_settings": "Mostrar configurações",
"column_header.unpin": "Desafixar",
- "column_subheading.settings": "Preferências",
- "community.column_settings.media_only": "Somente media",
- "compose_form.direct_message_warning": "Esta publicação só será enviada para os utilizadores mencionados.",
- "compose_form.direct_message_warning_learn_more": "Aprender mais",
- "compose_form.hashtag_warning": "Esta pulbicacção não será listada em nenhuma hashtag por ser não listada. Somente publicações públicas podem ser pesquisadas por hashtag.",
+ "column_subheading.settings": "Configurações",
+ "community.column_settings.media_only": "Somente multimédia",
+ "compose_form.direct_message_warning": "Esta publicação será enviada apenas para os utilizadores mencionados.",
+ "compose_form.direct_message_warning_learn_more": "Conhecer mais",
+ "compose_form.hashtag_warning": "Este toot não será listado em nenhuma hashtag por ser não listado. Apenas toots públics podem ser pesquisados por hashtag.",
"compose_form.lock_disclaimer": "A tua conta não está {locked}. Qualquer pessoa pode seguir-te e ver as publicações direcionadas apenas a seguidores.",
- "compose_form.lock_disclaimer.lock": "fechada",
+ "compose_form.lock_disclaimer.lock": "bloqueado",
"compose_form.placeholder": "Em que estás a pensar?",
- "compose_form.poll.add_option": "Add a choice",
- "compose_form.poll.duration": "Poll duration",
- "compose_form.poll.option_placeholder": "Choice {number}",
- "compose_form.poll.remove_option": "Remove this choice",
- "compose_form.publish": "Publicar",
- "compose_form.publish_loud": "{publicar}!",
- "compose_form.sensitive.hide": "Mark media as sensitive",
- "compose_form.sensitive.marked": "Media marcado como sensível",
- "compose_form.sensitive.unmarked": "Media não está marcado como sensível",
+ "compose_form.poll.add_option": "Adicionar uma opção",
+ "compose_form.poll.duration": "Duração da votação",
+ "compose_form.poll.option_placeholder": "Opção {number}",
+ "compose_form.poll.remove_option": "Eliminar esta opção",
+ "compose_form.publish": "Toot",
+ "compose_form.publish_loud": "{publish}!",
+ "compose_form.sensitive.hide": "Marcar multimédia como sensível",
+ "compose_form.sensitive.marked": "Média marcada como sensível",
+ "compose_form.sensitive.unmarked": "Média não está marcada como sensível",
"compose_form.spoiler.marked": "Texto escondido atrás de aviso",
"compose_form.spoiler.unmarked": "O texto não está escondido",
"compose_form.spoiler_placeholder": "Escreve o teu aviso aqui",
"confirmation_modal.cancel": "Cancelar",
- "confirmations.block.block_and_report": "Block & Report",
+ "confirmations.block.block_and_report": "Bloquear e denunciar",
"confirmations.block.confirm": "Bloquear",
"confirmations.block.message": "De certeza que queres bloquear {name}?",
"confirmations.delete.confirm": "Eliminar",
"confirmations.delete.message": "De certeza que queres eliminar esta publicação?",
- "confirmations.delete_list.confirm": "Apagar",
- "confirmations.delete_list.message": "Tens a certeza de que desejas apagar permanentemente esta lista?",
+ "confirmations.delete_list.confirm": "Eliminar",
+ "confirmations.delete_list.message": "Tens a certeza de que desejas eliminar permanentemente esta lista?",
"confirmations.domain_block.confirm": "Esconder tudo deste domínio",
- "confirmations.domain_block.message": "De certeza que queres bloquear completamente o domínio {domain}? Na maioria dos casos, silenciar ou bloquear alguns utilizadores é o suficiente e o recomendado. Não irás ver conteúdo daquele domínio em cronologia alguma, nem nas tuas notificações. Os teus seguidores daquele domínio serão removidos.",
+ "confirmations.domain_block.message": "De certeza que queres bloquear completamente o domínio {domain}? Na maioria dos casos, silenciar ou bloquear alguns utilizadores é suficiente e é o recomendado. Não irás ver conteúdo daquele domínio em cronologia alguma nem nas tuas notificações. Os teus seguidores daquele domínio serão removidos.",
"confirmations.mute.confirm": "Silenciar",
"confirmations.mute.message": "De certeza que queres silenciar {name}?",
"confirmations.redraft.confirm": "Apagar & redigir",
@@ -109,23 +109,23 @@
"emoji_button.food": "Comida & Bebida",
"emoji_button.label": "Inserir Emoji",
"emoji_button.nature": "Natureza",
- "emoji_button.not_found": "Não tem emojos!! (╯°□°)╯︵ ┻━┻",
+ "emoji_button.not_found": "Não tem emojis!! (╯°□°)╯︵ ┻━┻",
"emoji_button.objects": "Objectos",
"emoji_button.people": "Pessoas",
- "emoji_button.recent": "Regularmente utilizados",
- "emoji_button.search": "Procurar...",
+ "emoji_button.recent": "Utilizados regularmente",
+ "emoji_button.search": "Pesquisar...",
"emoji_button.search_results": "Resultados da pesquisa",
"emoji_button.symbols": "Símbolos",
"emoji_button.travel": "Viagens & Lugares",
- "empty_column.account_timeline": "Sem publicações!",
- "empty_column.account_unavailable": "Profile unavailable",
+ "empty_column.account_timeline": "Sem toots por aqui!",
+ "empty_column.account_unavailable": "Perfil indisponível",
"empty_column.blocks": "Ainda não bloqueaste qualquer utilizador.",
- "empty_column.community": "Ainda não existe conteúdo local para mostrar!",
+ "empty_column.community": "A timeline local está vazia. Escreve algo publicamente para começar!",
"empty_column.direct": "Ainda não tens qualquer mensagem directa. Quando enviares ou receberes alguma, ela irá aparecer aqui.",
"empty_column.domain_blocks": "Ainda não há qualquer domínio escondido.",
- "empty_column.favourited_statuses": "Ainda não tens quaisquer publicações favoritas. Quando tiveres alguma, ela irá aparecer aqui.",
- "empty_column.favourites": "Ainda ninguém favorizou esta publicação. Quando alguém o fizer, ela irá aparecer aqui.",
- "empty_column.follow_requests": "Ainda não tens pedido de seguimento algum. Quando receberes algum, ele irá aparecer aqui.",
+ "empty_column.favourited_statuses": "Ainda não tens quaisquer toots favoritos. Quando tiveres algum, ele irá aparecer aqui.",
+ "empty_column.favourites": "Ainda ninguém marcou este toot como favorito. Quando alguém o fizer, ele irá aparecer aqui.",
+ "empty_column.follow_requests": "Ainda não tens nenhum pedido de seguimento. Quando receberes algum, ele irá aparecer aqui.",
"empty_column.hashtag": "Não foram encontradas publicações com essa hashtag.",
"empty_column.home": "Ainda não segues qualquer utilizador. Visita {public} ou utiliza a pesquisa para procurar outros utilizadores.",
"empty_column.home.public_timeline": "Cronologia pública",
@@ -138,10 +138,10 @@
"follow_request.reject": "Rejeitar",
"getting_started.developers": "Responsáveis pelo desenvolvimento",
"getting_started.directory": "Directório de perfil",
- "getting_started.documentation": "Documentation",
+ "getting_started.documentation": "Documentação",
"getting_started.heading": "Primeiros passos",
"getting_started.invite": "Convidar pessoas",
- "getting_started.open_source_notice": "Mastodon é software de fonte aberta. Podes contribuir ou repostar problemas no GitHub do projecto: {github}.",
+ "getting_started.open_source_notice": "Mastodon é software de código aberto (open source). Podes contribuir ou reportar problemas no GitHub do projecto: {github}.",
"getting_started.security": "Segurança",
"getting_started.terms": "Termos de serviço",
"hashtag.column_header.tag_mode.all": "e {additional}",
@@ -154,28 +154,29 @@
"hashtag.column_settings.tag_mode.none": "Nenhum destes",
"hashtag.column_settings.tag_toggle": "Incluir etiquetas adicionais para esta coluna",
"home.column_settings.basic": "Básico",
- "home.column_settings.show_reblogs": "Mostrar as partilhas",
- "home.column_settings.show_replies": "Mostrar as respostas",
- "intervals.full.days": "{number, plural, one {# day} other {# days}}",
- "intervals.full.hours": "{number, plural, one {# hour} other {# hours}}",
- "intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}",
+ "home.column_settings.show_reblogs": "Mostrar boosts",
+ "home.column_settings.show_replies": "Mostrar respostas",
+ "home.column_settings.update_live": "Update in real-time",
+ "intervals.full.days": "{number, plural, one {# dia} other {# dias}}",
+ "intervals.full.hours": "{number, plural, one {# hora} other {# horas}}",
+ "intervals.full.minutes": "{number, plural, one {# minuto} other {# minutos}}",
"introduction.federation.action": "Seguinte",
- "introduction.federation.federated.headline": "Federated",
+ "introduction.federation.federated.headline": "Federada",
"introduction.federation.federated.text": "Publicações públicas de outros servidores do fediverse aparecerão na cronologia federativa.",
- "introduction.federation.home.headline": "Home",
+ "introduction.federation.home.headline": "Início",
"introduction.federation.home.text": "As publicações das pessoas que tu segues aparecerão na tua coluna inicial. Tu podes seguir qualquer pessoa em qualquer servidor!",
"introduction.federation.local.headline": "Local",
"introduction.federation.local.text": "Publicações públicas de pessoas que tu segues no teu servidor aparecerão na coluna local.",
"introduction.interactions.action": "Terminar o tutorial!",
"introduction.interactions.favourite.headline": "Favorito",
- "introduction.interactions.favourite.text": "Tu podes guardar um toot para depois e deixar o autor saber que gostaste dele, favoritando-o.",
- "introduction.interactions.reblog.headline": "Partilhar",
+ "introduction.interactions.favourite.text": "Podes guardar um toot para depois e deixar o autor saber que gostaste dele, marcando-o como favorito.",
+ "introduction.interactions.reblog.headline": "Boost",
"introduction.interactions.reblog.text": "Podes partilhar os toots de outras pessoas com os teus seguidores partilhando-os.",
"introduction.interactions.reply.headline": "Responder",
"introduction.interactions.reply.text": "Tu podes responder a toots de outras pessoas e aos teus, o que os irá juntar numa conversa.",
"introduction.welcome.action": "Vamos!",
"introduction.welcome.headline": "Primeiros passos",
- "introduction.welcome.text": "Bem-vindo ao fediverse! Em pouco tempo poderás enviar mensagens e falar com os teus amigos numa grande variedade de servidores. Mas este servidor, {domain}, é especial—ele alberga o teu perfil. Por isso, lembra-te do seu nome.",
+ "introduction.welcome.text": "Bem-vindo ao fediverso! Em pouco tempo poderás enviar mensagens e falar com os teus amigos numa grande variedade de servidores. Mas este servidor, {domain}, é especial—ele alberga o teu perfil. Por isso, lembra-te do seu nome.",
"keyboard_shortcuts.back": "para voltar",
"keyboard_shortcuts.blocked": "para abrir a lista de utilizadores bloqueados",
"keyboard_shortcuts.boost": "para partilhar",
@@ -184,10 +185,10 @@
"keyboard_shortcuts.description": "Descrição",
"keyboard_shortcuts.direct": "para abrir a coluna das mensagens directas",
"keyboard_shortcuts.down": "para mover para baixo na lista",
- "keyboard_shortcuts.enter": "para expandir uma publicação",
+ "keyboard_shortcuts.enter": "para expandir um estado",
"keyboard_shortcuts.favourite": "para adicionar aos favoritos",
"keyboard_shortcuts.favourites": "para abrir a lista dos favoritos",
- "keyboard_shortcuts.federated": "para abrir a cronologia federativa",
+ "keyboard_shortcuts.federated": "para abrir a cronologia federada",
"keyboard_shortcuts.heading": "Atalhos do teclado",
"keyboard_shortcuts.home": "para abrir a cronologia inicial",
"keyboard_shortcuts.hotkey": "Atalho",
@@ -204,31 +205,32 @@
"keyboard_shortcuts.search": "para focar na pesquisa",
"keyboard_shortcuts.start": "para abrir a coluna dos \"primeiros passos\"",
"keyboard_shortcuts.toggle_hidden": "para mostrar/esconder texto atrás de CW",
- "keyboard_shortcuts.toggle_sensitivity": "to show/hide media",
- "keyboard_shortcuts.toot": "para compor um novo post",
- "keyboard_shortcuts.unfocus": "para remover o foco da área de publicação/pesquisa",
+ "keyboard_shortcuts.toggle_sensitivity": "mostrar/ocultar média",
+ "keyboard_shortcuts.toot": "para compor um novo toot",
+ "keyboard_shortcuts.unfocus": "para remover o foco da área de texto/pesquisa",
"keyboard_shortcuts.up": "para mover para cima na lista",
"lightbox.close": "Fechar",
"lightbox.next": "Próximo",
"lightbox.previous": "Anterior",
- "lightbox.view_context": "View context",
+ "lightbox.view_context": "Ver contexto",
"lists.account.add": "Adicionar à lista",
"lists.account.remove": "Remover da lista",
- "lists.delete": "Delete list",
+ "lists.delete": "Remover lista",
"lists.edit": "Editar lista",
"lists.edit.submit": "Mudar o título",
"lists.new.create": "Adicionar lista",
- "lists.new.title_placeholder": "Novo título da lista",
+ "lists.new.title_placeholder": "Título da nova lista",
"lists.search": "Pesquisa entre as pessoas que segues",
"lists.subheading": "As tuas listas",
+ "load_pending": "{count, plural, one {# new item} other {# new items}}",
"loading_indicator.label": "A carregar...",
- "media_gallery.toggle_visible": "Esconder/Mostrar",
+ "media_gallery.toggle_visible": "Mostrar/ocultar",
"missing_indicator.label": "Não encontrado",
"missing_indicator.sublabel": "Este recurso não foi encontrado",
"mute_modal.hide_notifications": "Esconder notificações deste utilizador?",
"navigation_bar.apps": "Aplicações móveis",
"navigation_bar.blocks": "Utilizadores bloqueados",
- "navigation_bar.community_timeline": "Local",
+ "navigation_bar.community_timeline": "Cronologia local",
"navigation_bar.compose": "Escrever novo toot",
"navigation_bar.direct": "Mensagens directas",
"navigation_bar.discover": "Descobrir",
@@ -237,23 +239,23 @@
"navigation_bar.favourites": "Favoritos",
"navigation_bar.filters": "Palavras silenciadas",
"navigation_bar.follow_requests": "Seguidores pendentes",
- "navigation_bar.follows_and_followers": "Follows and followers",
+ "navigation_bar.follows_and_followers": "Seguindo e seguidores",
"navigation_bar.info": "Sobre este servidor",
"navigation_bar.keyboard_shortcuts": "Atalhos de teclado",
"navigation_bar.lists": "Listas",
"navigation_bar.logout": "Sair",
"navigation_bar.mutes": "Utilizadores silenciados",
- "navigation_bar.personal": "Personal",
- "navigation_bar.pins": "Posts fixos",
+ "navigation_bar.personal": "Pessoal",
+ "navigation_bar.pins": "Toots afixados",
"navigation_bar.preferences": "Preferências",
- "navigation_bar.profile_directory": "Profile directory",
- "navigation_bar.public_timeline": "Global",
+ "navigation_bar.profile_directory": "Directório de perfis",
+ "navigation_bar.public_timeline": "Cronologia federada",
"navigation_bar.security": "Segurança",
- "notification.favourite": "{name} adicionou o teu post aos favoritos",
- "notification.follow": "{name} seguiu-te",
+ "notification.favourite": "{name} adicionou o teu estado aos favoritos",
+ "notification.follow": "{name} começou a seguir-te",
"notification.mention": "{name} mencionou-te",
- "notification.poll": "A poll you have voted in has ended",
- "notification.reblog": "{name} partilhou o teu post",
+ "notification.poll": "Uma votação em participaste chegou ao fim",
+ "notification.reblog": "{name} fez boost ao teu o teu estado",
"notifications.clear": "Limpar notificações",
"notifications.clear_confirmation": "Queres mesmo limpar todas as notificações?",
"notifications.column_settings.alert": "Notificações no computador",
@@ -263,24 +265,24 @@
"notifications.column_settings.filter_bar.show": "Mostrar",
"notifications.column_settings.follow": "Novos seguidores:",
"notifications.column_settings.mention": "Menções:",
- "notifications.column_settings.poll": "Poll results:",
+ "notifications.column_settings.poll": "Resultados da votação:",
"notifications.column_settings.push": "Notificações Push",
- "notifications.column_settings.reblog": "Partilhas:",
- "notifications.column_settings.show": "Mostrar nas colunas",
+ "notifications.column_settings.reblog": "Boosts:",
+ "notifications.column_settings.show": "Mostrar na coluna",
"notifications.column_settings.sound": "Reproduzir som",
"notifications.filter.all": "Todas",
- "notifications.filter.boosts": "Partilhas",
- "notifications.filter.favourites": "Favoritas",
+ "notifications.filter.boosts": "Boosts",
+ "notifications.filter.favourites": "Favoritos",
"notifications.filter.follows": "Seguimento",
"notifications.filter.mentions": "Referências",
- "notifications.filter.polls": "Poll results",
+ "notifications.filter.polls": "Resultados da votação",
"notifications.group": "{count} notificações",
"poll.closed": "Fechado",
"poll.refresh": "Recarregar",
"poll.total_votes": "{contar, plural, um {# vote} outro {# votes}}",
"poll.vote": "Votar",
- "poll_button.add_poll": "Add a poll",
- "poll_button.remove_poll": "Remove poll",
+ "poll_button.add_poll": "Adicionar votação",
+ "poll_button.remove_poll": "Remover votação",
"privacy.change": "Ajustar a privacidade da mensagem",
"privacy.direct.long": "Apenas para utilizadores mencionados",
"privacy.direct.short": "Directo",
@@ -300,26 +302,27 @@
"reply_indicator.cancel": "Cancelar",
"report.forward": "Reenviar para {target}",
"report.forward_hint": "A conta é de outro servidor. Enviar uma cópia anónima do relatório para lá também?",
- "report.hint": "O relatório será enviado para os moderadores do teu servidor. Podes fornecer, em baixo, uma explicação do motivo pelo qual estás a relatar esta conta:",
+ "report.hint": "O relatório será enviado para os moderadores do teu servidor. Podes fornecer, em baixo, uma explicação do motivo pelo qual estás a denunciar esta conta:",
"report.placeholder": "Comentários adicionais",
"report.submit": "Enviar",
"report.target": "Denunciar",
"search.placeholder": "Pesquisar",
"search_popout.search_format": "Formato avançado de pesquisa",
- "search_popout.tips.full_text": "Texto simples devolve publicações que tu escreveste, favoritaste, partilhaste ou em que foste mencionado, tal como nomes de utilizador correspondentes, alcunhas e hashtags.",
+ "search_popout.tips.full_text": "Texto simples devolve publicações que tu escreveste, marcaste como favorita, partilhaste ou em que foste mencionado, tal como nomes de utilizador correspondentes, alcunhas e hashtags.",
"search_popout.tips.hashtag": "hashtag",
"search_popout.tips.status": "estado",
"search_popout.tips.text": "O texto simples retorna a correspondência de nomes, utilizadores e hashtags",
"search_popout.tips.user": "utilizador",
"search_results.accounts": "Pessoas",
"search_results.hashtags": "Hashtags",
- "search_results.statuses": "Publicações",
+ "search_results.statuses": "Toots",
+ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.",
"search_results.total": "{count, number} {count, plural, one {resultado} other {resultados}}",
"status.admin_account": "Abrir a interface de moderação para @{name}",
"status.admin_status": "Abrir esta publicação na interface de moderação",
- "status.block": "Block @{name}",
- "status.cancel_reblog_private": "Não partilhar",
- "status.cannot_reblog": "Este post não pode ser partilhado",
+ "status.block": "Bloquear @{name}",
+ "status.cancel_reblog_private": "Remover boost",
+ "status.cannot_reblog": "Não é possível fazer boost a esta publicação",
"status.copy": "Copiar o link para a publicação",
"status.delete": "Eliminar",
"status.detailed_status": "Vista de conversação detalhada",
@@ -328,7 +331,7 @@
"status.favourite": "Adicionar aos favoritos",
"status.filtered": "Filtrada",
"status.load_more": "Carregar mais",
- "status.media_hidden": "Media escondida",
+ "status.media_hidden": "Média escondida",
"status.mention": "Mencionar @{name}",
"status.more": "Mais",
"status.mute": "Silenciar @{name}",
@@ -338,15 +341,15 @@
"status.pinned": "Publicação fixa",
"status.read_more": "Ler mais",
"status.reblog": "Partilhar",
- "status.reblog_private": "Partilhar com a audiência original",
- "status.reblogged_by": "{name} partilhou",
- "status.reblogs.empty": "Ainda ninguém partilhou esta publicação. Quando alguém o fizer, ela irá aparecer aqui.",
+ "status.reblog_private": "Fazer boost com a audiência original",
+ "status.reblogged_by": "{name} fez boost",
+ "status.reblogs.empty": "Ainda ninguém fez boost a este toot. Quando alguém o fizer, ele irá aparecer aqui.",
"status.redraft": "Apagar & reescrever",
"status.reply": "Responder",
"status.replyAll": "Responder à conversa",
"status.report": "Denunciar @{name}",
"status.sensitive_warning": "Conteúdo sensível",
- "status.share": "Compartilhar",
+ "status.share": "Partilhar",
"status.show_less": "Mostrar menos",
"status.show_less_all": "Mostrar menos para todas",
"status.show_more": "Mostrar mais",
@@ -356,22 +359,22 @@
"status.unpin": "Não fixar no perfil",
"suggestions.dismiss": "Dispensar a sugestão",
"suggestions.header": "Tu podes estar interessado em…",
- "tabs_bar.federated_timeline": "Global",
- "tabs_bar.home": "Home",
+ "tabs_bar.federated_timeline": "Federada",
+ "tabs_bar.home": "Início",
"tabs_bar.local_timeline": "Local",
"tabs_bar.notifications": "Notificações",
"tabs_bar.search": "Pesquisar",
"time_remaining.days": "{número, plural, um {# day} outro {# days}} faltam",
"time_remaining.hours": "{número, plural, um {# hour} outro {# hours}} faltam",
"time_remaining.minutes": "{número, plural, um {# minute} outro {# minutes}} faltam",
- "time_remaining.moments": "Momentos em falta",
+ "time_remaining.moments": "Momentos restantes",
"time_remaining.seconds": "{número, plural, um {# second} outro {# seconds}} faltam",
"trends.count_by_accounts": "{count} {rawCount, plural, uma {person} outra {people}} a falar",
- "ui.beforeunload": "O teu rascunho vai ser perdido se abandonares o Mastodon.",
+ "ui.beforeunload": "O teu rascunho será perdido se abandonares o Mastodon.",
"upload_area.title": "Arraste e solte para enviar",
"upload_button.label": "Adicionar media",
"upload_error.limit": "Limite máximo do ficheiro a carregar excedido.",
- "upload_error.poll": "File upload not allowed with polls.",
+ "upload_error.poll": "Carregamento de ficheiros não é permitido em votações.",
"upload_form.description": "Descrição da imagem para pessoas com dificuldades visuais",
"upload_form.focus": "Alterar previsualização",
"upload_form.undo": "Apagar",
@@ -379,7 +382,7 @@
"video.close": "Fechar vídeo",
"video.exit_fullscreen": "Sair de full screen",
"video.expand": "Expandir vídeo",
- "video.fullscreen": "Full screen",
+ "video.fullscreen": "Ecrã completo",
"video.hide": "Esconder vídeo",
"video.mute": "Silenciar",
"video.pause": "Pausar",
diff --git a/app/javascript/mastodon/locales/ro.json b/app/javascript/mastodon/locales/ro.json
index dcb7a088df..ac10d46787 100644
--- a/app/javascript/mastodon/locales/ro.json
+++ b/app/javascript/mastodon/locales/ro.json
@@ -156,6 +156,7 @@
"home.column_settings.basic": "De bază",
"home.column_settings.show_reblogs": "Arată redistribuirile",
"home.column_settings.show_replies": "Arată răspunsurile",
+ "home.column_settings.update_live": "Update in real-time",
"intervals.full.days": "{number, plural, one {# day} other {# days}}",
"intervals.full.hours": "{number, plural, one {# hour} other {# hours}}",
"intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}",
@@ -221,6 +222,7 @@
"lists.new.title_placeholder": "Titlu pentru noua listă",
"lists.search": "Caută printre persoanale pe care le urmărești",
"lists.subheading": "Listele tale",
+ "load_pending": "{count, plural, one {# new item} other {# new items}}",
"loading_indicator.label": "Încărcare...",
"media_gallery.toggle_visible": "Comutați vizibilitatea",
"missing_indicator.label": "Nu a fost găsit",
@@ -314,6 +316,7 @@
"search_results.accounts": "Oameni",
"search_results.hashtags": "Hashtaguri",
"search_results.statuses": "Postări",
+ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.",
"search_results.total": "{count, number} {count, plural, one {result} other {results}}",
"status.admin_account": "Open moderation interface for @{name}",
"status.admin_status": "Open this status in the moderation interface",
diff --git a/app/javascript/mastodon/locales/ru.json b/app/javascript/mastodon/locales/ru.json
index d720b62729..8a7a39a069 100644
--- a/app/javascript/mastodon/locales/ru.json
+++ b/app/javascript/mastodon/locales/ru.json
@@ -13,20 +13,20 @@
"account.followers.empty": "Никто не подписан на этого пользователя.",
"account.follows": "Подписки",
"account.follows.empty": "Этот пользователь ни на кого не подписан.",
- "account.follows_you": "Подписан(а) на Вас",
+ "account.follows_you": "Подписан(а) на вас",
"account.hide_reblogs": "Скрыть реблоги от @{name}",
"account.link_verified_on": "Владение этой ссылкой было проверено {date}",
"account.locked_info": "Это закрытый аккаунт. Его владелец вручную одобряет подписчиков.",
"account.media": "Медиа",
"account.mention": "Упомянуть",
"account.moved_to": "Ищите {name} здесь:",
- "account.mute": "Заглушить",
+ "account.mute": "Скрыть @{name}",
"account.mute_notifications": "Скрыть уведомления от @{name}",
- "account.muted": "Приглушён",
+ "account.muted": "Скрыт",
"account.posts": "Посты",
- "account.posts_with_replies": "Посты и ответы",
+ "account.posts_with_replies": "Посты с ответами",
"account.report": "Пожаловаться",
- "account.requested": "Ожидает подтверждения",
+ "account.requested": "Ожидает подтверждения. Нажмите для отмены",
"account.share": "Поделиться профилем @{name}",
"account.show_reblogs": "Показывать продвижения от @{name}",
"account.unblock": "Разблокировать",
@@ -52,7 +52,7 @@
"column.follow_requests": "Запросы на подписку",
"column.home": "Главная",
"column.lists": "Списки",
- "column.mutes": "Список глушения",
+ "column.mutes": "Список скрытых пользователей",
"column.notifications": "Уведомления",
"column.pins": "Закреплённый пост",
"column.public": "Глобальная лента",
@@ -70,12 +70,12 @@
"compose_form.hashtag_warning": "Этот пост не будет показывается в поиске по хэштегу, т.к. он непубличный. Только публичные посты можно найти в поиске по хэштегу.",
"compose_form.lock_disclaimer": "Ваш аккаунт не {locked}. Любой человек может подписаться на Вас и просматривать посты для подписчиков.",
"compose_form.lock_disclaimer.lock": "закрыт",
- "compose_form.placeholder": "О чем Вы думаете?",
+ "compose_form.placeholder": "О чем вы думаете?",
"compose_form.poll.add_option": "Добавить",
"compose_form.poll.duration": "Длительность опроса",
"compose_form.poll.option_placeholder": "Вариант {number}",
"compose_form.poll.remove_option": "Удалить этот вариант",
- "compose_form.publish": "Трубить",
+ "compose_form.publish": "Запостить",
"compose_form.publish_loud": "{publish}!",
"compose_form.sensitive.hide": "Пометить медиафайл как чувствительный",
"compose_form.sensitive.marked": "Медиафайлы не отмечены как чувствительные",
@@ -117,31 +117,31 @@
"emoji_button.search_results": "Результаты поиска",
"emoji_button.symbols": "Символы",
"emoji_button.travel": "Путешествия",
- "empty_column.account_timeline": "Статусов нет!",
+ "empty_column.account_timeline": "Здесь нет постов!",
"empty_column.account_unavailable": "Профиль недоступен",
"empty_column.blocks": "Вы ещё никого не заблокировали.",
"empty_column.community": "Локальная лента пуста. Напишите что-нибудь, чтобы разогреть народ!",
- "empty_column.direct": "У Вас пока нет личных сообщений. Когда Вы начнёте их отправлять или получать, они появятся здесь.",
+ "empty_column.direct": "У вас пока нет личных сообщений. Как только вы отправите или получите одно, оно появится здесь.",
"empty_column.domain_blocks": "Скрытых доменов пока нет.",
- "empty_column.favourited_statuses": "Вы не добавили ни одного статуса в 'Избранное'. Как только Вы это сделаете, они появятся здесь.",
- "empty_column.favourites": "Никто ещё не добавил этот статус в 'Избранное'. Как только кто-то это сделает, они появятся здесь.",
+ "empty_column.favourited_statuses": "Вы не добавили ни один пост в «Избранное». Как только вы это сделаете, он появится здесь.",
+ "empty_column.favourites": "Никто ещё не добавил этот пост в «Избранное». Как только кто-то это сделает, это отобразится здесь.",
"empty_column.follow_requests": "Вам ещё не приходили запросы на подписку. Все новые запросы будут показаны здесь.",
"empty_column.hashtag": "Статусов с таким хэштегом еще не существует.",
- "empty_column.home": "Пока Вы ни на кого не подписаны. Полистайте {public} или используйте поиск, чтобы освоиться и завести новые знакомства.",
+ "empty_column.home": "Пока вы ни на кого не подписаны. Полистайте {public} или используйте поиск, чтобы освоиться и завести новые знакомства.",
"empty_column.home.public_timeline": "публичные ленты",
"empty_column.list": "В этом списке пока ничего нет.",
- "empty_column.lists": "У Вас ещё нет списков. Все созданные Вами списки будут показаны здесь.",
- "empty_column.mutes": "Вы ещё никого не заглушили.",
- "empty_column.notifications": "У Вас еще нет уведомлений. Заведите знакомство с другими пользователями, чтобы начать разговор.",
+ "empty_column.lists": "У вас ещё нет списков. Созданные вами списки будут показаны здесь.",
+ "empty_column.mutes": "Вы ещё никого не скрывали.",
+ "empty_column.notifications": "У вас пока нет уведомлений. Взаимодействуйте с другими, чтобы завести разговор.",
"empty_column.public": "Здесь ничего нет! Опубликуйте что-нибудь или подпишитесь на пользователей с других узлов, чтобы заполнить ленту.",
"follow_request.authorize": "Авторизовать",
"follow_request.reject": "Отказать",
- "getting_started.developers": "Для разработчиков",
+ "getting_started.developers": "Разработчикам",
"getting_started.directory": "Каталог профилей",
"getting_started.documentation": "Документация",
"getting_started.heading": "Добро пожаловать",
"getting_started.invite": "Пригласить людей",
- "getting_started.open_source_notice": "Mastodon - сервис с открытым исходным кодом. Вы можете помочь проекту или сообщить о проблемах на GitHub по адресу {github}.",
+ "getting_started.open_source_notice": "Mastodon — сервис с открытым исходным кодом. Вы можете внести вклад или сообщить о проблемах на GitHub: {github}.",
"getting_started.security": "Безопасность",
"getting_started.terms": "Условия использования",
"hashtag.column_header.tag_mode.all": "и {additional}",
@@ -156,9 +156,10 @@
"home.column_settings.basic": "Основные",
"home.column_settings.show_reblogs": "Показывать продвижения",
"home.column_settings.show_replies": "Показывать ответы",
- "intervals.full.days": "{number, plural, one {# день} few {# дня} many {# дней} other {# дней}}",
- "intervals.full.hours": "{number, plural, one {# час} few {# часа} many {# часов} other {# часов}}",
- "intervals.full.minutes": "{number, plural, one {# минута} few {# минуты} many {# минут} other {# минут}}",
+ "home.column_settings.update_live": "Update in real-time",
+ "intervals.full.days": "{number, plural, one {# день} few {# дня} other {# дней}}",
+ "intervals.full.hours": "{number, plural, one {# час} few {# часа} other {# часов}}",
+ "intervals.full.minutes": "{number, plural, one {# минута} few {# минуты} other {# минут}}",
"introduction.federation.action": "Далее",
"introduction.federation.federated.headline": "Глобальная лента",
"introduction.federation.federated.text": "Публичные статусы с других серверов федеративной сети расположатся в глобальной ленте.",
@@ -167,7 +168,7 @@
"introduction.federation.local.headline": "Локальная лента",
"introduction.federation.local.text": "Публичные статусы от людей с того же сервера, что и вы, будут отображены в локальной ленте.",
"introduction.interactions.action": "Завершить обучение",
- "introduction.interactions.favourite.headline": "Отметки \"нравится\"",
+ "introduction.interactions.favourite.headline": "Отметки «нравится»",
"introduction.interactions.favourite.text": "Вы можете отметить статус, чтобы вернуться к нему позже и дать знать автору, что запись вам понравилась, поставив отметку \"нравится\".",
"introduction.interactions.reblog.headline": "Продвижения",
"introduction.interactions.reblog.text": "Вы можете делиться статусами других людей, продвигая их в своём аккаунте.",
@@ -221,6 +222,7 @@
"lists.new.title_placeholder": "Заголовок списка",
"lists.search": "Искать из ваших подписок",
"lists.subheading": "Ваши списки",
+ "load_pending": "{count, plural, one {# new item} other {# new items}}",
"loading_indicator.label": "Загрузка...",
"media_gallery.toggle_visible": "Показать/скрыть",
"missing_indicator.label": "Не найдено",
@@ -242,7 +244,7 @@
"navigation_bar.keyboard_shortcuts": "Сочетания клавиш",
"navigation_bar.lists": "Списки",
"navigation_bar.logout": "Выйти",
- "navigation_bar.mutes": "Список глушения",
+ "navigation_bar.mutes": "Список скрытых пользователей",
"navigation_bar.personal": "Личное",
"navigation_bar.pins": "Закреплённые посты",
"navigation_bar.preferences": "Опции",
@@ -314,6 +316,7 @@
"search_results.accounts": "Люди",
"search_results.hashtags": "Хэштеги",
"search_results.statuses": "Посты",
+ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.",
"search_results.total": "{count, number} {count, plural, one {результат} few {результата} many {результатов} other {результатов}}",
"status.admin_account": "Открыть интерфейс модератора для @{name}",
"status.admin_status": "Открыть этот статус в интерфейсе модератора",
diff --git a/app/javascript/mastodon/locales/sk.json b/app/javascript/mastodon/locales/sk.json
index 18993af970..3cc2cbaa7f 100644
--- a/app/javascript/mastodon/locales/sk.json
+++ b/app/javascript/mastodon/locales/sk.json
@@ -156,6 +156,7 @@
"home.column_settings.basic": "Základné",
"home.column_settings.show_reblogs": "Zobraziť povýšené",
"home.column_settings.show_replies": "Ukázať odpovede",
+ "home.column_settings.update_live": "Update in real-time",
"intervals.full.days": "{number, plural, one {# deň} few {# dní} many {# dní} other {# dni}}",
"intervals.full.hours": "{number, plural, one {# hodina} few {# hodín} many {# hodín} other {# hodiny}}",
"intervals.full.minutes": "{number, plural, one {# minúta} few {# minút} many {# minút} other {# minúty}}",
@@ -221,6 +222,7 @@
"lists.new.title_placeholder": "Názov nového zoznamu",
"lists.search": "Vyhľadávaj medzi užívateľmi, ktorých sleduješ",
"lists.subheading": "Tvoje zoznamy",
+ "load_pending": "{count, plural, one {# new item} other {# new items}}",
"loading_indicator.label": "Načítam...",
"media_gallery.toggle_visible": "Zapni/Vypni viditeľnosť",
"missing_indicator.label": "Nenájdené",
@@ -254,7 +256,7 @@
"notification.mention": "{name} ťa spomenul/a",
"notification.poll": "Anketa v ktorej si hlasoval/a sa skončila",
"notification.reblog": "{name} zdieľal/a tvoj príspevok",
- "notifications.clear": "Vyčistiť zoznam oboznámení",
+ "notifications.clear": "Vyčisti oboznámenia",
"notifications.clear_confirmation": "Naozaj chceš nenávratne prečistiť všetky tvoje oboznámenia?",
"notifications.column_settings.alert": "Oboznámenia na ploche",
"notifications.column_settings.favourite": "Obľúbené:",
@@ -314,6 +316,7 @@
"search_results.accounts": "Ľudia",
"search_results.hashtags": "Haštagy",
"search_results.statuses": "Príspevky",
+ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.",
"search_results.total": "{count, number} {count, plural, one {výsledok} many {výsledkov} other {výsledky}}",
"status.admin_account": "Otvor moderovacie rozhranie užívateľa @{name}",
"status.admin_status": "Otvor tento príspevok v moderovacom rozhraní",
diff --git a/app/javascript/mastodon/locales/sl.json b/app/javascript/mastodon/locales/sl.json
index 51794a8625..f79a7051ae 100644
--- a/app/javascript/mastodon/locales/sl.json
+++ b/app/javascript/mastodon/locales/sl.json
@@ -156,6 +156,7 @@
"home.column_settings.basic": "Osnovno",
"home.column_settings.show_reblogs": "Pokaži spodbude",
"home.column_settings.show_replies": "Pokaži odgovore",
+ "home.column_settings.update_live": "Update in real-time",
"intervals.full.days": "{number, plural, one {# dan} two {# dni} few {# dni} other {# dni}}",
"intervals.full.hours": "{number, plural, one {# ura} two {# uri} few {# ure} other {# ur}}",
"intervals.full.minutes": "{number, plural, one {# minuta} two {# minuti} few {# minute} other {# minut}}",
@@ -167,7 +168,7 @@
"introduction.federation.local.headline": "Lokalno",
"introduction.federation.local.text": "Javne objave ljudi na istem strežniku, se bodo prikazale na lokalni časovnici.",
"introduction.interactions.action": "Zaključi vadnico!",
- "introduction.interactions.favourite.headline": "Priljubljeni",
+ "introduction.interactions.favourite.headline": "Vzljubi",
"introduction.interactions.favourite.text": "Tut lahko shranite za pozneje in ga vzljubite ter s tem pokažete avtorju, da vam je ta tut priljubljen.",
"introduction.interactions.reblog.headline": "Spodbudi",
"introduction.interactions.reblog.text": "Tute drugih ljudi lahko delite z vašimi sledilci, tako da spodbudite tute.",
@@ -221,6 +222,7 @@
"lists.new.title_placeholder": "Nov naslov seznama",
"lists.search": "Išči med ljudmi, katerim sledite",
"lists.subheading": "Vaši seznami",
+ "load_pending": "{count, plural, one {# new item} other {# new items}}",
"loading_indicator.label": "Nalaganje...",
"media_gallery.toggle_visible": "Preklopi vidljivost",
"missing_indicator.label": "Ni najdeno",
@@ -314,6 +316,7 @@
"search_results.accounts": "Ljudje",
"search_results.hashtags": "Ključniki",
"search_results.statuses": "Tuti",
+ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.",
"search_results.total": "{count, number} {count, plural, one {rezultat} other {rezultatov}}",
"status.admin_account": "Odpri vmesnik za moderiranje za @{name}",
"status.admin_status": "Odpri status v vmesniku za moderiranje",
@@ -351,29 +354,29 @@
"status.show_less_all": "Prikaži manj za vse",
"status.show_more": "Prikaži več",
"status.show_more_all": "Prikaži več za vse",
- "status.show_thread": "Show thread",
+ "status.show_thread": "Prikaži objavo",
"status.unmute_conversation": "Odtišaj pogovor",
"status.unpin": "Odpni iz profila",
- "suggestions.dismiss": "Dismiss suggestion",
- "suggestions.header": "You might be interested in…",
+ "suggestions.dismiss": "Zavrni predlog",
+ "suggestions.header": "Morda bi vas zanimalo…",
"tabs_bar.federated_timeline": "Združeno",
"tabs_bar.home": "Domov",
"tabs_bar.local_timeline": "Lokalno",
"tabs_bar.notifications": "Obvestila",
- "tabs_bar.search": "Poišči",
- "time_remaining.days": "{number, plural, one {# day} other {# days}} left",
- "time_remaining.hours": "{number, plural, one {# hour} other {# hours}} left",
- "time_remaining.minutes": "{number, plural, one {# minute} other {# minutes}} left",
- "time_remaining.moments": "Moments remaining",
- "time_remaining.seconds": "{number, plural, one {# second} other {# seconds}} left",
- "trends.count_by_accounts": "{count} {rawCount, plural, one {person} other {people}} talking",
+ "tabs_bar.search": "Iskanje",
+ "time_remaining.days": "{number, plural, one {# dan} other {# dni}} je ostalo",
+ "time_remaining.hours": "{number, plural, one {# ura} other {# ur}} je ostalo",
+ "time_remaining.minutes": "{number, plural, one {# minuta} other {# minut}} je ostalo",
+ "time_remaining.moments": "Preostali trenutki",
+ "time_remaining.seconds": "{number, plural, one {# sekunda} other {# sekund}} je ostalo",
+ "trends.count_by_accounts": "{count} {rawCount, plural, one {oseba} other {ljudi}} govori",
"ui.beforeunload": "Vaš osnutek bo izgubljen, če zapustite Mastodona.",
- "upload_area.title": "Povlecite in spustite za pošiljanje",
- "upload_button.label": "Dodaj medij",
- "upload_error.limit": "File upload limit exceeded.",
- "upload_error.poll": "File upload not allowed with polls.",
+ "upload_area.title": "Za pošiljanje povlecite in spustite",
+ "upload_button.label": "Dodaj medije ({formats})",
+ "upload_error.limit": "Omejitev prenosa datoteke je presežena.",
+ "upload_error.poll": "Prenos datoteke z anketami ni dovoljen.",
"upload_form.description": "Opišite za slabovidne",
- "upload_form.focus": "Obreži",
+ "upload_form.focus": "Spremeni predogled",
"upload_form.undo": "Izbriši",
"upload_progress.label": "Pošiljanje...",
"video.close": "Zapri video",
diff --git a/app/javascript/mastodon/locales/sq.json b/app/javascript/mastodon/locales/sq.json
index 13ce4e9789..21d45f2e8c 100644
--- a/app/javascript/mastodon/locales/sq.json
+++ b/app/javascript/mastodon/locales/sq.json
@@ -156,6 +156,7 @@
"home.column_settings.basic": "Bazë",
"home.column_settings.show_reblogs": "Shfaq përforcime",
"home.column_settings.show_replies": "Shfaq përgjigje",
+ "home.column_settings.update_live": "Update in real-time",
"intervals.full.days": "{number, plural, one {# day} other {# days}}",
"intervals.full.hours": "{number, plural, one {# hour} other {# hours}}",
"intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}",
@@ -221,6 +222,7 @@
"lists.new.title_placeholder": "Titull liste të re",
"lists.search": "Kërkoni mes personash që ndiqni",
"lists.subheading": "Listat tuaja",
+ "load_pending": "{count, plural, one {# new item} other {# new items}}",
"loading_indicator.label": "Po ngarkohet…",
"media_gallery.toggle_visible": "Ndërroni dukshmërinë",
"missing_indicator.label": "S’u gjet",
@@ -314,6 +316,7 @@
"search_results.accounts": "Persona",
"search_results.hashtags": "Hashtagë",
"search_results.statuses": "Mesazhe",
+ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.",
"search_results.total": "{count, number} {count, plural, një {result} {results} të tjera}",
"status.admin_account": "Hap ndërfaqe moderimi për @{name}",
"status.admin_status": "Hape këtë gjendje te ndërfaqja e moderimit",
diff --git a/app/javascript/mastodon/locales/sr-Latn.json b/app/javascript/mastodon/locales/sr-Latn.json
index 8f8ca7c303..55bae4cdd2 100644
--- a/app/javascript/mastodon/locales/sr-Latn.json
+++ b/app/javascript/mastodon/locales/sr-Latn.json
@@ -64,7 +64,7 @@
"column_header.show_settings": "Prikaži postavke",
"column_header.unpin": "Otkači",
"column_subheading.settings": "Postavke",
- "community.column_settings.media_only": "Media Only",
+ "community.column_settings.media_only": "Media only",
"compose_form.direct_message_warning": "This toot will only be visible to all the mentioned users.",
"compose_form.direct_message_warning_learn_more": "Learn more",
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
@@ -156,6 +156,7 @@
"home.column_settings.basic": "Osnovno",
"home.column_settings.show_reblogs": "Prikaži i podržavanja",
"home.column_settings.show_replies": "Prikaži odgovore",
+ "home.column_settings.update_live": "Update in real-time",
"intervals.full.days": "{number, plural, one {# day} other {# days}}",
"intervals.full.hours": "{number, plural, one {# hour} other {# hours}}",
"intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}",
@@ -221,6 +222,7 @@
"lists.new.title_placeholder": "Naslov nove liste",
"lists.search": "Pretraži među ljudima koje pratite",
"lists.subheading": "Vaše liste",
+ "load_pending": "{count, plural, one {# new item} other {# new items}}",
"loading_indicator.label": "Učitavam...",
"media_gallery.toggle_visible": "Uključi/isključi vidljivost",
"missing_indicator.label": "Nije pronađeno",
@@ -314,6 +316,7 @@
"search_results.accounts": "People",
"search_results.hashtags": "Hashtags",
"search_results.statuses": "Toots",
+ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.",
"search_results.total": "{count, number} {count, plural, one {rezultat} few {rezultata} other {rezultata}}",
"status.admin_account": "Open moderation interface for @{name}",
"status.admin_status": "Open this status in the moderation interface",
diff --git a/app/javascript/mastodon/locales/sr.json b/app/javascript/mastodon/locales/sr.json
index 8ef18a7743..a4ae9fcaa4 100644
--- a/app/javascript/mastodon/locales/sr.json
+++ b/app/javascript/mastodon/locales/sr.json
@@ -156,6 +156,7 @@
"home.column_settings.basic": "Основно",
"home.column_settings.show_reblogs": "Прикажи и подржавања",
"home.column_settings.show_replies": "Прикажи одговоре",
+ "home.column_settings.update_live": "Update in real-time",
"intervals.full.days": "{number, plural, one {# day} other {# days}}",
"intervals.full.hours": "{number, plural, one {# hour} other {# hours}}",
"intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}",
@@ -221,6 +222,7 @@
"lists.new.title_placeholder": "Наслов нове листе",
"lists.search": "Претражи међу људима које пратите",
"lists.subheading": "Ваше листе",
+ "load_pending": "{count, plural, one {# new item} other {# new items}}",
"loading_indicator.label": "Учитавам...",
"media_gallery.toggle_visible": "Укључи/искључи видљивост",
"missing_indicator.label": "Није пронађено",
@@ -314,6 +316,7 @@
"search_results.accounts": "Људи",
"search_results.hashtags": "Тарабе",
"search_results.statuses": "Трубе",
+ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.",
"search_results.total": "{count, number} {count, plural, one {резултат} few {резултата} other {резултата}}",
"status.admin_account": "Open moderation interface for @{name}",
"status.admin_status": "Open this status in the moderation interface",
diff --git a/app/javascript/mastodon/locales/sv.json b/app/javascript/mastodon/locales/sv.json
index ab12be885f..fda5c4d570 100644
--- a/app/javascript/mastodon/locales/sv.json
+++ b/app/javascript/mastodon/locales/sv.json
@@ -156,6 +156,7 @@
"home.column_settings.basic": "Grundläggande",
"home.column_settings.show_reblogs": "Visa knuffar",
"home.column_settings.show_replies": "Visa svar",
+ "home.column_settings.update_live": "Update in real-time",
"intervals.full.days": "{number, plural, one {# day} other {# days}}",
"intervals.full.hours": "{number, plural, one {# hour} other {# hours}}",
"intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}",
@@ -221,6 +222,7 @@
"lists.new.title_placeholder": "Ny listrubrik",
"lists.search": "Sök bland personer du följer",
"lists.subheading": "Dina listor",
+ "load_pending": "{count, plural, one {# new item} other {# new items}}",
"loading_indicator.label": "Laddar...",
"media_gallery.toggle_visible": "Växla synlighet",
"missing_indicator.label": "Hittades inte",
@@ -314,6 +316,7 @@
"search_results.accounts": "Människor",
"search_results.hashtags": "Hashtags",
"search_results.statuses": "Toots",
+ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.",
"search_results.total": "{count, number} {count, plural, ett {result} andra {results}}",
"status.admin_account": "Open moderation interface for @{name}",
"status.admin_status": "Open this status in the moderation interface",
diff --git a/app/javascript/mastodon/locales/ta.json b/app/javascript/mastodon/locales/ta.json
index 637ca884a3..87163e6603 100644
--- a/app/javascript/mastodon/locales/ta.json
+++ b/app/javascript/mastodon/locales/ta.json
@@ -156,6 +156,7 @@
"home.column_settings.basic": "அடிப்படையான",
"home.column_settings.show_reblogs": "காட்டு boosts",
"home.column_settings.show_replies": "பதில்களைக் காண்பி",
+ "home.column_settings.update_live": "Update in real-time",
"intervals.full.days": "{number, plural, one {# day} மற்ற {# days}}",
"intervals.full.hours": "{number, plural, one {# hour} மற்ற {# hours}}",
"intervals.full.minutes": "{number, plural, one {# minute} மற்ற {# minutes}}",
@@ -221,6 +222,7 @@
"lists.new.title_placeholder": "புதிய பட்டியல் தலைப்பு",
"lists.search": "நீங்கள் பின்தொடரும் நபர்கள் மத்தியில் தேடுதல்",
"lists.subheading": "உங்கள் பட்டியல்கள்",
+ "load_pending": "{count, plural, one {# new item} other {# new items}}",
"loading_indicator.label": "ஏற்றுதல்...",
"media_gallery.toggle_visible": "நிலைமாற்று தெரியும்",
"missing_indicator.label": "கிடைக்கவில்லை",
@@ -314,6 +316,7 @@
"search_results.accounts": "People",
"search_results.hashtags": "ஹாஷ்டேக்குகளைச்",
"search_results.statuses": "Toots",
+ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.",
"search_results.total": "{count, number} {count, plural, one {result} மற்ற {results}}",
"status.admin_account": "மிதமான இடைமுகத்தை திறக்க @{name}",
"status.admin_status": "மிதமான இடைமுகத்தில் இந்த நிலையை திறக்கவும்",
diff --git a/app/javascript/mastodon/locales/te.json b/app/javascript/mastodon/locales/te.json
index 269ea45c3b..ccb608812c 100644
--- a/app/javascript/mastodon/locales/te.json
+++ b/app/javascript/mastodon/locales/te.json
@@ -156,6 +156,7 @@
"home.column_settings.basic": "ప్రాథమిక",
"home.column_settings.show_reblogs": "బూస్ట్ లను చూపించు",
"home.column_settings.show_replies": "ప్రత్యుత్తరాలను చూపించు",
+ "home.column_settings.update_live": "Update in real-time",
"intervals.full.days": "{number, plural, one {# day} other {# days}}",
"intervals.full.hours": "{number, plural, one {# hour} other {# hours}}",
"intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}",
@@ -221,6 +222,7 @@
"lists.new.title_placeholder": "కొత్త జాబితా శీర్షిక",
"lists.search": "మీరు అనుసరించే వ్యక్తులలో శోధించండి",
"lists.subheading": "మీ జాబితాలు",
+ "load_pending": "{count, plural, one {# new item} other {# new items}}",
"loading_indicator.label": "లోడ్ అవుతోంది...",
"media_gallery.toggle_visible": "దృశ్యమానతను టోగుల్ చేయండి",
"missing_indicator.label": "దొరకలేదు",
@@ -314,6 +316,7 @@
"search_results.accounts": "వ్యక్తులు",
"search_results.hashtags": "హాష్ ట్యాగ్లు",
"search_results.statuses": "టూట్లు",
+ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.",
"search_results.total": "{count, number} {count, plural, one {result} other {results}}",
"status.admin_account": "@{name} కొరకు సమన్వయ వినిమయసీమను తెరువు",
"status.admin_status": "సమన్వయ వినిమయసీమలో ఈ స్టేటస్ ను తెరవండి",
diff --git a/app/javascript/mastodon/locales/th.json b/app/javascript/mastodon/locales/th.json
index 3bcf389c7f..e8d7a27edb 100644
--- a/app/javascript/mastodon/locales/th.json
+++ b/app/javascript/mastodon/locales/th.json
@@ -72,7 +72,7 @@
"compose_form.lock_disclaimer.lock": "ล็อคอยู่",
"compose_form.placeholder": "คุณกำลังคิดอะไรอยู่?",
"compose_form.poll.add_option": "เพิ่มทางเลือก",
- "compose_form.poll.duration": "Poll duration",
+ "compose_form.poll.duration": "ระยะเวลาการหยั่งเสียง",
"compose_form.poll.option_placeholder": "ทางเลือก {number}",
"compose_form.poll.remove_option": "เอาทางเลือกนี้ออก",
"compose_form.publish": "โพสต์",
@@ -156,9 +156,10 @@
"home.column_settings.basic": "พื้นฐาน",
"home.column_settings.show_reblogs": "แสดงการดัน",
"home.column_settings.show_replies": "แสดงการตอบกลับ",
- "intervals.full.days": "{number, plural, one {# day} other {# days}}",
- "intervals.full.hours": "{number, plural, one {# hour} other {# hours}}",
- "intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}",
+ "home.column_settings.update_live": "Update in real-time",
+ "intervals.full.days": "{number, plural, other {# วัน}}",
+ "intervals.full.hours": "{number, plural, other {# ชั่วโมง}}",
+ "intervals.full.minutes": "{number, plural, other {# นาที}}",
"introduction.federation.action": "ถัดไป",
"introduction.federation.federated.headline": "ที่ติดต่อกับภายนอก",
"introduction.federation.federated.text": "โพสต์สาธารณะจากเซิร์ฟเวอร์อื่น ๆ ของ Fediverse จะปรากฏในเส้นเวลาที่ติดต่อกับภายนอก",
@@ -221,6 +222,7 @@
"lists.new.title_placeholder": "ชื่อเรื่องรายการใหม่",
"lists.search": "ค้นหาในหมู่ผู้คนที่คุณติดตาม",
"lists.subheading": "รายการของคุณ",
+ "load_pending": "{count, plural, one {# new item} other {# new items}}",
"loading_indicator.label": "กำลังโหลด...",
"media_gallery.toggle_visible": "เปิด/ปิดการมองเห็น",
"missing_indicator.label": "ไม่พบ",
@@ -252,7 +254,7 @@
"notification.favourite": "{name} ได้ชื่นชอบสถานะของคุณ",
"notification.follow": "{name} ได้ติดตามคุณ",
"notification.mention": "{name} ได้กล่าวถึงคุณ",
- "notification.poll": "A poll you have voted in has ended",
+ "notification.poll": "การหยั่งเสียงที่คุณได้ลงคะแนนได้สิ้นสุดแล้ว",
"notification.reblog": "{name} ได้ดันสถานะของคุณ",
"notifications.clear": "ล้างการแจ้งเตือน",
"notifications.clear_confirmation": "คุณแน่ใจหรือไม่ว่าต้องการล้างการแจ้งเตือนทั้งหมดของคุณอย่างถาวร?",
@@ -263,7 +265,7 @@
"notifications.column_settings.filter_bar.show": "แสดง",
"notifications.column_settings.follow": "ผู้ติดตามใหม่:",
"notifications.column_settings.mention": "การกล่าวถึง:",
- "notifications.column_settings.poll": "Poll results:",
+ "notifications.column_settings.poll": "ผลลัพธ์การหยั่งเสียง:",
"notifications.column_settings.push": "การแจ้งเตือนแบบผลัก",
"notifications.column_settings.reblog": "การดัน:",
"notifications.column_settings.show": "แสดงในคอลัมน์",
@@ -273,14 +275,14 @@
"notifications.filter.favourites": "รายการโปรด",
"notifications.filter.follows": "การติดตาม",
"notifications.filter.mentions": "การกล่าวถึง",
- "notifications.filter.polls": "Poll results",
+ "notifications.filter.polls": "ผลลัพธ์การหยั่งเสียง",
"notifications.group": "{count} การแจ้งเตือน",
"poll.closed": "ปิดแล้ว",
"poll.refresh": "รีเฟรช",
- "poll.total_votes": "{count, plural, one {# vote} other {# votes}}",
- "poll.vote": "Vote",
- "poll_button.add_poll": "Add a poll",
- "poll_button.remove_poll": "Remove poll",
+ "poll.total_votes": "{count, plural, other {# การลงคะแนน}}",
+ "poll.vote": "ลงคะแนน",
+ "poll_button.add_poll": "เพิ่มการหยั่งเสียง",
+ "poll_button.remove_poll": "เอาการหยั่งเสียงออก",
"privacy.change": "ปรับเปลี่ยนความเป็นส่วนตัวของสถานะ",
"privacy.direct.long": "โพสต์ไปยังผู้ใช้ที่กล่าวถึงเท่านั้น",
"privacy.direct.short": "โดยตรง",
@@ -314,7 +316,8 @@
"search_results.accounts": "ผู้คน",
"search_results.hashtags": "แฮชแท็ก",
"search_results.statuses": "โพสต์",
- "search_results.total": "{count, number} {count, plural, one {result} other {results}}",
+ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.",
+ "search_results.total": "{count, number} {count, plural, other {ผลลัพธ์}}",
"status.admin_account": "เปิดส่วนติดต่อการควบคุมสำหรับ @{name}",
"status.admin_status": "เปิดสถานะนี้ในส่วนติดต่อการควบคุม",
"status.block": "ปิดกั้น @{name}",
@@ -361,11 +364,11 @@
"tabs_bar.local_timeline": "ในเว็บ",
"tabs_bar.notifications": "การแจ้งเตือน",
"tabs_bar.search": "ค้นหา",
- "time_remaining.days": "{number, plural, one {# day} other {# days}} left",
- "time_remaining.hours": "{number, plural, one {# hour} other {# hours}} left",
- "time_remaining.minutes": "{number, plural, one {# minute} other {# minutes}} left",
+ "time_remaining.days": "เหลืออีก {number, plural, other {# วัน}}",
+ "time_remaining.hours": "เหลืออีก {number, plural, other {# ชั่วโมง}}",
+ "time_remaining.minutes": "เหลืออีก {number, plural, other {# นาที}}",
"time_remaining.moments": "ช่วงเวลาที่เหลือ",
- "time_remaining.seconds": "{number, plural, one {# second} other {# seconds}} left",
+ "time_remaining.seconds": "เหลืออีก {number, plural, other {# วินาที}}",
"trends.count_by_accounts": "{count} {rawCount, plural, one {person} other {people}} talking",
"ui.beforeunload": "แบบร่างของคุณจะหายไปหากคุณออกจาก Mastodon",
"upload_area.title": "ลากแล้วปล่อยเพื่ออัปโหลด",
diff --git a/app/javascript/mastodon/locales/tr.json b/app/javascript/mastodon/locales/tr.json
index ec4657b9bf..0ea015cc64 100644
--- a/app/javascript/mastodon/locales/tr.json
+++ b/app/javascript/mastodon/locales/tr.json
@@ -156,6 +156,7 @@
"home.column_settings.basic": "Temel",
"home.column_settings.show_reblogs": "Boost edilenleri göster",
"home.column_settings.show_replies": "Cevapları göster",
+ "home.column_settings.update_live": "Update in real-time",
"intervals.full.days": "{number, plural, one {# day} other {# days}}",
"intervals.full.hours": "{number, plural, one {# hour} other {# hours}}",
"intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}",
@@ -221,6 +222,7 @@
"lists.new.title_placeholder": "Yeni liste başlığı",
"lists.search": "Takip ettiğiniz kişiler arasından arayın",
"lists.subheading": "Listeleriniz",
+ "load_pending": "{count, plural, one {# new item} other {# new items}}",
"loading_indicator.label": "Yükleniyor...",
"media_gallery.toggle_visible": "Görünürlüğü değiştir",
"missing_indicator.label": "Bulunamadı",
@@ -314,6 +316,7 @@
"search_results.accounts": "İnsanlar",
"search_results.hashtags": "Hashtagler",
"search_results.statuses": "Gönderiler",
+ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.",
"search_results.total": "{count, number} {count, plural, one {sonuç} other {sonuçlar}}",
"status.admin_account": "@{name} için denetim arayüzünü açın",
"status.admin_status": "Denetim arayüzünde bu durumu açın",
diff --git a/app/javascript/mastodon/locales/uk.json b/app/javascript/mastodon/locales/uk.json
index 124b9fb076..17e8cb49f4 100644
--- a/app/javascript/mastodon/locales/uk.json
+++ b/app/javascript/mastodon/locales/uk.json
@@ -156,6 +156,7 @@
"home.column_settings.basic": "Основні",
"home.column_settings.show_reblogs": "Показувати передмухи",
"home.column_settings.show_replies": "Показувати відповіді",
+ "home.column_settings.update_live": "Update in real-time",
"intervals.full.days": "{number, plural, one {# day} other {# days}}",
"intervals.full.hours": "{number, plural, one {# hour} other {# hours}}",
"intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}",
@@ -221,6 +222,7 @@
"lists.new.title_placeholder": "Нова назва списку",
"lists.search": "Шукати серед людей, на яких ви підписані",
"lists.subheading": "Ваші списки",
+ "load_pending": "{count, plural, one {# new item} other {# new items}}",
"loading_indicator.label": "Завантаження...",
"media_gallery.toggle_visible": "Показати/приховати",
"missing_indicator.label": "Не знайдено",
@@ -314,6 +316,7 @@
"search_results.accounts": "People",
"search_results.hashtags": "Hashtags",
"search_results.statuses": "Toots",
+ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.",
"search_results.total": "{count, number} {count, plural, one {результат} few {результати} many {результатів} other {результатів}}",
"status.admin_account": "Open moderation interface for @{name}",
"status.admin_status": "Open this status in the moderation interface",
diff --git a/app/javascript/mastodon/locales/zh-CN.json b/app/javascript/mastodon/locales/zh-CN.json
index 865d3a5142..bb774f1aaa 100644
--- a/app/javascript/mastodon/locales/zh-CN.json
+++ b/app/javascript/mastodon/locales/zh-CN.json
@@ -12,7 +12,7 @@
"account.followers": "关注者",
"account.followers.empty": "目前无人关注此用户。",
"account.follows": "正在关注",
- "account.follows.empty": "此用户目前没有关注任何人。",
+ "account.follows.empty": "此用户目前尚未关注任何人。",
"account.follows_you": "关注了你",
"account.hide_reblogs": "隐藏来自 @{name} 的转嘟",
"account.link_verified_on": "此链接的所有权已在 {date} 检查",
@@ -48,7 +48,7 @@
"column.community": "本站时间轴",
"column.direct": "私信",
"column.domain_blocks": "已屏蔽的网站",
- "column.favourites": "收藏过的嘟文",
+ "column.favourites": "收藏",
"column.follow_requests": "关注请求",
"column.home": "主页",
"column.lists": "列表",
@@ -92,11 +92,11 @@
"confirmations.delete_list.confirm": "删除",
"confirmations.delete_list.message": "你确定要永久删除这个列表吗?",
"confirmations.domain_block.confirm": "隐藏整个网站的内容",
- "confirmations.domain_block.message": "你真的确定要隐藏所有来自 {domain} 的内容吗?多数情况下,屏蔽或隐藏几个特定的用户应该就能满足你的需要了。来自该网站的内容将不再出现在你的公共时间轴或通知列表里。来自该网站的关注者将会被移除。",
+ "confirmations.domain_block.message": "你真的确定要隐藏所有来自 {domain} 的内容吗?多数情况下,屏蔽或隐藏几个特定的用户就已经足够了。来自该网站的内容将不再出现在你的任何公共时间轴或通知列表里。来自该网站的关注者将会被移除。",
"confirmations.mute.confirm": "隐藏",
"confirmations.mute.message": "你确定要隐藏 {name} 吗?",
"confirmations.redraft.confirm": "删除并重新编辑",
- "confirmations.redraft.message": "你确定要删除这条嘟文并重新编辑它吗?所有相关的转嘟和收藏都会被清除,回复将会被孤立。",
+ "confirmations.redraft.message": "你确定要删除这条嘟文并重新编辑它吗?所有相关的转嘟和收藏都会被清除,回复将会失去关联。",
"confirmations.reply.confirm": "回复",
"confirmations.reply.message": "回复此消息将会覆盖当前正在编辑的信息。确定继续吗?",
"confirmations.unfollow.confirm": "取消关注",
@@ -120,28 +120,28 @@
"empty_column.account_timeline": "这里没有嘟文!",
"empty_column.account_unavailable": "个人资料不可用",
"empty_column.blocks": "你目前没有屏蔽任何用户。",
- "empty_column.community": "本站时间轴暂时没有内容,快嘟几个来抢头香啊!",
+ "empty_column.community": "本站时间轴暂时没有内容,快写点什么让它动起来吧!",
"empty_column.direct": "你还没有使用过私信。当你发出或者收到私信时,它会在这里显示。",
"empty_column.domain_blocks": "目前没有被隐藏的站点。",
"empty_column.favourited_statuses": "你还没有收藏过任何嘟文。收藏过的嘟文会显示在这里。",
- "empty_column.favourites": "没人收藏过这条嘟文。假如有人收藏了,就会显示在这里。",
+ "empty_column.favourites": "没有人收藏过这条嘟文。如果有人收藏了,就会显示在这里。",
"empty_column.follow_requests": "你没有收到新的关注请求。收到了之后就会显示在这里。",
"empty_column.hashtag": "这个话题标签下暂时没有内容。",
- "empty_column.home": "你还没有关注任何用户。快看看{public},向其他用户搭讪吧。",
+ "empty_column.home": "你还没有关注任何用户。快看看{public},向其他人问个好吧。",
"empty_column.home.public_timeline": "公共时间轴",
"empty_column.list": "这个列表中暂时没有内容。列表中用户所发送的的新嘟文将会在这里显示。",
- "empty_column.lists": "你没有创建过列表。你创建的列表会在这里显示。",
+ "empty_column.lists": "你还没有创建过列表。你创建的列表会在这里显示。",
"empty_column.mutes": "你没有隐藏任何用户。",
- "empty_column.notifications": "你还没有收到过任何通知,快向其他用户搭讪吧。",
+ "empty_column.notifications": "你还没有收到过任何通知,快和其他用户互动吧。",
"empty_column.public": "这里什么都没有!写一些公开的嘟文,或者关注其他服务器的用户后,这里就会有嘟文出现了",
"follow_request.authorize": "同意",
"follow_request.reject": "拒绝",
"getting_started.developers": "开发",
- "getting_started.directory": "用户资料目录",
+ "getting_started.directory": "用户目录",
"getting_started.documentation": "文档",
"getting_started.heading": "开始使用",
"getting_started.invite": "邀请用户",
- "getting_started.open_source_notice": "Mastodon 是一个开源软件。欢迎前往 GitHub({github})贡献代码或反馈问题。",
+ "getting_started.open_source_notice": "Mastodon 是开源软件。欢迎前往 GitHub({github})贡献代码或反馈问题。",
"getting_started.security": "帐户安全",
"getting_started.terms": "使用条款",
"hashtag.column_header.tag_mode.all": "以及 {additional}",
@@ -156,14 +156,15 @@
"home.column_settings.basic": "基本设置",
"home.column_settings.show_reblogs": "显示转嘟",
"home.column_settings.show_replies": "显示回复",
+ "home.column_settings.update_live": "Update in real-time",
"intervals.full.days": "{number} 天",
"intervals.full.hours": "{number} 小时",
"intervals.full.minutes": "{number} 分钟",
"introduction.federation.action": "下一步",
"introduction.federation.federated.headline": "跨站",
- "introduction.federation.federated.text": "其他跨站服务器的公共动态会显示在跨站时间线中。",
+ "introduction.federation.federated.text": "联邦宇宙中其他服务器的公开嘟文会显示在跨站时间轴中。",
"introduction.federation.home.headline": "主页",
- "introduction.federation.home.text": "你所关注的用户的动态会显示在主页里。你可以关注任何服务器上的任何人!",
+ "introduction.federation.home.text": "你所关注的用户的动态会显示在主页里。你可以关注任何服务器上的任何人!",
"introduction.federation.local.headline": "本站",
"introduction.federation.local.text": "你所关注的用户的动态会显示在主页里,你可以关注任何服务器上的任何人。",
"introduction.interactions.action": "教程结束!",
@@ -172,10 +173,10 @@
"introduction.interactions.reblog.headline": "转嘟",
"introduction.interactions.reblog.text": "通过转嘟,你可以向你的关注者分享其他人的嘟文。",
"introduction.interactions.reply.headline": "回复",
- "introduction.interactions.reply.text": "你可以向其他人回复,这些回复会像对话一样串在一起。",
+ "introduction.interactions.reply.text": "你可以回复其他嘟文,这些回复会像对话一样关联在一起。",
"introduction.welcome.action": "让我们开始吧!",
"introduction.welcome.headline": "首先",
- "introduction.welcome.text": "欢迎来到联邦!稍后,您将可以广播消息并和您的朋友交流,这些消息将穿越于联邦中的各式服务器。但是这台服务器,{domain},是特殊的——它保存了你的个人资料,所以请记住它的名字。",
+ "introduction.welcome.text": "欢迎来到联邦宇宙!很快,您就可以发布信息并和您的朋友交流,这些消息将发送到联邦中的各个服务器中。但是这台服务器,{domain},是特殊的——它保存了你的个人资料,所以请记住它的名字。",
"keyboard_shortcuts.back": "返回上一页",
"keyboard_shortcuts.blocked": "打开被屏蔽用户列表",
"keyboard_shortcuts.boost": "转嘟",
@@ -194,9 +195,9 @@
"keyboard_shortcuts.legend": "显示此列表",
"keyboard_shortcuts.local": "打开本站时间轴",
"keyboard_shortcuts.mention": "提及嘟文作者",
- "keyboard_shortcuts.muted": "打开屏蔽用户列表",
+ "keyboard_shortcuts.muted": "打开隐藏用户列表",
"keyboard_shortcuts.my_profile": "打开你的个人资料",
- "keyboard_shortcuts.notifications": "打卡通知栏",
+ "keyboard_shortcuts.notifications": "打开通知栏",
"keyboard_shortcuts.pinned": "打开置顶嘟文列表",
"keyboard_shortcuts.profile": "打开作者的个人资料",
"keyboard_shortcuts.reply": "回复嘟文",
@@ -213,7 +214,7 @@
"lightbox.previous": "上一个",
"lightbox.view_context": "查看上下文",
"lists.account.add": "添加到列表",
- "lists.account.remove": "从列表中删除",
+ "lists.account.remove": "从列表中移除",
"lists.delete": "删除列表",
"lists.edit": "编辑列表",
"lists.edit.submit": "更改标题",
@@ -221,6 +222,7 @@
"lists.new.title_placeholder": "新列表的标题",
"lists.search": "搜索你关注的人",
"lists.subheading": "你的列表",
+ "load_pending": "{count, plural, one {# new item} other {# new items}}",
"loading_indicator.label": "加载中……",
"media_gallery.toggle_visible": "切换显示/隐藏",
"missing_indicator.label": "找不到内容",
@@ -235,29 +237,29 @@
"navigation_bar.domain_blocks": "已屏蔽的网站",
"navigation_bar.edit_profile": "修改个人资料",
"navigation_bar.favourites": "收藏的内容",
- "navigation_bar.filters": "被隐藏的词",
+ "navigation_bar.filters": "屏蔽关键词",
"navigation_bar.follow_requests": "关注请求",
- "navigation_bar.follows_and_followers": "正在关注以及关注者",
+ "navigation_bar.follows_and_followers": "关注管理",
"navigation_bar.info": "关于本站",
"navigation_bar.keyboard_shortcuts": "快捷键列表",
"navigation_bar.lists": "列表",
- "navigation_bar.logout": "注销",
+ "navigation_bar.logout": "登出",
"navigation_bar.mutes": "已隐藏的用户",
"navigation_bar.personal": "个人",
"navigation_bar.pins": "置顶嘟文",
"navigation_bar.preferences": "首选项",
- "navigation_bar.profile_directory": "用户资料目录",
+ "navigation_bar.profile_directory": "用户目录",
"navigation_bar.public_timeline": "跨站公共时间轴",
"navigation_bar.security": "安全",
"notification.favourite": "{name} 收藏了你的嘟文",
"notification.follow": "{name} 开始关注你",
- "notification.mention": "{name} 提及你",
+ "notification.mention": "{name} 提及了你",
"notification.poll": "你参与的一个投票已经结束",
- "notification.reblog": "{name} 转了你的嘟文",
+ "notification.reblog": "{name} 转嘟了你的嘟文",
"notifications.clear": "清空通知列表",
"notifications.clear_confirmation": "你确定要永久清空通知列表吗?",
"notifications.column_settings.alert": "桌面通知",
- "notifications.column_settings.favourite": "你的嘟文被收藏时:",
+ "notifications.column_settings.favourite": "当你的嘟文被收藏时:",
"notifications.column_settings.filter_bar.advanced": "显示所有类别",
"notifications.column_settings.filter_bar.category": "快速过滤栏",
"notifications.column_settings.filter_bar.show": "显示",
@@ -301,25 +303,26 @@
"report.forward": "发送举报至 {target}",
"report.forward_hint": "这名用户来自另一个服务器。是否要向那个服务器发送一条匿名的举报?",
"report.hint": "举报将会发送给你所在服务器的监察员。你可以在下面填写举报该用户的理由:",
- "report.placeholder": "附言",
+ "report.placeholder": "备注",
"report.submit": "提交",
"report.target": "举报 {target}",
"search.placeholder": "搜索",
"search_popout.search_format": "高级搜索格式",
- "search_popout.tips.full_text": "输入其他内容将会返回所有你撰写、收藏、转嘟过或提及到你的嘟文,同时也会在用户名、昵称和话题标签中进行搜索。",
+ "search_popout.tips.full_text": "输入关键词检索所有你发送、收藏、转嘟过或提及到你的嘟文,以及其他用户公开的用户名、昵称和话题标签。",
"search_popout.tips.hashtag": "话题标签",
"search_popout.tips.status": "嘟文",
- "search_popout.tips.text": "输入其他内容将会返回昵称、用户名和话题标签",
+ "search_popout.tips.text": "输入关键词检索昵称、用户名和话题标签",
"search_popout.tips.user": "用户",
"search_results.accounts": "用户",
"search_results.hashtags": "话题标签",
"search_results.statuses": "嘟文",
+ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.",
"search_results.total": "共 {count, number} 个结果",
"status.admin_account": "打开 @{name} 的管理界面",
"status.admin_status": "打开这条嘟文的管理界面",
"status.block": "屏蔽 @{name}",
"status.cancel_reblog_private": "取消转嘟",
- "status.cannot_reblog": "无法转嘟这条嘟文",
+ "status.cannot_reblog": "这条嘟文不允许被转嘟",
"status.copy": "复制嘟文链接",
"status.delete": "删除",
"status.detailed_status": "对话详情",
@@ -338,9 +341,9 @@
"status.pinned": "置顶嘟文",
"status.read_more": "阅读全文",
"status.reblog": "转嘟",
- "status.reblog_private": "转嘟给原有关注者",
+ "status.reblog_private": "转嘟(可见者不变)",
"status.reblogged_by": "{name} 转嘟了",
- "status.reblogs.empty": "无人转嘟此条。如果有人转嘟了,就会显示在这里。",
+ "status.reblogs.empty": "没有人转嘟过此条嘟文。如果有人转嘟了,就会显示在这里。",
"status.redraft": "删除并重新编辑",
"status.reply": "回复",
"status.replyAll": "回复所有人",
@@ -367,15 +370,15 @@
"time_remaining.moments": "即将结束",
"time_remaining.seconds": "剩余 {number, plural, one {# 秒} other {# 秒}}",
"trends.count_by_accounts": "{count} 人正在讨论",
- "ui.beforeunload": "如果你现在离开 Mastodon,你的草稿内容将会被丢弃。",
+ "ui.beforeunload": "如果你现在离开 Mastodon,你的草稿内容将会丢失。",
"upload_area.title": "将文件拖放到此处开始上传",
"upload_button.label": "上传媒体文件 (JPEG, PNG, GIF, WebM, MP4, MOV)",
- "upload_error.limit": "超过文件上传限制。",
+ "upload_error.limit": "文件大小超过限制。",
"upload_error.poll": "投票中不允许上传文件。",
"upload_form.description": "为视觉障碍人士添加文字说明",
- "upload_form.focus": "剪裁",
+ "upload_form.focus": "设置缩略图",
"upload_form.undo": "删除",
- "upload_progress.label": "上传中…",
+ "upload_progress.label": "上传中……",
"video.close": "关闭视频",
"video.exit_fullscreen": "退出全屏",
"video.expand": "展开视频",
diff --git a/app/javascript/mastodon/locales/zh-HK.json b/app/javascript/mastodon/locales/zh-HK.json
index 2cfc11703d..b4c8b874a8 100644
--- a/app/javascript/mastodon/locales/zh-HK.json
+++ b/app/javascript/mastodon/locales/zh-HK.json
@@ -156,6 +156,7 @@
"home.column_settings.basic": "基本",
"home.column_settings.show_reblogs": "顯示被轉推的文章",
"home.column_settings.show_replies": "顯示回應文章",
+ "home.column_settings.update_live": "Update in real-time",
"intervals.full.days": "{number, plural, one {# day} other {# days}}",
"intervals.full.hours": "{number, plural, one {# hour} other {# hours}}",
"intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}",
@@ -221,6 +222,7 @@
"lists.new.title_placeholder": "新列表標題",
"lists.search": "從你關注的用戶中搜索",
"lists.subheading": "列表",
+ "load_pending": "{count, plural, one {# new item} other {# new items}}",
"loading_indicator.label": "載入中...",
"media_gallery.toggle_visible": "打開或關上",
"missing_indicator.label": "找不到內容",
@@ -314,6 +316,7 @@
"search_results.accounts": "使用者",
"search_results.hashtags": "標籤",
"search_results.statuses": "文章",
+ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.",
"search_results.total": "{count, number} 項結果",
"status.admin_account": "Open moderation interface for @{name}",
"status.admin_status": "Open this status in the moderation interface",
diff --git a/app/javascript/mastodon/locales/zh-TW.json b/app/javascript/mastodon/locales/zh-TW.json
index 5715ef01a1..5f75b38d6c 100644
--- a/app/javascript/mastodon/locales/zh-TW.json
+++ b/app/javascript/mastodon/locales/zh-TW.json
@@ -156,6 +156,7 @@
"home.column_settings.basic": "基本",
"home.column_settings.show_reblogs": "顯示轉推",
"home.column_settings.show_replies": "顯示回覆",
+ "home.column_settings.update_live": "Update in real-time",
"intervals.full.days": "{number, plural, one {# 天} other {# 天}}",
"intervals.full.hours": "{number, plural, one {# 小時} other {# 小時}}",
"intervals.full.minutes": "{number, plural, one {# 分鐘} other {# 分鐘}}",
@@ -221,6 +222,7 @@
"lists.new.title_placeholder": "新名單標題",
"lists.search": "搜尋您關注的使用者",
"lists.subheading": "您的名單",
+ "load_pending": "{count, plural, one {# new item} other {# new items}}",
"loading_indicator.label": "讀取中...",
"media_gallery.toggle_visible": "切換可見性",
"missing_indicator.label": "找不到",
@@ -314,6 +316,7 @@
"search_results.accounts": "使用者",
"search_results.hashtags": "主題標籤",
"search_results.statuses": "嘟文",
+ "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.",
"search_results.total": "{count, number} 項結果",
"status.admin_account": "開啟 @{name} 的管理介面",
"status.admin_status": "在管理介面開啟此嘟文",
diff --git a/app/javascript/packs/public.js b/app/javascript/packs/public.js
index 69e6ba0ecc..69441d3150 100644
--- a/app/javascript/packs/public.js
+++ b/app/javascript/packs/public.js
@@ -91,14 +91,6 @@ function main() {
if (parallaxComponents.length > 0 ) {
new Rellax('.parallax', { speed: -1 });
}
-
- if (document.body.classList.contains('with-modals')) {
- const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;
- const scrollbarWidthStyle = document.createElement('style');
- scrollbarWidthStyle.id = 'scrollbar-width';
- document.head.appendChild(scrollbarWidthStyle);
- scrollbarWidthStyle.sheet.insertRule(`body.with-modals--active { margin-right: ${scrollbarWidth}px; }`, 0);
- }
});
}
diff --git a/app/javascript/styles/application.scss b/app/javascript/styles/application.scss
index 6db3bc3dc9..8ebc45b62d 100644
--- a/app/javascript/styles/application.scss
+++ b/app/javascript/styles/application.scss
@@ -13,7 +13,7 @@
@import 'mastodon/widgets';
@import 'mastodon/forms';
@import 'mastodon/accounts';
-@import 'mastodon/stream_entries';
+@import 'mastodon/statuses';
@import 'mastodon/boost';
@import 'mastodon/components';
@import 'mastodon/polls';
diff --git a/app/javascript/styles/mastodon/basics.scss b/app/javascript/styles/mastodon/basics.scss
index b5a77ce94f..7df76bdff6 100644
--- a/app/javascript/styles/mastodon/basics.scss
+++ b/app/javascript/styles/mastodon/basics.scss
@@ -8,7 +8,7 @@
body {
font-family: $font-sans-serif, sans-serif;
- background: darken($ui-base-color, 8%);
+ background: darken($ui-base-color, 7%);
font-size: 13px;
line-height: 18px;
font-weight: 400;
@@ -35,11 +35,19 @@ body {
}
&.app-body {
- position: absolute;
- width: 100%;
- height: 100%;
padding: 0;
- background: $ui-base-color;
+
+ &.layout-single-column {
+ height: auto;
+ min-height: 100%;
+ overflow-y: scroll;
+ }
+
+ &.layout-multiple-columns {
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ }
&.with-modals--active {
overflow-y: hidden;
@@ -56,7 +64,6 @@ body {
&--active {
overflow-y: hidden;
- margin-right: 13px;
}
}
@@ -134,9 +141,22 @@ button {
& > div {
display: flex;
width: 100%;
- height: 100%;
align-items: center;
justify-content: center;
outline: 0 !important;
}
}
+
+.layout-single-column .app-holder {
+ &,
+ & > div {
+ min-height: 100%;
+ }
+}
+
+.layout-multiple-columns .app-holder {
+ &,
+ & > div {
+ height: 100%;
+ }
+}
diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss
index 1063d18366..1ff0b234e7 100644
--- a/app/javascript/styles/mastodon/components.scss
+++ b/app/javascript/styles/mastodon/components.scss
@@ -1804,6 +1804,7 @@ a.account__display-name {
justify-content: center;
width: 100%;
height: 100%;
+ min-height: 100vh;
&__pane {
height: 100%;
@@ -1817,6 +1818,7 @@ a.account__display-name {
}
&__inner {
+ position: fixed;
width: 285px;
pointer-events: auto;
height: 100%;
@@ -1871,7 +1873,6 @@ a.account__display-name {
flex-direction: column;
width: 100%;
height: 100%;
- background: darken($ui-base-color, 7%);
}
.drawer {
@@ -2012,6 +2013,10 @@ a.account__display-name {
top: 15px;
}
+ .scrollable {
+ overflow: visible;
+ }
+
@media screen and (min-width: $no-gap-breakpoint) {
padding: 10px 0;
}
diff --git a/app/javascript/styles/mastodon/containers.scss b/app/javascript/styles/mastodon/containers.scss
index 3564bf07b4..2b6794ee2c 100644
--- a/app/javascript/styles/mastodon/containers.scss
+++ b/app/javascript/styles/mastodon/containers.scss
@@ -145,6 +145,10 @@
min-height: 100%;
}
+ .flash-message {
+ margin-bottom: 10px;
+ }
+
@media screen and (max-width: 738px) {
grid-template-columns: minmax(0, 50%) minmax(0, 50%);
diff --git a/app/javascript/styles/mastodon/stream_entries.scss b/app/javascript/styles/mastodon/statuses.scss
similarity index 100%
rename from app/javascript/styles/mastodon/stream_entries.scss
rename to app/javascript/styles/mastodon/statuses.scss
diff --git a/app/lib/activitypub/activity/announce.rb b/app/lib/activitypub/activity/announce.rb
index 1aa6ee9ec2..34c646668b 100644
--- a/app/lib/activitypub/activity/announce.rb
+++ b/app/lib/activitypub/activity/announce.rb
@@ -40,7 +40,7 @@ class ActivityPub::Activity::Announce < ActivityPub::Activity
end
def announceable?(status)
- status.account_id == @account.id || status.public_visibility? || status.unlisted_visibility?
+ status.account_id == @account.id || status.distributable?
end
def related_to_local_activity?
diff --git a/app/lib/activitypub/activity/create.rb b/app/lib/activitypub/activity/create.rb
index 00f0dd42d7..56c24680a7 100644
--- a/app/lib/activitypub/activity/create.rb
+++ b/app/lib/activitypub/activity/create.rb
@@ -41,8 +41,9 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
resolve_thread(@status)
fetch_replies(@status)
+ check_for_spam
distribute(@status)
- forward_for_reply if @status.public_visibility? || @status.unlisted_visibility?
+ forward_for_reply if @status.distributable?
end
def find_existing_status
@@ -406,6 +407,18 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
Account.local.where(username: local_usernames).exists?
end
+ def check_for_spam
+ spam_check = SpamCheck.new(@status)
+
+ return if spam_check.skip?
+
+ if spam_check.spam?
+ spam_check.flag!
+ else
+ spam_check.remember!
+ end
+ end
+
def forward_for_reply
return unless @json['signature'].present? && reply_to_local?
ActivityPub::RawDistributionWorker.perform_async(Oj.dump(@json), replied_to_status.account_id, [@account.preferred_inbox_url])
diff --git a/app/lib/activitypub/activity/delete.rb b/app/lib/activitypub/activity/delete.rb
index 0eb14b89ce..1f2b40c150 100644
--- a/app/lib/activitypub/activity/delete.rb
+++ b/app/lib/activitypub/activity/delete.rb
@@ -31,7 +31,7 @@ class ActivityPub::Activity::Delete < ActivityPub::Activity
return if @status.nil?
- if @status.public_visibility? || @status.unlisted_visibility?
+ if @status.distributable?
forward_for_reply
forward_for_reblogs
end
diff --git a/app/lib/activitypub/activity/follow.rb b/app/lib/activitypub/activity/follow.rb
index 3eb88339ae..28f1da19f8 100644
--- a/app/lib/activitypub/activity/follow.rb
+++ b/app/lib/activitypub/activity/follow.rb
@@ -8,7 +8,7 @@ class ActivityPub::Activity::Follow < ActivityPub::Activity
return if target_account.nil? || !target_account.local? || delete_arrived_first?(@json['id']) || @account.requested?(target_account)
- if target_account.blocking?(@account) || target_account.domain_blocking?(@account.domain) || target_account.moved?
+ if target_account.blocking?(@account) || target_account.domain_blocking?(@account.domain) || target_account.moved? || target_account.instance_actor?
reject_follow_request!(target_account)
return
end
diff --git a/app/lib/activitypub/adapter.rb b/app/lib/activitypub/adapter.rb
index c259c96f41..a1d84de2fb 100644
--- a/app/lib/activitypub/adapter.rb
+++ b/app/lib/activitypub/adapter.rb
@@ -33,6 +33,7 @@ class ActivityPub::Adapter < ActiveModelSerializers::Adapter::Base
def serializable_hash(options = nil)
options = serialization_options(options)
serialized_hash = serializer.serializable_hash(options)
+ serialized_hash = serialized_hash.select { |k, _| options[:fields].include?(k) } if options[:fields]
serialized_hash = self.class.transform_key_casing!(serialized_hash, instance_options)
{ '@context' => serialized_context }.merge(serialized_hash)
diff --git a/app/lib/activitypub/tag_manager.rb b/app/lib/activitypub/tag_manager.rb
index 595291342a..512272dbeb 100644
--- a/app/lib/activitypub/tag_manager.rb
+++ b/app/lib/activitypub/tag_manager.rb
@@ -17,7 +17,7 @@ class ActivityPub::TagManager
case target.object_type
when :person
- short_account_url(target)
+ target.instance_actor? ? about_more_url(instance_actor: true) : short_account_url(target)
when :note, :comment, :activity
return activity_account_status_url(target.account, target) if target.reblog?
short_account_status_url(target.account, target)
@@ -29,7 +29,7 @@ class ActivityPub::TagManager
case target.object_type
when :person
- account_url(target)
+ target.instance_actor? ? instance_actor_url : account_url(target)
when :note, :comment, :activity
return activity_account_status_url(target.account, target) if target.reblog?
account_status_url(target.account, target)
@@ -51,7 +51,7 @@ class ActivityPub::TagManager
def replies_uri_for(target, page_params = nil)
raise ArgumentError, 'target must be a local activity' unless %i(note comment activity).include?(target.object_type) && target.local?
- replies_account_status_url(target.account, target, page_params)
+ account_status_replies_url(target.account, target, page_params)
end
# Primary audience of a status
@@ -119,6 +119,7 @@ class ActivityPub::TagManager
def uri_to_local_id(uri, param = :id)
path_params = Rails.application.routes.recognize_path(uri)
+ path_params[:username] = Rails.configuration.x.local_domain if path_params[:controller] == 'instance_actors'
path_params[param]
end
diff --git a/app/lib/formatter.rb b/app/lib/formatter.rb
index 4c11ca2914..85bc8eb1f9 100644
--- a/app/lib/formatter.rb
+++ b/app/lib/formatter.rb
@@ -314,7 +314,7 @@ class Formatter
gaps = []
total_offset = 0
- escaped = html.gsub(/<[^>]*>/) do |match|
+ escaped = html.gsub(/<[^>]*>|[0-9]+;/) do |match|
total_offset += match.length - 1
end_offset = Regexp.last_match.end(0)
gaps << [end_offset - total_offset, total_offset]
@@ -381,6 +381,6 @@ class Formatter
end
def mention_html(account)
- "@#{encode(account.username)}"
+ "@#{encode(account.username)}"
end
end
diff --git a/app/lib/language_detector.rb b/app/lib/language_detector.rb
index 1e90af42d7..6f9511a541 100644
--- a/app/lib/language_detector.rb
+++ b/app/lib/language_detector.rb
@@ -69,7 +69,7 @@ class LanguageDetector
new_text = remove_html(text)
new_text.gsub!(FetchLinkCardService::URL_PATTERN, '')
new_text.gsub!(Account::MENTION_RE, '')
- new_text.gsub!(Tag::HASHTAG_RE, '')
+ new_text.gsub!(Tag::HASHTAG_RE) { |string| string.gsub(/[#_]/, '#' => '', '_' => ' ').gsub(/[a-z][A-Z]|[a-zA-Z][\d]/) { |s| s.insert(1, ' ') }.downcase }
new_text.gsub!(/:#{CustomEmoji::SHORTCODE_RE_FRAGMENT}:/, '')
new_text.gsub!(/\s+/, ' ')
new_text
diff --git a/app/lib/ostatus/activity/base.rb b/app/lib/ostatus/activity/base.rb
deleted file mode 100644
index db70f19980..0000000000
--- a/app/lib/ostatus/activity/base.rb
+++ /dev/null
@@ -1,71 +0,0 @@
-# frozen_string_literal: true
-
-class OStatus::Activity::Base
- include Redisable
-
- def initialize(xml, account = nil, **options)
- @xml = xml
- @account = account
- @options = options
- end
-
- def status?
- [:activity, :note, :comment].include?(type)
- end
-
- def verb
- raw = @xml.at_xpath('./activity:verb', activity: OStatus::TagManager::AS_XMLNS).content
- OStatus::TagManager::VERBS.key(raw)
- rescue
- :post
- end
-
- def type
- raw = @xml.at_xpath('./activity:object-type', activity: OStatus::TagManager::AS_XMLNS).content
- OStatus::TagManager::TYPES.key(raw)
- rescue
- :activity
- end
-
- def id
- @xml.at_xpath('./xmlns:id', xmlns: OStatus::TagManager::XMLNS).content
- end
-
- def url
- link = @xml.xpath('./xmlns:link[@rel="alternate"]', xmlns: OStatus::TagManager::XMLNS).find { |link_candidate| link_candidate['type'] == 'text/html' }
- link.nil? ? nil : link['href']
- end
-
- def activitypub_uri
- link = @xml.xpath('./xmlns:link[@rel="alternate"]', xmlns: OStatus::TagManager::XMLNS).find { |link_candidate| ['application/activity+json', 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"'].include?(link_candidate['type']) }
- link.nil? ? nil : link['href']
- end
-
- def activitypub_uri?
- activitypub_uri.present?
- end
-
- private
-
- def find_status(uri)
- if OStatus::TagManager.instance.local_id?(uri)
- local_id = OStatus::TagManager.instance.unique_tag_to_local_id(uri, 'Status')
- return Status.find_by(id: local_id)
- elsif ActivityPub::TagManager.instance.local_uri?(uri)
- local_id = ActivityPub::TagManager.instance.uri_to_local_id(uri)
- return Status.find_by(id: local_id)
- end
-
- Status.find_by(uri: uri)
- end
-
- def find_activitypub_status(uri, href)
- tag_matches = /tag:([^,:]+)[^:]*:objectId=([\d]+)/.match(uri)
- href_matches = %r{/users/([^/]+)}.match(href)
-
- unless tag_matches.nil? || href_matches.nil?
- uri = "https://#{tag_matches[1]}/users/#{href_matches[1]}/statuses/#{tag_matches[2]}"
- Status.find_by(uri: uri)
- end
- end
-end
diff --git a/app/lib/ostatus/activity/creation.rb b/app/lib/ostatus/activity/creation.rb
deleted file mode 100644
index 60de712db8..0000000000
--- a/app/lib/ostatus/activity/creation.rb
+++ /dev/null
@@ -1,219 +0,0 @@
-# frozen_string_literal: true
-
-class OStatus::Activity::Creation < OStatus::Activity::Base
- def perform
- if redis.exists("delete_upon_arrival:#{@account.id}:#{id}")
- Rails.logger.debug "Delete for status #{id} was queued, ignoring"
- return [nil, false]
- end
-
- return [nil, false] if @account.suspended? || invalid_origin?
-
- RedisLock.acquire(lock_options) do |lock|
- if lock.acquired?
- # Return early if status already exists in db
- @status = find_status(id)
- return [@status, false] unless @status.nil?
- @status = process_status
- else
- raise Mastodon::RaceConditionError
- end
- end
-
- [@status, true]
- end
-
- def process_status
- Rails.logger.debug "Creating remote status #{id}"
- cached_reblog = reblog
- status = nil
-
- # Skip if the reblogged status is not public
- return if cached_reblog && !(cached_reblog.public_visibility? || cached_reblog.unlisted_visibility?)
-
- media_attachments = save_media.take(4)
-
- ApplicationRecord.transaction do
- status = Status.create!(
- uri: id,
- url: url,
- account: @account,
- reblog: cached_reblog,
- text: content,
- spoiler_text: content_warning,
- created_at: published,
- override_timestamps: @options[:override_timestamps],
- reply: thread?,
- language: content_language,
- visibility: visibility_scope,
- conversation: find_or_create_conversation,
- thread: thread? ? find_status(thread.first) || find_activitypub_status(thread.first, thread.second) : nil,
- media_attachment_ids: media_attachments.map(&:id),
- sensitive: sensitive?
- )
-
- save_mentions(status)
- save_hashtags(status)
- save_emojis(status)
- end
-
- if thread? && status.thread.nil? && Request.valid_url?(thread.second)
- Rails.logger.debug "Trying to attach #{status.id} (#{id}) to #{thread.first}"
- ThreadResolveWorker.perform_async(status.id, thread.second)
- end
-
- Rails.logger.debug "Queuing remote status #{status.id} (#{id}) for distribution"
-
- LinkCrawlWorker.perform_async(status.id) unless status.spoiler_text?
-
- # Only continue if the status is supposed to have arrived in real-time.
- # Note that if @options[:override_timestamps] isn't set, the status
- # may have a lower snowflake id than other existing statuses, potentially
- # "hiding" it from paginated API calls
- return status unless @options[:override_timestamps] || status.within_realtime_window?
-
- DistributionWorker.perform_async(status.id)
-
- status
- end
-
- def content
- @xml.at_xpath('./xmlns:content', xmlns: OStatus::TagManager::XMLNS).content
- end
-
- def content_language
- @xml.at_xpath('./xmlns:content', xmlns: OStatus::TagManager::XMLNS)['xml:lang']&.presence || 'en'
- end
-
- def content_warning
- @xml.at_xpath('./xmlns:summary', xmlns: OStatus::TagManager::XMLNS)&.content || ''
- end
-
- def visibility_scope
- @xml.at_xpath('./mastodon:scope', mastodon: OStatus::TagManager::MTDN_XMLNS)&.content&.to_sym || :public
- end
-
- def published
- @xml.at_xpath('./xmlns:published', xmlns: OStatus::TagManager::XMLNS).content
- end
-
- def thread?
- !@xml.at_xpath('./thr:in-reply-to', thr: OStatus::TagManager::THR_XMLNS).nil?
- end
-
- def thread
- thr = @xml.at_xpath('./thr:in-reply-to', thr: OStatus::TagManager::THR_XMLNS)
- [thr['ref'], thr['href']]
- end
-
- private
-
- def sensitive?
- # OStatus-specific convention (not standard)
- @xml.xpath('./xmlns:category', xmlns: OStatus::TagManager::XMLNS).any? { |category| category['term'] == 'nsfw' }
- end
-
- def find_or_create_conversation
- uri = @xml.at_xpath('./ostatus:conversation', ostatus: OStatus::TagManager::OS_XMLNS)&.attribute('ref')&.content
- return if uri.nil?
-
- if OStatus::TagManager.instance.local_id?(uri)
- local_id = OStatus::TagManager.instance.unique_tag_to_local_id(uri, 'Conversation')
- return Conversation.find_by(id: local_id)
- end
-
- Conversation.find_by(uri: uri) || Conversation.create!(uri: uri)
- end
-
- def save_mentions(parent)
- processed_account_ids = []
-
- @xml.xpath('./xmlns:link[@rel="mentioned"]', xmlns: OStatus::TagManager::XMLNS).each do |link|
- next if [OStatus::TagManager::TYPES[:group], OStatus::TagManager::TYPES[:collection]].include? link['ostatus:object-type']
-
- mentioned_account = account_from_href(link['href'])
-
- next if mentioned_account.nil? || processed_account_ids.include?(mentioned_account.id)
-
- mentioned_account.mentions.where(status: parent).first_or_create(status: parent)
-
- # So we can skip duplicate mentions
- processed_account_ids << mentioned_account.id
- end
- end
-
- def save_hashtags(parent)
- tags = @xml.xpath('./xmlns:category', xmlns: OStatus::TagManager::XMLNS).map { |category| category['term'] }.select(&:present?)
- ProcessHashtagsService.new.call(parent, tags)
- end
-
- def save_media
- do_not_download = DomainBlock.reject_media?(@account.domain)
- media_attachments = []
-
- @xml.xpath('./xmlns:link[@rel="enclosure"]', xmlns: OStatus::TagManager::XMLNS).each do |link|
- next unless link['href']
-
- media = MediaAttachment.where(status: nil, remote_url: link['href']).first_or_initialize(account: @account, status: nil, remote_url: link['href'])
- parsed_url = Addressable::URI.parse(link['href']).normalize
-
- next if !%w(http https).include?(parsed_url.scheme) || parsed_url.host.empty?
-
- media.save
- media_attachments << media
-
- next if do_not_download
-
- begin
- media.file_remote_url = link['href']
- media.save!
- rescue ActiveRecord::RecordInvalid
- next
- end
- end
-
- media_attachments
- end
-
- def save_emojis(parent)
- do_not_download = DomainBlock.reject_media?(parent.account.domain)
-
- return if do_not_download
-
- @xml.xpath('./xmlns:link[@rel="emoji"]', xmlns: OStatus::TagManager::XMLNS).each do |link|
- next unless link['href'] && link['name']
-
- shortcode = link['name'].delete(':')
- emoji = CustomEmoji.find_by(shortcode: shortcode, domain: parent.account.domain)
-
- next unless emoji.nil?
-
- emoji = CustomEmoji.new(shortcode: shortcode, domain: parent.account.domain)
- emoji.image_remote_url = link['href']
- emoji.save
- end
- end
-
- def account_from_href(href)
- url = Addressable::URI.parse(href).normalize
-
- if TagManager.instance.web_domain?(url.host)
- Account.find_local(url.path.gsub('/users/', ''))
- else
- Account.where(uri: href).or(Account.where(url: href)).first || FetchRemoteAccountService.new.call(href)
- end
- end
-
- def invalid_origin?
- return false unless id.start_with?('http') # Legacy IDs cannot be checked
-
- needle = Addressable::URI.parse(id).normalized_host
-
- !(needle.casecmp(@account.domain).zero? ||
- needle.casecmp(Addressable::URI.parse(@account.remote_url.presence || @account.uri).normalized_host).zero?)
- end
-
- def lock_options
- { redis: Redis.current, key: "create:#{id}" }
- end
-end
diff --git a/app/lib/ostatus/activity/deletion.rb b/app/lib/ostatus/activity/deletion.rb
deleted file mode 100644
index c98f5ee0ad..0000000000
--- a/app/lib/ostatus/activity/deletion.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-# frozen_string_literal: true
-
-class OStatus::Activity::Deletion < OStatus::Activity::Base
- def perform
- Rails.logger.debug "Deleting remote status #{id}"
-
- status = Status.find_by(uri: id, account: @account)
- status ||= Status.find_by(uri: activitypub_uri, account: @account) if activitypub_uri?
-
- if status.nil?
- redis.setex("delete_upon_arrival:#{@account.id}:#{id}", 6 * 3_600, id)
- else
- RemoveStatusService.new.call(status)
- end
- end
-end
diff --git a/app/lib/ostatus/activity/general.rb b/app/lib/ostatus/activity/general.rb
deleted file mode 100644
index 8a6aabc337..0000000000
--- a/app/lib/ostatus/activity/general.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-# frozen_string_literal: true
-
-class OStatus::Activity::General < OStatus::Activity::Base
- def specialize
- special_class&.new(@xml, @account, @options)
- end
-
- private
-
- def special_class
- case verb
- when :post
- OStatus::Activity::Post
- when :share
- OStatus::Activity::Share
- when :delete
- OStatus::Activity::Deletion
- end
- end
-end
diff --git a/app/lib/ostatus/activity/post.rb b/app/lib/ostatus/activity/post.rb
deleted file mode 100644
index 755ed86563..0000000000
--- a/app/lib/ostatus/activity/post.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-# frozen_string_literal: true
-
-class OStatus::Activity::Post < OStatus::Activity::Creation
- def perform
- status, just_created = super
-
- if just_created
- status.mentions.includes(:account).each do |mention|
- mentioned_account = mention.account
- next unless mentioned_account.local?
- NotifyService.new.call(mentioned_account, mention)
- end
- end
-
- status
- end
-
- private
-
- def reblog
- nil
- end
-end
diff --git a/app/lib/ostatus/activity/remote.rb b/app/lib/ostatus/activity/remote.rb
deleted file mode 100644
index 5b204b6d8f..0000000000
--- a/app/lib/ostatus/activity/remote.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-# frozen_string_literal: true
-
-class OStatus::Activity::Remote < OStatus::Activity::Base
- def perform
- if activitypub_uri?
- find_status(activitypub_uri) || FetchRemoteStatusService.new.call(url)
- else
- find_status(id) || FetchRemoteStatusService.new.call(url)
- end
- end
-end
diff --git a/app/lib/ostatus/activity/share.rb b/app/lib/ostatus/activity/share.rb
deleted file mode 100644
index 5ca6014154..0000000000
--- a/app/lib/ostatus/activity/share.rb
+++ /dev/null
@@ -1,26 +0,0 @@
-# frozen_string_literal: true
-
-class OStatus::Activity::Share < OStatus::Activity::Creation
- def perform
- return if reblog.nil?
-
- status, just_created = super
- NotifyService.new.call(reblog.account, status) if reblog.account.local? && just_created
- status
- end
-
- def object
- @xml.at_xpath('.//activity:object', activity: OStatus::TagManager::AS_XMLNS)
- end
-
- private
-
- def reblog
- return @reblog if defined? @reblog
-
- original_status = OStatus::Activity::Remote.new(object).perform
- return if original_status.nil?
-
- @reblog = original_status.reblog? ? original_status.reblog : original_status
- end
-end
diff --git a/app/lib/ostatus/atom_serializer.rb b/app/lib/ostatus/atom_serializer.rb
deleted file mode 100644
index 9a05d96cf9..0000000000
--- a/app/lib/ostatus/atom_serializer.rb
+++ /dev/null
@@ -1,378 +0,0 @@
-# frozen_string_literal: true
-
-class OStatus::AtomSerializer
- include RoutingHelper
- include ActionView::Helpers::SanitizeHelper
-
- class << self
- def render(element)
- document = Ox::Document.new(version: '1.0')
- document << element
- ('' + Ox.dump(element, effort: :tolerant)).force_encoding('UTF-8')
- end
- end
-
- def author(account)
- author = Ox::Element.new('author')
-
- uri = OStatus::TagManager.instance.uri_for(account)
-
- append_element(author, 'id', uri)
- append_element(author, 'activity:object-type', OStatus::TagManager::TYPES[:person])
- append_element(author, 'uri', uri)
- append_element(author, 'name', account.username)
- append_element(author, 'email', account.local? ? account.local_username_and_domain : account.acct)
- append_element(author, 'summary', Formatter.instance.simplified_format(account).to_str, type: :html) if account.note?
- append_element(author, 'link', nil, rel: :alternate, type: 'text/html', href: ::TagManager.instance.url_for(account))
- append_element(author, 'link', nil, rel: :avatar, type: account.avatar_content_type, 'media:width': 120, 'media:height': 120, href: full_asset_url(account.avatar.url(:original))) if account.avatar?
- append_element(author, 'link', nil, rel: :header, type: account.header_content_type, 'media:width': 700, 'media:height': 335, href: full_asset_url(account.header.url(:original))) if account.header?
- account.emojis.each do |emoji|
- append_element(author, 'link', nil, rel: :emoji, href: full_asset_url(emoji.image.url), name: emoji.shortcode)
- end
- append_element(author, 'poco:preferredUsername', account.username)
- append_element(author, 'poco:displayName', account.display_name) if account.display_name?
- append_element(author, 'poco:note', account.local? ? account.note : strip_tags(account.note)) if account.note?
- append_element(author, 'mastodon:scope', account.locked? ? :private : :public)
-
- author
- end
-
- def feed(account, stream_entries)
- feed = Ox::Element.new('feed')
-
- add_namespaces(feed)
-
- append_element(feed, 'id', account_url(account, format: 'atom'))
- append_element(feed, 'title', account.display_name.presence || account.username)
- append_element(feed, 'subtitle', account.note)
- append_element(feed, 'updated', account.updated_at.iso8601)
- append_element(feed, 'logo', full_asset_url(account.avatar.url(:original)))
-
- feed << author(account)
-
- append_element(feed, 'link', nil, rel: :alternate, type: 'text/html', href: ::TagManager.instance.url_for(account))
- append_element(feed, 'link', nil, rel: :self, type: 'application/atom+xml', href: account_url(account, format: 'atom'))
- append_element(feed, 'link', nil, rel: :next, type: 'application/atom+xml', href: account_url(account, format: 'atom', max_id: stream_entries.last.id)) if stream_entries.size == 20
- append_element(feed, 'link', nil, rel: :hub, href: api_push_url)
- append_element(feed, 'link', nil, rel: :salmon, href: api_salmon_url(account.id))
-
- stream_entries.each do |stream_entry|
- feed << entry(stream_entry)
- end
-
- feed
- end
-
- def entry(stream_entry, root = false)
- entry = Ox::Element.new('entry')
-
- add_namespaces(entry) if root
-
- append_element(entry, 'id', OStatus::TagManager.instance.uri_for(stream_entry.status))
- append_element(entry, 'published', stream_entry.created_at.iso8601)
- append_element(entry, 'updated', stream_entry.updated_at.iso8601)
- append_element(entry, 'title', stream_entry&.status&.title || "#{stream_entry.account.acct} deleted status")
-
- entry << author(stream_entry.account) if root
-
- append_element(entry, 'activity:object-type', OStatus::TagManager::TYPES[stream_entry.object_type])
- append_element(entry, 'activity:verb', OStatus::TagManager::VERBS[stream_entry.verb])
-
- entry << object(stream_entry.target) if stream_entry.targeted?
-
- if stream_entry.status.nil?
- append_element(entry, 'content', 'Deleted status')
- elsif stream_entry.status.destroyed?
- append_element(entry, 'content', 'Deleted status')
- append_element(entry, 'link', nil, rel: :alternate, type: 'application/activity+json', href: ActivityPub::TagManager.instance.uri_for(stream_entry.status)) if stream_entry.account.local?
- else
- serialize_status_attributes(entry, stream_entry.status)
- end
-
- append_element(entry, 'link', nil, rel: :alternate, type: 'text/html', href: ::TagManager.instance.url_for(stream_entry.status))
- append_element(entry, 'link', nil, rel: :self, type: 'application/atom+xml', href: account_stream_entry_url(stream_entry.account, stream_entry, format: 'atom'))
- append_element(entry, 'thr:in-reply-to', nil, ref: OStatus::TagManager.instance.uri_for(stream_entry.thread), href: ::TagManager.instance.url_for(stream_entry.thread)) if stream_entry.threaded?
- append_element(entry, 'ostatus:conversation', nil, ref: conversation_uri(stream_entry.status.conversation)) unless stream_entry&.status&.conversation_id.nil?
-
- entry
- end
-
- def object(status)
- object = Ox::Element.new('activity:object')
-
- append_element(object, 'id', OStatus::TagManager.instance.uri_for(status))
- append_element(object, 'published', status.created_at.iso8601)
- append_element(object, 'updated', status.updated_at.iso8601)
- append_element(object, 'title', status.title)
-
- object << author(status.account)
-
- append_element(object, 'activity:object-type', OStatus::TagManager::TYPES[status.object_type])
- append_element(object, 'activity:verb', OStatus::TagManager::VERBS[status.verb])
-
- serialize_status_attributes(object, status)
-
- append_element(object, 'link', nil, rel: :alternate, type: 'text/html', href: ::TagManager.instance.url_for(status))
- append_element(object, 'thr:in-reply-to', nil, ref: OStatus::TagManager.instance.uri_for(status.thread), href: ::TagManager.instance.url_for(status.thread)) unless status.thread.nil?
- append_element(object, 'ostatus:conversation', nil, ref: conversation_uri(status.conversation)) unless status.conversation_id.nil?
-
- object
- end
-
- def follow_salmon(follow)
- entry = Ox::Element.new('entry')
- add_namespaces(entry)
-
- description = "#{follow.account.acct} started following #{follow.target_account.acct}"
-
- append_element(entry, 'id', OStatus::TagManager.instance.unique_tag(follow.created_at, follow.id, 'Follow'))
- append_element(entry, 'title', description)
- append_element(entry, 'content', description, type: :html)
-
- entry << author(follow.account)
-
- append_element(entry, 'activity:object-type', OStatus::TagManager::TYPES[:activity])
- append_element(entry, 'activity:verb', OStatus::TagManager::VERBS[:follow])
-
- object = author(follow.target_account)
- object.value = 'activity:object'
-
- entry << object
- entry
- end
-
- def follow_request_salmon(follow_request)
- entry = Ox::Element.new('entry')
- add_namespaces(entry)
-
- append_element(entry, 'id', OStatus::TagManager.instance.unique_tag(follow_request.created_at, follow_request.id, 'FollowRequest'))
- append_element(entry, 'title', "#{follow_request.account.acct} requested to follow #{follow_request.target_account.acct}")
-
- entry << author(follow_request.account)
-
- append_element(entry, 'activity:object-type', OStatus::TagManager::TYPES[:activity])
- append_element(entry, 'activity:verb', OStatus::TagManager::VERBS[:request_friend])
-
- object = author(follow_request.target_account)
- object.value = 'activity:object'
-
- entry << object
- entry
- end
-
- def authorize_follow_request_salmon(follow_request)
- entry = Ox::Element.new('entry')
- add_namespaces(entry)
-
- append_element(entry, 'id', OStatus::TagManager.instance.unique_tag(Time.now.utc, follow_request.id, 'FollowRequest'))
- append_element(entry, 'title', "#{follow_request.target_account.acct} authorizes follow request by #{follow_request.account.acct}")
-
- entry << author(follow_request.target_account)
-
- append_element(entry, 'activity:object-type', OStatus::TagManager::TYPES[:activity])
- append_element(entry, 'activity:verb', OStatus::TagManager::VERBS[:authorize])
-
- object = Ox::Element.new('activity:object')
- object << author(follow_request.account)
-
- append_element(object, 'activity:object-type', OStatus::TagManager::TYPES[:activity])
- append_element(object, 'activity:verb', OStatus::TagManager::VERBS[:request_friend])
-
- inner_object = author(follow_request.target_account)
- inner_object.value = 'activity:object'
-
- object << inner_object
- entry << object
- entry
- end
-
- def reject_follow_request_salmon(follow_request)
- entry = Ox::Element.new('entry')
- add_namespaces(entry)
-
- append_element(entry, 'id', OStatus::TagManager.instance.unique_tag(Time.now.utc, follow_request.id, 'FollowRequest'))
- append_element(entry, 'title', "#{follow_request.target_account.acct} rejects follow request by #{follow_request.account.acct}")
-
- entry << author(follow_request.target_account)
-
- append_element(entry, 'activity:object-type', OStatus::TagManager::TYPES[:activity])
- append_element(entry, 'activity:verb', OStatus::TagManager::VERBS[:reject])
-
- object = Ox::Element.new('activity:object')
- object << author(follow_request.account)
-
- append_element(object, 'activity:object-type', OStatus::TagManager::TYPES[:activity])
- append_element(object, 'activity:verb', OStatus::TagManager::VERBS[:request_friend])
-
- inner_object = author(follow_request.target_account)
- inner_object.value = 'activity:object'
-
- object << inner_object
- entry << object
- entry
- end
-
- def unfollow_salmon(follow)
- entry = Ox::Element.new('entry')
- add_namespaces(entry)
-
- description = "#{follow.account.acct} is no longer following #{follow.target_account.acct}"
-
- append_element(entry, 'id', OStatus::TagManager.instance.unique_tag(Time.now.utc, follow.id, 'Follow'))
- append_element(entry, 'title', description)
- append_element(entry, 'content', description, type: :html)
-
- entry << author(follow.account)
-
- append_element(entry, 'activity:object-type', OStatus::TagManager::TYPES[:activity])
- append_element(entry, 'activity:verb', OStatus::TagManager::VERBS[:unfollow])
-
- object = author(follow.target_account)
- object.value = 'activity:object'
-
- entry << object
- entry
- end
-
- def block_salmon(block)
- entry = Ox::Element.new('entry')
- add_namespaces(entry)
-
- description = "#{block.account.acct} no longer wishes to interact with #{block.target_account.acct}"
-
- append_element(entry, 'id', OStatus::TagManager.instance.unique_tag(Time.now.utc, block.id, 'Block'))
- append_element(entry, 'title', description)
-
- entry << author(block.account)
-
- append_element(entry, 'activity:object-type', OStatus::TagManager::TYPES[:activity])
- append_element(entry, 'activity:verb', OStatus::TagManager::VERBS[:block])
-
- object = author(block.target_account)
- object.value = 'activity:object'
-
- entry << object
- entry
- end
-
- def unblock_salmon(block)
- entry = Ox::Element.new('entry')
- add_namespaces(entry)
-
- description = "#{block.account.acct} no longer blocks #{block.target_account.acct}"
-
- append_element(entry, 'id', OStatus::TagManager.instance.unique_tag(Time.now.utc, block.id, 'Block'))
- append_element(entry, 'title', description)
-
- entry << author(block.account)
-
- append_element(entry, 'activity:object-type', OStatus::TagManager::TYPES[:activity])
- append_element(entry, 'activity:verb', OStatus::TagManager::VERBS[:unblock])
-
- object = author(block.target_account)
- object.value = 'activity:object'
-
- entry << object
- entry
- end
-
- def favourite_salmon(favourite)
- entry = Ox::Element.new('entry')
- add_namespaces(entry)
-
- description = "#{favourite.account.acct} favourited a status by #{favourite.status.account.acct}"
-
- append_element(entry, 'id', OStatus::TagManager.instance.unique_tag(favourite.created_at, favourite.id, 'Favourite'))
- append_element(entry, 'title', description)
- append_element(entry, 'content', description, type: :html)
-
- entry << author(favourite.account)
-
- append_element(entry, 'activity:object-type', OStatus::TagManager::TYPES[:activity])
- append_element(entry, 'activity:verb', OStatus::TagManager::VERBS[:favorite])
-
- entry << object(favourite.status)
-
- append_element(entry, 'thr:in-reply-to', nil, ref: OStatus::TagManager.instance.uri_for(favourite.status), href: ::TagManager.instance.url_for(favourite.status))
-
- entry
- end
-
- def unfavourite_salmon(favourite)
- entry = Ox::Element.new('entry')
- add_namespaces(entry)
-
- description = "#{favourite.account.acct} no longer favourites a status by #{favourite.status.account.acct}"
-
- append_element(entry, 'id', OStatus::TagManager.instance.unique_tag(Time.now.utc, favourite.id, 'Favourite'))
- append_element(entry, 'title', description)
- append_element(entry, 'content', description, type: :html)
-
- entry << author(favourite.account)
-
- append_element(entry, 'activity:object-type', OStatus::TagManager::TYPES[:activity])
- append_element(entry, 'activity:verb', OStatus::TagManager::VERBS[:unfavorite])
-
- entry << object(favourite.status)
-
- append_element(entry, 'thr:in-reply-to', nil, ref: OStatus::TagManager.instance.uri_for(favourite.status), href: ::TagManager.instance.url_for(favourite.status))
-
- entry
- end
-
- private
-
- def append_element(parent, name, content = nil, **attributes)
- element = Ox::Element.new(name)
- attributes.each { |k, v| element[k] = sanitize_str(v) }
- element << sanitize_str(content) unless content.nil?
- parent << element
- end
-
- def sanitize_str(raw_str)
- raw_str.to_s
- end
-
- def conversation_uri(conversation)
- return conversation.uri if conversation.uri?
- OStatus::TagManager.instance.unique_tag(conversation.created_at, conversation.id, 'Conversation')
- end
-
- def add_namespaces(parent)
- parent['xmlns'] = OStatus::TagManager::XMLNS
- parent['xmlns:thr'] = OStatus::TagManager::THR_XMLNS
- parent['xmlns:activity'] = OStatus::TagManager::AS_XMLNS
- parent['xmlns:poco'] = OStatus::TagManager::POCO_XMLNS
- parent['xmlns:media'] = OStatus::TagManager::MEDIA_XMLNS
- parent['xmlns:ostatus'] = OStatus::TagManager::OS_XMLNS
- parent['xmlns:mastodon'] = OStatus::TagManager::MTDN_XMLNS
- end
-
- def serialize_status_attributes(entry, status)
- append_element(entry, 'link', nil, rel: :alternate, type: 'application/activity+json', href: ActivityPub::TagManager.instance.uri_for(status)) if status.account.local?
-
- append_element(entry, 'summary', status.spoiler_text, 'xml:lang': status.language) if status.spoiler_text?
- append_element(entry, 'content', Formatter.instance.format(status, inline_poll_options: true).to_str || '.', type: 'html', 'xml:lang': status.language)
-
- status.active_mentions.sort_by(&:id).each do |mentioned|
- append_element(entry, 'link', nil, rel: :mentioned, 'ostatus:object-type': OStatus::TagManager::TYPES[:person], href: OStatus::TagManager.instance.uri_for(mentioned.account))
- end
-
- append_element(entry, 'link', nil, rel: :mentioned, 'ostatus:object-type': OStatus::TagManager::TYPES[:collection], href: OStatus::TagManager::COLLECTIONS[:public]) if status.public_visibility?
-
- status.tags.each do |tag|
- append_element(entry, 'category', nil, term: tag.name)
- end
-
- status.media_attachments.each do |media|
- append_element(entry, 'link', nil, rel: :enclosure, type: media.file_content_type, length: media.file_file_size, href: full_asset_url(media.file.url(:original, false)))
- end
-
- append_element(entry, 'category', nil, term: 'nsfw') if status.sensitive? && status.media_attachments.any?
- append_element(entry, 'mastodon:scope', status.visibility)
-
- status.emojis.each do |emoji|
- append_element(entry, 'link', nil, rel: :emoji, href: full_asset_url(emoji.image.url), name: emoji.shortcode)
- end
- end
-end
diff --git a/app/lib/request.rb b/app/lib/request.rb
index 5f7075a3c9..9d874fe2ca 100644
--- a/app/lib/request.rb
+++ b/app/lib/request.rb
@@ -40,8 +40,8 @@ class Request
set_digest! if options.key?(:body)
end
- def on_behalf_of(account, key_id_format = :acct, sign_with: nil)
- raise ArgumentError unless account.local?
+ def on_behalf_of(account, key_id_format = :uri, sign_with: nil)
+ raise ArgumentError, 'account must not be nil' if account.nil?
@account = account
@keypair = sign_with.present? ? OpenSSL::PKey::RSA.new(sign_with) : @account.keypair
@@ -59,7 +59,7 @@ class Request
begin
response = http_client.public_send(@verb, @url.to_s, @options.merge(headers: headers))
rescue => e
- raise e.class, "#{e.message} on #{@url}", e.backtrace[0]
+ raise e.class, "#{e.message} on #{@url}", e.backtrace
end
begin
diff --git a/app/lib/spam_check.rb b/app/lib/spam_check.rb
new file mode 100644
index 0000000000..0cf1b87903
--- /dev/null
+++ b/app/lib/spam_check.rb
@@ -0,0 +1,173 @@
+# frozen_string_literal: true
+
+class SpamCheck
+ include Redisable
+ include ActionView::Helpers::TextHelper
+
+ NILSIMSA_COMPARE_THRESHOLD = 95
+ NILSIMSA_MIN_SIZE = 10
+ EXPIRE_SET_AFTER = 1.week.seconds
+
+ def initialize(status)
+ @account = status.account
+ @status = status
+ end
+
+ def skip?
+ disabled? || already_flagged? || trusted? || no_unsolicited_mentions? || solicited_reply?
+ end
+
+ def spam?
+ if insufficient_data?
+ false
+ elsif nilsimsa?
+ any_other_digest?('nilsimsa') { |_, other_digest| nilsimsa_compare_value(digest, other_digest) >= NILSIMSA_COMPARE_THRESHOLD }
+ else
+ any_other_digest?('md5') { |_, other_digest| other_digest == digest }
+ end
+ end
+
+ def flag!
+ auto_silence_account!
+ auto_report_status!
+ end
+
+ def remember!
+ # The scores in sorted sets don't actually have enough bits to hold an exact
+ # value of our snowflake IDs, so we use it only for its ordering property. To
+ # get the correct status ID back, we have to save it in the string value
+
+ redis.zadd(redis_key, @status.id, digest_with_algorithm)
+ redis.zremrangebyrank(redis_key, '0', '-10')
+ redis.expire(redis_key, EXPIRE_SET_AFTER)
+ end
+
+ def reset!
+ redis.del(redis_key)
+ end
+
+ def hashable_text
+ return @hashable_text if defined?(@hashable_text)
+
+ @hashable_text = @status.text
+ @hashable_text = remove_mentions(@hashable_text)
+ @hashable_text = strip_tags(@hashable_text) unless @status.local?
+ @hashable_text = normalize_unicode(@status.spoiler_text + ' ' + @hashable_text)
+ @hashable_text = remove_whitespace(@hashable_text)
+ end
+
+ def insufficient_data?
+ hashable_text.blank?
+ end
+
+ def digest
+ @digest ||= begin
+ if nilsimsa?
+ Nilsimsa.new(hashable_text).hexdigest
+ else
+ Digest::MD5.hexdigest(hashable_text)
+ end
+ end
+ end
+
+ def digest_with_algorithm
+ if nilsimsa?
+ ['nilsimsa', digest, @status.id].join(':')
+ else
+ ['md5', digest, @status.id].join(':')
+ end
+ end
+
+ private
+
+ def disabled?
+ !Setting.spam_check_enabled
+ end
+
+ def remove_mentions(text)
+ return text.gsub(Account::MENTION_RE, '') if @status.local?
+
+ Nokogiri::HTML.fragment(text).tap do |html|
+ mentions = @status.mentions.map { |mention| ActivityPub::TagManager.instance.url_for(mention.account) }
+
+ html.traverse do |element|
+ element.unlink if element.name == 'a' && mentions.include?(element['href'])
+ end
+ end.to_s
+ end
+
+ def normalize_unicode(text)
+ text.unicode_normalize(:nfkc).downcase
+ end
+
+ def remove_whitespace(text)
+ text.gsub(/\s+/, ' ').strip
+ end
+
+ def auto_silence_account!
+ @account.silence!
+ end
+
+ def auto_report_status!
+ status_ids = Status.where(visibility: %i(public unlisted)).where(id: matching_status_ids).pluck(:id) + [@status.id] if @status.distributable?
+ ReportService.new.call(Account.representative, @account, status_ids: status_ids, comment: I18n.t('spam_check.spam_detected_and_silenced'))
+ end
+
+ def already_flagged?
+ @account.silenced?
+ end
+
+ def trusted?
+ @account.trust_level > Account::TRUST_LEVELS[:untrusted]
+ end
+
+ def no_unsolicited_mentions?
+ @status.mentions.all? { |mention| mention.silent? || (!@account.local? && !mention.account.local?) || mention.account.following?(@account) }
+ end
+
+ def solicited_reply?
+ !@status.thread.nil? && @status.thread.mentions.where(account: @account).exists?
+ end
+
+ def nilsimsa_compare_value(first, second)
+ first = [first].pack('H*')
+ second = [second].pack('H*')
+ bits = 0
+
+ 0.upto(31) do |i|
+ bits += Nilsimsa::POPC[255 & (first[i].ord ^ second[i].ord)].ord
+ end
+
+ 128 - bits # -128 <= Nilsimsa Compare Value <= 128
+ end
+
+ def nilsimsa?
+ hashable_text.size > NILSIMSA_MIN_SIZE
+ end
+
+ def other_digests
+ redis.zrange(redis_key, 0, -1)
+ end
+
+ def any_other_digest?(filter_algorithm)
+ other_digests.any? do |record|
+ algorithm, other_digest, status_id = record.split(':')
+
+ next unless algorithm == filter_algorithm
+
+ yield algorithm, other_digest, status_id
+ end
+ end
+
+ def matching_status_ids
+ if nilsimsa?
+ other_digests.select { |record| record.start_with?('nilsimsa') && nilsimsa_compare_value(digest, record.split(':')[1]) >= NILSIMSA_COMPARE_THRESHOLD }.map { |record| record.split(':')[2] }.compact
+ else
+ other_digests.select { |record| record.start_with?('md5') && record.split(':')[1] == digest }.map { |record| record.split(':')[2] }.compact
+ end
+ end
+
+ def redis_key
+ @redis_key ||= "spam_check:#{@account.id}"
+ end
+end
diff --git a/app/lib/status_finder.rb b/app/lib/status_finder.rb
index 4d1aed2979..22ced8bf82 100644
--- a/app/lib/status_finder.rb
+++ b/app/lib/status_finder.rb
@@ -13,8 +13,6 @@ class StatusFinder
raise ActiveRecord::RecordNotFound unless TagManager.instance.local_url?(url)
case recognized_params[:controller]
- when 'stream_entries'
- StreamEntry.find(recognized_params[:id]).status
when 'statuses'
Status.find(recognized_params[:id])
else
diff --git a/app/lib/tag_manager.rb b/app/lib/tag_manager.rb
index fb364cb98a..c88cf49947 100644
--- a/app/lib/tag_manager.rb
+++ b/app/lib/tag_manager.rb
@@ -24,24 +24,16 @@ class TagManager
def same_acct?(canonical, needle)
return true if canonical.casecmp(needle).zero?
+
username, domain = needle.split('@')
+
local_domain?(domain) && canonical.casecmp(username).zero?
end
def local_url?(url)
uri = Addressable::URI.parse(url).normalize
domain = uri.host + (uri.port ? ":#{uri.port}" : '')
- TagManager.instance.web_domain?(domain)
- end
-
- def url_for(target)
- return target.url if target.respond_to?(:local?) && !target.local?
- case target.object_type
- when :person
- short_account_url(target)
- when :note, :comment, :activity
- short_account_status_url(target.account, target)
- end
+ TagManager.instance.web_domain?(domain)
end
end
diff --git a/app/lib/webfinger_resource.rb b/app/lib/webfinger_resource.rb
index a54a702a2e..22d78874a4 100644
--- a/app/lib/webfinger_resource.rb
+++ b/app/lib/webfinger_resource.rb
@@ -23,11 +23,17 @@ class WebfingerResource
def username_from_url
if account_show_page?
path_params[:username]
+ elsif instance_actor_page?
+ Rails.configuration.x.local_domain
else
raise ActiveRecord::RecordNotFound
end
end
+ def instance_actor_page?
+ path_params[:controller] == 'instance_actors'
+ end
+
def account_show_page?
path_params[:controller] == 'accounts' && path_params[:action] == 'show'
end
diff --git a/app/mailers/admin_mailer.rb b/app/mailers/admin_mailer.rb
index db154cad53..9ab3e2bbdc 100644
--- a/app/mailers/admin_mailer.rb
+++ b/app/mailers/admin_mailer.rb
@@ -3,7 +3,7 @@
class AdminMailer < ApplicationMailer
layout 'plain_mailer'
- helper :stream_entries
+ helper :statuses
def new_report(recipient, report)
@report = report
diff --git a/app/mailers/notification_mailer.rb b/app/mailers/notification_mailer.rb
index 66fa337c1f..723d901fc6 100644
--- a/app/mailers/notification_mailer.rb
+++ b/app/mailers/notification_mailer.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
class NotificationMailer < ApplicationMailer
- helper :stream_entries
+ helper :statuses
add_template_helper RoutingHelper
diff --git a/app/models/account.rb b/app/models/account.rb
index 3d7b0dda3b..3370fbc5e6 100644
--- a/app/models/account.rb
+++ b/app/models/account.rb
@@ -45,6 +45,7 @@
# also_known_as :string is an Array
# silenced_at :datetime
# suspended_at :datetime
+# trust_level :integer
#
class Account < ApplicationRecord
@@ -66,6 +67,11 @@ class Account < ApplicationRecord
MAX_NOTE_LENGTH = (ENV['MAX_BIO_CHARS'] || 500).to_i
MAX_FIELDS = (ENV['MAX_PROFILE_FIELDS'] || 4).to_i
+ TRUST_LEVELS = {
+ untrusted: 0,
+ trusted: 1,
+ }.freeze
+
enum protocol: [:ostatus, :activitypub]
validates :username, presence: true
@@ -75,7 +81,7 @@ class Account < ApplicationRecord
validates :username, format: { with: /\A#{USERNAME_RE}\z/i }, if: -> { !local? && will_save_change_to_username? }
# Local user validations
- validates :username, format: { with: /\A[a-z0-9_]+\z/i }, length: { maximum: 30 }, if: -> { local? && will_save_change_to_username? }
+ validates :username, format: { with: /\A[a-z0-9_]+\z/i }, length: { maximum: 30 }, if: -> { local? && will_save_change_to_username? && actor_type != 'Application' }
validates_with UniqueUsernameValidator, if: -> { local? && will_save_change_to_username? }
validates_with UnreservedUsernameValidator, if: -> { local? && will_save_change_to_username? }
validates :display_name, length: { maximum: MAX_DISPLAY_NAME_LENGTH }, if: -> { local? && will_save_change_to_display_name? }
@@ -137,6 +143,10 @@ class Account < ApplicationRecord
%w(Application Service).include? actor_type
end
+ def instance_actor?
+ id == -99
+ end
+
alias bot bot?
def bot=(val)
@@ -167,30 +177,31 @@ class Account < ApplicationRecord
last_webfingered_at.nil? || last_webfingered_at <= 1.day.ago
end
+ def trust_level
+ self[:trust_level] || 0
+ end
+
def refresh!
- return if local?
- ResolveAccountService.new.call(acct)
+ ResolveAccountService.new.call(acct) unless local?
end
def silenced?
silenced_at.present?
end
- def silence!(date = nil)
- date ||= Time.now.utc
+ def silence!(date = Time.now.utc)
update!(silenced_at: date)
end
def unsilence!
- update!(silenced_at: nil)
+ update!(silenced_at: nil, trust_level: trust_level == TRUST_LEVELS[:untrusted] ? TRUST_LEVELS[:trusted] : trust_level)
end
def suspended?
suspended_at.present?
end
- def suspend!(date = nil)
- date ||= Time.now.utc
+ def suspend!(date = Time.now.utc)
transaction do
user&.disable! if local?
update!(suspended_at: date)
@@ -296,21 +307,6 @@ class Account < ApplicationRecord
self.fields = tmp
end
- def magic_key
- modulus, exponent = [keypair.public_key.n, keypair.public_key.e].map do |component|
- result = []
-
- until component.zero?
- result << [component % 256].pack('C')
- component >>= 8
- end
-
- result.reverse.join
- end
-
- (['RSA'] + [modulus, exponent].map { |n| Base64.urlsafe_encode64(n) }).join('.')
- end
-
def subscription(webhook_url)
@subscription ||= OStatus2::Subscription.new(remote_url, secret: secret, webhook: webhook_url, hub: hub_url)
end
@@ -508,7 +504,7 @@ class Account < ApplicationRecord
end
def generate_keys
- return unless local? && !Rails.env.test?
+ return unless local? && private_key.blank? && public_key.blank?
keypair = OpenSSL::PKey::RSA.new(2048)
self.private_key = keypair.to_pem
diff --git a/app/models/concerns/account_associations.rb b/app/models/concerns/account_associations.rb
index ecccaf35ef..2877b9c254 100644
--- a/app/models/concerns/account_associations.rb
+++ b/app/models/concerns/account_associations.rb
@@ -11,7 +11,6 @@ module AccountAssociations
has_many :identity_proofs, class_name: 'AccountIdentityProof', dependent: :destroy, inverse_of: :account
# Timelines
- has_many :stream_entries, inverse_of: :account, dependent: :destroy
has_many :statuses, inverse_of: :account, dependent: :destroy
has_many :favourites, inverse_of: :account, dependent: :destroy
has_many :bookmarks, inverse_of: :account, dependent: :destroy
diff --git a/app/models/concerns/account_finder_concern.rb b/app/models/concerns/account_finder_concern.rb
index ccd7bfa123..a54c2174d4 100644
--- a/app/models/concerns/account_finder_concern.rb
+++ b/app/models/concerns/account_finder_concern.rb
@@ -13,7 +13,7 @@ module AccountFinderConcern
end
def representative
- find_local(Setting.site_contact_username.strip.gsub(/\A@/, '')) || Account.local.without_suspended.first
+ Account.find(-99)
end
def find_local(username)
diff --git a/app/models/concerns/streamable.rb b/app/models/concerns/streamable.rb
deleted file mode 100644
index 7c9edb8ef8..0000000000
--- a/app/models/concerns/streamable.rb
+++ /dev/null
@@ -1,43 +0,0 @@
-# frozen_string_literal: true
-
-module Streamable
- extend ActiveSupport::Concern
-
- included do
- has_one :stream_entry, as: :activity
-
- after_create do
- account.stream_entries.create!(activity: self, hidden: hidden?) if needs_stream_entry?
- end
- end
-
- def title
- super
- end
-
- def content
- title
- end
-
- def target
- super
- end
-
- def object_type
- :activity
- end
-
- def thread
- super
- end
-
- def hidden?
- false
- end
-
- private
-
- def needs_stream_entry?
- account.local?
- end
-end
diff --git a/app/models/form/admin_settings.rb b/app/models/form/admin_settings.rb
index 0e9bfb265e..ecaed44f60 100644
--- a/app/models/form/admin_settings.rb
+++ b/app/models/form/admin_settings.rb
@@ -34,6 +34,7 @@ class Form::AdminSettings
mascot
show_reblogs_in_public_timelines
show_replies_in_public_timelines
+ spam_check_enabled
).freeze
BOOLEAN_KEYS = %i(
@@ -49,6 +50,7 @@ class Form::AdminSettings
enable_keybase
show_reblogs_in_public_timelines
show_replies_in_public_timelines
+ spam_check_enabled
).freeze
UPLOAD_KEYS = %i(
diff --git a/app/models/media_attachment.rb b/app/models/media_attachment.rb
index 815ac0258c..189d80e77a 100644
--- a/app/models/media_attachment.rb
+++ b/app/models/media_attachment.rb
@@ -26,14 +26,14 @@ class MediaAttachment < ApplicationRecord
enum type: [:image, :gifv, :video, :unknown, :audio]
- IMAGE_FILE_EXTENSIONS = ['.jpg', '.jpeg', '.png', '.gif', '.webp'].freeze
- VIDEO_FILE_EXTENSIONS = ['.webm', '.mp4', '.m4v', '.mov'].freeze
- AUDIO_FILE_EXTENSIONS = ['.ogg', '.oga', '.mp3', '.m4a', '.wav', '.flac', '.opus'].freeze
-
- IMAGE_MIME_TYPES = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'].freeze
- VIDEO_MIME_TYPES = ['video/webm', 'video/mp4', 'video/quicktime', 'video/ogg'].freeze
- VIDEO_CONVERTIBLE_MIME_TYPES = ['video/webm', 'video/quicktime'].freeze
- AUDIO_MIME_TYPES = ['audio/wave', 'audio/wav', 'audio/x-wav', 'audio/x-wave', 'audio/vdn.wav', 'audio/x-pn-wave', 'audio/ogg', 'audio/mpeg', 'audio/mp3', 'audio/mp4', 'audio/webm', 'audio/flac'].freeze
+ IMAGE_FILE_EXTENSIONS = %w(.jpg .jpeg .png .gif .webp).freeze
+ VIDEO_FILE_EXTENSIONS = %w(.webm .mp4 .m4v .mov).freeze
+ AUDIO_FILE_EXTENSIONS = %w(.ogg .oga .mp3 .wav .flac .opus .aac .m4a .3gp).freeze
+
+ IMAGE_MIME_TYPES = %w(image/jpeg image/png image/gif image/webp).freeze
+ VIDEO_MIME_TYPES = %w(video/webm video/mp4 video/quicktime video/ogg).freeze
+ VIDEO_CONVERTIBLE_MIME_TYPES = %w(video/webm video/quicktime).freeze
+ AUDIO_MIME_TYPES = %w(audio/wave audio/wav audio/x-wav audio/x-pn-wave audio/ogg audio/mpeg audio/mp3 audio/webm audio/flac audio/aac audio/m4a audio/3gpp).freeze
BLURHASH_OPTIONS = {
x_comp: 4,
diff --git a/app/models/remote_profile.rb b/app/models/remote_profile.rb
deleted file mode 100644
index 742d2b56f4..0000000000
--- a/app/models/remote_profile.rb
+++ /dev/null
@@ -1,57 +0,0 @@
-# frozen_string_literal: true
-
-class RemoteProfile
- include ActiveModel::Model
-
- attr_reader :document
-
- def initialize(body)
- @document = Nokogiri::XML.parse(body, nil, 'utf-8')
- end
-
- def root
- @root ||= document.at_xpath('/atom:feed|/atom:entry', atom: OStatus::TagManager::XMLNS)
- end
-
- def author
- @author ||= root.at_xpath('./atom:author|./dfrn:owner', atom: OStatus::TagManager::XMLNS, dfrn: OStatus::TagManager::DFRN_XMLNS)
- end
-
- def hub_link
- @hub_link ||= link_href_from_xml(root, 'hub')
- end
-
- def display_name
- @display_name ||= author.at_xpath('./poco:displayName', poco: OStatus::TagManager::POCO_XMLNS)&.content
- end
-
- def note
- @note ||= author.at_xpath('./atom:summary|./poco:note', atom: OStatus::TagManager::XMLNS, poco: OStatus::TagManager::POCO_XMLNS)&.content
- end
-
- def scope
- @scope ||= author.at_xpath('./mastodon:scope', mastodon: OStatus::TagManager::MTDN_XMLNS)&.content
- end
-
- def avatar
- @avatar ||= link_href_from_xml(author, 'avatar')
- end
-
- def header
- @header ||= link_href_from_xml(author, 'header')
- end
-
- def emojis
- @emojis ||= author.xpath('./xmlns:link[@rel="emoji"]', xmlns: OStatus::TagManager::XMLNS)
- end
-
- def locked?
- scope == 'private'
- end
-
- private
-
- def link_href_from_xml(xml, type)
- xml.at_xpath(%(./atom:link[@rel="#{type}"]/@href), atom: OStatus::TagManager::XMLNS)&.content
- end
-end
diff --git a/app/models/status.rb b/app/models/status.rb
index 5adccb7226..642d3cf5e8 100644
--- a/app/models/status.rb
+++ b/app/models/status.rb
@@ -31,7 +31,6 @@ class Status < ApplicationRecord
before_destroy :unlink_from_conversations
include Paginable
- include Streamable
include Cacheable
include StatusThreadingConcern
@@ -65,7 +64,6 @@ class Status < ApplicationRecord
has_and_belongs_to_many :preview_cards
has_one :notification, as: :activity, dependent: :destroy
- has_one :stream_entry, as: :activity, inverse_of: :status
has_one :status_stat, inverse_of: :status
has_one :poll, inverse_of: :status, dependent: :destroy
@@ -113,13 +111,11 @@ class Status < ApplicationRecord
:status_stat,
:tags,
:preview_cards,
- :stream_entry,
:preloadable_poll,
account: :account_stat,
active_mentions: { account: :account_stat },
reblog: [
:application,
- :stream_entry,
:tags,
:preview_cards,
:media_attachments,
@@ -204,7 +200,7 @@ class Status < ApplicationRecord
end
def hidden?
- private_visibility? || direct_visibility? || limited_visibility?
+ !distributable?
end
def distributable?
@@ -523,7 +519,8 @@ class Status < ApplicationRecord
end
def update_statistics
- return unless public_visibility? || unlisted_visibility?
+ return unless distributable?
+
ActivityTracker.increment('activity:statuses:local')
end
@@ -532,7 +529,7 @@ class Status < ApplicationRecord
account&.increment_count!(:statuses_count)
reblog&.increment_count!(:reblogs_count) if reblog?
- thread&.increment_count!(:replies_count) if in_reply_to_id.present? && (public_visibility? || unlisted_visibility?)
+ thread&.increment_count!(:replies_count) if in_reply_to_id.present? && distributable?
end
def decrement_counter_caches
@@ -540,7 +537,7 @@ class Status < ApplicationRecord
account&.decrement_count!(:statuses_count)
reblog&.decrement_count!(:reblogs_count) if reblog?
- thread&.decrement_count!(:replies_count) if in_reply_to_id.present? && (public_visibility? || unlisted_visibility?)
+ thread&.decrement_count!(:replies_count) if in_reply_to_id.present? && distributable?
end
def unlink_from_conversations
diff --git a/app/models/stream_entry.rb b/app/models/stream_entry.rb
deleted file mode 100644
index edd30487e6..0000000000
--- a/app/models/stream_entry.rb
+++ /dev/null
@@ -1,59 +0,0 @@
-# frozen_string_literal: true
-# == Schema Information
-#
-# Table name: stream_entries
-#
-# id :bigint(8) not null, primary key
-# activity_id :bigint(8)
-# activity_type :string
-# created_at :datetime not null
-# updated_at :datetime not null
-# hidden :boolean default(FALSE), not null
-# account_id :bigint(8)
-#
-
-class StreamEntry < ApplicationRecord
- include Paginable
-
- belongs_to :account, inverse_of: :stream_entries
- belongs_to :activity, polymorphic: true
- belongs_to :status, foreign_type: 'Status', foreign_key: 'activity_id', inverse_of: :stream_entry
-
- validates :account, :activity, presence: true
-
- STATUS_INCLUDES = [:account, :stream_entry, :conversation, :media_attachments, :tags, mentions: :account, reblog: [:stream_entry, :account, :conversation, :media_attachments, :tags, mentions: :account], thread: [:stream_entry, :account]].freeze
-
- default_scope { where(activity_type: 'Status') }
- scope :recent, -> { reorder(id: :desc) }
- scope :with_includes, -> { includes(:account, status: STATUS_INCLUDES) }
-
- delegate :target, :title, :content, :thread, :local_only?,
- to: :status,
- allow_nil: true
-
- def object_type
- orphaned? || targeted? ? :activity : status.object_type
- end
-
- def verb
- orphaned? ? :delete : status.verb
- end
-
- def targeted?
- [:follow, :request_friend, :authorize, :reject, :unfollow, :block, :unblock, :share, :favorite].include? verb
- end
-
- def threaded?
- (verb == :favorite || object_type == :comment) && !thread.nil?
- end
-
- def mentions
- orphaned? ? [] : status.active_mentions.map(&:account)
- end
-
- private
-
- def orphaned?
- status.nil?
- end
-end
diff --git a/app/models/tag.rb b/app/models/tag.rb
index 7db76d157b..b371d59c1b 100644
--- a/app/models/tag.rb
+++ b/app/models/tag.rb
@@ -17,10 +17,10 @@ class Tag < ApplicationRecord
has_many :featured_tags, dependent: :destroy, inverse_of: :tag
has_one :account_tag_stat, dependent: :destroy
- HASHTAG_NAME_RE = '[[:word:]_]*[[:alpha:]_·][[:word:]_]*'
+ HASHTAG_NAME_RE = '([[:word:]_][[:word:]_·]*[[:alpha:]_·][[:word:]_·]*[[:word:]_])|([[:word:]_]*[[:alpha:]][[:word:]_]*)'
HASHTAG_RE = /(?:^|[^\/\)\w])#(#{HASHTAG_NAME_RE})/i
- validates :name, presence: true, uniqueness: true, format: { with: /\A#{HASHTAG_NAME_RE}\z/i }
+ validates :name, presence: true, uniqueness: true, format: { with: /\A(#{HASHTAG_NAME_RE})\z/i }
scope :discoverable, -> { joins(:account_tag_stat).where(AccountTagStat.arel_table[:accounts_count].gt(0)).where(account_tag_stats: { hidden: false }).order(Arel.sql('account_tag_stats.accounts_count desc')) }
scope :hidden, -> { where(account_tag_stats: { hidden: true }) }
diff --git a/app/models/user.rb b/app/models/user.rb
index bb903a45cb..72fc921956 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -106,7 +106,7 @@ class User < ApplicationRecord
delegate :auto_play_gif, :default_sensitive, :unfollow_modal, :boost_modal, :favourite_modal, :delete_modal,
:reduce_motion, :system_font_ui, :noindex, :flavour, :skin, :display_media, :hide_network, :hide_followers_count,
:expand_spoilers, :default_language, :aggregate_reblogs, :show_application,
- :advanced_layout, :default_content_type, :use_blurhash, :use_pending_items, to: :settings, prefix: :setting, allow_nil: false
+ :advanced_layout, :default_content_type, :use_blurhash, :use_pending_items, :use_pending_items, to: :settings, prefix: :setting, allow_nil: false
attr_reader :invite_code
attr_writer :external
diff --git a/app/policies/status_policy.rb b/app/policies/status_policy.rb
index 5e32826816..fa5c0dd9ce 100644
--- a/app/policies/status_policy.rb
+++ b/app/policies/status_policy.rb
@@ -19,7 +19,7 @@ class StatusPolicy < ApplicationPolicy
elsif private?
owned? || following_author? || mention_exists?
else
- current_account.nil? || !author_blocking?
+ current_account.nil? || (!author_blocking? && !author_blocking_domain?)
end
end
@@ -65,6 +65,12 @@ class StatusPolicy < ApplicationPolicy
end
end
+ def author_blocking_domain?
+ return false if current_account.nil? || current_account.domain.nil?
+
+ author.domain_blocking?(current_account.domain)
+ end
+
def blocking_author?
return false if current_account.nil?
diff --git a/app/serializers/activitypub/activity_serializer.rb b/app/serializers/activitypub/activity_serializer.rb
index c06d5c87ca..d0edad7868 100644
--- a/app/serializers/activitypub/activity_serializer.rb
+++ b/app/serializers/activitypub/activity_serializer.rb
@@ -4,6 +4,7 @@ class ActivityPub::ActivitySerializer < ActivityPub::Serializer
attributes :id, :type, :actor, :published, :to, :cc
has_one :proper, key: :object, serializer: ActivityPub::NoteSerializer, if: :serialize_object?
+
attribute :proper_uri, key: :object, unless: :serialize_object?
attribute :atom_uri, if: :announce?
diff --git a/app/serializers/activitypub/actor_serializer.rb b/app/serializers/activitypub/actor_serializer.rb
index 0644219fb6..0bd7aed2e9 100644
--- a/app/serializers/activitypub/actor_serializer.rb
+++ b/app/serializers/activitypub/actor_serializer.rb
@@ -39,11 +39,17 @@ class ActivityPub::ActorSerializer < ActivityPub::Serializer
delegate :moved?, to: :object
def id
- account_url(object)
+ object.instance_actor? ? instance_actor_url : account_url(object)
end
def type
- object.bot? ? 'Service' : 'Person'
+ if object.instance_actor?
+ 'Application'
+ elsif object.bot?
+ 'Service'
+ else
+ 'Person'
+ end
end
def following
@@ -55,7 +61,7 @@ class ActivityPub::ActorSerializer < ActivityPub::Serializer
end
def inbox
- account_inbox_url(object)
+ object.instance_actor? ? instance_actor_inbox_url : account_inbox_url(object)
end
def outbox
@@ -95,7 +101,7 @@ class ActivityPub::ActorSerializer < ActivityPub::Serializer
end
def url
- short_account_url(object)
+ object.instance_actor? ? about_more_url(instance_actor: true) : short_account_url(object)
end
def avatar_exists?
diff --git a/app/serializers/rest/account_serializer.rb b/app/serializers/rest/account_serializer.rb
index c34d234521..3ecce8f0a0 100644
--- a/app/serializers/rest/account_serializer.rb
+++ b/app/serializers/rest/account_serializer.rb
@@ -29,7 +29,7 @@ class REST::AccountSerializer < ActiveModel::Serializer
end
def url
- TagManager.instance.url_for(object)
+ ActivityPub::TagManager.instance.url_for(object)
end
def avatar
diff --git a/app/serializers/rest/status_serializer.rb b/app/serializers/rest/status_serializer.rb
index b07937014a..e739928998 100644
--- a/app/serializers/rest/status_serializer.rb
+++ b/app/serializers/rest/status_serializer.rb
@@ -61,7 +61,7 @@ class REST::StatusSerializer < ActiveModel::Serializer
end
def uri
- OStatus::TagManager.instance.uri_for(object)
+ ActivityPub::TagManager.instance.uri_for(object)
end
def content
@@ -69,7 +69,7 @@ class REST::StatusSerializer < ActiveModel::Serializer
end
def url
- TagManager.instance.url_for(object)
+ ActivityPub::TagManager.instance.url_for(object)
end
def favourited
@@ -143,7 +143,7 @@ class REST::StatusSerializer < ActiveModel::Serializer
end
def url
- TagManager.instance.url_for(object.account)
+ ActivityPub::TagManager.instance.url_for(object.account)
end
def acct
diff --git a/app/serializers/rss/account_serializer.rb b/app/serializers/rss/account_serializer.rb
index 88eca79ed2..278affe136 100644
--- a/app/serializers/rss/account_serializer.rb
+++ b/app/serializers/rss/account_serializer.rb
@@ -2,7 +2,7 @@
class RSS::AccountSerializer
include ActionView::Helpers::NumberHelper
- include StreamEntriesHelper
+ include StatusesHelper
include RoutingHelper
def render(account, statuses)
@@ -10,7 +10,7 @@ class RSS::AccountSerializer
builder.title("#{display_name(account)} (@#{account.local_username_and_domain})")
.description(account_description(account))
- .link(TagManager.instance.url_for(account))
+ .link(ActivityPub::TagManager.instance.url_for(account))
.logo(full_pack_url('media/images/logo.svg'))
.accent_color('2b90d9')
@@ -20,7 +20,7 @@ class RSS::AccountSerializer
statuses.each do |status|
builder.item do |item|
item.title(status.title)
- .link(TagManager.instance.url_for(status))
+ .link(ActivityPub::TagManager.instance.url_for(status))
.pub_date(status.created_at)
.description(status.spoiler_text.presence || Formatter.instance.format(status, inline_poll_options: true).to_str)
diff --git a/app/serializers/rss/tag_serializer.rb b/app/serializers/rss/tag_serializer.rb
index 644380149b..e8562ee87d 100644
--- a/app/serializers/rss/tag_serializer.rb
+++ b/app/serializers/rss/tag_serializer.rb
@@ -3,7 +3,7 @@
class RSS::TagSerializer
include ActionView::Helpers::NumberHelper
include ActionView::Helpers::SanitizeHelper
- include StreamEntriesHelper
+ include StatusesHelper
include RoutingHelper
def render(tag, statuses)
@@ -18,7 +18,7 @@ class RSS::TagSerializer
statuses.each do |status|
builder.item do |item|
item.title(status.title)
- .link(TagManager.instance.url_for(status))
+ .link(ActivityPub::TagManager.instance.url_for(status))
.pub_date(status.created_at)
.description(status.spoiler_text.presence || Formatter.instance.format(status).to_str)
diff --git a/app/serializers/webfinger_serializer.rb b/app/serializers/webfinger_serializer.rb
index 8c0b077020..008d0c1829 100644
--- a/app/serializers/webfinger_serializer.rb
+++ b/app/serializers/webfinger_serializer.rb
@@ -10,17 +10,26 @@ class WebfingerSerializer < ActiveModel::Serializer
end
def aliases
- [short_account_url(object), account_url(object)]
+ if object.instance_actor?
+ [instance_actor_url]
+ else
+ [short_account_url(object), account_url(object)]
+ end
end
def links
- [
- { rel: 'http://webfinger.net/rel/profile-page', type: 'text/html', href: short_account_url(object) },
- { rel: 'http://schemas.google.com/g/2010#updates-from', type: 'application/atom+xml', href: account_url(object, format: 'atom') },
- { rel: 'self', type: 'application/activity+json', href: account_url(object) },
- { rel: 'salmon', href: api_salmon_url(object.id) },
- { rel: 'magic-public-key', href: "data:application/magic-public-key,#{object.magic_key}" },
- { rel: 'http://ostatus.org/schema/1.0/subscribe', template: "#{authorize_interaction_url}?uri={uri}" },
- ]
+ if object.instance_actor?
+ [
+ { rel: 'http://webfinger.net/rel/profile-page', type: 'text/html', href: about_more_url(instance_actor: true) },
+ { rel: 'self', type: 'application/activity+json', href: instance_actor_url },
+ ]
+ else
+ [
+ { rel: 'http://webfinger.net/rel/profile-page', type: 'text/html', href: short_account_url(object) },
+ { rel: 'http://schemas.google.com/g/2010#updates-from', type: 'application/atom+xml', href: account_url(object, format: 'atom') },
+ { rel: 'self', type: 'application/activity+json', href: account_url(object) },
+ { rel: 'http://ostatus.org/schema/1.0/subscribe', template: "#{authorize_interaction_url}?uri={uri}" },
+ ]
+ end
end
end
diff --git a/app/services/activitypub/fetch_featured_collection_service.rb b/app/services/activitypub/fetch_featured_collection_service.rb
index 6a137b520b..2c27704661 100644
--- a/app/services/activitypub/fetch_featured_collection_service.rb
+++ b/app/services/activitypub/fetch_featured_collection_service.rb
@@ -4,13 +4,12 @@ class ActivityPub::FetchFeaturedCollectionService < BaseService
include JsonLdHelper
def call(account)
- return if account.featured_collection_url.blank?
+ return if account.featured_collection_url.blank? || account.suspended? || account.local?
@account = account
@json = fetch_resource(@account.featured_collection_url, true)
return unless supported_context?
- return if @account.suspended? || @account.local?
case @json['type']
when 'Collection', 'CollectionPage'
diff --git a/app/services/activitypub/fetch_remote_account_service.rb b/app/services/activitypub/fetch_remote_account_service.rb
index 3c20449412..d65c8f9511 100644
--- a/app/services/activitypub/fetch_remote_account_service.rb
+++ b/app/services/activitypub/fetch_remote_account_service.rb
@@ -2,18 +2,22 @@
class ActivityPub::FetchRemoteAccountService < BaseService
include JsonLdHelper
+ include DomainControlHelper
SUPPORTED_TYPES = %w(Application Group Organization Person Service).freeze
# Does a WebFinger roundtrip on each call, unless `only_key` is true
def call(uri, id: true, prefetched_body: nil, break_on_redirect: false, only_key: false)
+ return if domain_not_allowed?(uri)
return ActivityPub::TagManager.instance.uri_to_resource(uri, Account) if ActivityPub::TagManager.instance.local_uri?(uri)
- @json = if prefetched_body.nil?
- fetch_resource(uri, id)
- else
- body_to_json(prefetched_body, compare_id: id ? uri : nil)
- end
+ @json = begin
+ if prefetched_body.nil?
+ fetch_resource(uri, id)
+ else
+ body_to_json(prefetched_body, compare_id: id ? uri : nil)
+ end
+ end
return if !supported_context? || !expected_type? || (break_on_redirect && @json['movedTo'].present?)
diff --git a/app/services/activitypub/fetch_remote_poll_service.rb b/app/services/activitypub/fetch_remote_poll_service.rb
index 854a32d050..1c79ecf116 100644
--- a/app/services/activitypub/fetch_remote_poll_service.rb
+++ b/app/services/activitypub/fetch_remote_poll_service.rb
@@ -5,7 +5,9 @@ class ActivityPub::FetchRemotePollService < BaseService
def call(poll, on_behalf_of = nil)
json = fetch_resource(poll.status.uri, true, on_behalf_of)
+
return unless supported_context?(json)
+
ActivityPub::ProcessPollService.new.call(poll, json)
end
end
diff --git a/app/services/activitypub/fetch_remote_status_service.rb b/app/services/activitypub/fetch_remote_status_service.rb
index 469821032a..cf4f62899f 100644
--- a/app/services/activitypub/fetch_remote_status_service.rb
+++ b/app/services/activitypub/fetch_remote_status_service.rb
@@ -5,18 +5,18 @@ class ActivityPub::FetchRemoteStatusService < BaseService
# Should be called when uri has already been checked for locality
def call(uri, id: true, prefetched_body: nil, on_behalf_of: nil)
- @json = if prefetched_body.nil?
- fetch_resource(uri, id, on_behalf_of)
- else
- body_to_json(prefetched_body, compare_id: id ? uri : nil)
- end
+ @json = begin
+ if prefetched_body.nil?
+ fetch_resource(uri, id, on_behalf_of)
+ else
+ body_to_json(prefetched_body, compare_id: id ? uri : nil)
+ end
+ end
- return unless supported_context? && expected_type?
-
- return if actor_id.nil? || !trustworthy_attribution?(@json['id'], actor_id)
+ return if !(supported_context? && expected_type?) || actor_id.nil? || !trustworthy_attribution?(@json['id'], actor_id)
actor = ActivityPub::TagManager.instance.uri_to_resource(actor_id, Account)
- actor = ActivityPub::FetchRemoteAccountService.new.call(actor_id, id: true) if actor.nil? || needs_update(actor)
+ actor = ActivityPub::FetchRemoteAccountService.new.call(actor_id, id: true) if actor.nil? || needs_update?(actor)
return if actor.nil? || actor.suspended?
@@ -46,7 +46,7 @@ class ActivityPub::FetchRemoteStatusService < BaseService
equals_or_includes_any?(@json['type'], ActivityPub::Activity::Create::SUPPORTED_TYPES + ActivityPub::Activity::Create::CONVERTED_TYPES)
end
- def needs_update(actor)
+ def needs_update?(actor)
actor.possibly_stale?
end
end
diff --git a/app/services/activitypub/process_account_service.rb b/app/services/activitypub/process_account_service.rb
index 3857e7c16d..603e27ed97 100644
--- a/app/services/activitypub/process_account_service.rb
+++ b/app/services/activitypub/process_account_service.rb
@@ -2,11 +2,12 @@
class ActivityPub::ProcessAccountService < BaseService
include JsonLdHelper
+ include DomainControlHelper
# Should be called with confirmed valid JSON
# and WebFinger-resolved username and domain
def call(username, domain, json, options = {})
- return if json['inbox'].blank? || unsupported_uri_scheme?(json['id'])
+ return if json['inbox'].blank? || unsupported_uri_scheme?(json['id']) || domain_not_allowed?(domain)
@options = options
@json = json
@@ -15,8 +16,6 @@ class ActivityPub::ProcessAccountService < BaseService
@domain = domain
@collections = {}
- return if auto_suspend?
-
RedisLock.acquire(lock_options) do |lock|
if lock.acquired?
@account = Account.find_remote(@username, @domain)
diff --git a/app/services/activitypub/process_collection_service.rb b/app/services/activitypub/process_collection_service.rb
index 881df478bf..a2a2e70715 100644
--- a/app/services/activitypub/process_collection_service.rb
+++ b/app/services/activitypub/process_collection_service.rb
@@ -8,9 +8,7 @@ class ActivityPub::ProcessCollectionService < BaseService
@json = Oj.load(body, mode: :strict)
@options = options
- return unless supported_context?
- return if different_actor? && verify_account!.nil?
- return if @account.suspended? || @account.local?
+ return if !supported_context? || (different_actor? && verify_account!.nil?) || @account.suspended? || @account.local?
case @json['type']
when 'Collection', 'CollectionPage'
diff --git a/app/services/activitypub/process_poll_service.rb b/app/services/activitypub/process_poll_service.rb
index 61357abd3c..2fbce65b9c 100644
--- a/app/services/activitypub/process_poll_service.rb
+++ b/app/services/activitypub/process_poll_service.rb
@@ -5,6 +5,7 @@ class ActivityPub::ProcessPollService < BaseService
def call(poll, json)
@json = json
+
return unless expected_type?
previous_expires_at = poll.expires_at
diff --git a/app/services/authorize_follow_service.rb b/app/services/authorize_follow_service.rb
index 29b8700c7c..49bef727e6 100644
--- a/app/services/authorize_follow_service.rb
+++ b/app/services/authorize_follow_service.rb
@@ -11,25 +11,17 @@ class AuthorizeFollowService < BaseService
follow_request.authorize!
end
- create_notification(follow_request) unless source_account.local?
+ create_notification(follow_request) if !source_account.local? && source_account.activitypub?
follow_request
end
private
def create_notification(follow_request)
- if follow_request.account.ostatus?
- NotificationWorker.perform_async(build_xml(follow_request), follow_request.target_account_id, follow_request.account_id)
- elsif follow_request.account.activitypub?
- ActivityPub::DeliveryWorker.perform_async(build_json(follow_request), follow_request.target_account_id, follow_request.account.inbox_url)
- end
+ ActivityPub::DeliveryWorker.perform_async(build_json(follow_request), follow_request.target_account_id, follow_request.account.inbox_url)
end
def build_json(follow_request)
Oj.dump(serialize_payload(follow_request, ActivityPub::AcceptFollowSerializer))
end
-
- def build_xml(follow_request)
- OStatus::AtomSerializer.render(OStatus::AtomSerializer.new.authorize_follow_request_salmon(follow_request))
- end
end
diff --git a/app/services/batched_remove_status_service.rb b/app/services/batched_remove_status_service.rb
index 2fe009c913..bbee47cb70 100644
--- a/app/services/batched_remove_status_service.rb
+++ b/app/services/batched_remove_status_service.rb
@@ -1,7 +1,6 @@
# frozen_string_literal: true
class BatchedRemoveStatusService < BaseService
- include StreamEntryRenderer
include Redisable
# Delete given statuses and reblogs of them
@@ -13,15 +12,12 @@ class BatchedRemoveStatusService < BaseService
# @param [Hash] options
# @option [Boolean] :skip_side_effects
def call(statuses, **options)
- statuses = Status.where(id: statuses.map(&:id)).includes(:account, :stream_entry).flat_map { |status| [status] + status.reblogs.includes(:account, :stream_entry).to_a }
+ statuses = Status.where(id: statuses.map(&:id)).includes(:account).flat_map { |status| [status] + status.reblogs.includes(:account).to_a }
@mentions = statuses.each_with_object({}) { |s, h| h[s.id] = s.active_mentions.includes(:account).to_a }
@tags = statuses.each_with_object({}) { |s, h| h[s.id] = s.tags.pluck(:name) }
- @stream_entry_batches = []
- @salmon_batches = []
- @json_payloads = statuses.each_with_object({}) { |s, h| h[s.id] = Oj.dump(event: :delete, payload: s.id.to_s) }
- @activity_xml = {}
+ @json_payloads = statuses.each_with_object({}) { |s, h| h[s.id] = Oj.dump(event: :delete, payload: s.id.to_s) }
# Ensure that rendered XML reflects destroyed state
statuses.each do |status|
@@ -39,29 +35,17 @@ class BatchedRemoveStatusService < BaseService
unpush_from_home_timelines(account, account_statuses)
unpush_from_list_timelines(account, account_statuses)
-
- batch_stream_entries(account, account_statuses) if account.local?
end
# Cannot be batched
statuses.each do |status|
unpush_from_public_timelines(status)
unpush_from_direct_timelines(status) if status.direct_visibility?
- batch_salmon_slaps(status) if status.local?
end
-
- Pubsubhubbub::RawDistributionWorker.push_bulk(@stream_entry_batches) { |batch| batch }
- NotificationWorker.push_bulk(@salmon_batches) { |batch| batch }
end
private
- def batch_stream_entries(account, statuses)
- statuses.each do |status|
- @stream_entry_batches << [build_xml(status.stream_entry), account.id]
- end
- end
-
def unpush_from_home_timelines(account, statuses)
recipients = account.followers_for_local_distribution.to_a
@@ -112,20 +96,4 @@ class BatchedRemoveStatusService < BaseService
FeedManager.instance.unpush_from_direct(status.account, status) if status.account.local?
end
end
-
- def batch_salmon_slaps(status)
- return if @mentions[status.id].empty?
-
- recipients = @mentions[status.id].map(&:account).reject(&:local?).select(&:ostatus?).uniq(&:domain).map(&:id)
-
- recipients.each do |recipient_id|
- @salmon_batches << [build_xml(status.stream_entry), status.account_id, recipient_id]
- end
- end
-
- def build_xml(stream_entry)
- return @activity_xml[stream_entry.id] if @activity_xml.key?(stream_entry.id)
-
- @activity_xml[stream_entry.id] = stream_entry_to_xml(stream_entry)
- end
end
diff --git a/app/services/block_domain_service.rb b/app/services/block_domain_service.rb
index c6eef04d42..c5e5e57613 100644
--- a/app/services/block_domain_service.rb
+++ b/app/services/block_domain_service.rb
@@ -44,7 +44,6 @@ class BlockDomainService < BaseService
def suspend_accounts!
blocked_domain_accounts.without_suspended.reorder(nil).find_each do |account|
- UnsubscribeService.new.call(account) if account.subscribed?
SuspendAccountService.new.call(account, suspended_at: @domain_block.created_at)
end
end
diff --git a/app/services/block_service.rb b/app/services/block_service.rb
index 0d9a6eccda..266a0f4b9d 100644
--- a/app/services/block_service.rb
+++ b/app/services/block_service.rb
@@ -13,25 +13,17 @@ class BlockService < BaseService
block = account.block!(target_account)
BlockWorker.perform_async(account.id, target_account.id)
- create_notification(block) unless target_account.local?
+ create_notification(block) if !target_account.local? && target_account.activitypub?
block
end
private
def create_notification(block)
- if block.target_account.ostatus?
- NotificationWorker.perform_async(build_xml(block), block.account_id, block.target_account_id)
- elsif block.target_account.activitypub?
- ActivityPub::DeliveryWorker.perform_async(build_json(block), block.account_id, block.target_account.inbox_url)
- end
+ ActivityPub::DeliveryWorker.perform_async(build_json(block), block.account_id, block.target_account.inbox_url)
end
def build_json(block)
Oj.dump(serialize_payload(block, ActivityPub::BlockSerializer))
end
-
- def build_xml(block)
- OStatus::AtomSerializer.render(OStatus::AtomSerializer.new.block_salmon(block))
- end
end
diff --git a/app/services/concerns/author_extractor.rb b/app/services/concerns/author_extractor.rb
deleted file mode 100644
index c2419e9ecb..0000000000
--- a/app/services/concerns/author_extractor.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-# frozen_string_literal: true
-
-module AuthorExtractor
- def author_from_xml(xml, update_profile = true)
- return nil if xml.nil?
-
- # Try for acct
- acct = xml.at_xpath('./xmlns:author/xmlns:email', xmlns: OStatus::TagManager::XMLNS)&.content
-
- # Try +
- if acct.blank?
- username = xml.at_xpath('./xmlns:author/xmlns:name', xmlns: OStatus::TagManager::XMLNS)&.content
- uri = xml.at_xpath('./xmlns:author/xmlns:uri', xmlns: OStatus::TagManager::XMLNS)&.content
-
- return nil if username.blank? || uri.blank?
-
- domain = Addressable::URI.parse(uri).normalized_host
- acct = "#{username}@#{domain}"
- end
-
- ResolveAccountService.new.call(acct, update_profile: update_profile)
- end
-end
diff --git a/app/services/concerns/payloadable.rb b/app/services/concerns/payloadable.rb
index 13d9c35483..953740faa3 100644
--- a/app/services/concerns/payloadable.rb
+++ b/app/services/concerns/payloadable.rb
@@ -14,6 +14,6 @@ module Payloadable
end
def signing_enabled?
- true
+ ENV['AUTHORIZED_FETCH'] != 'true'
end
end
diff --git a/app/services/concerns/stream_entry_renderer.rb b/app/services/concerns/stream_entry_renderer.rb
deleted file mode 100644
index 9f6c8a082a..0000000000
--- a/app/services/concerns/stream_entry_renderer.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-# frozen_string_literal: true
-
-module StreamEntryRenderer
- def stream_entry_to_xml(stream_entry)
- OStatus::AtomSerializer.render(OStatus::AtomSerializer.new.entry(stream_entry, true))
- end
-end
diff --git a/app/services/favourite_service.rb b/app/services/favourite_service.rb
index 128a24ad61..02b26458a6 100644
--- a/app/services/favourite_service.rb
+++ b/app/services/favourite_service.rb
@@ -30,8 +30,6 @@ class FavouriteService < BaseService
if status.account.local?
NotifyService.new.call(status.account, favourite)
- elsif status.account.ostatus?
- NotificationWorker.perform_async(build_xml(favourite), favourite.account_id, status.account_id)
elsif status.account.activitypub?
ActivityPub::DeliveryWorker.perform_async(build_json(favourite), favourite.account_id, status.account.inbox_url)
end
@@ -46,8 +44,4 @@ class FavouriteService < BaseService
def build_json(favourite)
Oj.dump(serialize_payload(favourite, ActivityPub::LikeSerializer))
end
-
- def build_xml(favourite)
- OStatus::AtomSerializer.render(OStatus::AtomSerializer.new.favourite_salmon(favourite))
- end
end
diff --git a/app/services/fetch_atom_service.rb b/app/services/fetch_atom_service.rb
deleted file mode 100644
index d6508a9888..0000000000
--- a/app/services/fetch_atom_service.rb
+++ /dev/null
@@ -1,93 +0,0 @@
-# frozen_string_literal: true
-
-class FetchAtomService < BaseService
- include JsonLdHelper
-
- def call(url)
- return if url.blank?
-
- result = process(url)
-
- # retry without ActivityPub
- result ||= process(url) if @unsupported_activity
-
- result
- rescue OpenSSL::SSL::SSLError => e
- Rails.logger.debug "SSL error: #{e}"
- nil
- rescue HTTP::ConnectionError => e
- Rails.logger.debug "HTTP ConnectionError: #{e}"
- nil
- end
-
- private
-
- def process(url, terminal = false)
- @url = url
- perform_request { |response| process_response(response, terminal) }
- end
-
- def perform_request(&block)
- accept = 'text/html'
- accept = 'application/activity+json, application/ld+json; profile="https://www.w3.org/ns/activitystreams", application/atom+xml, ' + accept unless @unsupported_activity
-
- Request.new(:get, @url).add_headers('Accept' => accept).perform(&block)
- end
-
- def process_response(response, terminal = false)
- return nil if response.code != 200
-
- if response.mime_type == 'application/atom+xml'
- [@url, { prefetched_body: response.body_with_limit }, :ostatus]
- elsif ['application/activity+json', 'application/ld+json'].include?(response.mime_type)
- body = response.body_with_limit
- json = body_to_json(body)
- if supported_context?(json) && equals_or_includes_any?(json['type'], ActivityPub::FetchRemoteAccountService::SUPPORTED_TYPES) && json['inbox'].present?
- [json['id'], { prefetched_body: body, id: true }, :activitypub]
- elsif supported_context?(json) && expected_type?(json)
- [json['id'], { prefetched_body: body, id: true }, :activitypub]
- else
- @unsupported_activity = true
- nil
- end
- elsif !terminal
- link_header = response['Link'] && parse_link_header(response)
-
- if link_header&.find_link(%w(rel alternate))
- process_link_headers(link_header)
- elsif response.mime_type == 'text/html'
- process_html(response)
- end
- end
- end
-
- def expected_type?(json)
- equals_or_includes_any?(json['type'], ActivityPub::Activity::Create::SUPPORTED_TYPES + ActivityPub::Activity::Create::CONVERTED_TYPES)
- end
-
- def process_html(response)
- page = Nokogiri::HTML(response.body_with_limit)
-
- json_link = page.xpath('//link[@rel="alternate"]').find { |link| ['application/activity+json', 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"'].include?(link['type']) }
- atom_link = page.xpath('//link[@rel="alternate"]').find { |link| link['type'] == 'application/atom+xml' }
-
- result ||= process(json_link['href'], terminal: true) unless json_link.nil? || @unsupported_activity
- result ||= process(atom_link['href'], terminal: true) unless atom_link.nil?
-
- result
- end
-
- def process_link_headers(link_header)
- json_link = link_header.find_link(%w(rel alternate), %w(type application/activity+json)) || link_header.find_link(%w(rel alternate), ['type', 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"'])
- atom_link = link_header.find_link(%w(rel alternate), %w(type application/atom+xml))
-
- result ||= process(json_link.href, terminal: true) unless json_link.nil? || @unsupported_activity
- result ||= process(atom_link.href, terminal: true) unless atom_link.nil?
-
- result
- end
-
- def parse_link_header(response)
- LinkHeader.parse(response['Link'].is_a?(Array) ? response['Link'].first : response['Link'])
- end
-end
diff --git a/app/services/fetch_link_card_service.rb b/app/services/fetch_link_card_service.rb
index 494aaed759..4e75c370fa 100644
--- a/app/services/fetch_link_card_service.rb
+++ b/app/services/fetch_link_card_service.rb
@@ -29,7 +29,7 @@ class FetchLinkCardService < BaseService
end
attach_card if @card&.persisted?
- rescue HTTP::Error, Addressable::URI::InvalidURIError, Mastodon::HostValidationError, Mastodon::LengthValidationError => e
+ rescue HTTP::Error, OpenSSL::SSL::SSLError, Addressable::URI::InvalidURIError, Mastodon::HostValidationError, Mastodon::LengthValidationError => e
Rails.logger.debug "Error fetching link #{@url}: #{e}"
nil
end
@@ -84,7 +84,7 @@ class FetchLinkCardService < BaseService
def mention_link?(a)
@status.mentions.any? do |mention|
- a['href'] == TagManager.instance.url_for(mention.account)
+ a['href'] == ActivityPub::TagManager.instance.url_for(mention.account)
end
end
diff --git a/app/services/fetch_remote_account_service.rb b/app/services/fetch_remote_account_service.rb
index cfc560022f..3cd06e30f6 100644
--- a/app/services/fetch_remote_account_service.rb
+++ b/app/services/fetch_remote_account_service.rb
@@ -1,45 +1,17 @@
# frozen_string_literal: true
class FetchRemoteAccountService < BaseService
- include AuthorExtractor
-
def call(url, prefetched_body = nil, protocol = :ostatus)
if prefetched_body.nil?
- resource_url, resource_options, protocol = FetchAtomService.new.call(url)
+ resource_url, resource_options, protocol = FetchResourceService.new.call(url)
else
resource_url = url
resource_options = { prefetched_body: prefetched_body }
end
case protocol
- when :ostatus
- process_atom(resource_url, **resource_options)
when :activitypub
ActivityPub::FetchRemoteAccountService.new.call(resource_url, **resource_options)
end
end
-
- private
-
- def process_atom(url, prefetched_body:)
- xml = Nokogiri::XML(prefetched_body)
- xml.encoding = 'utf-8'
-
- account = author_from_xml(xml.at_xpath('/xmlns:feed', xmlns: OStatus::TagManager::XMLNS), false)
-
- UpdateRemoteProfileService.new.call(xml, account) if account.present? && trusted_domain?(url, account)
-
- account
- rescue TypeError
- Rails.logger.debug "Unparseable URL given: #{url}"
- nil
- rescue Nokogiri::XML::XPath::SyntaxError
- Rails.logger.debug 'Invalid XML or missing namespace'
- nil
- end
-
- def trusted_domain?(url, account)
- domain = Addressable::URI.parse(url).normalized_host
- domain.casecmp(account.domain).zero? || domain.casecmp(Addressable::URI.parse(account.remote_url.presence || account.uri).normalized_host).zero?
- end
end
diff --git a/app/services/fetch_remote_status_service.rb b/app/services/fetch_remote_status_service.rb
index 9c3008035d..208dc7809c 100644
--- a/app/services/fetch_remote_status_service.rb
+++ b/app/services/fetch_remote_status_service.rb
@@ -1,45 +1,17 @@
# frozen_string_literal: true
class FetchRemoteStatusService < BaseService
- include AuthorExtractor
-
def call(url, prefetched_body = nil, protocol = :ostatus)
if prefetched_body.nil?
- resource_url, resource_options, protocol = FetchAtomService.new.call(url)
+ resource_url, resource_options, protocol = FetchResourceService.new.call(url)
else
resource_url = url
resource_options = { prefetched_body: prefetched_body }
end
case protocol
- when :ostatus
- process_atom(resource_url, **resource_options)
when :activitypub
ActivityPub::FetchRemoteStatusService.new.call(resource_url, **resource_options)
end
end
-
- private
-
- def process_atom(url, prefetched_body:)
- Rails.logger.debug "Processing Atom for remote status at #{url}"
-
- xml = Nokogiri::XML(prefetched_body)
- xml.encoding = 'utf-8'
-
- account = author_from_xml(xml.at_xpath('/xmlns:entry', xmlns: OStatus::TagManager::XMLNS))
- domain = Addressable::URI.parse(url).normalized_host
-
- return nil unless !account.nil? && confirmed_domain?(domain, account)
-
- statuses = ProcessFeedService.new.call(prefetched_body, account)
- statuses.first
- rescue Nokogiri::XML::XPath::SyntaxError
- Rails.logger.debug 'Invalid XML or missing namespace'
- nil
- end
-
- def confirmed_domain?(domain, account)
- account.domain.nil? || domain.casecmp(account.domain).zero? || domain.casecmp(Addressable::URI.parse(account.remote_url.presence || account.uri).normalized_host).zero?
- end
end
diff --git a/app/services/fetch_resource_service.rb b/app/services/fetch_resource_service.rb
new file mode 100644
index 0000000000..3676d899d2
--- /dev/null
+++ b/app/services/fetch_resource_service.rb
@@ -0,0 +1,68 @@
+# frozen_string_literal: true
+
+class FetchResourceService < BaseService
+ include JsonLdHelper
+
+ ACCEPT_HEADER = 'application/activity+json, application/ld+json; profile="https://www.w3.org/ns/activitystreams", text/html'
+
+ def call(url)
+ return if url.blank?
+
+ process(url)
+ rescue HTTP::Error, OpenSSL::SSL::SSLError, Addressable::URI::InvalidURIError, Mastodon::HostValidationError, Mastodon::LengthValidationError => e
+ Rails.logger.debug "Error fetching resource #{@url}: #{e}"
+ nil
+ end
+
+ private
+
+ def process(url, terminal = false)
+ @url = url
+
+ perform_request { |response| process_response(response, terminal) }
+ end
+
+ def perform_request(&block)
+ Request.new(:get, @url).add_headers('Accept' => ACCEPT_HEADER).on_behalf_of(Account.representative).perform(&block)
+ end
+
+ def process_response(response, terminal = false)
+ return nil if response.code != 200
+
+ if ['application/activity+json', 'application/ld+json'].include?(response.mime_type)
+ body = response.body_with_limit
+ json = body_to_json(body)
+
+ [json['id'], { prefetched_body: body, id: true }, :activitypub] if supported_context?(json) && (equals_or_includes_any?(json['type'], ActivityPub::FetchRemoteAccountService::SUPPORTED_TYPES) || expected_type?(json))
+ elsif !terminal
+ link_header = response['Link'] && parse_link_header(response)
+
+ if link_header&.find_link(%w(rel alternate))
+ process_link_headers(link_header)
+ elsif response.mime_type == 'text/html'
+ process_html(response)
+ end
+ end
+ end
+
+ def expected_type?(json)
+ equals_or_includes_any?(json['type'], ActivityPub::Activity::Create::SUPPORTED_TYPES + ActivityPub::Activity::Create::CONVERTED_TYPES)
+ end
+
+ def process_html(response)
+ page = Nokogiri::HTML(response.body_with_limit)
+ json_link = page.xpath('//link[@rel="alternate"]').find { |link| ['application/activity+json', 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"'].include?(link['type']) }
+
+ process(json_link['href'], terminal: true) unless json_link.nil?
+ end
+
+ def process_link_headers(link_header)
+ json_link = link_header.find_link(%w(rel alternate), %w(type application/activity+json)) || link_header.find_link(%w(rel alternate), ['type', 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"'])
+
+ process(json_link.href, terminal: true) unless json_link.nil?
+ end
+
+ def parse_link_header(response)
+ LinkHeader.parse(response['Link'].is_a?(Array) ? response['Link'].first : response['Link'])
+ end
+end
diff --git a/app/services/follow_service.rb b/app/services/follow_service.rb
index 0305e2d621..8e118f5d34 100644
--- a/app/services/follow_service.rb
+++ b/app/services/follow_service.rb
@@ -13,7 +13,7 @@ class FollowService < BaseService
target_account = ResolveAccountService.new.call(target_account, skip_webfinger: true)
raise ActiveRecord::RecordNotFound if target_account.nil? || target_account.id == source_account.id || target_account.suspended?
- raise Mastodon::NotPermittedError if target_account.blocking?(source_account) || source_account.blocking?(target_account) || target_account.moved?
+ raise Mastodon::NotPermittedError if target_account.blocking?(source_account) || source_account.blocking?(target_account) || target_account.moved? || (!target_account.local? && target_account.ostatus?)
if source_account.following?(target_account)
# We're already following this account, but we'll call follow! again to
@@ -32,7 +32,7 @@ class FollowService < BaseService
if target_account.locked? || target_account.activitypub?
request_follow(source_account, target_account, reblogs: reblogs)
- else
+ elsif target_account.local?
direct_follow(source_account, target_account, reblogs: reblogs)
end
end
@@ -44,9 +44,6 @@ class FollowService < BaseService
if target_account.local?
LocalNotificationWorker.perform_async(target_account.id, follow_request.id, follow_request.class.name)
- elsif target_account.ostatus?
- NotificationWorker.perform_async(build_follow_request_xml(follow_request), source_account.id, target_account.id)
- AfterRemoteFollowRequestWorker.perform_async(follow_request.id)
elsif target_account.activitypub?
ActivityPub::DeliveryWorker.perform_async(build_json(follow_request), source_account.id, target_account.inbox_url)
end
@@ -57,27 +54,12 @@ class FollowService < BaseService
def direct_follow(source_account, target_account, reblogs: true)
follow = source_account.follow!(target_account, reblogs: reblogs)
- if target_account.local?
- LocalNotificationWorker.perform_async(target_account.id, follow.id, follow.class.name)
- else
- Pubsubhubbub::SubscribeWorker.perform_async(target_account.id) unless target_account.subscribed?
- NotificationWorker.perform_async(build_follow_xml(follow), source_account.id, target_account.id)
- AfterRemoteFollowWorker.perform_async(follow.id)
- end
-
+ LocalNotificationWorker.perform_async(target_account.id, follow.id, follow.class.name)
MergeWorker.perform_async(target_account.id, source_account.id)
follow
end
- def build_follow_request_xml(follow_request)
- OStatus::AtomSerializer.render(OStatus::AtomSerializer.new.follow_request_salmon(follow_request))
- end
-
- def build_follow_xml(follow)
- OStatus::AtomSerializer.render(OStatus::AtomSerializer.new.follow_salmon(follow))
- end
-
def build_json(follow_request)
Oj.dump(serialize_payload(follow_request, ActivityPub::FollowSerializer))
end
diff --git a/app/services/post_status_service.rb b/app/services/post_status_service.rb
index 6d7c44913b..b364713394 100644
--- a/app/services/post_status_service.rb
+++ b/app/services/post_status_service.rb
@@ -91,12 +91,7 @@ class PostStatusService < BaseService
def postprocess_status!
LinkCrawlWorker.perform_async(@status.id) unless @status.spoiler_text?
DistributionWorker.perform_async(@status.id)
-
- unless @status.local_only?
- Pubsubhubbub::DistributionWorker.perform_async(@status.stream_entry.id)
- ActivityPub::DistributionWorker.perform_async(@status.id)
- end
-
+ ActivityPub::DistributionWorker.perform_async(@status.id) unless @status.local_only?
PollExpirationNotifyWorker.perform_at(@status.poll.expires_at, @status.poll.id) if @status.poll
end
diff --git a/app/services/process_feed_service.rb b/app/services/process_feed_service.rb
deleted file mode 100644
index 30a9dd85eb..0000000000
--- a/app/services/process_feed_service.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-# frozen_string_literal: true
-
-class ProcessFeedService < BaseService
- def call(body, account, **options)
- @options = options
-
- xml = Nokogiri::XML(body)
- xml.encoding = 'utf-8'
-
- update_author(body, account)
- process_entries(xml, account)
- end
-
- private
-
- def update_author(body, account)
- RemoteProfileUpdateWorker.perform_async(account.id, body.force_encoding('UTF-8'), true)
- end
-
- def process_entries(xml, account)
- xml.xpath('//xmlns:entry', xmlns: OStatus::TagManager::XMLNS).reverse_each.map { |entry| process_entry(entry, account) }.compact
- end
-
- def process_entry(xml, account)
- activity = OStatus::Activity::General.new(xml, account, @options)
- activity.specialize&.perform if activity.status?
- rescue ActiveRecord::RecordInvalid => e
- Rails.logger.debug "Nothing was saved for #{activity.id} because: #{e}"
- nil
- end
-end
diff --git a/app/services/process_hashtags_service.rb b/app/services/process_hashtags_service.rb
index d5ec076a8b..b6974e598b 100644
--- a/app/services/process_hashtags_service.rb
+++ b/app/services/process_hashtags_service.rb
@@ -14,7 +14,7 @@ class ProcessHashtagsService < BaseService
TrendingTags.record_use!(tag, status.account, status.created_at) if status.public_visibility?
end
- return unless status.public_visibility? || status.unlisted_visibility?
+ return unless status.distributable?
status.account.featured_tags.where(tag_id: records.map(&:id)).each do |featured_tag|
featured_tag.increment(status.created_at)
diff --git a/app/services/process_interaction_service.rb b/app/services/process_interaction_service.rb
deleted file mode 100644
index 1fca3832b7..0000000000
--- a/app/services/process_interaction_service.rb
+++ /dev/null
@@ -1,151 +0,0 @@
-# frozen_string_literal: true
-
-class ProcessInteractionService < BaseService
- include AuthorExtractor
- include Authorization
-
- # Record locally the remote interaction with our user
- # @param [String] envelope Salmon envelope
- # @param [Account] target_account Account the Salmon was addressed to
- def call(envelope, target_account)
- body = salmon.unpack(envelope)
-
- xml = Nokogiri::XML(body)
- xml.encoding = 'utf-8'
-
- account = author_from_xml(xml.at_xpath('/xmlns:entry', xmlns: OStatus::TagManager::XMLNS))
-
- return if account.nil? || account.suspended?
-
- if salmon.verify(envelope, account.keypair)
- RemoteProfileUpdateWorker.perform_async(account.id, body.force_encoding('UTF-8'), true)
-
- case verb(xml)
- when :follow
- follow!(account, target_account) unless target_account.locked? || target_account.blocking?(account) || target_account.domain_blocking?(account.domain)
- when :request_friend
- follow_request!(account, target_account) unless !target_account.locked? || target_account.blocking?(account) || target_account.domain_blocking?(account.domain)
- when :authorize
- authorize_follow_request!(account, target_account)
- when :reject
- reject_follow_request!(account, target_account)
- when :unfollow
- unfollow!(account, target_account)
- when :favorite
- favourite!(xml, account)
- when :unfavorite
- unfavourite!(xml, account)
- when :post
- add_post!(body, account) if mentions_account?(xml, target_account)
- when :share
- add_post!(body, account) unless status(xml).nil?
- when :delete
- delete_post!(xml, account)
- when :block
- reflect_block!(account, target_account)
- when :unblock
- reflect_unblock!(account, target_account)
- end
- end
- rescue HTTP::Error, OStatus2::BadSalmonError, Mastodon::NotPermittedError
- nil
- end
-
- private
-
- def mentions_account?(xml, account)
- xml.xpath('/xmlns:entry/xmlns:link[@rel="mentioned"]', xmlns: OStatus::TagManager::XMLNS).each { |mention_link| return true if [OStatus::TagManager.instance.uri_for(account), OStatus::TagManager.instance.url_for(account)].include?(mention_link.attribute('href').value) }
- false
- end
-
- def verb(xml)
- raw = xml.at_xpath('//activity:verb', activity: OStatus::TagManager::AS_XMLNS).content
- OStatus::TagManager::VERBS.key(raw)
- rescue
- :post
- end
-
- def follow!(account, target_account)
- follow = account.follow!(target_account)
- FollowRequest.find_by(account: account, target_account: target_account)&.destroy
- NotifyService.new.call(target_account, follow)
- end
-
- def follow_request!(account, target_account)
- return if account.requested?(target_account)
-
- follow_request = FollowRequest.create!(account: account, target_account: target_account)
- NotifyService.new.call(target_account, follow_request)
- end
-
- def authorize_follow_request!(account, target_account)
- follow_request = FollowRequest.find_by(account: target_account, target_account: account)
- follow_request&.authorize!
- Pubsubhubbub::SubscribeWorker.perform_async(account.id) unless account.subscribed?
- end
-
- def reject_follow_request!(account, target_account)
- follow_request = FollowRequest.find_by(account: target_account, target_account: account)
- follow_request&.reject!
- end
-
- def unfollow!(account, target_account)
- account.unfollow!(target_account)
- FollowRequest.find_by(account: account, target_account: target_account)&.destroy
- end
-
- def reflect_block!(account, target_account)
- UnfollowService.new.call(target_account, account) if target_account.following?(account)
- account.block!(target_account)
- end
-
- def reflect_unblock!(account, target_account)
- UnblockService.new.call(account, target_account)
- end
-
- def delete_post!(xml, account)
- status = Status.find(xml.at_xpath('//xmlns:id', xmlns: OStatus::TagManager::XMLNS).content)
-
- return if status.nil?
-
- authorize_with account, status, :destroy?
-
- RemovalWorker.perform_async(status.id)
- end
-
- def favourite!(xml, from_account)
- current_status = status(xml)
-
- return if current_status.nil?
-
- favourite = current_status.favourites.where(account: from_account).first_or_create!(account: from_account)
- NotifyService.new.call(current_status.account, favourite)
- end
-
- def unfavourite!(xml, from_account)
- current_status = status(xml)
-
- return if current_status.nil?
-
- favourite = current_status.favourites.where(account: from_account).first
- favourite&.destroy
- end
-
- def add_post!(body, account)
- ProcessingWorker.perform_async(account.id, body.force_encoding('UTF-8'))
- end
-
- def status(xml)
- uri = activity_id(xml)
- return nil unless OStatus::TagManager.instance.local_id?(uri)
- Status.find(OStatus::TagManager.instance.unique_tag_to_local_id(uri, 'Status'))
- end
-
- def activity_id(xml)
- xml.at_xpath('//activity:object', activity: OStatus::TagManager::AS_XMLNS).at_xpath('./xmlns:id', xmlns: OStatus::TagManager::XMLNS).content
- end
-
- def salmon
- @salmon ||= OStatus2::Salmon.new
- end
-end
diff --git a/app/services/process_mentions_service.rb b/app/services/process_mentions_service.rb
index 1804e0c93f..a374206eb8 100644
--- a/app/services/process_mentions_service.rb
+++ b/app/services/process_mentions_service.rb
@@ -1,7 +1,6 @@
# frozen_string_literal: true
class ProcessMentionsService < BaseService
- include StreamEntryRenderer
include Payloadable
# Scan status for mentions and fetch remote mentioned users, create
@@ -41,7 +40,7 @@ class ProcessMentionsService < BaseService
private
def mention_undeliverable?(mentioned_account)
- mentioned_account.nil? || (!mentioned_account.local? && mentioned_account.ostatus? && @status.stream_entry.hidden?)
+ mentioned_account.nil? || (!mentioned_account.local? && mentioned_account.ostatus?)
end
def create_notification(mention)
@@ -49,17 +48,11 @@ class ProcessMentionsService < BaseService
if mentioned_account.local?
LocalNotificationWorker.perform_async(mentioned_account.id, mention.id, mention.class.name)
- elsif mentioned_account.ostatus? && !@status.stream_entry.hidden? && !@status.local_only?
- NotificationWorker.perform_async(ostatus_xml, @status.account_id, mentioned_account.id)
elsif mentioned_account.activitypub? && !@status.local_only?
ActivityPub::DeliveryWorker.perform_async(activitypub_json, mention.status.account_id, mentioned_account.inbox_url)
end
end
- def ostatus_xml
- @ostatus_xml ||= stream_entry_to_xml(@status.stream_entry)
- end
-
def activitypub_json
return @activitypub_json if defined?(@activitypub_json)
@activitypub_json = Oj.dump(serialize_payload(@status, ActivityPub::ActivitySerializer, signer: @status.account))
diff --git a/app/services/pubsubhubbub/subscribe_service.rb b/app/services/pubsubhubbub/subscribe_service.rb
deleted file mode 100644
index 550da63281..0000000000
--- a/app/services/pubsubhubbub/subscribe_service.rb
+++ /dev/null
@@ -1,53 +0,0 @@
-# frozen_string_literal: true
-
-class Pubsubhubbub::SubscribeService < BaseService
- URL_PATTERN = /\A#{URI.regexp(%w(http https))}\z/
-
- attr_reader :account, :callback, :secret,
- :lease_seconds, :domain
-
- def call(account, callback, secret, lease_seconds, verified_domain = nil)
- @account = account
- @callback = Addressable::URI.parse(callback).normalize.to_s
- @secret = secret
- @lease_seconds = lease_seconds
- @domain = verified_domain
-
- process_subscribe
- end
-
- private
-
- def process_subscribe
- if account.nil?
- ['Invalid topic URL', 422]
- elsif !valid_callback?
- ['Invalid callback URL', 422]
- elsif blocked_domain?
- ['Callback URL not allowed', 403]
- else
- confirm_subscription
- ['', 202]
- end
- end
-
- def confirm_subscription
- subscription = locate_subscription
- Pubsubhubbub::ConfirmationWorker.perform_async(subscription.id, 'subscribe', secret, lease_seconds)
- end
-
- def valid_callback?
- callback.present? && callback =~ URL_PATTERN
- end
-
- def blocked_domain?
- DomainBlock.blocked? Addressable::URI.parse(callback).host
- end
-
- def locate_subscription
- subscription = Subscription.find_or_initialize_by(account: account, callback_url: callback)
- subscription.domain = domain
- subscription.save!
- subscription
- end
-end
diff --git a/app/services/pubsubhubbub/unsubscribe_service.rb b/app/services/pubsubhubbub/unsubscribe_service.rb
deleted file mode 100644
index 646150f7bb..0000000000
--- a/app/services/pubsubhubbub/unsubscribe_service.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-# frozen_string_literal: true
-
-class Pubsubhubbub::UnsubscribeService < BaseService
- attr_reader :account, :callback
-
- def call(account, callback)
- @account = account
- @callback = Addressable::URI.parse(callback).normalize.to_s
-
- process_unsubscribe
- end
-
- private
-
- def process_unsubscribe
- if account.nil?
- ['Invalid topic URL', 422]
- else
- confirm_unsubscribe unless subscription.nil?
- ['', 202]
- end
- end
-
- def confirm_unsubscribe
- Pubsubhubbub::ConfirmationWorker.perform_async(subscription.id, 'unsubscribe')
- end
-
- def subscription
- @_subscription ||= Subscription.find_by(account: account, callback_url: callback)
- end
-end
diff --git a/app/services/reblog_service.rb b/app/services/reblog_service.rb
index 09403bae0f..0b12f143ca 100644
--- a/app/services/reblog_service.rb
+++ b/app/services/reblog_service.rb
@@ -2,7 +2,6 @@
class ReblogService < BaseService
include Authorization
- include StreamEntryRenderer
include Payloadable
# Reblog a status and notify its remote author
@@ -24,11 +23,7 @@ class ReblogService < BaseService
reblog = account.statuses.create!(reblog: reblogged_status, text: '', visibility: visibility)
DistributionWorker.perform_async(reblog.id)
-
- unless reblogged_status.local_only?
- Pubsubhubbub::DistributionWorker.perform_async(reblog.stream_entry.id)
- ActivityPub::DistributionWorker.perform_async(reblog.id)
- end
+ ActivityPub::DistributionWorker.perform_async(reblog.id) unless reblogged_status.local_only?
create_notification(reblog)
bump_potential_friendship(account, reblog)
@@ -43,8 +38,6 @@ class ReblogService < BaseService
if reblogged_status.account.local?
LocalNotificationWorker.perform_async(reblogged_status.account_id, reblog.id, reblog.class.name)
- elsif reblogged_status.account.ostatus?
- NotificationWorker.perform_async(stream_entry_to_xml(reblog.stream_entry), reblog.account_id, reblogged_status.account_id)
elsif reblogged_status.account.activitypub? && !reblogged_status.account.following?(reblog.account)
ActivityPub::DeliveryWorker.perform_async(build_json(reblog), reblog.account_id, reblogged_status.account.inbox_url)
end
diff --git a/app/services/reject_follow_service.rb b/app/services/reject_follow_service.rb
index f87d0ba914..bc0000c8c8 100644
--- a/app/services/reject_follow_service.rb
+++ b/app/services/reject_follow_service.rb
@@ -6,25 +6,17 @@ class RejectFollowService < BaseService
def call(source_account, target_account)
follow_request = FollowRequest.find_by!(account: source_account, target_account: target_account)
follow_request.reject!
- create_notification(follow_request) unless source_account.local?
+ create_notification(follow_request) if !source_account.local? && source_account.activitypub?
follow_request
end
private
def create_notification(follow_request)
- if follow_request.account.ostatus?
- NotificationWorker.perform_async(build_xml(follow_request), follow_request.target_account_id, follow_request.account_id)
- elsif follow_request.account.activitypub?
- ActivityPub::DeliveryWorker.perform_async(build_json(follow_request), follow_request.target_account_id, follow_request.account.inbox_url)
- end
+ ActivityPub::DeliveryWorker.perform_async(build_json(follow_request), follow_request.target_account_id, follow_request.account.inbox_url)
end
def build_json(follow_request)
Oj.dump(serialize_payload(follow_request, ActivityPub::RejectFollowSerializer))
end
-
- def build_xml(follow_request)
- OStatus::AtomSerializer.render(OStatus::AtomSerializer.new.reject_follow_request_salmon(follow_request))
- end
end
diff --git a/app/services/remove_status_service.rb b/app/services/remove_status_service.rb
index 9d5d0fc147..958a67e8f1 100644
--- a/app/services/remove_status_service.rb
+++ b/app/services/remove_status_service.rb
@@ -1,19 +1,17 @@
# frozen_string_literal: true
class RemoveStatusService < BaseService
- include StreamEntryRenderer
include Redisable
include Payloadable
def call(status, **options)
- @payload = Oj.dump(event: :delete, payload: status.id.to_s)
- @status = status
- @account = status.account
- @tags = status.tags.pluck(:name).to_a
- @mentions = status.active_mentions.includes(:account).to_a
- @reblogs = status.reblogs.includes(:account).to_a
- @stream_entry = status.stream_entry
- @options = options
+ @payload = Oj.dump(event: :delete, payload: status.id.to_s)
+ @status = status
+ @account = status.account
+ @tags = status.tags.pluck(:name).to_a
+ @mentions = status.active_mentions.includes(:account).to_a
+ @reblogs = status.reblogs.includes(:account).to_a
+ @options = options
RedisLock.acquire(lock_options) do |lock|
if lock.acquired?
@@ -26,6 +24,7 @@ class RemoveStatusService < BaseService
remove_from_public
remove_from_media if status.media_attachments.any?
remove_from_direct if status.direct_visibility?
+ remove_from_spam_check
@status.destroy!
else
@@ -80,11 +79,6 @@ class RemoveStatusService < BaseService
target_accounts << @status.reblog.account if @status.reblog? && !@status.reblog.account.local?
target_accounts.uniq!(&:id)
- # Ostatus
- NotificationWorker.push_bulk(target_accounts.select(&:ostatus?).uniq(&:domain)) do |target_account|
- [salmon_xml, @account.id, target_account.id]
- end
-
# ActivityPub
ActivityPub::DeliveryWorker.push_bulk(target_accounts.select(&:activitypub?).uniq(&:preferred_inbox_url)) do |target_account|
[signed_activity_json, @account.id, target_account.preferred_inbox_url]
@@ -92,9 +86,6 @@ class RemoveStatusService < BaseService
end
def remove_from_remote_followers
- # OStatus
- Pubsubhubbub::RawDistributionWorker.perform_async(salmon_xml, @account.id)
-
# ActivityPub
ActivityPub::DeliveryWorker.push_bulk(@account.followers.inboxes) do |inbox_url|
[signed_activity_json, @account.id, inbox_url]
@@ -113,10 +104,6 @@ class RemoveStatusService < BaseService
end
end
- def salmon_xml
- @salmon_xml ||= stream_entry_to_xml(@stream_entry)
- end
-
def signed_activity_json
@signed_activity_json ||= Oj.dump(serialize_payload(@status, @status.reblog? ? ActivityPub::UndoAnnounceSerializer : ActivityPub::DeleteSerializer, signer: @account))
end
@@ -164,6 +151,10 @@ class RemoveStatusService < BaseService
end
end
+ def remove_from_spam_check
+ redis.zremrangebyscore("spam_check:#{@status.account_id}", @status.id, @status.id)
+ end
+
def lock_options
{ redis: Redis.current, key: "distribute:#{@status.id}" }
end
diff --git a/app/services/resolve_account_service.rb b/app/services/resolve_account_service.rb
index e557706da5..7864c4bcdb 100644
--- a/app/services/resolve_account_service.rb
+++ b/app/services/resolve_account_service.rb
@@ -1,89 +1,107 @@
# frozen_string_literal: true
class ResolveAccountService < BaseService
- include OStatus2::MagicKey
include JsonLdHelper
+ include DomainControlHelper
- DFRN_NS = 'http://purl.org/macgirvin/dfrn/1.0'
+ class WebfingerRedirectError < StandardError; end
- # Find or create a local account for a remote user.
- # When creating, look up the user's webfinger and fetch all
- # important information from their feed
- # @param [String, Account] uri User URI in the form of username@domain
+ # Find or create an account record for a remote user. When creating,
+ # look up the user's webfinger and fetch ActivityPub data
+ # @param [String, Account] uri URI in the username@domain format or account record
# @param [Hash] options
+ # @option options [Boolean] :redirected Do not follow further Webfinger redirects
+ # @option options [Boolean] :skip_webfinger Do not attempt to refresh account data
# @return [Account]
def call(uri, options = {})
+ return if uri.blank?
+
+ process_options!(uri, options)
+
+ # First of all we want to check if we've got the account
+ # record with the URI already, and if so, we can exit early
+
+ return if domain_not_allowed?(@domain)
+
+ @account ||= Account.find_remote(@username, @domain)
+
+ return @account if @account&.local? || !webfinger_update_due?
+
+ # At this point we are in need of a Webfinger query, which may
+ # yield us a different username/domain through a redirect
+
+ process_webfinger!(@uri)
+
+ # Because the username/domain pair may be different than what
+ # we already checked, we need to check if we've already got
+ # the record with that URI, again
+
+ return if domain_not_allowed?(@domain)
+
+ @account ||= Account.find_remote(@username, @domain)
+
+ return @account if @account&.local? || !webfinger_update_due?
+
+ # Now it is certain, it is definitely a remote account, and it
+ # either needs to be created, or updated from fresh data
+
+ process_account!
+ rescue Goldfinger::Error, WebfingerRedirectError, Oj::ParseError => e
+ Rails.logger.debug "Webfinger query for #{@uri} failed: #{e}"
+ nil
+ end
+
+ private
+
+ def process_options!(uri, options)
@options = options
if uri.is_a?(Account)
@account = uri
@username = @account.username
@domain = @account.domain
- uri = "#{@username}@#{@domain}"
-
- return @account if @account.local? || !webfinger_update_due?
+ @uri = [@username, @domain].compact.join('@')
else
+ @uri = uri
@username, @domain = uri.split('@')
-
- return Account.find_local(@username) if TagManager.instance.local_domain?(@domain)
-
- @account = Account.find_remote(@username, @domain)
-
- return @account unless webfinger_update_due?
end
- Rails.logger.debug "Looking up webfinger for #{uri}"
-
- @webfinger = Goldfinger.finger("acct:#{uri}")
+ @domain = nil if TagManager.instance.local_domain?(@domain)
+ end
+ def process_webfinger!(uri, redirected = false)
+ @webfinger = Goldfinger.finger("acct:#{@uri}")
confirmed_username, confirmed_domain = @webfinger.subject.gsub(/\Aacct:/, '').split('@')
if confirmed_username.casecmp(@username).zero? && confirmed_domain.casecmp(@domain).zero?
@username = confirmed_username
@domain = confirmed_domain
- elsif options[:redirected].nil?
- return call("#{confirmed_username}@#{confirmed_domain}", options.merge(redirected: true))
+ @uri = uri
+ elsif !redirected
+ return process_webfinger!("#{confirmed_username}@#{confirmed_domain}", true)
else
- Rails.logger.debug 'Requested and returned acct URIs do not match'
- return
+ raise WebfingerRedirectError, "The URI #{uri} tries to hijack #{@username}@#{@domain}"
end
- return if links_missing? || auto_suspend?
- return Account.find_local(@username) if TagManager.instance.local_domain?(@domain)
+ @domain = nil if TagManager.instance.local_domain?(@domain)
+ end
+
+ def process_account!
+ return unless activitypub_ready?
RedisLock.acquire(lock_options) do |lock|
if lock.acquired?
@account = Account.find_remote(@username, @domain)
- if activitypub_ready? || @account&.activitypub?
- handle_activitypub
- else
- handle_ostatus
- end
+ next if (@account.present? && !@account.activitypub?) || actor_json.nil?
+
+ @account = ActivityPub::ProcessAccountService.new.call(@username, @domain, actor_json)
else
raise Mastodon::RaceConditionError
end
end
@account
- rescue Goldfinger::Error => e
- Rails.logger.debug "Webfinger query for #{uri} unsuccessful: #{e}"
- nil
- end
-
- private
-
- def links_missing?
- !(activitypub_ready? || ostatus_ready?)
- end
-
- def ostatus_ready?
- !(@webfinger.link('http://schemas.google.com/g/2010#updates-from').nil? ||
- @webfinger.link('salmon').nil? ||
- @webfinger.link('http://webfinger.net/rel/profile-page').nil? ||
- @webfinger.link('magic-public-key').nil? ||
- canonical_uri.nil? ||
- hub_url.nil?)
end
def webfinger_update_due?
@@ -91,113 +109,13 @@ class ResolveAccountService < BaseService
end
def activitypub_ready?
- !@webfinger.link('self').nil? &&
- ['application/activity+json', 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"'].include?(@webfinger.link('self').type) &&
- !actor_json.nil? &&
- actor_json['inbox'].present?
- end
-
- def handle_ostatus
- create_account if @account.nil?
- update_account
- update_account_profile if update_profile?
- end
-
- def update_profile?
- @options[:update_profile]
- end
-
- def handle_activitypub
- return if actor_json.nil?
-
- @account = ActivityPub::ProcessAccountService.new.call(@username, @domain, actor_json)
- rescue Oj::ParseError
- nil
- end
-
- def create_account
- Rails.logger.debug "Creating new remote account for #{@username}@#{@domain}"
-
- @account = Account.new(username: @username, domain: @domain)
- @account.suspended_at = domain_block.created_at if auto_suspend?
- @account.silenced_at = domain_block.created_at if auto_silence?
- @account.private_key = nil
- end
-
- def update_account
- @account.last_webfingered_at = Time.now.utc
- @account.protocol = :ostatus
- @account.remote_url = atom_url
- @account.salmon_url = salmon_url
- @account.url = url
- @account.public_key = public_key
- @account.uri = canonical_uri
- @account.hub_url = hub_url
- @account.save!
- end
-
- def auto_suspend?
- domain_block&.suspend?
- end
-
- def auto_silence?
- domain_block&.silence?
- end
-
- def domain_block
- return @domain_block if defined?(@domain_block)
- @domain_block = DomainBlock.rule_for(@domain)
- end
-
- def atom_url
- @atom_url ||= @webfinger.link('http://schemas.google.com/g/2010#updates-from').href
- end
-
- def salmon_url
- @salmon_url ||= @webfinger.link('salmon').href
+ !@webfinger.link('self').nil? && ['application/activity+json', 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"'].include?(@webfinger.link('self').type)
end
def actor_url
@actor_url ||= @webfinger.link('self').href
end
- def url
- @url ||= @webfinger.link('http://webfinger.net/rel/profile-page').href
- end
-
- def public_key
- @public_key ||= magic_key_to_pem(@webfinger.link('magic-public-key').href)
- end
-
- def canonical_uri
- return @canonical_uri if defined?(@canonical_uri)
-
- author_uri = atom.at_xpath('/xmlns:feed/xmlns:author/xmlns:uri')
-
- if author_uri.nil?
- owner = atom.at_xpath('/xmlns:feed').at_xpath('./dfrn:owner', dfrn: DFRN_NS)
- author_uri = owner.at_xpath('./xmlns:uri') unless owner.nil?
- end
-
- @canonical_uri = author_uri.nil? ? nil : author_uri.content
- end
-
- def hub_url
- return @hub_url if defined?(@hub_url)
-
- hubs = atom.xpath('//xmlns:link[@rel="hub"]')
- @hub_url = hubs.empty? || hubs.first['href'].nil? ? nil : hubs.first['href']
- end
-
- def atom_body
- return @atom_body if defined?(@atom_body)
-
- @atom_body = Request.new(:get, atom_url).perform do |response|
- raise Mastodon::UnexpectedResponseError, response unless response.code == 200
- response.body_with_limit
- end
- end
-
def actor_json
return @actor_json if defined?(@actor_json)
@@ -205,15 +123,6 @@ class ResolveAccountService < BaseService
@actor_json = supported_context?(json) && equals_or_includes_any?(json['type'], ActivityPub::FetchRemoteAccountService::SUPPORTED_TYPES) ? json : nil
end
- def atom
- return @atom if defined?(@atom)
- @atom = Nokogiri::XML(atom_body)
- end
-
- def update_account_profile
- RemoteProfileUpdateWorker.perform_async(@account.id, atom_body.force_encoding('UTF-8'), false)
- end
-
def lock_options
{ redis: Redis.current, key: "resolve:#{@username}@#{@domain}" }
end
diff --git a/app/services/resolve_url_service.rb b/app/services/resolve_url_service.rb
index bbdc0a5955..aa883597a4 100644
--- a/app/services/resolve_url_service.rb
+++ b/app/services/resolve_url_service.rb
@@ -4,64 +4,51 @@ class ResolveURLService < BaseService
include JsonLdHelper
include Authorization
- attr_reader :url
-
def call(url, on_behalf_of: nil)
- @url = url
+ @url = url
@on_behalf_of = on_behalf_of
- return process_local_url if local_url?
-
- process_url unless fetched_atom_feed.nil?
+ if local_url?
+ process_local_url
+ elsif !fetched_resource.nil?
+ process_url
+ end
end
private
def process_url
if equals_or_includes_any?(type, ActivityPub::FetchRemoteAccountService::SUPPORTED_TYPES)
- FetchRemoteAccountService.new.call(atom_url, body, protocol)
+ FetchRemoteAccountService.new.call(resource_url, body, protocol)
elsif equals_or_includes_any?(type, ActivityPub::Activity::Create::SUPPORTED_TYPES + ActivityPub::Activity::Create::CONVERTED_TYPES)
- FetchRemoteStatusService.new.call(atom_url, body, protocol)
+ status = FetchRemoteStatusService.new.call(resource_url, body, protocol)
+ authorize_with @on_behalf_of, status, :show? unless status.nil?
+ status
end
end
- def fetched_atom_feed
- @_fetched_atom_feed ||= FetchAtomService.new.call(url)
+ def fetched_resource
+ @fetched_resource ||= FetchResourceService.new.call(@url)
end
- def atom_url
- fetched_atom_feed.first
+ def resource_url
+ fetched_resource.first
end
def body
- fetched_atom_feed.second[:prefetched_body]
+ fetched_resource.second[:prefetched_body]
end
def protocol
- fetched_atom_feed.third
+ fetched_resource.third
end
def type
return json_data['type'] if protocol == :activitypub
-
- case xml_root
- when 'feed'
- 'Person'
- when 'entry'
- 'Note'
- end
end
def json_data
- @_json_data ||= body_to_json(body)
- end
-
- def xml_root
- xml_data.root.name
- end
-
- def xml_data
- @_xml_data ||= Nokogiri::XML(body, nil, 'utf-8')
+ @json_data ||= body_to_json(body)
end
def local_url?
@@ -73,10 +60,7 @@ class ResolveURLService < BaseService
return unless recognized_params[:action] == 'show'
- if recognized_params[:controller] == 'stream_entries'
- status = StreamEntry.find_by(id: recognized_params[:id])&.status
- check_local_status(status)
- elsif recognized_params[:controller] == 'statuses'
+ if recognized_params[:controller] == 'statuses'
status = Status.find_by(id: recognized_params[:id])
check_local_status(status)
elsif recognized_params[:controller] == 'accounts'
@@ -86,10 +70,10 @@ class ResolveURLService < BaseService
def check_local_status(status)
return if status.nil?
+
authorize_with @on_behalf_of, status, :show?
status
rescue Mastodon::NotPermittedError
- # Do not disclose the existence of status the user is not authorized to see
nil
end
end
diff --git a/app/services/send_interaction_service.rb b/app/services/send_interaction_service.rb
deleted file mode 100644
index 3419043e56..0000000000
--- a/app/services/send_interaction_service.rb
+++ /dev/null
@@ -1,39 +0,0 @@
-# frozen_string_literal: true
-
-class SendInteractionService < BaseService
- # Send an Atom representation of an interaction to a remote Salmon endpoint
- # @param [String] Entry XML
- # @param [Account] source_account
- # @param [Account] target_account
- def call(xml, source_account, target_account)
- @xml = xml
- @source_account = source_account
- @target_account = target_account
-
- return if !target_account.ostatus? || block_notification?
-
- build_request.perform do |delivery|
- raise Mastodon::UnexpectedResponseError, delivery unless delivery.code > 199 && delivery.code < 300
- end
- end
-
- private
-
- def build_request
- request = Request.new(:post, @target_account.salmon_url, body: envelope)
- request.add_headers('Content-Type' => 'application/magic-envelope+xml')
- request
- end
-
- def envelope
- salmon.pack(@xml, @source_account.keypair)
- end
-
- def block_notification?
- DomainBlock.blocked?(@target_account.domain)
- end
-
- def salmon
- @salmon ||= OStatus2::Salmon.new
- end
-end
diff --git a/app/services/subscribe_service.rb b/app/services/subscribe_service.rb
deleted file mode 100644
index 83fd64396a..0000000000
--- a/app/services/subscribe_service.rb
+++ /dev/null
@@ -1,58 +0,0 @@
-# frozen_string_literal: true
-
-class SubscribeService < BaseService
- def call(account)
- return if account.hub_url.blank?
-
- @account = account
- @account.secret = SecureRandom.hex
-
- build_request.perform do |response|
- if response_failed_permanently? response
- # We're not allowed to subscribe. Fail and move on.
- @account.secret = ''
- @account.save!
- elsif response_successful? response
- # The subscription will be confirmed asynchronously.
- @account.save!
- else
- # The response was either a 429 rate limit, or a 5xx error.
- # We need to retry at a later time. Fail loudly!
- raise Mastodon::UnexpectedResponseError, response
- end
- end
- end
-
- private
-
- def build_request
- request = Request.new(:post, @account.hub_url, form: subscription_params)
- request.on_behalf_of(some_local_account) if some_local_account
- request
- end
-
- def subscription_params
- {
- 'hub.topic': @account.remote_url,
- 'hub.mode': 'subscribe',
- 'hub.callback': api_subscription_url(@account.id),
- 'hub.verify': 'async',
- 'hub.secret': @account.secret,
- 'hub.lease_seconds': 7.days.seconds,
- }
- end
-
- def some_local_account
- @some_local_account ||= Account.local.without_suspended.first
- end
-
- # Any response in the 3xx or 4xx range, except for 429 (rate limit)
- def response_failed_permanently?(response)
- (response.status.redirect? || response.status.client_error?) && !response.status.too_many_requests?
- end
-
- # Any response in the 2xx range
- def response_successful?(response)
- response.status.success?
- end
-end
diff --git a/app/services/suspend_account_service.rb b/app/services/suspend_account_service.rb
index a5ce3dbd9b..0ebe0b562d 100644
--- a/app/services/suspend_account_service.rb
+++ b/app/services/suspend_account_service.rb
@@ -24,7 +24,6 @@ class SuspendAccountService < BaseService
report_notes
scheduled_statuses
status_pins
- stream_entries
subscriptions
).freeze
diff --git a/app/services/unblock_service.rb b/app/services/unblock_service.rb
index 95a858e9f5..c263ac8afe 100644
--- a/app/services/unblock_service.rb
+++ b/app/services/unblock_service.rb
@@ -7,25 +7,17 @@ class UnblockService < BaseService
return unless account.blocking?(target_account)
unblock = account.unblock!(target_account)
- create_notification(unblock) unless target_account.local?
+ create_notification(unblock) if !target_account.local? && target_account.activitypub?
unblock
end
private
def create_notification(unblock)
- if unblock.target_account.ostatus?
- NotificationWorker.perform_async(build_xml(unblock), unblock.account_id, unblock.target_account_id)
- elsif unblock.target_account.activitypub?
- ActivityPub::DeliveryWorker.perform_async(build_json(unblock), unblock.account_id, unblock.target_account.inbox_url)
- end
+ ActivityPub::DeliveryWorker.perform_async(build_json(unblock), unblock.account_id, unblock.target_account.inbox_url)
end
def build_json(unblock)
Oj.dump(serialize_payload(unblock, ActivityPub::UndoBlockSerializer))
end
-
- def build_xml(block)
- OStatus::AtomSerializer.render(OStatus::AtomSerializer.new.unblock_salmon(block))
- end
end
diff --git a/app/services/unfavourite_service.rb b/app/services/unfavourite_service.rb
index dcc890b7de..37917a64f1 100644
--- a/app/services/unfavourite_service.rb
+++ b/app/services/unfavourite_service.rb
@@ -6,7 +6,7 @@ class UnfavouriteService < BaseService
def call(account, status)
favourite = Favourite.find_by!(account: account, status: status)
favourite.destroy!
- create_notification(favourite) unless status.local?
+ create_notification(favourite) if !status.account.local? && status.account.activitypub?
favourite
end
@@ -14,19 +14,10 @@ class UnfavouriteService < BaseService
def create_notification(favourite)
status = favourite.status
-
- if status.account.ostatus?
- NotificationWorker.perform_async(build_xml(favourite), favourite.account_id, status.account_id)
- elsif status.account.activitypub?
- ActivityPub::DeliveryWorker.perform_async(build_json(favourite), favourite.account_id, status.account.inbox_url)
- end
+ ActivityPub::DeliveryWorker.perform_async(build_json(favourite), favourite.account_id, status.account.inbox_url)
end
def build_json(favourite)
Oj.dump(serialize_payload(favourite, ActivityPub::UndoLikeSerializer))
end
-
- def build_xml(favourite)
- OStatus::AtomSerializer.render(OStatus::AtomSerializer.new.unfavourite_salmon(favourite))
- end
end
diff --git a/app/services/unfollow_service.rb b/app/services/unfollow_service.rb
index 17dc29735f..b7033d7ebe 100644
--- a/app/services/unfollow_service.rb
+++ b/app/services/unfollow_service.rb
@@ -21,8 +21,8 @@ class UnfollowService < BaseService
return unless follow
follow.destroy!
- create_notification(follow) unless @target_account.local?
- create_reject_notification(follow) if @target_account.local? && !@source_account.local?
+ create_notification(follow) if !@target_account.local? && @target_account.activitypub?
+ create_reject_notification(follow) if @target_account.local? && !@source_account.local? && @source_account.activitypub?
UnmergeWorker.perform_async(@target_account.id, @source_account.id)
follow
end
@@ -38,16 +38,10 @@ class UnfollowService < BaseService
end
def create_notification(follow)
- if follow.target_account.ostatus?
- NotificationWorker.perform_async(build_xml(follow), follow.account_id, follow.target_account_id)
- elsif follow.target_account.activitypub?
- ActivityPub::DeliveryWorker.perform_async(build_json(follow), follow.account_id, follow.target_account.inbox_url)
- end
+ ActivityPub::DeliveryWorker.perform_async(build_json(follow), follow.account_id, follow.target_account.inbox_url)
end
def create_reject_notification(follow)
- # Rejecting an already-existing follow request
- return unless follow.account.activitypub?
ActivityPub::DeliveryWorker.perform_async(build_reject_json(follow), follow.target_account_id, follow.account.inbox_url)
end
@@ -58,8 +52,4 @@ class UnfollowService < BaseService
def build_reject_json(follow)
Oj.dump(serialize_payload(follow, ActivityPub::RejectFollowSerializer))
end
-
- def build_xml(follow)
- OStatus::AtomSerializer.render(OStatus::AtomSerializer.new.unfollow_salmon(follow))
- end
end
diff --git a/app/services/unsubscribe_service.rb b/app/services/unsubscribe_service.rb
deleted file mode 100644
index 95c1fb4fc0..0000000000
--- a/app/services/unsubscribe_service.rb
+++ /dev/null
@@ -1,36 +0,0 @@
-# frozen_string_literal: true
-
-class UnsubscribeService < BaseService
- def call(account)
- return if account.hub_url.blank?
-
- @account = account
-
- begin
- build_request.perform do |response|
- Rails.logger.debug "PuSH unsubscribe for #{@account.acct} failed: #{response.status}" unless response.status.success?
- end
- rescue HTTP::Error, OpenSSL::SSL::SSLError => e
- Rails.logger.debug "PuSH unsubscribe for #{@account.acct} failed: #{e}"
- end
-
- @account.secret = ''
- @account.subscription_expires_at = nil
- @account.save!
- end
-
- private
-
- def build_request
- Request.new(:post, @account.hub_url, form: subscription_params)
- end
-
- def subscription_params
- {
- 'hub.topic': @account.remote_url,
- 'hub.mode': 'unsubscribe',
- 'hub.callback': api_subscription_url(@account.id),
- 'hub.verify': 'async',
- }
- end
-end
diff --git a/app/services/update_remote_profile_service.rb b/app/services/update_remote_profile_service.rb
deleted file mode 100644
index 403395a0dd..0000000000
--- a/app/services/update_remote_profile_service.rb
+++ /dev/null
@@ -1,66 +0,0 @@
-# frozen_string_literal: true
-
-class UpdateRemoteProfileService < BaseService
- attr_reader :account, :remote_profile
-
- def call(body, account, resubscribe = false)
- @account = account
- @remote_profile = RemoteProfile.new(body)
-
- return if remote_profile.root.nil?
-
- update_account unless remote_profile.author.nil?
-
- old_hub_url = account.hub_url
- account.hub_url = remote_profile.hub_link if remote_profile.hub_link.present? && remote_profile.hub_link != old_hub_url
-
- account.save_with_optional_media!
-
- Pubsubhubbub::SubscribeWorker.perform_async(account.id) if resubscribe && account.hub_url != old_hub_url
- end
-
- private
-
- def update_account
- account.display_name = remote_profile.display_name || ''
- account.note = remote_profile.note || ''
- account.locked = remote_profile.locked?
-
- if !account.suspended? && !DomainBlock.reject_media?(account.domain)
- if remote_profile.avatar.present?
- account.avatar_remote_url = remote_profile.avatar
- else
- account.avatar_remote_url = ''
- account.avatar.destroy
- end
-
- if remote_profile.header.present?
- account.header_remote_url = remote_profile.header
- else
- account.header_remote_url = ''
- account.header.destroy
- end
-
- save_emojis if remote_profile.emojis.present?
- end
- end
-
- def save_emojis
- do_not_download = DomainBlock.reject_media?(account.domain)
-
- return if do_not_download
-
- remote_profile.emojis.each do |link|
- next unless link['href'] && link['name']
-
- shortcode = link['name'].delete(':')
- emoji = CustomEmoji.find_by(shortcode: shortcode, domain: account.domain)
-
- next unless emoji.nil?
-
- emoji = CustomEmoji.new(shortcode: shortcode, domain: account.domain)
- emoji.image_remote_url = link['href']
- emoji.save
- end
- end
-end
diff --git a/app/services/verify_salmon_service.rb b/app/services/verify_salmon_service.rb
deleted file mode 100644
index 205b35d8b1..0000000000
--- a/app/services/verify_salmon_service.rb
+++ /dev/null
@@ -1,26 +0,0 @@
-# frozen_string_literal: true
-
-class VerifySalmonService < BaseService
- include AuthorExtractor
-
- def call(payload)
- body = salmon.unpack(payload)
-
- xml = Nokogiri::XML(body)
- xml.encoding = 'utf-8'
-
- account = author_from_xml(xml.at_xpath('/xmlns:entry', xmlns: OStatus::TagManager::XMLNS))
-
- if account.nil?
- false
- else
- salmon.verify(payload, account.keypair)
- end
- end
-
- private
-
- def salmon
- @salmon ||= OStatus2::Salmon.new
- end
-end
diff --git a/app/views/about/more.html.haml b/app/views/about/more.html.haml
index f02a7906a6..4922f0f54f 100644
--- a/app/views/about/more.html.haml
+++ b/app/views/about/more.html.haml
@@ -42,5 +42,7 @@
= mail_to @instance_presenter.site_contact_email, nil, title: @instance_presenter.site_contact_email
.column-3
+ = render 'application/flashes'
+
.box-widget
.rich-formatting= @instance_presenter.site_extended_description.html_safe.presence || t('about.extended_description_html')
diff --git a/app/views/accounts/_moved.html.haml b/app/views/accounts/_moved.html.haml
index 7a777bfea8..02fd7bf429 100644
--- a/app/views/accounts/_moved.html.haml
+++ b/app/views/accounts/_moved.html.haml
@@ -3,10 +3,10 @@
.moved-account-widget
.moved-account-widget__message
= fa_icon 'suitcase'
- = t('accounts.moved_html', name: content_tag(:bdi, content_tag(:strong, display_name(account, custom_emojify: true), class: :emojify)), new_profile_link: link_to(content_tag(:strong, safe_join(['@', content_tag(:span, moved_to_account.acct)])), TagManager.instance.url_for(moved_to_account), class: 'mention'))
+ = t('accounts.moved_html', name: content_tag(:bdi, content_tag(:strong, display_name(account, custom_emojify: true), class: :emojify)), new_profile_link: link_to(content_tag(:strong, safe_join(['@', content_tag(:span, moved_to_account.acct)])), ActivityPub::TagManager.instance.url_for(moved_to_account), class: 'mention'))
.moved-account-widget__card
- = link_to TagManager.instance.url_for(moved_to_account), class: 'detailed-status__display-name p-author h-card', target: '_blank', rel: 'me noopener' do
+ = link_to ActivityPub::TagManager.instance.url_for(moved_to_account), class: 'detailed-status__display-name p-author h-card', target: '_blank', rel: 'me noopener' do
.detailed-status__display-avatar
.account__avatar-overlay
.account__avatar-overlay-base{ style: "background-image: url('#{moved_to_account.avatar.url(:original)}')" }
diff --git a/app/views/accounts/show.html.haml b/app/views/accounts/show.html.haml
index 950e618477..0dc984dcc2 100644
--- a/app/views/accounts/show.html.haml
+++ b/app/views/accounts/show.html.haml
@@ -7,7 +7,6 @@
- if @account.user&.setting_noindex
%meta{ name: 'robots', content: 'noindex' }/
- %link{ rel: 'salmon', href: api_salmon_url(@account.id) }/
%link{ rel: 'alternate', type: 'application/atom+xml', href: account_url(@account, format: 'atom') }/
%link{ rel: 'alternate', type: 'application/rss+xml', href: account_url(@account, format: 'rss') }/
%link{ rel: 'alternate', type: 'application/activity+json', href: ActivityPub::TagManager.instance.uri_for(@account) }/
@@ -40,12 +39,12 @@
- else
.activity-stream.activity-stream--under-tabs
- if params[:page].to_i.zero?
- = render partial: 'stream_entries/status', collection: @pinned_statuses, as: :status, locals: { pinned: true }
+ = render partial: 'statuses/status', collection: @pinned_statuses, as: :status, locals: { pinned: true }
- if @newer_url
.entry= link_to_more @newer_url
- = render partial: 'stream_entries/status', collection: @statuses, as: :status
+ = render partial: 'statuses/status', collection: @statuses, as: :status
- if @older_url
.entry= link_to_more @older_url
diff --git a/app/views/admin/accounts/_account.html.haml b/app/views/admin/accounts/_account.html.haml
index eba3ad8041..b057d3e42e 100644
--- a/app/views/admin/accounts/_account.html.haml
+++ b/app/views/admin/accounts/_account.html.haml
@@ -19,4 +19,4 @@
= table_link_to 'times', t('admin.accounts.reject'), reject_admin_account_path(account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') } if can?(:reject, account.user)
- else
= table_link_to 'circle', t('admin.accounts.web'), web_path("accounts/#{account.id}")
- = table_link_to 'globe', t('admin.accounts.public'), TagManager.instance.url_for(account)
+ = table_link_to 'globe', t('admin.accounts.public'), ActivityPub::TagManager.instance.url_for(account)
diff --git a/app/views/admin/dashboard/index.html.haml b/app/views/admin/dashboard/index.html.haml
index 76dbf4388a..54cf9af5d4 100644
--- a/app/views/admin/dashboard/index.html.haml
+++ b/app/views/admin/dashboard/index.html.haml
@@ -53,6 +53,8 @@
= feature_hint(link_to(t('admin.dashboard.keybase'), edit_admin_settings_path), @keybase_integration)
%li
= feature_hint(link_to(t('admin.dashboard.feature_relay'), admin_relays_path), @relay_enabled)
+ %li
+ = feature_hint(link_to(t('admin.dashboard.feature_spam_check'), edit_admin_settings_path), @spam_check_enabled)
.dashboard__widgets__versions
%div
diff --git a/app/views/admin/reports/_status.html.haml b/app/views/admin/reports/_status.html.haml
index b3c145120a..9376db7ffe 100644
--- a/app/views/admin/reports/_status.html.haml
+++ b/app/views/admin/reports/_status.html.haml
@@ -19,7 +19,7 @@
= react_component :media_gallery, height: 343, sensitive: !current_account&.user&.show_all_media? && status.sensitive? || current_account&.user&.hide_all_media?, 'autoPlayGif': current_account&.user&.setting_auto_play_gif, media: status.proper.media_attachments.map { |a| ActiveModelSerializers::SerializableResource.new(a, serializer: REST::MediaAttachmentSerializer).as_json }
.detailed-status__meta
- = link_to TagManager.instance.url_for(status), class: 'detailed-status__datetime', target: stream_link_target, rel: 'noopener' do
+ = link_to ActivityPub::TagManager.instance.url_for(status), class: 'detailed-status__datetime', target: stream_link_target, rel: 'noopener' do
%time.formatted{ datetime: status.created_at.iso8601, title: l(status.created_at) }= l(status.created_at)
·
- if status.reblog?
diff --git a/app/views/admin/settings/edit.html.haml b/app/views/admin/settings/edit.html.haml
index a8c9f6a583..854f4cf870 100644
--- a/app/views/admin/settings/edit.html.haml
+++ b/app/views/admin/settings/edit.html.haml
@@ -78,6 +78,9 @@
.fields-group
= f.input :show_replies_in_public_timelines, as: :boolean, wrapper: :with_label, label: t('admin.settings.show_replies_in_public_timelines.title'), hint: t('admin.settings.show_replies_in_public_timelines.desc_html')
+ .fields-group
+ = f.input :spam_check_enabled, as: :boolean, wrapper: :with_label, label: t('admin.settings.spam_check_enabled.title'), hint: t('admin.settings.spam_check_enabled.desc_html')
+
%hr.spacer/
.fields-group
diff --git a/app/views/admin/subscriptions/_subscription.html.haml b/app/views/admin/subscriptions/_subscription.html.haml
deleted file mode 100644
index 1dec8e3962..0000000000
--- a/app/views/admin/subscriptions/_subscription.html.haml
+++ /dev/null
@@ -1,18 +0,0 @@
-%tr
- %td
- %samp= subscription.account.acct
- %td
- %samp= subscription.callback_url
- %td
- - if subscription.confirmed?
- %i.fa.fa-check
- %td{ style: "color: #{subscription.expired? ? 'red' : 'inherit'};" }
- %time.time-ago{ datetime: subscription.expires_at.iso8601, title: l(subscription.expires_at) }
- = precede subscription.expired? ? '-' : '' do
- = time_ago_in_words(subscription.expires_at)
- %td
- - if subscription.last_successful_delivery_at?
- %time.formatted{ datetime: subscription.last_successful_delivery_at.iso8601, title: l(subscription.last_successful_delivery_at) }
- = l subscription.last_successful_delivery_at
- - else
- %i.fa.fa-times
diff --git a/app/views/admin/subscriptions/index.html.haml b/app/views/admin/subscriptions/index.html.haml
deleted file mode 100644
index 83704c8ee5..0000000000
--- a/app/views/admin/subscriptions/index.html.haml
+++ /dev/null
@@ -1,16 +0,0 @@
-- content_for :page_title do
- = t('admin.subscriptions.title')
-
-.table-wrapper
- %table.table
- %thead
- %tr
- %th= t('admin.subscriptions.topic')
- %th= t('admin.subscriptions.callback_url')
- %th= t('admin.subscriptions.confirmed')
- %th= t('admin.subscriptions.expires_in')
- %th= t('admin.subscriptions.last_delivery')
- %tbody
- = render @subscriptions
-
-= paginate @subscriptions
diff --git a/app/views/application/_card.html.haml b/app/views/application/_card.html.haml
index e6059b0350..00254c40c7 100644
--- a/app/views/application/_card.html.haml
+++ b/app/views/application/_card.html.haml
@@ -1,4 +1,4 @@
-- account_url = local_assigns[:admin] ? admin_account_path(account.id) : TagManager.instance.url_for(account)
+- account_url = local_assigns[:admin] ? admin_account_path(account.id) : ActivityPub::TagManager.instance.url_for(account)
.card.h-card
= link_to account_url, target: '_blank', rel: 'noopener' do
diff --git a/app/views/authorize_interactions/_post_follow_actions.html.haml b/app/views/authorize_interactions/_post_follow_actions.html.haml
index 561c60137f..dd71160e2d 100644
--- a/app/views/authorize_interactions/_post_follow_actions.html.haml
+++ b/app/views/authorize_interactions/_post_follow_actions.html.haml
@@ -1,4 +1,4 @@
.post-follow-actions
%div= link_to t('authorize_follow.post_follow.web'), web_url("accounts/#{@resource.id}"), class: 'button button--block'
- %div= link_to t('authorize_follow.post_follow.return'), TagManager.instance.url_for(@resource), class: 'button button--block'
+ %div= link_to t('authorize_follow.post_follow.return'), ActivityPub::TagManager.instance.url_for(@resource), class: 'button button--block'
%div= t('authorize_follow.post_follow.close')
diff --git a/app/views/remote_interaction/new.html.haml b/app/views/remote_interaction/new.html.haml
index c8c08991f0..2cc0fcb93d 100644
--- a/app/views/remote_interaction/new.html.haml
+++ b/app/views/remote_interaction/new.html.haml
@@ -7,7 +7,7 @@
.public-layout
.activity-stream.activity-stream--highlighted
- = render 'stream_entries/status', status: @status
+ = render 'statuses/status', status: @status
= simple_form_for @remote_follow, as: :remote_follow, url: remote_interaction_path(@status) do |f|
= render 'shared/error_messages', object: @remote_follow
diff --git a/app/views/remote_unfollows/_card.html.haml b/app/views/remote_unfollows/_card.html.haml
deleted file mode 100644
index 9abcfd37e1..0000000000
--- a/app/views/remote_unfollows/_card.html.haml
+++ /dev/null
@@ -1,13 +0,0 @@
-.account-card
- .detailed-status__display-name
- %div
- = image_tag account.avatar.url(:original), alt: '', width: 48, height: 48, class: 'avatar'
-
- %span.display-name
- - account_url = local_assigns[:admin] ? admin_account_path(account.id) : TagManager.instance.url_for(account)
- = link_to account_url, class: 'detailed-status__display-name p-author h-card', target: '_blank', rel: 'noopener' do
- %strong.emojify= display_name(account, custom_emojify: true)
- %span @#{account.acct}
-
- - if account.note?
- .account__header__content.emojify= Formatter.instance.simplified_format(account)
diff --git a/app/views/remote_unfollows/_post_follow_actions.html.haml b/app/views/remote_unfollows/_post_follow_actions.html.haml
deleted file mode 100644
index 2a9c062e9c..0000000000
--- a/app/views/remote_unfollows/_post_follow_actions.html.haml
+++ /dev/null
@@ -1,4 +0,0 @@
-.post-follow-actions
- %div= link_to t('authorize_follow.post_follow.web'), web_url("accounts/#{@account.id}"), class: 'button button--block'
- %div= link_to t('authorize_follow.post_follow.return'), TagManager.instance.url_for(@account), class: 'button button--block'
- %div= t('authorize_follow.post_follow.close')
diff --git a/app/views/remote_unfollows/error.html.haml b/app/views/remote_unfollows/error.html.haml
deleted file mode 100644
index cb63f02be3..0000000000
--- a/app/views/remote_unfollows/error.html.haml
+++ /dev/null
@@ -1,3 +0,0 @@
-.form-container
- .flash-message#error_explanation
- = t('remote_unfollow.error')
diff --git a/app/views/remote_unfollows/success.html.haml b/app/views/remote_unfollows/success.html.haml
deleted file mode 100644
index b007eedc7e..0000000000
--- a/app/views/remote_unfollows/success.html.haml
+++ /dev/null
@@ -1,10 +0,0 @@
-- content_for :page_title do
- = t('remote_unfollow.title', acct: @account.acct)
-
-.form-container
- .follow-prompt
- %h2= t('remote_unfollow.unfollowed')
-
- = render 'application/card', account: @account
-
- = render 'post_follow_actions'
diff --git a/app/views/stream_entries/_attachment_list.html.haml b/app/views/statuses/_attachment_list.html.haml
similarity index 100%
rename from app/views/stream_entries/_attachment_list.html.haml
rename to app/views/statuses/_attachment_list.html.haml
diff --git a/app/views/stream_entries/_detailed_status.html.haml b/app/views/statuses/_detailed_status.html.haml
similarity index 87%
rename from app/views/stream_entries/_detailed_status.html.haml
rename to app/views/statuses/_detailed_status.html.haml
index 069d0053fc..8686c20335 100644
--- a/app/views/stream_entries/_detailed_status.html.haml
+++ b/app/views/statuses/_detailed_status.html.haml
@@ -1,6 +1,6 @@
.detailed-status.detailed-status--flex
.p-author.h-card
- = link_to TagManager.instance.url_for(status.account), class: 'detailed-status__display-name u-url', target: stream_link_target, rel: 'noopener' do
+ = link_to ActivityPub::TagManager.instance.url_for(status.account), class: 'detailed-status__display-name u-url', target: stream_link_target, rel: 'noopener' do
.detailed-status__display-avatar
- if current_account&.user&.setting_auto_play_gif || autoplay
= image_tag status.account.avatar_original_url, width: 48, height: 48, alt: '', class: 'account__avatar u-photo'
@@ -24,23 +24,23 @@
= Formatter.instance.format(status, custom_emojify: true, autoplay: autoplay)
- if status.preloadable_poll
= react_component :poll, disabled: true, poll: ActiveModelSerializers::SerializableResource.new(status.preloadable_poll, serializer: REST::PollSerializer, scope: current_user, scope_name: :current_user).as_json do
- = render partial: 'stream_entries/poll', locals: { status: status, poll: status.preloadable_poll, autoplay: autoplay }
+ = render partial: 'statuses/poll', locals: { status: status, poll: status.preloadable_poll, autoplay: autoplay }
- if !status.media_attachments.empty?
- if status.media_attachments.first.audio_or_video?
- video = status.media_attachments.first
= react_component :video, src: video.file.url(:original), preview: video.file.url(:small), blurhash: video.blurhash, sensitive: !current_account&.user&.show_all_media? && status.sensitive? || current_account&.user&.hide_all_media?, width: 670, height: 380, detailed: true, inline: true, alt: video.description do
- = render partial: 'stream_entries/attachment_list', locals: { attachments: status.media_attachments }
+ = render partial: 'statuses/attachment_list', locals: { attachments: status.media_attachments }
- else
= react_component :media_gallery, height: 380, sensitive: !current_account&.user&.show_all_media? && status.sensitive? || current_account&.user&.hide_all_media?, standalone: true, 'autoPlayGif': current_account&.user&.setting_auto_play_gif || autoplay, 'reduceMotion': current_account&.user&.setting_reduce_motion, media: status.media_attachments.map { |a| ActiveModelSerializers::SerializableResource.new(a, serializer: REST::MediaAttachmentSerializer).as_json } do
- = render partial: 'stream_entries/attachment_list', locals: { attachments: status.media_attachments }
+ = render partial: 'statuses/attachment_list', locals: { attachments: status.media_attachments }
- elsif status.preview_card
= react_component :card, 'maxDescription': 160, card: ActiveModelSerializers::SerializableResource.new(status.preview_card, serializer: REST::PreviewCardSerializer).as_json
.detailed-status__meta
%data.dt-published{ value: status.created_at.to_time.iso8601 }
- = link_to TagManager.instance.url_for(status), class: 'detailed-status__datetime u-url u-uid', target: stream_link_target, rel: 'noopener' do
+ = link_to ActivityPub::TagManager.instance.url_for(status), class: 'detailed-status__datetime u-url u-uid', target: stream_link_target, rel: 'noopener' do
%time.formatted{ datetime: status.created_at.iso8601, title: l(status.created_at) }= l(status.created_at)
·
- if status.application && @account.user&.setting_show_application
diff --git a/app/views/stream_entries/_og_description.html.haml b/app/views/statuses/_og_description.html.haml
similarity index 100%
rename from app/views/stream_entries/_og_description.html.haml
rename to app/views/statuses/_og_description.html.haml
diff --git a/app/views/stream_entries/_og_image.html.haml b/app/views/statuses/_og_image.html.haml
similarity index 100%
rename from app/views/stream_entries/_og_image.html.haml
rename to app/views/statuses/_og_image.html.haml
diff --git a/app/views/stream_entries/_poll.html.haml b/app/views/statuses/_poll.html.haml
similarity index 100%
rename from app/views/stream_entries/_poll.html.haml
rename to app/views/statuses/_poll.html.haml
diff --git a/app/views/stream_entries/_simple_status.html.haml b/app/views/statuses/_simple_status.html.haml
similarity index 83%
rename from app/views/stream_entries/_simple_status.html.haml
rename to app/views/statuses/_simple_status.html.haml
index dcb4ce0b92..27f6fc2270 100644
--- a/app/views/stream_entries/_simple_status.html.haml
+++ b/app/views/statuses/_simple_status.html.haml
@@ -1,11 +1,11 @@
.status
.status__info
- = link_to TagManager.instance.url_for(status), class: 'status__relative-time u-url u-uid', target: stream_link_target, rel: 'noopener' do
+ = link_to ActivityPub::TagManager.instance.url_for(status), class: 'status__relative-time u-url u-uid', target: stream_link_target, rel: 'noopener' do
%time.time-ago{ datetime: status.created_at.iso8601, title: l(status.created_at) }= l(status.created_at)
%data.dt-published{ value: status.created_at.to_time.iso8601 }
.p-author.h-card
- = link_to TagManager.instance.url_for(status.account), class: 'status__display-name u-url', target: stream_link_target, rel: 'noopener' do
+ = link_to ActivityPub::TagManager.instance.url_for(status.account), class: 'status__display-name u-url', target: stream_link_target, rel: 'noopener' do
.status__avatar
%div
- if current_account&.user&.setting_auto_play_gif || autoplay
@@ -28,16 +28,16 @@
= Formatter.instance.format(status, custom_emojify: true, autoplay: autoplay)
- if status.preloadable_poll
= react_component :poll, disabled: true, poll: ActiveModelSerializers::SerializableResource.new(status.preloadable_poll, serializer: REST::PollSerializer, scope: current_user, scope_name: :current_user).as_json do
- = render partial: 'stream_entries/poll', locals: { status: status, poll: status.preloadable_poll, autoplay: autoplay }
+ = render partial: 'statuses/poll', locals: { status: status, poll: status.preloadable_poll, autoplay: autoplay }
- if !status.media_attachments.empty?
- if status.media_attachments.first.audio_or_video?
- video = status.media_attachments.first
= react_component :video, src: video.file.url(:original), preview: video.file.url(:small), blurhash: video.blurhash, sensitive: !current_account&.user&.show_all_media? && status.sensitive? || current_account&.user&.hide_all_media?, width: 610, height: 343, inline: true, alt: video.description do
- = render partial: 'stream_entries/attachment_list', locals: { attachments: status.media_attachments }
+ = render partial: 'statuses/attachment_list', locals: { attachments: status.media_attachments }
- else
= react_component :media_gallery, height: 343, sensitive: !current_account&.user&.show_all_media? && status.sensitive? || current_account&.user&.hide_all_media?, 'autoPlayGif': current_account&.user&.setting_auto_play_gif || autoplay, media: status.media_attachments.map { |a| ActiveModelSerializers::SerializableResource.new(a, serializer: REST::MediaAttachmentSerializer).as_json } do
- = render partial: 'stream_entries/attachment_list', locals: { attachments: status.media_attachments }
+ = render partial: 'statuses/attachment_list', locals: { attachments: status.media_attachments }
- elsif status.preview_card
= react_component :card, 'maxDescription': 160, card: ActiveModelSerializers::SerializableResource.new(status.preview_card, serializer: REST::PreviewCardSerializer).as_json
@@ -50,9 +50,9 @@
= fa_icon 'reply-all fw'
.status__action-bar__counter__label= obscured_counter status.replies_count
= link_to remote_interaction_path(status, type: :reblog), class: 'status__action-bar-button icon-button modal-button', style: 'font-size: 18px; width: 23.1429px; height: 23.1429px; line-height: 23.15px;' do
- - if status.public_visibility? || status.unlisted_visibility?
+ - if status.distributable?
= fa_icon 'retweet fw'
- - elsif status.private_visibility?
+ - elsif status.private_visibility? || status.limited_visibility?
= fa_icon 'lock fw'
- else
= fa_icon 'envelope fw'
diff --git a/app/views/stream_entries/_status.html.haml b/app/views/statuses/_status.html.haml
similarity index 74%
rename from app/views/stream_entries/_status.html.haml
rename to app/views/statuses/_status.html.haml
index 83887cd874..0e36525030 100644
--- a/app/views/stream_entries/_status.html.haml
+++ b/app/views/statuses/_status.html.haml
@@ -17,9 +17,9 @@
- if status.reply? && include_threads
- if @next_ancestor
.entry{ class: entry_classes }
- = link_to_more TagManager.instance.url_for(@next_ancestor)
+ = link_to_more ActivityPub::TagManager.instance.url_for(@next_ancestor)
- = render partial: 'stream_entries/status', collection: @ancestors, as: :status, locals: { is_predecessor: true, direct_reply_id: status.in_reply_to_id }, autoplay: autoplay
+ = render partial: 'statuses/status', collection: @ancestors, as: :status, locals: { is_predecessor: true, direct_reply_id: status.in_reply_to_id }, autoplay: autoplay
.entry{ class: entry_classes }
@@ -28,7 +28,7 @@
.status__prepend-icon-wrapper
%i.status__prepend-icon.fa.fa-fw.fa-retweet
%span
- = link_to TagManager.instance.url_for(status.account), class: 'status__display-name muted' do
+ = link_to ActivityPub::TagManager.instance.url_for(status.account), class: 'status__display-name muted' do
%bdi
%strong.emojify= display_name(status.account, custom_emojify: true)
= t('stream_entries.reblogged')
@@ -39,18 +39,18 @@
%span
= t('stream_entries.pinned')
- = render (centered ? 'stream_entries/detailed_status' : 'stream_entries/simple_status'), status: status.proper, autoplay: autoplay
+ = render (centered ? 'statuses/detailed_status' : 'statuses/simple_status'), status: status.proper, autoplay: autoplay
- if include_threads
- if @since_descendant_thread_id
.entry{ class: entry_classes }
= link_to_more short_account_status_url(status.account.username, status, max_descendant_thread_id: @since_descendant_thread_id + 1)
- @descendant_threads.each do |thread|
- = render partial: 'stream_entries/status', collection: thread[:statuses], as: :status, locals: { is_successor: true, parent_id: status.id }, autoplay: autoplay
+ = render partial: 'statuses/status', collection: thread[:statuses], as: :status, locals: { is_successor: true, parent_id: status.id }, autoplay: autoplay
- if thread[:next_status]
.entry{ class: entry_classes }
- = link_to_more TagManager.instance.url_for(thread[:next_status])
+ = link_to_more ActivityPub::TagManager.instance.url_for(thread[:next_status])
- if @next_descendant_thread
.entry{ class: entry_classes }
= link_to_more short_account_status_url(status.account.username, status, since_descendant_thread_id: @max_descendant_thread_id - 1)
diff --git a/app/views/statuses/embed.html.haml b/app/views/statuses/embed.html.haml
new file mode 100644
index 0000000000..6f2ec646fe
--- /dev/null
+++ b/app/views/statuses/embed.html.haml
@@ -0,0 +1,3 @@
+- cache @status do
+ .activity-stream.activity-stream--headless
+ = render 'status', status: @status, centered: true, autoplay: @autoplay
diff --git a/app/views/statuses/show.html.haml b/app/views/statuses/show.html.haml
new file mode 100644
index 0000000000..704e37a3df
--- /dev/null
+++ b/app/views/statuses/show.html.haml
@@ -0,0 +1,24 @@
+- content_for :page_title do
+ = t('statuses.title', name: display_name(@account), quote: truncate(@status.spoiler_text.presence || @status.text, length: 50, omission: '…', escape: false))
+
+- content_for :header_tags do
+ - if @account.user&.setting_noindex
+ %meta{ name: 'robots', content: 'noindex' }/
+
+ %link{ rel: 'alternate', type: 'application/json+oembed', href: api_oembed_url(url: short_account_status_url(@account, @status), format: 'json') }/
+ %link{ rel: 'alternate', type: 'application/activity+json', href: ActivityPub::TagManager.instance.uri_for(@status) }/
+
+ = opengraph 'og:site_name', site_title
+ = opengraph 'og:type', 'article'
+ = opengraph 'og:title', "#{display_name(@account)} (@#{@account.local_username_and_domain})"
+ = opengraph 'og:url', short_account_status_url(@account, @status)
+
+ = render 'og_description', activity: @status
+ = render 'og_image', activity: @status, account: @account
+
+.grid
+ .column-0
+ .activity-stream.h-entry
+ = render partial: 'status', locals: { status: @status, include_threads: true }
+ .column-1
+ = render 'application/sidebar'
diff --git a/app/views/stream_entries/embed.html.haml b/app/views/stream_entries/embed.html.haml
deleted file mode 100644
index 4871c101e1..0000000000
--- a/app/views/stream_entries/embed.html.haml
+++ /dev/null
@@ -1,3 +0,0 @@
-- cache @stream_entry.activity do
- .activity-stream.activity-stream--headless
- = render "stream_entries/#{@type}", @type.to_sym => @stream_entry.activity, centered: true, autoplay: @autoplay
diff --git a/app/views/stream_entries/show.html.haml b/app/views/stream_entries/show.html.haml
deleted file mode 100644
index 0e81c4f685..0000000000
--- a/app/views/stream_entries/show.html.haml
+++ /dev/null
@@ -1,25 +0,0 @@
-- content_for :page_title do
- = t('statuses.title', name: display_name(@account), quote: truncate(@stream_entry.activity.spoiler_text.presence || @stream_entry.activity.text, length: 50, omission: '…', escape: false))
-
-- content_for :header_tags do
- - if @account.user&.setting_noindex
- %meta{ name: 'robots', content: 'noindex' }/
-
- %link{ rel: 'alternate', type: 'application/atom+xml', href: account_stream_entry_url(@account, @stream_entry, format: 'atom') }/
- %link{ rel: 'alternate', type: 'application/json+oembed', href: api_oembed_url(url: account_stream_entry_url(@account, @stream_entry), format: 'json') }/
- %link{ rel: 'alternate', type: 'application/activity+json', href: ActivityPub::TagManager.instance.uri_for(@stream_entry.activity) }/
-
- = opengraph 'og:site_name', site_title
- = opengraph 'og:type', 'article'
- = opengraph 'og:title', "#{display_name(@account)} (@#{@account.local_username_and_domain})"
- = opengraph 'og:url', short_account_status_url(@account, @stream_entry.activity)
-
- = render 'stream_entries/og_description', activity: @stream_entry.activity
- = render 'stream_entries/og_image', activity: @stream_entry.activity, account: @account
-
-.grid
- .column-0
- .activity-stream.h-entry
- = render partial: "stream_entries/#{@type}", locals: { @type.to_sym => @stream_entry.activity, include_threads: true }
- .column-1
- = render 'application/sidebar'
diff --git a/app/views/well_known/webfinger/show.xml.ruby b/app/views/well_known/webfinger/show.xml.ruby
index 968c8c1380..f5a54052a6 100644
--- a/app/views/well_known/webfinger/show.xml.ruby
+++ b/app/views/well_known/webfinger/show.xml.ruby
@@ -4,40 +4,47 @@ doc << Ox::Element.new('XRD').tap do |xrd|
xrd['xmlns'] = 'http://docs.oasis-open.org/ns/xri/xrd-1.0'
xrd << (Ox::Element.new('Subject') << @account.to_webfinger_s)
- xrd << (Ox::Element.new('Alias') << short_account_url(@account))
- xrd << (Ox::Element.new('Alias') << account_url(@account))
- xrd << Ox::Element.new('Link').tap do |link|
- link['rel'] = 'http://webfinger.net/rel/profile-page'
- link['type'] = 'text/html'
- link['href'] = short_account_url(@account)
- end
-
- xrd << Ox::Element.new('Link').tap do |link|
- link['rel'] = 'http://schemas.google.com/g/2010#updates-from'
- link['type'] = 'application/atom+xml'
- link['href'] = account_url(@account, format: 'atom')
- end
-
- xrd << Ox::Element.new('Link').tap do |link|
- link['rel'] = 'self'
- link['type'] = 'application/activity+json'
- link['href'] = account_url(@account)
- end
-
- xrd << Ox::Element.new('Link').tap do |link|
- link['rel'] = 'salmon'
- link['href'] = api_salmon_url(@account.id)
- end
-
- xrd << Ox::Element.new('Link').tap do |link|
- link['rel'] = 'magic-public-key'
- link['href'] = "data:application/magic-public-key,#{@account.magic_key}"
- end
-
- xrd << Ox::Element.new('Link').tap do |link|
- link['rel'] = 'http://ostatus.org/schema/1.0/subscribe'
- link['template'] = "#{authorize_interaction_url}?acct={uri}"
+ if @account.instance_actor?
+ xrd << (Ox::Element.new('Alias') << instance_actor_url)
+
+ xrd << Ox::Element.new('Link').tap do |link|
+ link['rel'] = 'http://webfinger.net/rel/profile-page'
+ link['type'] = 'text/html'
+ link['href'] = about_more_url(instance_actor: true)
+ end
+
+ xrd << Ox::Element.new('Link').tap do |link|
+ link['rel'] = 'self'
+ link['type'] = 'application/activity+json'
+ link['href'] = instance_actor_url
+ end
+ else
+ xrd << (Ox::Element.new('Alias') << short_account_url(@account))
+ xrd << (Ox::Element.new('Alias') << account_url(@account))
+
+ xrd << Ox::Element.new('Link').tap do |link|
+ link['rel'] = 'http://webfinger.net/rel/profile-page'
+ link['type'] = 'text/html'
+ link['href'] = short_account_url(@account)
+ end
+
+ xrd << Ox::Element.new('Link').tap do |link|
+ link['rel'] = 'http://schemas.google.com/g/2010#updates-from'
+ link['type'] = 'application/atom+xml'
+ link['href'] = account_url(@account, format: 'atom')
+ end
+
+ xrd << Ox::Element.new('Link').tap do |link|
+ link['rel'] = 'self'
+ link['type'] = 'application/activity+json'
+ link['href'] = account_url(@account)
+ end
+
+ xrd << Ox::Element.new('Link').tap do |link|
+ link['rel'] = 'http://ostatus.org/schema/1.0/subscribe'
+ link['template'] = "#{authorize_interaction_url}?acct={uri}"
+ end
end
end
diff --git a/app/workers/activitypub/delivery_worker.rb b/app/workers/activitypub/delivery_worker.rb
index 818fd8f5d9..5457d9d4b0 100644
--- a/app/workers/activitypub/delivery_worker.rb
+++ b/app/workers/activitypub/delivery_worker.rb
@@ -2,6 +2,7 @@
class ActivityPub::DeliveryWorker
include Sidekiq::Worker
+ include JsonLdHelper
STOPLIGHT_FAILURE_THRESHOLD = 10
STOPLIGHT_COOLDOWN = 60
@@ -18,21 +19,24 @@ class ActivityPub::DeliveryWorker
@source_account = Account.find(source_account_id)
@inbox_url = inbox_url
@host = Addressable::URI.parse(inbox_url).normalized_site
+ @performed = false
perform_request
-
- failure_tracker.track_success!
- rescue => e
- failure_tracker.track_failure!
- raise e.class, "Delivery failed for #{inbox_url}: #{e.message}", e.backtrace[0]
+ ensure
+ if @performed
+ failure_tracker.track_success!
+ else
+ failure_tracker.track_failure!
+ end
end
private
def build_request(http_client)
- request = Request.new(:post, @inbox_url, body: @json, http_client: http_client)
- request.on_behalf_of(@source_account, :uri, sign_with: @options[:sign_with])
- request.add_headers(HEADERS)
+ Request.new(:post, @inbox_url, body: @json, http_client: http_client).tap do |request|
+ request.on_behalf_of(@source_account, :uri, sign_with: @options[:sign_with])
+ request.add_headers(HEADERS)
+ end
end
def perform_request
@@ -40,6 +44,8 @@ class ActivityPub::DeliveryWorker
request_pool.with(@host) do |http_client|
build_request(http_client).perform do |response|
raise Mastodon::UnexpectedResponseError, response unless response_successful?(response) || response_error_unsalvageable?(response)
+
+ @performed = true
end
end
end
@@ -49,14 +55,6 @@ class ActivityPub::DeliveryWorker
.run
end
- def response_successful?(response)
- (200...300).cover?(response.code)
- end
-
- def response_error_unsalvageable?(response)
- response.code == 501 || ((400...500).cover?(response.code) && ![401, 408, 429].include?(response.code))
- end
-
def failure_tracker
@failure_tracker ||= DeliveryFailureTracker.new(@inbox_url)
end
diff --git a/app/workers/after_remote_follow_request_worker.rb b/app/workers/after_remote_follow_request_worker.rb
index 84eb6ade23..ce9c65834c 100644
--- a/app/workers/after_remote_follow_request_worker.rb
+++ b/app/workers/after_remote_follow_request_worker.rb
@@ -5,27 +5,5 @@ class AfterRemoteFollowRequestWorker
sidekiq_options queue: 'pull', retry: 5
- attr_reader :follow_request
-
- def perform(follow_request_id)
- @follow_request = FollowRequest.find(follow_request_id)
- process_follow_service if processing_required?
- rescue ActiveRecord::RecordNotFound
- true
- end
-
- private
-
- def process_follow_service
- follow_request.destroy
- FollowService.new.call(follow_request.account, updated_account.acct)
- end
-
- def processing_required?
- !updated_account.nil? && !updated_account.locked?
- end
-
- def updated_account
- @_updated_account ||= FetchRemoteAccountService.new.call(follow_request.target_account.remote_url)
- end
+ def perform(follow_request_id); end
end
diff --git a/app/workers/after_remote_follow_worker.rb b/app/workers/after_remote_follow_worker.rb
index edab83f853..d9719f2bf8 100644
--- a/app/workers/after_remote_follow_worker.rb
+++ b/app/workers/after_remote_follow_worker.rb
@@ -5,27 +5,5 @@ class AfterRemoteFollowWorker
sidekiq_options queue: 'pull', retry: 5
- attr_reader :follow
-
- def perform(follow_id)
- @follow = Follow.find(follow_id)
- process_follow_service if processing_required?
- rescue ActiveRecord::RecordNotFound
- true
- end
-
- private
-
- def process_follow_service
- follow.destroy
- FollowService.new.call(follow.account, updated_account.acct)
- end
-
- def updated_account
- @_updated_account ||= FetchRemoteAccountService.new.call(follow.target_account.remote_url)
- end
-
- def processing_required?
- !updated_account.nil? && updated_account.locked?
- end
+ def perform(follow_id); end
end
diff --git a/app/workers/maintenance/uncache_preview_worker.rb b/app/workers/maintenance/uncache_preview_worker.rb
new file mode 100644
index 0000000000..810ffd8ccf
--- /dev/null
+++ b/app/workers/maintenance/uncache_preview_worker.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+class Maintenance::UncachePreviewWorker
+ include Sidekiq::Worker
+
+ sidekiq_options queue: 'pull'
+
+ def perform(preview_card_id)
+ preview_card = PreviewCard.find(preview_card_id)
+
+ return if preview_card.image.blank?
+
+ preview_card.image.destroy
+ preview_card.save
+ rescue ActiveRecord::RecordNotFound
+ true
+ end
+end
diff --git a/app/workers/notification_worker.rb b/app/workers/notification_worker.rb
index da1d6ab455..1c0f001cf2 100644
--- a/app/workers/notification_worker.rb
+++ b/app/workers/notification_worker.rb
@@ -5,7 +5,5 @@ class NotificationWorker
sidekiq_options queue: 'push', retry: 5
- def perform(xml, source_account_id, target_account_id)
- SendInteractionService.new.call(xml, Account.find(source_account_id), Account.find(target_account_id))
- end
+ def perform(xml, source_account_id, target_account_id); end
end
diff --git a/app/workers/processing_worker.rb b/app/workers/processing_worker.rb
index 978c3aba26..cf3bd83979 100644
--- a/app/workers/processing_worker.rb
+++ b/app/workers/processing_worker.rb
@@ -5,7 +5,5 @@ class ProcessingWorker
sidekiq_options backtrace: true
- def perform(account_id, body)
- ProcessFeedService.new.call(body, Account.find(account_id), override_timestamps: true)
- end
+ def perform(account_id, body); end
end
diff --git a/app/workers/pubsubhubbub/confirmation_worker.rb b/app/workers/pubsubhubbub/confirmation_worker.rb
index c0e7b677e4..783a8c95fb 100644
--- a/app/workers/pubsubhubbub/confirmation_worker.rb
+++ b/app/workers/pubsubhubbub/confirmation_worker.rb
@@ -2,81 +2,8 @@
class Pubsubhubbub::ConfirmationWorker
include Sidekiq::Worker
- include RoutingHelper
sidekiq_options queue: 'push', retry: false
- attr_reader :subscription, :mode, :secret, :lease_seconds
-
- def perform(subscription_id, mode, secret = nil, lease_seconds = nil)
- @subscription = Subscription.find(subscription_id)
- @mode = mode
- @secret = secret
- @lease_seconds = lease_seconds
- process_confirmation
- end
-
- private
-
- def process_confirmation
- prepare_subscription
-
- callback_get_with_params
- logger.debug "Confirming PuSH subscription for #{subscription.callback_url} with challenge #{challenge}: #{@callback_response_body}"
-
- update_subscription
- end
-
- def update_subscription
- if successful_subscribe?
- subscription.save!
- elsif successful_unsubscribe?
- subscription.destroy!
- end
- end
-
- def successful_subscribe?
- subscribing? && response_matches_challenge?
- end
-
- def successful_unsubscribe?
- (unsubscribing? && response_matches_challenge?) || !subscription.confirmed?
- end
-
- def response_matches_challenge?
- @callback_response_body == challenge
- end
-
- def subscribing?
- mode == 'subscribe'
- end
-
- def unsubscribing?
- mode == 'unsubscribe'
- end
-
- def callback_get_with_params
- Request.new(:get, subscription.callback_url, params: callback_params).perform do |response|
- @callback_response_body = response.body_with_limit
- end
- end
-
- def callback_params
- {
- 'hub.topic': account_url(subscription.account, format: :atom),
- 'hub.mode': mode,
- 'hub.challenge': challenge,
- 'hub.lease_seconds': subscription.lease_seconds,
- }
- end
-
- def prepare_subscription
- subscription.secret = secret
- subscription.lease_seconds = lease_seconds
- subscription.confirmed = true
- end
-
- def challenge
- @_challenge ||= SecureRandom.hex
- end
+ def perform(subscription_id, mode, secret = nil, lease_seconds = nil); end
end
diff --git a/app/workers/pubsubhubbub/delivery_worker.rb b/app/workers/pubsubhubbub/delivery_worker.rb
index 619bfa48aa..1260060bd5 100644
--- a/app/workers/pubsubhubbub/delivery_worker.rb
+++ b/app/workers/pubsubhubbub/delivery_worker.rb
@@ -2,80 +2,8 @@
class Pubsubhubbub::DeliveryWorker
include Sidekiq::Worker
- include RoutingHelper
sidekiq_options queue: 'push', retry: 3, dead: false
- sidekiq_retry_in do |count|
- 5 * (count + 1)
- end
-
- attr_reader :subscription, :payload
-
- def perform(subscription_id, payload)
- @subscription = Subscription.find(subscription_id)
- @payload = payload
- process_delivery unless blocked_domain?
- rescue => e
- raise e.class, "Delivery failed for #{subscription&.callback_url}: #{e.message}", e.backtrace[0]
- end
-
- private
-
- def process_delivery
- callback_post_payload do |payload_delivery|
- raise Mastodon::UnexpectedResponseError, payload_delivery unless response_successful? payload_delivery
- end
-
- subscription.touch(:last_successful_delivery_at)
- end
-
- def callback_post_payload(&block)
- request = Request.new(:post, subscription.callback_url, body: payload)
- request.add_headers(headers)
- request.perform(&block)
- end
-
- def blocked_domain?
- DomainBlock.blocked?(host)
- end
-
- def host
- Addressable::URI.parse(subscription.callback_url).normalized_host
- end
-
- def headers
- {
- 'Content-Type' => 'application/atom+xml',
- 'Link' => link_header,
- }.merge(signature_headers.to_h)
- end
-
- def link_header
- LinkHeader.new([hub_link_header, self_link_header]).to_s
- end
-
- def hub_link_header
- [api_push_url, [%w(rel hub)]]
- end
-
- def self_link_header
- [account_url(subscription.account, format: :atom), [%w(rel self)]]
- end
-
- def signature_headers
- { 'X-Hub-Signature' => payload_signature } if subscription.secret?
- end
-
- def payload_signature
- "sha1=#{hmac_payload_digest}"
- end
-
- def hmac_payload_digest
- OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha1'), subscription.secret, payload)
- end
-
- def response_successful?(payload_delivery)
- payload_delivery.code > 199 && payload_delivery.code < 300
- end
+ def perform(subscription_id, payload); end
end
diff --git a/app/workers/pubsubhubbub/distribution_worker.rb b/app/workers/pubsubhubbub/distribution_worker.rb
index fed5e917d3..75bac5d6fa 100644
--- a/app/workers/pubsubhubbub/distribution_worker.rb
+++ b/app/workers/pubsubhubbub/distribution_worker.rb
@@ -5,28 +5,5 @@ class Pubsubhubbub::DistributionWorker
sidekiq_options queue: 'push'
- def perform(stream_entry_ids)
- stream_entries = StreamEntry.where(id: stream_entry_ids).includes(:status).reject { |e| e.status.nil? || e.status.hidden? }
-
- return if stream_entries.empty?
-
- @account = stream_entries.first.account
- @subscriptions = active_subscriptions.to_a
-
- distribute_public!(stream_entries)
- end
-
- private
-
- def distribute_public!(stream_entries)
- @payload = OStatus::AtomSerializer.render(OStatus::AtomSerializer.new.feed(@account, stream_entries))
-
- Pubsubhubbub::DeliveryWorker.push_bulk(@subscriptions) do |subscription_id|
- [subscription_id, @payload]
- end
- end
-
- def active_subscriptions
- Subscription.where(account: @account).active.pluck(:id)
- end
+ def perform(stream_entry_ids); end
end
diff --git a/app/workers/pubsubhubbub/raw_distribution_worker.rb b/app/workers/pubsubhubbub/raw_distribution_worker.rb
index 16962a623c..ece9c80ac5 100644
--- a/app/workers/pubsubhubbub/raw_distribution_worker.rb
+++ b/app/workers/pubsubhubbub/raw_distribution_worker.rb
@@ -5,18 +5,5 @@ class Pubsubhubbub::RawDistributionWorker
sidekiq_options queue: 'push'
- def perform(xml, source_account_id)
- @account = Account.find(source_account_id)
- @subscriptions = active_subscriptions.to_a
-
- Pubsubhubbub::DeliveryWorker.push_bulk(@subscriptions) do |subscription|
- [subscription.id, xml]
- end
- end
-
- private
-
- def active_subscriptions
- Subscription.where(account: @account).active.select('id, callback_url, domain')
- end
+ def perform(xml, source_account_id); end
end
diff --git a/app/workers/pubsubhubbub/subscribe_worker.rb b/app/workers/pubsubhubbub/subscribe_worker.rb
index 2e176d1c10..b861b5e67a 100644
--- a/app/workers/pubsubhubbub/subscribe_worker.rb
+++ b/app/workers/pubsubhubbub/subscribe_worker.rb
@@ -5,30 +5,5 @@ class Pubsubhubbub::SubscribeWorker
sidekiq_options queue: 'push', retry: 10, unique: :until_executed, dead: false
- sidekiq_retry_in do |count|
- case count
- when 0
- 30.minutes.seconds
- when 1
- 2.hours.seconds
- when 2
- 12.hours.seconds
- else
- 24.hours.seconds * (count - 2)
- end
- end
-
- sidekiq_retries_exhausted do |msg, _e|
- account = Account.find(msg['args'].first)
- Sidekiq.logger.error "PuSH subscription attempts for #{account.acct} exhausted. Unsubscribing"
- ::UnsubscribeService.new.call(account)
- end
-
- def perform(account_id)
- account = Account.find(account_id)
- logger.debug "PuSH re-subscribing to #{account.acct}"
- ::SubscribeService.new.call(account)
- rescue => e
- raise e.class, "Subscribe failed for #{account&.acct}: #{e.message}", e.backtrace[0]
- end
+ def perform(account_id); end
end
diff --git a/app/workers/pubsubhubbub/unsubscribe_worker.rb b/app/workers/pubsubhubbub/unsubscribe_worker.rb
index a271715b7a..0c1c263f6e 100644
--- a/app/workers/pubsubhubbub/unsubscribe_worker.rb
+++ b/app/workers/pubsubhubbub/unsubscribe_worker.rb
@@ -5,11 +5,5 @@ class Pubsubhubbub::UnsubscribeWorker
sidekiq_options queue: 'push', retry: false, unique: :until_executed, dead: false
- def perform(account_id)
- account = Account.find(account_id)
- logger.debug "PuSH unsubscribing from #{account.acct}"
- ::UnsubscribeService.new.call(account)
- rescue ActiveRecord::RecordNotFound
- true
- end
+ def perform(account_id); end
end
diff --git a/app/workers/remote_profile_update_worker.rb b/app/workers/remote_profile_update_worker.rb
index 03585ad2d6..01e8daf8f2 100644
--- a/app/workers/remote_profile_update_worker.rb
+++ b/app/workers/remote_profile_update_worker.rb
@@ -5,9 +5,5 @@ class RemoteProfileUpdateWorker
sidekiq_options queue: 'pull'
- def perform(account_id, body, resubscribe)
- UpdateRemoteProfileService.new.call(body, Account.find(account_id), resubscribe)
- rescue ActiveRecord::RecordNotFound
- true
- end
+ def perform(account_id, body, resubscribe); end
end
diff --git a/app/workers/salmon_worker.rb b/app/workers/salmon_worker.rb
index d37d404323..10200b06cf 100644
--- a/app/workers/salmon_worker.rb
+++ b/app/workers/salmon_worker.rb
@@ -5,9 +5,5 @@ class SalmonWorker
sidekiq_options backtrace: true
- def perform(account_id, body)
- ProcessInteractionService.new.call(body, Account.find(account_id))
- rescue Nokogiri::XML::XPath::SyntaxError, ActiveRecord::RecordNotFound
- true
- end
+ def perform(account_id, body); end
end
diff --git a/app/workers/scheduler/preview_cards_cleanup_scheduler.rb b/app/workers/scheduler/preview_cards_cleanup_scheduler.rb
new file mode 100644
index 0000000000..2b38792f03
--- /dev/null
+++ b/app/workers/scheduler/preview_cards_cleanup_scheduler.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+class Scheduler::PreviewCardsCleanupScheduler
+ include Sidekiq::Worker
+
+ sidekiq_options unique: :until_executed, retry: 0
+
+ def perform
+ Maintenance::UncachePreviewWorker.push_bulk(recent_link_preview_cards.pluck(:id))
+ Maintenance::UncachePreviewWorker.push_bulk(older_preview_cards.pluck(:id))
+ end
+
+ private
+
+ def recent_link_preview_cards
+ PreviewCard.where(type: :link).where('updated_at < ?', 1.month.ago)
+ end
+
+ def older_preview_cards
+ PreviewCard.where('updated_at < ?', 6.months.ago)
+ end
+end
diff --git a/app/workers/scheduler/subscriptions_scheduler.rb b/app/workers/scheduler/subscriptions_scheduler.rb
index d5873bccb0..6903cadc76 100644
--- a/app/workers/scheduler/subscriptions_scheduler.rb
+++ b/app/workers/scheduler/subscriptions_scheduler.rb
@@ -5,13 +5,5 @@ class Scheduler::SubscriptionsScheduler
sidekiq_options unique: :until_executed, retry: 0
- def perform
- Pubsubhubbub::SubscribeWorker.push_bulk(expiring_accounts.pluck(:id))
- end
-
- private
-
- def expiring_accounts
- Account.expiring(1.day.from_now).partitioned
- end
+ def perform; end
end
diff --git a/config/locales/activerecord.bn.yml b/config/locales/activerecord.bn.yml
index 152c698290..e0e6ac90c2 100644
--- a/config/locales/activerecord.bn.yml
+++ b/config/locales/activerecord.bn.yml
@@ -1 +1,17 @@
+---
bn:
+ activerecord:
+ attributes:
+ poll:
+ expires_at: শেষ হবে
+ options: বিকল্প
+ errors:
+ models:
+ account:
+ attributes:
+ username:
+ invalid: শুধুমাত্র অক্ষর, সংখ্যা এবং _ বেবহার করা যাবে
+ status:
+ attributes:
+ reblog:
+ taken: লেখাটি ইতিপূর্বে ছিল
diff --git a/config/locales/activerecord.cy.yml b/config/locales/activerecord.cy.yml
index 19547df986..92fba043fb 100644
--- a/config/locales/activerecord.cy.yml
+++ b/config/locales/activerecord.cy.yml
@@ -3,7 +3,7 @@ cy:
activerecord:
attributes:
poll:
- expires_at: Terfyn
+ expires_at: Terfyn amser
options: Dewisiadau
errors:
models:
diff --git a/config/locales/ar.yml b/config/locales/ar.yml
index eb6a5ef06c..e48ee89c56 100644
--- a/config/locales/ar.yml
+++ b/config/locales/ar.yml
@@ -478,12 +478,6 @@ ar:
no_status_selected: لم يطرأ أي تغيير على أي منشور بما أنه لم يتم اختيار أي واحد
title: منشورات الحساب
with_media: تحتوي على وسائط
- subscriptions:
- callback_url: عاود الاتصال بالعنوان
- confirmed: مؤكَّد
- expires_in: تنتهي مدة صلاحيتها في
- last_delivery: آخر إيداع
- topic: الموضوع
tags:
accounts: الحسابات
hidden: المخفية
@@ -818,10 +812,6 @@ ar:
reply:
proceed: المواصلة إلى الرد
prompt: 'ترغب في الرد على هذا التبويق:'
- remote_unfollow:
- error: خطأ
- title: العنوان
- unfollowed: غير متابَع
sessions:
activity: آخر نشاط
browser: المتصفح
diff --git a/config/locales/ast.yml b/config/locales/ast.yml
index ec545ca578..30390c1633 100644
--- a/config/locales/ast.yml
+++ b/config/locales/ast.yml
@@ -227,8 +227,6 @@ ast:
no_account_html: "¿Nun tienes una cuenta? Pues rexistrate equí"
proceed: Siguir
prompt: 'Vas siguir a:'
- remote_unfollow:
- error: Fallu
sessions:
browser: Restolador
browsers:
diff --git a/config/locales/ca.yml b/config/locales/ca.yml
index a5d96cc1ca..d05406ebb3 100644
--- a/config/locales/ca.yml
+++ b/config/locales/ca.yml
@@ -469,13 +469,6 @@ ca:
no_status_selected: No s’han canviat els estatus perquè cap no ha estat seleccionat
title: Estats del compte
with_media: Amb contingut multimèdia
- subscriptions:
- callback_url: URL de retorn
- confirmed: Confirmat
- expires_in: Expira en
- last_delivery: Últim lliurament
- title: WebSub
- topic: Tema
tags:
accounts: Comptes
hidden: Amagat
@@ -816,10 +809,6 @@ ca:
reply:
proceed: Procedir a respondre
prompt: 'Vols respondre a aquest toot:'
- remote_unfollow:
- error: Error
- title: Títol
- unfollowed: Sense seguir
scheduled_statuses:
over_daily_limit: Has superat el límit de %{limit} toots programats per a aquell dia
over_total_limit: Has superat el limit de %{limit} toots programats
diff --git a/config/locales/co.yml b/config/locales/co.yml
index b3d14fdb53..4e2ceda228 100644
--- a/config/locales/co.yml
+++ b/config/locales/co.yml
@@ -469,13 +469,6 @@ co:
no_status_selected: I statuti ùn sò micca stati mudificati perchè manc'unu era selezziunatu
title: Statutu di u contu
with_media: Cù media
- subscriptions:
- callback_url: URL di richjama
- confirmed: Cunfirmatu
- expires_in: Spira in
- last_delivery: Ultima arricata
- title: WebSub
- topic: Sughjettu
tags:
accounts: Conti
hidden: Piattatu
@@ -816,10 +809,6 @@ co:
reply:
proceed: Cuntinuà per risponde
prompt: 'Vulete risponde à stu statutu:'
- remote_unfollow:
- error: Errore
- title: Titulu
- unfollowed: Disabbunatu
scheduled_statuses:
over_daily_limit: Avete trapassatu a limita di %{limit} statuti planificati per stu ghjornu
over_total_limit: Avete trapassatu a limita di %{limit} statuti planificati
diff --git a/config/locales/cs.yml b/config/locales/cs.yml
index 0735a86981..3518b3b91f 100644
--- a/config/locales/cs.yml
+++ b/config/locales/cs.yml
@@ -481,13 +481,6 @@ cs:
no_status_selected: Nebyly změněny žádné tooty, neboť žádné nebyly vybrány
title: Tooty účtu
with_media: S médii
- subscriptions:
- callback_url: Zpáteční URL
- confirmed: Potvrzeno
- expires_in: Vyprší v
- last_delivery: Poslední doručení
- title: WebSub
- topic: Téma
tags:
accounts: Účty
hidden: Skryté
@@ -838,10 +831,6 @@ cs:
reply:
proceed: Pokračovat k odpovězení
prompt: 'Chcete odpovědět na tento toot:'
- remote_unfollow:
- error: Chyba
- title: Nadpis
- unfollowed: Už nesledujete
scheduled_statuses:
over_daily_limit: Překročil/a jste limit %{limit} plánovaných tootů pro tento den
over_total_limit: Překročil/a jste limit %{limit} plánovaných tootů
diff --git a/config/locales/cy.yml b/config/locales/cy.yml
index 080e89214b..fbeaa22b16 100644
--- a/config/locales/cy.yml
+++ b/config/locales/cy.yml
@@ -493,13 +493,6 @@ cy:
no_status_selected: Ni newidwyd dim statws achos ni ddewiswyd dim un
title: Statysau cyfrif
with_media: A chyfryngau
- subscriptions:
- callback_url: URL galw-nôl
- confirmed: Wedi'i gadarnhau
- expires_in: Dod i ben ymhen
- last_delivery: Danfoniad diwethaf
- title: WebSub
- topic: Pwnc
tags:
accounts: Cyfrifon
hidden: Cudd
@@ -862,10 +855,6 @@ cy:
reply:
proceed: Ymlaen i ateb
prompt: 'Hoffech ateb y tŵt hon:'
- remote_unfollow:
- error: Gwall
- title: Teitl
- unfollowed: Dad-ddilynwyd
scheduled_statuses:
over_daily_limit: Rydych wedi rhagori'r cyfwng o %{limit} o dŵtiau rhestredig ar y dydd hynny
over_total_limit: Rydych wedi rhagori'r cyfwng o %{limit} o dŵtiau rhestredig
diff --git a/config/locales/da.yml b/config/locales/da.yml
index da6ab10545..b24c9475c8 100644
--- a/config/locales/da.yml
+++ b/config/locales/da.yml
@@ -390,13 +390,6 @@ da:
no_status_selected: Ingen statusser blev ændret eller ingen blev valgt
title: Konto statusser
with_media: Med multimedier
- subscriptions:
- callback_url: Callback-URL
- confirmed: Bekræftet
- expires_in: Udløber om
- last_delivery: Sidste levering
- title: Websub
- topic: Emne
tags:
accounts: Kontoer
hidden: Skjult
@@ -616,10 +609,6 @@ da:
no_account_html: Har du ikke en konto? Du kan oprette dig her
proceed: Fortsæt for at følge
prompt: 'Du er ved at følge:'
- remote_unfollow:
- error: Fejl
- title: Titel
- unfollowed: Følger ikke længere
sessions:
activity: Sidste aktivitet
browsers:
diff --git a/config/locales/de.yml b/config/locales/de.yml
index cfdaacab06..b9b8c02df6 100644
--- a/config/locales/de.yml
+++ b/config/locales/de.yml
@@ -469,13 +469,6 @@ de:
no_status_selected: Keine Beiträge wurden geändert, weil keine ausgewählt wurden
title: Beiträge des Kontos
with_media: Mit Medien
- subscriptions:
- callback_url: Callback-URL
- confirmed: Bestätigt
- expires_in: Verfällt in
- last_delivery: Letzte Zustellung
- title: WebSub
- topic: Thema
tags:
accounts: Konten
hidden: Versteckt
@@ -816,10 +809,6 @@ de:
reply:
proceed: Fortfahren zum Antworten
prompt: 'Du möchtest auf diesen Beitrag antworten:'
- remote_unfollow:
- error: Fehler
- title: Titel
- unfollowed: Entfolgt
scheduled_statuses:
over_daily_limit: Du hast das Limit für geplante Beiträge, dass %{limit} beträgt, für heute erreicht
over_total_limit: Du hast das Limit für geplante Beiträge, dass %{limit} beträgt, erreicht
diff --git a/config/locales/devise.bn.yml b/config/locales/devise.bn.yml
index 152c698290..cb7179da6f 100644
--- a/config/locales/devise.bn.yml
+++ b/config/locales/devise.bn.yml
@@ -1 +1,40 @@
+---
bn:
+ devise:
+ confirmations:
+ confirmed: আপনার ইমেইলটি সঠিকভাবে নিশ্চিত করা হয়েছে।
+ send_instructions: আপনি একটি ইমেইল পাবেন যেটাতে কিভাবে আপনার ইমেইলটি নিশ্চিত করতে হবে সেটা পাঠানো হবে। যদি না পান, অনুগ্রহ করে আপনার স্প্যাম ফোল্ডারটি চেক করবেন।
+ send_paranoid_instructions: আমাদের ডাটাবেসে যদি আপনার ইমেইল থেকে থাকে, আপনার কাছে একটা ইমেইল পাঠানো হবে যেখানে কিভাবে আপনার ইমেইল নিশ্চিত করতে হবে লেখা থাকবে। যদি না পান, অনুগ্রহ করে আপনার স্প্যাম ফোল্ডারটি চেক করবেন।
+ failure:
+ already_authenticated: আপনি ইতিপূর্বে ভেতরে ঢুকেছেন (আবার লাগবে না)।
+ inactive: আনার নিবন্ধনটি এখনো চালু করা হয়নি।
+ invalid: ভুল %{authentication_keys} বা পাসওয়ার্ড ।
+ last_attempt: আপনার আর একবার চেষ্টা করার সুযোক আছে, তারপর আপনার নিবন্ধনে ঢোকার ক্ষেত্রে তালা দেওয়া হবে।
+ locked: নিবন্ধনে ঢোকার ক্ষেত্রে তালা দেওয়া হয়েছে।
+ not_found_in_database: ভুল %{authentication_keys} বা পাসওয়ার্ড।
+ pending: আপনার নিবন্ধনটি এখনো পর্যালোচনার জন্য অপেক্ষায় আছে।
+ timeout: আপনার সেশনটির সময় শেষ হয়ে গেছে। অনুগ্রহ করে আবার নিবন্ধনে ঢুকে চালাতে থাকেন।
+ unauthenticated: এটা ব্যবহার করতে আপনার আগে আপনার নিবন্ধনে ঢুকতে হবে অথবা নিবন্ধন তৈরি করতে হবে।
+ unconfirmed: এটা ব্যবহার করতে আপনার আগে আপনার ইমেইলটি নিশ্চিত করতে হবে।
+ mailer:
+ confirmation_instructions:
+ action: ইমেইলটি নিশ্চিত করুন
+ action_with_app: নিশ্চিত করুন এবং %{app} তে ফিরে যান
+ explanation: "%{host} তে এই ইমেইল ব্যবহার করে নিবন্ধন করতে হবে। আর একটা ক্লিক করলেই এটা চালু হয়ে যাবে। যদি আপনি এটা না পাঠিয়ে থাকেন, তাহলে অনুগ্রহ করে এই ইমেইলটি উপেক্ষা করুন।"
+ password_change:
+ extra: আপনি নিজে যদি পাসওয়ার্ডটি না বদলে থাকেন, খুব সম্ভব অন্যকেও আপনার নিবন্ধনে প্রবেশ করে এটা করেছে। অনুগ্রহ করে যত দ্রুত সম্ভব আপনার পাসওয়ার্ডটি বদলান অথবা যদি আপনি আপনার নিবন্ধনে আর না ঢুকতে পারেন, এই সার্ভারের পরিচালককে জানান।
+ subject: 'মাস্টাডন: পাসওয়ার্ড বদলানো হয়েছে'
+ title: পাসওয়ার্ড বদলানো হয়েছে
+ reconfirmation_instructions:
+ explanation: নতুন ইমেইলটি নিশ্চিত করুন।
+ extra: আপনি যদি এটা না চেয়ে থাকেন, এই ইমেইলটি উপেক্ষা করুন। উপরের লিংকটিতে না গেলে আপনার নিবন্ধনের সাথে যুক্ত ইমেইল বদলাবে না।
+ subject: 'মাস্টাডন: ইমেইল নিশ্চিত করুন %{instance} জন্য'
+ title: আপনার ইমেইলটি নিশ্চিত করুন
+ reset_password_instructions:
+ action: পাসওয়ার্ড বদলান
+ explanation: আপনি আপনার নিবন্ধনের জন্য নতুন পাসওয়ার্ড চেয়েছেন।
+ extra: আপনি যদি এটা না চেয়ে থাকেন, এই ইমেইলটি উপেক্ষা করুন। উপরের লিংকটিতে না গেলে আপনার পাসওয়ার্ড বদলাবে না।
+ subject: 'মাস্টাডন: পাসওয়ার্ড বদলানোর নির্দেশনা'
+ title: পাসওয়ার্ড বদলানো
+ registrations:
+ signed_up: স্বাগতম! আপনার নিবন্ধনটি সঠিকভাবে হয়েছে।
diff --git a/config/locales/devise.sk.yml b/config/locales/devise.sk.yml
index 85de603d3e..4837390dba 100644
--- a/config/locales/devise.sk.yml
+++ b/config/locales/devise.sk.yml
@@ -38,7 +38,7 @@ sk:
explanation: Potvrď novú emailovú adresu na ktorú chceš zmeniť svoj email.
extra: Pokiaľ si túto akciu nevyžiadal/a, prosím ignoruj tento email. Emailová adresa pre tvoj Mastodon účet totiž nebude zmenená pokiaľ nepostúpiš na adresu uvedenú vyššie.
subject: 'Mastodon: Potvrďenie emailu pre %{instance}'
- title: Overiť emailovú adresu
+ title: Over emailovú adresu
reset_password_instructions:
action: Zmeň svoje heslo
explanation: Vyžiadal/a si si nové heslo pre svoj účet.
diff --git a/config/locales/devise.sl.yml b/config/locales/devise.sl.yml
index 7d1e05fdf0..dee1b91253 100644
--- a/config/locales/devise.sl.yml
+++ b/config/locales/devise.sl.yml
@@ -6,7 +6,7 @@ sl:
send_instructions: V nekaj minutah boste prejeli e-poštno sporočilo z navodili za potrditev vašega e-poštnega naslova. Če niste prejeli e-poštnega sporočila, preverite mapo neželena pošta.
send_paranoid_instructions: Če vaš e-poštni naslov obstaja v naši podatkovni bazi, boste v nekaj minutah prejeli e-poštno sporočilo z navodili za potrditev vašega e-poštnega naslova. Če niste prejeli e-poštnega sporočila, preverite mapo neželena pošta.
failure:
- already_authenticated: Prijavljeni ste že.
+ already_authenticated: Ste že prijavljeni.
inactive: Vaš račun še ni aktiviran.
invalid: Neveljavno %{authentication_keys} ali geslo.
last_attempt: Pred zaklepom računa imate še en poskus.
@@ -45,9 +45,44 @@ sl:
explanation: Zahtevali ste novo geslo za svoj račun.
extra: Če tega niste zahtevali, prezrite to e-poštno sporočilo. Vaše geslo se ne bo spremenilo, dokler ne kliknete na zgornjo povezavo in ustvarite novega.
subject: 'Mastodon: Navodila za ponastavitev gesla'
- title: Ponastavitev gesla
+ title: Ponastavi geslo
unlock_instructions:
subject: 'Mastodon: Odkleni navodila'
omniauth_callbacks:
failure: Overitev iz %{kind} ni možna zaradi "%{reason}".
success: Overitev iz računa %{kind} je bila uspešna.
+ passwords:
+ no_token: Do te strani ne morete dostopati, ne da bi prišli iz e-poštne za ponastavitev gesla. Če prihajate iz e-poštne za ponastavitev gesla, se prepričajte, da ste uporabili celoten navedeni URL.
+ send_instructions: Če vaš e-poštni naslov obstaja v naši bazi podatkov, boste v nekaj minutah na vaš e-poštni naslov prejeli povezavo za obnovitev gesla. Če niste prejeli e-pošte, preverite mapo z neželeno pošto.
+ send_paranoid_instructions: Če vaš e-poštni naslov obstaja v naši bazi podatkov, boste v nekaj minutah na vaš e-poštni naslov prejeli povezavo za obnovitev gesla. Če niste prejeli e-pošte, preverite mapo z neželeno pošto.
+ updated: Vaše geslo je bilo uspešno spremenjeno. Zdaj ste prijavljeni.
+ updated_not_active: Vaše geslo je bilo uspešno spremenjeno.
+ registrations:
+ destroyed: Adijo! Vaš račun je bil uspešno preklican. Upamo, da vas bomo kmalu spet videli.
+ signed_up: Dobrodošli! Uspešno ste se vpisali.
+ signed_up_but_inactive: Uspešno ste se vpisali. Vendar vas nismo mogli prijaviti, ker vaš račun še ni aktiviran.
+ signed_up_but_locked: Uspešno ste se vpisali. Vendar vas nismo mogli prijaviti, ker je vaš račun zaklenjen.
+ signed_up_but_pending: Na vaš e-poštni naslov je bilo poslano sporočilo s povezavo za potrditev. Ko kliknete na povezavo, bomo pregledali vašo prijavo. Obveščeni boste, če bo odobren.
+ signed_up_but_unconfirmed: Na vaš e-poštni naslov je bilo poslano sporočilo s povezavo za potrditev. Sledite povezavi, da aktivirate svoj račun. Če niste prejeli te e-pošte, preverite mapo z neželeno pošto.
+ update_needs_confirmation: Uspešno ste posodobili račun, vendar moramo potrditi vaš novi e-poštni naslov. Preverite svojo e-pošto in sledite povezavi za potrditev, da potrdite nov e-poštni naslov. Če niste prejeli te e-poše, preverite mapo z neželeno pošto.
+ updated: Vaš račun je bil uspešno posodobljen.
+ sessions:
+ already_signed_out: Uspešno ste se odjavili.
+ signed_in: Uspešno ste se prijavili.
+ signed_out: Uspešno ste se odjavili.
+ unlocks:
+ send_instructions: Prejeli boste e-pošto z navodili o tem, kako v nekaj minutah odklenete svoj račun. Če niste prejeli te e-pošte, preverite mapo z neželeno pošto.
+ send_paranoid_instructions: Če vaš račun obstaja, boste prejeli e-pošto z navodili za njegovo odklepanje v nekaj minutah. Če niste prejeli te e-pošte, preverite mapo z neželeno pošto.
+ unlocked: Vaš račun je bil uspešno odklenjen. Če želite nadaljevati, se prijavite.
+ errors:
+ messages:
+ already_confirmed: je bil potrjen, poskusite se prijaviti
+ confirmation_period_expired: mora biti potrjena v %{period}, zahtevajte novo
+ expired: je potekla, zahtevajte novo
+ not_found: ni najdeno
+ not_locked: ni bil zaklenjen
+ not_saved:
+ few: "%{count} napake so preprečile shranjevanje %{resource}:"
+ one: '1 napaka je preprečila shranjevanje %{resource}:'
+ other: "%{count} napak je preprečilo shranjevanje %{resource}:"
+ two: "%{count} napaki sta preprečili shranjevanje %{resource}:"
diff --git a/config/locales/devise.zh-CN.yml b/config/locales/devise.zh-CN.yml
index 22fa130f60..f9943238e3 100644
--- a/config/locales/devise.zh-CN.yml
+++ b/config/locales/devise.zh-CN.yml
@@ -58,7 +58,7 @@ zh-CN:
updated: 你的密码已修改成功,你现在已登录。
updated_not_active: 你的密码已修改成功。
registrations:
- destroyed: 再见!你的帐户已成功注销。我们希望很快可以再见到你。
+ destroyed: 再见!你的帐户已成功销毁。我们希望很快可以再见到你。
signed_up: 欢迎!你已注册成功。
signed_up_but_inactive: 你已注册,但尚未激活帐户。
signed_up_but_locked: 你已注册,但帐户被锁定了。
diff --git a/config/locales/doorkeeper.cy.yml b/config/locales/doorkeeper.cy.yml
index 19798c4d9f..e29043e86f 100644
--- a/config/locales/doorkeeper.cy.yml
+++ b/config/locales/doorkeeper.cy.yml
@@ -114,6 +114,12 @@ cy:
application:
title: Mae awdurdodiad OAuth yn ofynnol
scopes:
+ admin:read: darllenwch yr holl ddata ar y serfiwr
+ admin:read:accounts: darllen gwybodaeth sensitif o'r holl gyfrifon
+ admin:read:reports: darllen gwybodaeth sensitif am bob adroddiad a chyfrifon yr adroddir amdanynt
+ admin:write: addasu pob data ar y serfiwr
+ admin:write:accounts: cyflawni camau cymedroli ar gyfrifon
+ admin:write:reports: cyflawni camau cymedroli ar adroddiadau
follow: addasu perthnasau cyfrif
push: derbyn eich hysbysiadau gwthiadwy
read: darllen holl ddata eich cyfrif
diff --git a/config/locales/doorkeeper.es.yml b/config/locales/doorkeeper.es.yml
index 752387d870..1b03e33f2f 100644
--- a/config/locales/doorkeeper.es.yml
+++ b/config/locales/doorkeeper.es.yml
@@ -114,7 +114,35 @@ es:
application:
title: OAuth autorización requerida
scopes:
+ admin:read: leer todos los datos en el servidor
+ admin:read:accounts: leer información sensible de todas las cuentas
+ admin:read:reports: leer información sensible de todos los informes y cuentas reportadas
+ admin:write: modificar todos los datos en el servidor
+ admin:write:accounts: realizar acciones de moderación en cuentas
+ admin:write:reports: realizar acciones de moderación en informes
follow: seguir, bloquear, desbloquear y dejar de seguir cuentas
+ push: recibir tus notificaciones push
read: leer los datos de tu cuenta
+ read:accounts: ver información de cuentas
+ read:blocks: ver a quién has bloqueado
+ read:favourites: ver tus favoritos
+ read:filters: ver tus filtros
+ read:follows: ver a quién sigues
+ read:lists: ver tus listas
+ read:mutes: ver a quién has silenciado
+ read:notifications: ver tus notificaciones
+ read:reports: ver tus informes
+ read:search: buscar en su nombre
+ read:statuses: ver todos los estados
write: publicar en tu nombre
+ write:accounts: modifica tu perfil
write:blocks: bloquear cuentas y dominios
+ write:favourites: toots favoritos
+ write:filters: crear filtros
+ write:follows: seguir usuarios
+ write:lists: crear listas
+ write:media: subir archivos multimedia
+ write:mutes: silenciar usuarios y conversaciones
+ write:notifications: limpia tus notificaciones
+ write:reports: reportar a otras personas
+ write:statuses: publicar estados
diff --git a/config/locales/doorkeeper.eu.yml b/config/locales/doorkeeper.eu.yml
index f98babae65..70e52e8ad9 100644
--- a/config/locales/doorkeeper.eu.yml
+++ b/config/locales/doorkeeper.eu.yml
@@ -5,7 +5,7 @@ eu:
doorkeeper/application:
name: Aplikazioaren izena
redirect_uri: Birbideratu URIa
- scopes: Esparruak
+ scopes: Irismena
website: Aplikazioaren webgunea
errors:
models:
@@ -33,14 +33,14 @@ eu:
help:
native_redirect_uri: Erabili %{native_redirect_uri} proba lokaletarako
redirect_uri: Erabili lerro bat URI bakoitzeko
- scopes: Banandu esparruak espazioekin. Laga hutsik lehenetsitako esparruak erabiltzeko.
+ scopes: Banandu irismenak espazioekin. Laga hutsik lehenetsitako irismenak erabiltzeko.
index:
application: Aplikazioa
callback_url: Itzulera URLa
delete: Ezabatu
name: Izena
new: Aplikazio berria
- scopes: Esparruak
+ scopes: Irismena
show: Erakutsi
title: Zure aplikazioak
new:
@@ -49,7 +49,7 @@ eu:
actions: Ekintzak
application_id: Bezeroaren gakoa
callback_urls: Itzulera URL-ak
- scopes: Esparruak
+ scopes: Irismena
secret: Bezeroaren sekretua
title: 'Aplikazioa: %{name}'
authorizations:
@@ -73,7 +73,7 @@ eu:
application: Aplikazioa
created_at: Baimenduta
date_format: "%Y-%m-%d %H:%M:%S"
- scopes: Esparruak
+ scopes: Irismena
title: Zuk baimendutako aplikazioak
errors:
messages:
@@ -114,6 +114,12 @@ eu:
application:
title: OAuth autorizazioa behar da
scopes:
+ admin:read: zerbitzariko datu guztiak irakurri
+ admin:read:accounts: kontu guztien informazio sentsiblea irakurri
+ admin:read:reports: salaketa guztietako eta salatutako kontu guztietako informazio sentsiblea irakurri
+ admin:write: zerbitzariko datu guztiak aldatu
+ admin:write:accounts: kontuetan moderazio ekintzak burutu
+ admin:write:reports: salaketetan moderazio ekintzak burutu
follow: aldatu kontuaren erlazioak
push: jaso push jakinarazpenak
read: irakurri zure kontuko datu guztiak
diff --git a/config/locales/doorkeeper.hu.yml b/config/locales/doorkeeper.hu.yml
index 122392864d..92b4e6839b 100644
--- a/config/locales/doorkeeper.hu.yml
+++ b/config/locales/doorkeeper.hu.yml
@@ -114,6 +114,12 @@ hu:
application:
title: OAuth engedély szükséges
scopes:
+ admin:read: szerver minden adatának olvasása
+ admin:read:accounts: minden érzékeny fiókadat olvasása
+ admin:read:reports: minden bejelentés és bejelentett fiók érzékeny adatainak olvasása
+ admin:write: szerver minden adatának változtatása
+ admin:write:accounts: moderációs műveletek végzése fiókokon
+ admin:write:reports: moderációs műveletek végzése bejelentéseken
follow: fiókok követése, letiltása, tiltás feloldása és követés abbahagyása
push: push értesítések fogadása
read: fiókod adatainak olvasása
diff --git a/config/locales/doorkeeper.nl.yml b/config/locales/doorkeeper.nl.yml
index aa37ea190a..1fabfc1239 100644
--- a/config/locales/doorkeeper.nl.yml
+++ b/config/locales/doorkeeper.nl.yml
@@ -114,6 +114,12 @@ nl:
application:
title: OAuth-autorisatie vereist
scopes:
+ admin:read: lees alle gegevens op de server
+ admin:read:accounts: lees gevoelige informatie van alle accounts
+ admin:read:reports: lees gevoelige informatie van alle rapportages en gerapporteerde accounts
+ admin:write: wijzig alle gegevens op de server
+ admin:write:accounts: moderatieacties op accounts uitvoeren
+ admin:write:reports: moderatieacties op rapportages uitvoeren
follow: relaties tussen accounts bewerken
push: ontvang jouw pushmeldingen
read: alle gegevens van jouw account lezen
diff --git a/config/locales/doorkeeper.oc.yml b/config/locales/doorkeeper.oc.yml
index d97c2f600e..e715cc7d52 100644
--- a/config/locales/doorkeeper.oc.yml
+++ b/config/locales/doorkeeper.oc.yml
@@ -114,6 +114,12 @@ oc:
application:
title: Cal una autorizacion OAuth
scopes:
+ admin:read: lectura de totas las donadas del servidor
+ admin:read:accounts: lectura de las informacions sensiblas dels comptes
+ admin:read:reports: lectura de las informacions sensiblas dels senhalaments e dels comptes senhalats
+ admin:write: modificacion de las donadas del servidor
+ admin:write:accounts: realizacion d’accions de moderacion suls comptes
+ admin:write:reports: realizacion d’accions suls senhalaments
follow: modificar las relacions del compte
push: recebre vòstras notificacions push
read: legir totas las donadas de vòstre compte
diff --git a/config/locales/doorkeeper.sk.yml b/config/locales/doorkeeper.sk.yml
index f54eb6d48d..9eaef177fb 100644
--- a/config/locales/doorkeeper.sk.yml
+++ b/config/locales/doorkeeper.sk.yml
@@ -19,34 +19,34 @@ sk:
doorkeeper:
applications:
buttons:
- authorize: Overiť
- cancel: Zrušiť
+ authorize: Autorizuj
+ cancel: Zruš
destroy: Zničiť
- edit: Upraviť
- submit: Poslať
+ edit: Uprav
+ submit: Pošli
confirmations:
destroy: Si si istý/á?
edit:
- title: Upraviť aplikáciu
+ title: Uprav aplikáciu
form:
- error: No teda! Pozrite formulár pre prípadné chyby
+ error: No teda! Skontroluj formulár pre prípadné chyby
help:
- native_redirect_uri: Použite %{native_redirect_uri} pre lokálne testy
- redirect_uri: Iba jedna URI na riadok
- scopes: Oprávnenia oddeľujte medzerami. Nechajte prázdne pre štandardné oprávnenia.
+ native_redirect_uri: Použi %{native_redirect_uri} pre lokálne testy
+ redirect_uri: Použi jeden riadok pre každú URI
+ scopes: Oprávnenia oddeľuj medzerami. Nechaj prázdne pre štandardné oprávnenia.
index:
application: Aplikácia
callback_url: Návratová URL
- delete: Zmazať
+ delete: Vymaž
name: Názov
new: Nová aplikácia
scopes: Oprávnenia
- show: Ukázať
- title: Vaše aplikácie
+ show: Ukáž
+ title: Tvoje aplikácie
new:
title: Nová aplikácia
show:
- actions: Akcie
+ actions: Úkony
application_id: Kľúč klienta
callback_urls: Návratové URL adresy
scopes: Oprávnenia
@@ -54,7 +54,7 @@ sk:
title: 'Aplikácia: %{name}'
authorizations:
buttons:
- authorize: Overiť
+ authorize: Over
deny: Zamietni
error:
title: Nastala chyba
@@ -91,7 +91,7 @@ sk:
resource_owner_authenticator_not_configured: Resource Owner zlyhal pretože Doorkeeper.configure.resource_owner_authenticator nebol nakonfigurovaný.
server_error: Nastala neočakávaná chyba na autorizačnom serveri ktorá zabránila vykonať požiadavku.
temporarily_unavailable: Autorizačný server ťa teraz nemôže obslúžiť, pretože prebieha údržba alebo je dočasne preťažený.
- unauthorized_client: Klient nie je autorizovaný vykonať danú požiadavku takouto metódou.
+ unauthorized_client: Klient nie je autorizovaný vykonať danú požiadavku týmto spôsobom.
unsupported_grant_type: Tento typ oprávnenia nie je podporovaný autorizačným serverom.
unsupported_response_type: Autorizačný server nepodporuje typ tejto odpovede.
flash:
@@ -113,6 +113,11 @@ sk:
application:
title: Požadovaná OAuth autorizácia
scopes:
+ admin:read: prezeraj všetky dáta na serveri
+ admin:read:accounts: prezeraj chúlostivé informácie na všetkých účtoch
+ admin:write: uprav všetky dáta na serveri
+ admin:write:accounts: urob moderovacie úkony na účtoch
+ admin:write:reports: urob moderovacie úkony voči hláseniam
follow: uprav vzťahy svojho účtu
push: dostávaj oboznámenia ohľadom tvojho účtu na obrazovku
read: prezri si všetky dáta ohľadom svojho účetu
diff --git a/config/locales/doorkeeper.zh-CN.yml b/config/locales/doorkeeper.zh-CN.yml
index dd9337904a..015d2c0ce1 100644
--- a/config/locales/doorkeeper.zh-CN.yml
+++ b/config/locales/doorkeeper.zh-CN.yml
@@ -72,6 +72,7 @@ zh-CN:
index:
application: 应用
created_at: 授权时间
+ date_format: "%H:%M:%S"
scopes: 权限范围
title: 已授权的应用列表
errors:
diff --git a/config/locales/el.yml b/config/locales/el.yml
index a08ec71416..21b0da25c4 100644
--- a/config/locales/el.yml
+++ b/config/locales/el.yml
@@ -469,13 +469,6 @@ el:
no_status_selected: Καμία δημοσίευση δεν άλλαξε αφού καμία δεν ήταν επιλεγμένη
title: Καταστάσεις λογαριασμού
with_media: Με πολυμέσα
- subscriptions:
- callback_url: URL επιστροφής (Callback)
- confirmed: Επιβεβαιωμένες
- expires_in: Λήγει σε
- last_delivery: Τελευταία παράδοση
- title: Πρωτόκολλο WebSub
- topic: Θέμα
tags:
accounts: Λογαριασμοί
hidden: Κρυμμένες
@@ -816,10 +809,6 @@ el:
reply:
proceed: Συνέχισε για να απαντήσεις
prompt: 'Θέλεις να απαντήσεις σε αυτό το τουτ:'
- remote_unfollow:
- error: Σφάλμα
- title: Τίτλος
- unfollowed: Σταμάτησες να ακολουθείς
scheduled_statuses:
over_daily_limit: Έχεις υπερβεί το όριο των %{limit} προγραμματισμένων τουτ για εκείνη τη μέρα
over_total_limit: Έχεις υπερβεί το όριο των %{limit} προγραμματισμένων τουτ
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 3a8a0c4858..f05d69d36f 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -24,6 +24,9 @@ en:
generic_description: "%{domain} is one server in the network"
get_apps: Try a mobile app
hosted_on: Mastodon hosted on %{domain}
+ instance_actor_flash: |
+ This account is a virtual actor used to represent the server itself and not any individual user.
+ It is used for federation purposes and should not be blocked unless you want to block the whole instance, in which case you should use a domain block.
learn_more: Learn more
privacy_policy: Privacy policy
see_whats_happening: See what's happening
@@ -250,6 +253,7 @@ en:
feature_profile_directory: Profile directory
feature_registrations: Registrations
feature_relay: Federation relay
+ feature_spam_check: Anti-spam
feature_timeline_preview: Timeline preview
features: Features
hidden_service: Federation with hidden services
@@ -462,6 +466,9 @@ en:
desc_html: You can write your own privacy policy, terms of service or other legalese. You can use HTML tags
title: Custom terms of service
site_title: Server name
+ spam_check_enabled:
+ desc_html: Mastodon can auto-silence and auto-report accounts based on measures such as detecting accounts who send repeated unsolicited messages. There may be false positives.
+ title: Anti-spam
thumbnail:
desc_html: Used for previews via OpenGraph and API. 1200x630px recommended
title: Server thumbnail
@@ -482,13 +489,6 @@ en:
no_status_selected: No statuses were changed as none were selected
title: Account statuses
with_media: With media
- subscriptions:
- callback_url: Callback URL
- confirmed: Confirmed
- expires_in: Expires in
- last_delivery: Last delivery
- title: WebSub
- topic: Topic
tags:
accounts: Accounts
hidden: Hidden
@@ -831,10 +831,6 @@ en:
reply:
proceed: Proceed to reply
prompt: 'You want to reply to this toot:'
- remote_unfollow:
- error: Error
- title: Title
- unfollowed: Unfollowed
scheduled_statuses:
over_daily_limit: You have exceeded the limit of %{limit} scheduled toots for that day
over_total_limit: You have exceeded the limit of %{limit} scheduled toots
@@ -901,6 +897,8 @@ en:
profile: Profile
relationships: Follows and followers
two_factor_authentication: Two-factor Auth
+ spam_check:
+ spam_detected_and_silenced: This is an automated report. Spam has been detected and the sender has been silenced automatically. If this is a mistake, please unsilence the account.
statuses:
attached:
description: 'Attached: %{attached}'
diff --git a/config/locales/eo.yml b/config/locales/eo.yml
index c71b42fdd8..de28be0108 100644
--- a/config/locales/eo.yml
+++ b/config/locales/eo.yml
@@ -174,6 +174,7 @@ eo:
statuses: Mesaĝoj
subscribe: Aboni
suspended: Haltigita
+ time_in_queue: Atendado en atendovico %{time}
title: Kontoj
unconfirmed_email: Nekonfirmita retadreso
undo_silenced: Malfari kaŝon
@@ -334,6 +335,8 @@ eo:
expired: Eksvalida
title: Filtri
title: Invitoj
+ pending_accounts:
+ title: Pritraktataj kontoj (%{count})
relays:
add_new: Aldoni novan ripetilon
delete: Forigi
@@ -465,13 +468,6 @@ eo:
no_status_selected: Neniu mesaĝo estis ŝanĝita ĉar neniu estis elektita
title: Mesaĝoj de la konto
with_media: Kun aŭdovidaĵoj
- subscriptions:
- callback_url: Revena URL
- confirmed: Konfirmita
- expires_in: Eksvalidiĝas je
- last_delivery: Lasta livero
- title: WebSub
- topic: Temo
tags:
accounts: Kontoj
hidden: Kaŝitaj
@@ -780,7 +776,10 @@ eo:
too_many_options: ne povas enhavi pli da %{max} proponoj
preferences:
other: Aliaj aferoj
+ posting_defaults: Afiŝadoj defaŭltoj
+ public_timelines: Publikaj templinioj
relationships:
+ activity: Konto aktiveco
dormant: Dormanta
last_active: Lasta aktiva
most_recent: Plej lasta
@@ -788,6 +787,9 @@ eo:
mutual: Reciproka
primary: Primara
relationship: Rilato
+ remove_selected_domains: Forigi ĉiuj sekvantojn el la selektitajn domajnojn
+ remove_selected_followers: Forigi selektitajn sekvantojn
+ remove_selected_follows: Malsekvi selektitajn uzantojn
status: Statuso de la konto
remote_follow:
acct: Enmetu vian uzantnomo@domajno de kie vi volas agi
@@ -806,10 +808,6 @@ eo:
reply:
proceed: Konfirmi la respondon
prompt: 'Vi volas respondi al ĉi tiu mesaĝo:'
- remote_unfollow:
- error: Eraro
- title: Titolo
- unfollowed: Ne plu sekvita
scheduled_statuses:
over_daily_limit: Vi transpasis la limigon al %{limit} samtage planitaj mesaĝoj
over_total_limit: Vi transpasis la limigon al %{limit} planitaj mesaĝoj
diff --git a/config/locales/es.yml b/config/locales/es.yml
index 49765cd0a3..d6adf4062f 100644
--- a/config/locales/es.yml
+++ b/config/locales/es.yml
@@ -5,9 +5,13 @@ es:
about_mastodon_html: Mastodon es un servidor de red social libre y de código abierto. Una alternativa descentralizada a plataformas comerciales, que evita el riesgo de que una única compañía monopolice tu comunicación. Cualquiera puede ejecutar Mastodon y participar sin problemas en la red social.
about_this: Acerca de esta instancia
active_count_after: activo
+ active_footnote: Usuarios Activos Mensuales (UAM)
administered_by: 'Administrado por:'
api: API
apps: Aplicaciones móviles
+ apps_platforms: Utiliza Mastodon desde iOS, Android y otras plataformas
+ browse_directory: Navega por el directorio de perfiles y filtra por intereses
+ browse_public_posts: Navega por un transmisión en vivo de publicaciones públicas en Mastodon
contact: Contacto
contact_missing: No especificado
contact_unavailable: N/A
@@ -111,6 +115,7 @@ es:
inbox_url: URL de la bandeja de entrada
invited_by: Invitado por
ip: IP
+ joined: Unido
location:
all: Todos
local: Local
@@ -245,6 +250,7 @@ es:
feature_profile_directory: Directorio de perfil
feature_registrations: Registros
feature_relay: Relés de federación
+ feature_timeline_preview: Vista previa de la línea de tiempo
features: Características
hidden_service: Federación con servicios ocultos
open_reports: informes abiertos
@@ -279,6 +285,7 @@ es:
reject_reports: Rechazar informes
reject_reports_hint: Ignore todos los reportes de este dominio. Irrelevante para suspensiones
rejecting_media: rechazar archivos multimedia
+ rejecting_reports: rechazando informes
severity:
silence: silenciado
suspend: susependido
@@ -304,8 +311,13 @@ es:
title: Lista negra de correo
followers:
back_to_account: Volver a la cuenta
+ title: Seguidores de %{acct}
instances:
by_domain: Dominio
+ delivery_available: Entrega disponible
+ known_accounts:
+ one: "%{count} cuenta conocida"
+ other: "%{count} cuentas conocidas"
moderation:
all: Todos
limited: Limitado
@@ -314,6 +326,7 @@ es:
total_blocked_by_us: Bloqueado por nosotros
total_followed_by_them: Seguidos por ellos
total_followed_by_us: Seguido por nosotros
+ total_reported: Informes sobre ellas
total_storage: Archivos multimedia
invites:
deactivate_all: Desactivar todos
@@ -323,6 +336,8 @@ es:
expired: Expiradas
title: Filtrar
title: Invitaciones
+ pending_accounts:
+ title: Cuentas pendientes (%{count})
relays:
add_new: Añadir un nuevo relés
delete: Borrar
@@ -396,6 +411,9 @@ es:
preview_sensitive_media:
desc_html: Los enlaces de vistas previas en otras web mostrarán una miniatura incluso si el medio está marcado como contenido sensible
title: Mostrar contenido sensible en previews de OpenGraph
+ profile_directory:
+ desc_html: Permitir que los usuarios puedan ser descubiertos
+ title: Habilitar directorio de perfiles
registrations:
closed_message:
desc_html: Se muestra en la portada cuando los registros están cerrados. Puedes usar tags HTML
@@ -408,8 +426,10 @@ es:
title: Permitir invitaciones de
registrations_mode:
modes:
+ approved: Se requiere aprobación para registrarse
none: Nadie puede registrarse
open: Cualquiera puede registrarse
+ title: Modo de registros
show_known_fediverse_at_about_page:
desc_html: Cuando esté activado, se mostrarán toots de todo el fediverso conocido en la vista previa. En otro caso, se mostrarán solamente toots locales.
title: Mostrar fediverso conocido en la vista previa de la historia
@@ -449,26 +469,38 @@ es:
no_status_selected: No se cambió ningún estado al no seleccionar ninguno
title: Estado de las cuentas
with_media: Con multimedia
- subscriptions:
- callback_url: URL del callback
- confirmed: Confirmado
- expires_in: Expira en
- last_delivery: Última entrega
- topic: Tópico
+ tags:
+ accounts: Cuentas
+ hidden: Oculto
+ hide: Ocultar del directorio
+ name: Etiqueta
+ title: Etiquetas
+ unhide: Mostrar en el directorio
+ visible: Visible
title: Administración
warning_presets:
add_new: Añadir nuevo
delete: Borrar
edit: Editar
+ edit_preset: Editar aviso predeterminado
+ title: Editar configuración predeterminada de avisos
admin_mailer:
new_pending_account:
body: Los detalles de la nueva cuenta están abajos. Puedes aprobar o rechazar esta aplicación.
+ subject: Nueva cuenta para revisión en %{instance} (%{username})
new_report:
body: "%{reporter} ha reportado a %{target}"
body_remote: Alguien de %{domain} a reportado a %{target}
subject: Nuevo reporte para la %{instance} (#%{id})
+ appearance:
+ advanced_web_interface: Interfaz web avanzada
+ advanced_web_interface_hint: 'Si desea utilizar todo el ancho de pantalla, la interfaz web avanzada le permite configurar varias columnas diferentes para ver tanta información al mismo tiempo como quiera: Inicio, notificaciones, línea de tiempo federada, cualquier número de listas y etiquetas.'
+ animations_and_accessibility: Animaciones y accesibilidad
+ confirmation_dialogs: Diálogos de confirmación
+ sensitive_content: Contenido sensible
application_mailer:
notification_preferences: Cambiar preferencias de correo electrónico
+ salutation: "%{name},"
settings: 'Cambiar preferencias de correo: %{link}'
view: 'Vista:'
view_profile: Ver perfil
@@ -482,6 +514,7 @@ es:
warning: Ten mucho cuidado con estos datos. ¡No los compartas con nadie!
your_token: Tu token de acceso
auth:
+ apply_for_account: Solicitar una invitación
change_password: Contraseña
checkbox_agreement_html: Acepto las reglas del servidor y términos de servicio
confirm_email: Confirmar email
@@ -495,12 +528,16 @@ es:
migrate_account: Mudarse a otra cuenta
migrate_account_html: Si deseas redireccionar esta cuenta a otra distinta, puedes configurarlo aquí.
or_log_in_with: O inicia sesión con
+ providers:
+ cas: CAS
+ saml: SAML
register: Registrarse
registration_closed: "%{instance} no está aceptando nuevos miembros"
resend_confirmation: Volver a enviar el correo de confirmación
reset_password: Restablecer contraseña
security: Cambiar contraseña
set_new_password: Establecer nueva contraseña
+ trouble_logging_in: "¿Problemas para iniciar sesión?"
authorize_follow:
already_following: Ya estás siguiendo a esta cuenta
error: Desafortunadamente, ha ocurrido un error buscando la cuenta remota
@@ -514,10 +551,18 @@ es:
title: Seguir a %{acct}
datetime:
distance_in_words:
+ about_x_hours: "%{count}h"
about_x_months: "%{count}m"
+ about_x_years: "%{count}a"
+ almost_x_years: "%{count}a"
half_a_minute: Justo ahora
+ less_than_x_minutes: "%{count}m"
less_than_x_seconds: Justo ahora
+ over_x_years: "%{count}a"
+ x_days: "%{count}d"
+ x_minutes: "%{count}m"
x_months: "%{count}m"
+ x_seconds: "%{count}s"
deletes:
bad_password_msg: "¡Buen intento, hackers! Contraseña incorrecta"
confirm_password: Ingresa tu contraseña actual para demostrar tu identidad
@@ -527,6 +572,10 @@ es:
warning_html: Se garantiza únicamente la eliminación del contenido de esta instancia. El contenido que se haya compartido extensamente dejará sus huellas. Los servidores fuera de línea y los que se hayan desuscrito de tus actualizaciones ya no actualizarán sus bases de datos.
warning_title: Disponibilidad diseminada del contenido
directories:
+ directory: Directorio de perfiles
+ enabled: Actualmente está listado en el directorio.
+ enabled_but_waiting: Ha optado por ser listado en el directorio, pero aún no cumple con el número mínimo de seguidores (%{min_followers}) para ser listado.
+ explanation: Descubre usuarios según sus intereses
explore_mastodon: Explorar %{title}
how_to_enable: Usted no está registrado por el directorio. Puede registrar por abajo. ¡Utilice hashtags en su bio para aparecer bajo hashtags específicos!
people:
@@ -557,6 +606,7 @@ es:
size: Tamaño
blocks: Personas que has bloqueado
csv: CSV
+ domain_blocks: Bloqueos de dominios
follows: Personas que sigues
lists: Listas
mutes: Tienes en silencio
@@ -594,6 +644,8 @@ es:
validation_errors:
one: "¡Algo no está bien! Por favor, revisa el error"
other: "¡Algo no está bien! Por favor, revise %{count} errores más abajo"
+ html_validator:
+ invalid_markup: 'contiene código HTML no válido: %{error}'
identity_proofs:
active: Activo
authorize: Sí, autorizar
@@ -603,18 +655,26 @@ es:
keybase:
invalid_token: Los tokens de Keybase son hashes de firmas y deben tener 66 caracteres hex
verification_failed: Keybase no reconoce este token como una firma del usuario de Keybase %{kb_username}. Por favor, inténtelo de nuevo desde Keybase.
+ wrong_user: No se puede crear una prueba para %{proving} mientras se inicia sesión como %{current}. Inicia sesión como %{proving} e inténtalo de nuevo.
+ explanation_html: Aquí puedes conectar criptográficamente sus otras identidades, como un perfil de Keybase. Esto permite a otras personas enviarle mensajes encriptados y confiar en el contenido que les envías.
+ i_am_html: Soy %{username} en %{service}.
identity: Identidad
inactive: Inactivo
+ publicize_checkbox: 'Y tootee esto:'
+ publicize_toot: "¡Comprobado! Soy %{username} en %{service}: %{url}"
status: Estado de la verificación
view_proof: Ver prueba
imports:
modes:
merge: Unir
+ merge_long: Mantener registros existentes y añadir nuevos
overwrite: Sobrescribir
+ overwrite_long: Reemplazar registros actuales con los nuevos
preface: Puedes importar ciertos datos, como todas las personas que estás siguiendo o bloqueando en tu cuenta en esta instancia, desde archivos exportados de otra instancia.
success: Sus datos se han cargado correctamente y serán procesados en brevedad
types:
blocking: Lista de bloqueados
+ domain_blocking: Lista de dominios bloqueados
following: Lista de seguidos
muting: Lista de silenciados
upload: Cargar
@@ -689,26 +749,70 @@ es:
body: "%{name} ha retooteado tu estado:"
subject: "%{name} ha retooteado tu estado"
title: Nueva difusión
+ number:
+ human:
+ decimal_units:
+ format: "%n%u"
+ units:
+ billion: B
+ million: M
+ quadrillion: Q
+ thousand: m
+ trillion: T
pagination:
newer: Más nuevo
next: Próximo
older: Más antiguo
prev: Anterior
+ truncate: "…"
+ polls:
+ errors:
+ already_voted: Ya has votado en esta encuesta
+ duplicate_options: contiene elementos duplicados
+ duration_too_long: está demasiado lejos en el futuro
+ duration_too_short: es demasiado pronto
+ expired: La encuesta ya ha terminado
+ over_character_limit: no puede exceder %{max} caracteres cada uno
+ too_few_options: debe tener más de un elemento
+ too_many_options: no puede contener más de %{max} elementos
preferences:
other: Otros
+ posting_defaults: Configuración por defecto de publicaciones
+ public_timelines: Líneas de tiempo públicas
relationships:
+ activity: Actividad de la cuenta
+ dormant: Inactivo
last_active: Última actividad
most_recent: Más reciente
+ moved: Movido
+ mutual: Mutuo
+ primary: Principal
+ relationship: Relación
+ remove_selected_domains: Eliminar todos los seguidores de los dominios seleccionados
+ remove_selected_followers: Eliminar los seguidores seleccionados
+ remove_selected_follows: Dejar de seguir a los usuarios seleccionados
+ status: Estado de la cuenta
remote_follow:
acct: Ingesa tu usuario@dominio desde el que quieres seguir
missing_resource: No se pudo encontrar la URL de redirección requerida para tu cuenta
no_account_html: "¿No tienes una cuenta? Puedes registrarte aqui"
proceed: Proceder a seguir
prompt: 'Vas a seguir a:'
- remote_unfollow:
- error: Error
- title: Título
- unfollowed: Ha dejado de seguirse
+ reason_html: "¿¿Por qué es necesario este paso?%{instance} puede que no sea el servidor donde estás registrado, así que necesitamos redirigirte primero a tu servidor de origen."
+ remote_interaction:
+ favourite:
+ proceed: Proceder a marcar como favorito
+ prompt: 'Quieres marcar como favorito este toot:'
+ reblog:
+ proceed: Proceder a retootear
+ prompt: 'Quieres retootear este toot:'
+ reply:
+ proceed: Proceder a responder
+ prompt: 'Quieres responder a este toot:'
+ scheduled_statuses:
+ over_daily_limit: Ha superado el límite de %{limit} toots programados para ese día
+ over_total_limit: Ha superado el límite de %{limit} toots programados
+ too_soon: La fecha programada debe estar en el futuro
sessions:
activity: Última actividad
browser: Navegador
@@ -761,10 +865,14 @@ es:
edit_profile: Editar perfil
export: Exportar información
featured_tags: Hashtags destacados
+ identity_proofs: Pruebas de identidad
import: Importar
+ import_and_export: Importar y exportar
migrate: Migración de cuenta
notifications: Notificaciones
preferences: Preferencias
+ profile: Perfil
+ relationships: Siguiendo y seguidores
two_factor_authentication: Autenticación de dos factores
statuses:
attached:
@@ -788,8 +896,14 @@ es:
ownership: El toot de alguien más no puede fijarse
private: Los toots no-públicos no pueden fijarse
reblog: Un boost no puede fijarse
+ poll:
+ total_votes:
+ one: "%{count} voto"
+ other: "%{count} votos"
+ vote: Vota
show_more: Mostrar más
sign_in_to_participate: Regístrate para participar en la conversación
+ title: '%{name}: "%{quote}"'
visibilities:
private: Sólo mostrar a seguidores
private_long: Solo mostrar a tus seguidores
@@ -802,6 +916,87 @@ es:
reblogged: retooteado
sensitive_content: Contenido sensible
terms:
+ body_html: |
+
Política de Privacidad
+
¿Qué información recogemos?
+
+
+
Información básica sobre su cuenta: Si se registra en este servidor, se le requerirá un nombre de usuario, una dirección de correo electrónico y una contraseña. Además puede incluir información adicional en el perfil como un nombre de perfil y una biografía, y subir una foto de perfil y una imagen de cabecera. El nombre de usuario, nombre de perfil, biografía, foto de perfil e imagen de cabecera siempre son visibles públicamente
+
Publicaciones, seguimiento y otra información pública: La lista de gente a la que sigue es mostrada públicamente, al igual que sus seguidores. Cuando publica un mensaje, la fecha y hora es almacenada, así como la aplicación desde la cual publicó el mensaje. Los mensajes pueden contener archivos adjuntos multimedia, como imágenes y vídeos. Las publicaciones públicas y no listadas están disponibles públicamente. Cuando destaca una entrada en su perfil, también es información disponible públicamente. Sus publicaciones son entregadas a sus seguidores, en algunos casos significa que son entregadas a diferentes servidores y las copias son almacenadas allí. Cuando elimina publicaciones, esto también se transfiere a sus seguidores. La acción de rebloguear o marcar como favorito otra publicación es siempre pública.
+
Publicaciones directas y sólo para seguidores: Todos los mensajes se almacenan y procesan en el servidor. Los mensajes sólo para seguidores se entregan a los seguidores y usuarios que se mencionan en ellos, y los mensajes directos se entregan sólo a los usuarios que se mencionan en ellos. En algunos casos significa que se entregan a diferentes servidores y que las copias se almacenan allí. Hacemos un esfuerzo de buena fe para limitar el acceso a esas publicaciones sólo a las personas autorizadas, pero otros servidores pueden no hacerlo. Por lo tanto, es importante revisar los servidores a los que pertenecen sus seguidores. Puede cambiar una opción para aprobar y rechazar nuevos seguidores manualmente en la configuración Por favor, tenga en cuenta que los operadores del servidor y de cualquier servidor receptor pueden ver dichos mensajes, y que los destinatarios pueden capturarlos, copiarlos o volver a compartirlos de alguna otra manera. No comparta ninguna información peligrosa en Mastodon.
+
Direcciones IP y otros metadatos: Al iniciar sesión, registramos la dirección IP desde la que se ha iniciado sesión, así como el nombre de la aplicación de su navegador. Todas las sesiones iniciadas están disponibles para su revisión y revocación en los ajustes. La última dirección IP utilizada se almacena hasta 12 meses. También podemos conservar los registros del servidor que incluyen la dirección IP de cada solicitud a nuestro servidor.
+
+
+
+
+
¿Para qué utilizamos su información?
+
+
Toda la información que obtenemos de usted puede ser utilizada de las siguientes maneras:
+
+
+
Para proporcionar la funcionalidad principal de Mastodon. Sólo puedes interactuar con el contenido de otras personas y publicar tu propio contenido cuando estés conectado. Por ejemplo, puedes seguir a otras personas para ver sus mensajes combinados en tu propia línea de tiempo personalizada.
+
Para ayudar a la moderación de la comunidad, por ejemplo, comparando su dirección IP con otras conocidas para determinar la evasión de prohibiciones u otras violaciones.
+
La dirección de correo electrónico que nos proporcione podrá utilizarse para enviarle información, notificaciones sobre otras personas que interactúen con su contenido o para enviarle mensajes, así como para responder a consultas y/u otras solicitudes o preguntas.
+
+
+
+
+
¿Cómo protegemos su información?
+
+
Implementamos una variedad de medidas de seguridad para mantener la seguridad de su información personal cuando usted ingresa, envía o accede a su información personal. Entre otras cosas, la sesión de su navegador, así como el tráfico entre sus aplicaciones y la API, están protegidos con SSL, y su contraseña está protegida mediante un algoritmo unidireccional fuerte. Puede habilitar la autenticación de dos factores para un acceso más seguro a su cuenta.
+
+
+
+
¿Cuál es nuestra política de retención de datos?
+
+
Haremos un esfuerzo de buena fe para:
+
+
+
Conservar los registros del servidor que contengan la dirección IP de todas las peticiones a este servidor, en la medida en que se mantengan dichos registros, no más de 90 días.
+
Conservar las direcciones IP asociadas a los usuarios registrados no más de 12 meses.
+
+
+
Puede solicitar y descargar un archivo de su contenido, incluidos sus mensajes, archivos adjuntos multimedia, foto de perfil e imagen de cabecera.
+
+
Usted puede borrar su cuenta de forma irreversible en cualquier momento.
+
+
+
+
¿Utilizamos cookies?
+
+
Sí. Las cookies son pequeños archivos que un sitio o su proveedor de servicios transfiere al disco duro de su ordenador a través de su navegador web (si usted lo permite). Estas cookies permiten al sitio reconocer su navegador y, si tiene una cuenta registrada, asociarla con su cuenta registrada.
+
+
Utilizamos cookies para entender y guardar sus preferencias para futuras visitas.
+
+
+
+
¿Revelamos alguna información a terceros?
+
+
No vendemos, comerciamos ni transferimos a terceros su información personal identificable. Esto no incluye a los terceros de confianza que nos asisten en la operación de nuestro sitio, en la realización de nuestros negocios o en la prestación de servicios, siempre y cuando dichas partes acuerden mantener la confidencialidad de esta información. También podemos divulgar su información cuando creamos que es apropiado para cumplir con la ley, hacer cumplir las políticas de nuestro sitio, o proteger nuestros u otros derechos, propiedad o seguridad.
+
+
Su contenido público puede ser descargado por otros servidores de la red. Tus mensajes públicos y sólo para seguidores se envían a los servidores donde residen tus seguidores, y los mensajes directos se envían a los servidores de los destinatarios, en la medida en que dichos seguidores o destinatarios residan en un servidor diferente.
+
+
Cuando usted autoriza a una aplicación a usar su cuenta, dependiendo del alcance de los permisos que usted apruebe, puede acceder a la información de su perfil público, su lista de seguimiento, sus seguidores, sus listas, todos sus mensajes y sus favoritos. Las aplicaciones nunca podrán acceder a su dirección de correo electrónico o contraseña.
+
+
+
+
Uso del sitio por parte de los niños
+
+
Si este servidor está en la UE o en el EEE: Nuestro sitio, productos y servicios están dirigidos a personas mayores de 16 años. Si es menor de 16 años, según los requisitos de la GDPR (General Data Protection Regulation) no utilice este sitio.
+
+
Si este servidor está en los EE.UU.: Nuestro sitio, productos y servicios están todos dirigidos a personas que tienen al menos 13 años de edad. Si usted es menor de 13 años, según los requisitos de COPPA (Children's Online Privacy Protection Act) no utilice este sitio.
+
+
Los requisitos legales pueden ser diferentes si este servidor está en otra jurisdicción.
+
+
+
+
Cambios en nuestra Política de Privacidad
+
+
Si decidimos cambiar nuestra política de privacidad, publicaremos esos cambios en esta página.
+
+
Este documento es CC-BY-SA. Fue actualizado por última vez el 7 de marzo de 2018.
title: Términos del Servicio y Políticas de Privacidad de %{instance}
themes:
contrast: Alto contraste
@@ -810,6 +1005,7 @@ es:
time:
formats:
default: "%d de %b del %Y, %H:%M"
+ month: "%b %Y"
two_factor_authentication:
code_hint: Ingresa el código generado por tu aplicación de autenticación para confirmar
description_html: Si habilitas la autenticación de dos factores, se requerirá estar en posesión de su teléfono, lo que generará tokens para que usted pueda iniciar sesión.
@@ -831,6 +1027,22 @@ es:
explanation: Has solicitado una copia completa de tu cuenta de Mastodon. ¡Ya está preparada para descargar!
subject: Tu archivo está preparado para descargar
title: Descargar archivo
+ warning:
+ explanation:
+ disable: Mientras su cuenta esté congelada, la información de su cuenta permanecerá intacta, pero no puede realizar ninguna acción hasta que se desbloquee.
+ silence: Mientras su cuenta está limitada, sólo las personas que ya le están siguiendo verán sus toots en este servidor, y puede que se le excluya de varios listados públicos. Sin embargo, otros pueden seguirle manualmente.
+ suspend: Su cuenta ha sido suspendida, y todos tus toots y tus archivos multimedia subidos han sido irreversiblemente eliminados de este servidor, y de los servidores donde tenías seguidores.
+ review_server_policies: Revisar las políticas del servidor
+ subject:
+ disable: Su cuenta %{acct} ha sido congelada
+ none: Advertencia para %{acct}
+ silence: Su cuenta %{acct} ha sido limitada
+ suspend: Su cuenta %{acct} ha sido suspendida
+ title:
+ disable: Cuenta congelada
+ none: Advertencia
+ silence: Cuenta limitada
+ suspend: Cuenta suspendida
welcome:
edit_profile_action: Configurar el perfil
edit_profile_step: Puedes personalizar tu perfil subiendo un avatar, una cabecera, cambiando tu nombre de usuario y más cosas. Si quieres revisar a tus nuevos seguidores antes de que se les permita seguirte, puedes bloquear tu cuenta.
@@ -846,6 +1058,7 @@ es:
tip_following: Sigues a tus administradores de servidor por defecto. Para encontrar más gente interesante, revisa las lineas de tiempo local y federada.
tip_local_timeline: La linea de tiempo local is una vista de la gente en %{instance}. Estos son tus vecinos inmediatos!
tip_mobile_webapp: Si el navegador de tu dispositivo móvil ofrece agregar Mastodon a tu página de inicio, puedes recibir notificaciones. Actúa como una aplicación nativa en muchas formas!
+ tips: Consejos
title: Te damos la bienvenida a bordo, %{name}!
users:
follow_limit_reached: No puedes seguir a más de %{limit} personas
diff --git a/config/locales/eu.yml b/config/locales/eu.yml
index 9b9c2c0271..d3299d7756 100644
--- a/config/locales/eu.yml
+++ b/config/locales/eu.yml
@@ -61,8 +61,8 @@ eu:
posts:
one: Toot
other: Toot
- posts_tab_heading: Toot
- posts_with_replies: Toot eta erantzunak
+ posts_tab_heading: Toot-ak
+ posts_with_replies: Toot-ak eta erantzunak
reserved_username: Erabiltzaile-izena erreserbatuta dago
roles:
admin: Administratzailea
@@ -431,7 +431,7 @@ eu:
open: Edonork eman dezake izena
title: Erregistratzeko modua
show_known_fediverse_at_about_page:
- desc_html: Txandakatzean, fedibertsu ezagun osoko toot-ak bistaratuko ditu aurrebistan. Bestela, toot lokalak besterik ez ditu erakutsiko.
+ desc_html: Txandakatzean, fedibertso ezagun osoko toot-ak bistaratuko ditu aurrebistan. Bestela, toot lokalak besterik ez ditu erakutsiko.
title: Erakutsi fedibertsu ezagun osoko denbora-lerroa aurrebistan
show_staff_badge:
desc_html: Erakutsi langile banda erabiltzailearen orrian
@@ -469,13 +469,6 @@ eu:
no_status_selected: Ez da mezurik aldatu ez delako mezurik aukeratu
title: Kontuaren mezuak
with_media: Multimediarekin
- subscriptions:
- callback_url: Itzulera URL-a
- confirmed: Berretsita
- expires_in: Iraungitzea
- last_delivery: Azken bidalketa
- title: WebSub
- topic: Mintzagaia
tags:
accounts: Kontuak
hidden: Ezkutatuta
@@ -783,7 +776,7 @@ eu:
too_few_options: elementu bat baino gehiago izan behar du
too_many_options: ezin ditu %{max} elementu baino gehiago izan
preferences:
- other: Beste bat
+ other: Denetarik
posting_defaults: Bidalketarako lehenetsitakoak
public_timelines: Denbora-lerro publikoak
relationships:
@@ -816,10 +809,6 @@ eu:
reply:
proceed: Ekin erantzuteari
prompt: 'Toot honi erantzun nahi diozu:'
- remote_unfollow:
- error: Errorea
- title: Izenburua
- unfollowed: Jarraitzeari utzita
scheduled_statuses:
over_daily_limit: Egun horretarako programatutako toot kopuruaren muga gainditu duzu (%{limit})
over_total_limit: Programatutako toot kopuruaren muga gainditu duzu (%{limit})
diff --git a/config/locales/fa.yml b/config/locales/fa.yml
index d37dbdeb49..f6b6c87583 100644
--- a/config/locales/fa.yml
+++ b/config/locales/fa.yml
@@ -469,13 +469,6 @@ fa:
no_status_selected: هیچ بوقی تغییری نکرد زیرا هیچکدام از آنها انتخاب نشده بودند
title: نوشتههای حساب
with_media: دارای عکس یا ویدیو
- subscriptions:
- callback_url: نشانی Callback
- confirmed: تأییدشده
- expires_in: مهلت انقضا
- last_delivery: آخرین ارسال
- title: WebSub
- topic: موضوع
tags:
accounts: حسابها
hidden: پنهانشده
@@ -816,10 +809,6 @@ fa:
reply:
proceed: به سمت پاسخدادن
prompt: 'شما میخواهید به این بوق پاسخ دهید:'
- remote_unfollow:
- error: خطا
- title: عنوان
- unfollowed: پایان پیگیری
scheduled_statuses:
over_daily_limit: شما از حد مجاز %{limit} بوق زمانبندیشده در آن روز فراتر رفتهاید
over_total_limit: شما از حد مجاز %{limit} بوق زمانبندیشده فراتر رفتهاید
diff --git a/config/locales/fi.yml b/config/locales/fi.yml
index e0dc0f756e..07a8e367b2 100644
--- a/config/locales/fi.yml
+++ b/config/locales/fi.yml
@@ -330,12 +330,6 @@ fi:
no_media: Ei mediaa
title: Tilin tilat
with_media: Sisältää mediaa
- subscriptions:
- callback_url: Paluu-URL
- confirmed: Vahvistettu
- expires_in: Vanhenee
- last_delivery: Viimeisin toimitus
- topic: Aihe
title: Ylläpito
admin_mailer:
new_report:
@@ -536,8 +530,6 @@ fi:
missing_resource: Vaadittavaa uudelleenohjaus-URL:ää tiliisi ei löytynyt
proceed: Siirry seuraamaan
prompt: 'Olet aikeissa seurata:'
- remote_unfollow:
- error: Virhe
sessions:
activity: Viimeisin toiminta
browser: Selain
diff --git a/config/locales/fr.yml b/config/locales/fr.yml
index 5c15ab6a42..b3ee1d3bde 100644
--- a/config/locales/fr.yml
+++ b/config/locales/fr.yml
@@ -469,13 +469,6 @@ fr:
no_status_selected: Aucun statut n’a été modifié car aucun n’a été sélectionné
title: État du compte
with_media: avec médias
- subscriptions:
- callback_url: URL de rappel
- confirmed: Confirmé
- expires_in: Expire dans
- last_delivery: Dernière livraison
- title: WebSub
- topic: Sujet
tags:
accounts: Comptes
hidden: Masqué
@@ -816,10 +809,6 @@ fr:
reply:
proceed: Confirmer la réponse
prompt: 'Vous souhaitez répondre à ce pouet :'
- remote_unfollow:
- error: Erreur
- title: Titre
- unfollowed: Non-suivi
scheduled_statuses:
over_daily_limit: Vous avez dépassé la limite de %{limit} pouets planifiés pour ce jour
over_total_limit: Vous avez dépassé la limite de %{limit} pouets planifiés
diff --git a/config/locales/gl.yml b/config/locales/gl.yml
index 79ef993e2e..7ecb50e408 100644
--- a/config/locales/gl.yml
+++ b/config/locales/gl.yml
@@ -469,13 +469,6 @@ gl:
no_status_selected: Non se cambiou ningún estado xa que ningún foi seleccionado
title: Estados da conta
with_media: con medios
- subscriptions:
- callback_url: URL de chamada
- confirmed: Confirmado
- expires_in: Caduca en
- last_delivery: Última entrega
- title: WebSub
- topic: Asunto
tags:
accounts: Contas
hidden: Ocultas
@@ -816,10 +809,6 @@ gl:
reply:
proceed: Respostar
prompt: 'Vostede quere respostar a este toot:'
- remote_unfollow:
- error: Fallo
- title: Título
- unfollowed: Deixou de seguir
scheduled_statuses:
over_daily_limit: Excedeu o límite de %{limit} toots programados para ese día
over_total_limit: Excedeu o límite de %{limit} toots programados
diff --git a/config/locales/he.yml b/config/locales/he.yml
index 5e50f738df..12953c2234 100644
--- a/config/locales/he.yml
+++ b/config/locales/he.yml
@@ -177,13 +177,6 @@ he:
title: תיאור אתר מורחב
site_title: כותרת האתר
title: הגדרות אתר
- subscriptions:
- callback_url: קישורית Callback
- confirmed: מאושר
- expires_in: פג תוקף ב-
- last_delivery: משלוח אחרון
- title: מנוי WebSub
- topic: נושא
title: ניהול
application_mailer:
settings: 'שינוי הגדרות דוא"ל: %{link}'
diff --git a/config/locales/hu.yml b/config/locales/hu.yml
index d771b96832..948f0db13c 100644
--- a/config/locales/hu.yml
+++ b/config/locales/hu.yml
@@ -10,7 +10,7 @@ hu:
api: API
apps: Mobil appok
apps_platforms: Használd a Mastodont iOS-ről, Androidról vagy más platformról
- browse_directory: Böngészd a profil adatbázist és szűrj érdeklődési kör szerint
+ browse_directory: Böngészd a profilokat és szűrj érdeklődési körre
browse_public_posts: Nézz bele a Mastodon élő adatfolyamába
contact: Kapcsolat
contact_missing: Nincs megadva
@@ -469,13 +469,6 @@ hu:
no_status_selected: Nem változtattunk meg semmit, mert semmi sem volt kiválasztva
title: Felhasználó tülkjei
with_media: Médiafájlokkal
- subscriptions:
- callback_url: Callback URL
- confirmed: Megerősítve
- expires_in: Elévül
- last_delivery: Utolsó kézbesítés
- title: WebSub
- topic: Téma
tags:
accounts: Fiókok
hidden: Rejtett
@@ -816,10 +809,6 @@ hu:
reply:
proceed: Válaszadás
prompt: 'Erre a tülkre szeretnél válaszolni:'
- remote_unfollow:
- error: Hiba
- title: Cím
- unfollowed: Nem követett
scheduled_statuses:
over_daily_limit: Túllépted az időzített tülkökre vonatkozó napi limitet (%{limit})
over_total_limit: Túllépted az időzített tülkökre vonatkozó limitet (%{limit})
@@ -924,7 +913,7 @@ hu:
unlisted_long: Mindenki látja, de a nyilvános idővonalakon nem jelenik meg
stream_entries:
pinned: Kitűzött tülk
- reblogged: megtolt
+ reblogged: megtolta
sensitive_content: Szenzitív tartalom
terms:
body_html: |
@@ -932,17 +921,17 @@ hu:
Milyen adatokat gyűjtünk?
-
Alapvető fiókadatok: Ha regisztrálsz ezen a szerveren, kérhetünk tőled felhasználói nevet, e-mail címet és jelszót is. Megadhatsz magadról egyéb profil információt, mint megjelenítendő név, bemutatkozás, feltölthetsz profilképet, háttérképet. A felhasználói neved, megjelenítendő neved, bemutatkozásod, profil képed és háttér képed mindig nyilvánosak mindenki számára.
-
Tülkök (posztok), követések, más nyilvános adatok: Az általad követett emberek listája nyilvános. Ugyanez igaz a te követőidre is. Ha küldesz egy üzenetet, ennek az idejét eltároljuk azzal az alkalmazással együtt, melyből az üzenetet küldted. Az üzenetek tartalmazhatnak média csatolmányt, képeket, videókat. A nyilvános tülkök (posztok) bárki számára elérhetőek. Ha egy tülköt kiemelsz a profilodon, az is nyilvánossá válik. Amikor a tülkjeidet a követőidnek továbbítjuk, a poszt más szerverekre is kerülhet, melyeken így másolatok képződhetnek. Ha törölsz tülköket, ez is továbbítódik a követőid felé. A megtolás (reblog) és kedvencnek jelölés művelete is mindig nyilvános.
-
Közvetlen üzenetek és csak követőknek szánt tülkök: Minden tülk a szerveren tárolódik. A csak követőknek szánt tülköket a követőidnek és az ezekben megemlítetteknek továbbítjuk, míg a közvetlen üzeneteket kizárólag az ebben megemlítettek kapják. Néhány esetben ez azt jelenti, hogy ezek más szerverekre is továbbítódnak, így ott másolatok keletkezhetnek. Jóhiszeműen feltételezzük, hogy más szerverek is hasonlóan járnak el, mikor ezeket az üzeneteket csak az arra jogosultaknak mutatják meg. Ugyanakkor ez nem feltétlenül igaz. Ezért érdemes megnézni azokat a szervereket, melyeken követőid vannak. Be tudod állítani, hogy minden követési kérelmet jóvá kelljen hagynod. Tartsd észben, hogy a szerver üzemeltetői láthatják az üzeneteket, illetve a fogadók képernyőképet, másolatot készíthetnek belőlük, vagy újraoszthatják őket.Ne ossz meg veszélyes információt a Mastodon hálózaton!
-
IP címek és egyéb metaadatok: Bejelentkezéskor letároljuk a használt böngésződet és IP címedet. Mindent rögzített munkamenet elérhető és visszavonható a beállítások között. A legutolsó IP címet maximum 12 hónapig tárolunk. Egyéb szerver logokat is megtarthatunk, melyek HTTP kérésenként is tárolhatják az IP címedet.
+
Alapvető fiókadatok: Ha regisztrálsz ezen a szerveren, kérhetünk tőled felhasználói nevet, e-mail címet és jelszót is. Megadhatsz magadról egyéb profil információt, megjelenítendő nevet, bemutatkozást, feltölthetsz profilképet, háttérképet. A felhasználói neved, megjelenítendő neved, bemutatkozásod, profil képed és háttér képed mindig nyilvánosak mindenki számára.
+
Tülkök (posztok), követések, más nyilvános adatok: Az általad követett emberek listája nyilvános. Ugyanez igaz a te követőidre is. Ha küldesz egy üzenetet, ennek az idejét eltároljuk azzal az alkalmazással együtt, melyből az üzenetet küldted. Az üzenetek tartalmazhatnak média csatolmányt, képeket, videókat. A nyilvános tülkök (posztok) bárki számára elérhetőek. Ha egy tülköt kiemelsz a profilodon, az is nyilvánossá válik. Amikor a tülkjeidet a követőidnek továbbítjuk, a poszt más szerverekre is átkerülhet, melyeken így másolatok képződhetnek. Ha törölsz tülköket, ez is továbbítódik a követőid felé. A megtolás (reblog) és kedvencnek jelölés művelete is mindig nyilvános.
+
Közvetlen üzenetek és csak követőknek szánt tülkök: Minden tülk a szerveren tárolódik. A csak követőknek szánt tülköket a követőidnek és az ezekben megemlítetteknek továbbítjuk, míg a közvetlen üzeneteket kizárólag az ebben megemlítettek kapják. Néhány esetben ez azt jelenti, hogy ezek más szerverekre is továbbítódnak, így ott másolatok keletkezhetnek. Jóhiszeműen feltételezzük, hogy más szerverek is hasonlóan járnak el, mikor ezeket az üzeneteket csak az arra jogosultaknak mutatják meg. Ugyanakkor ez nem feltétlenül igaz. Érdemes ezért megvizsgálni azokat a szervereket, melyeken követőid vannak. Be tudod állítani, hogy minden követési kérelmet jóvá kelljen hagynod. Tartsd észben, hogy a szerver üzemeltetői láthatják az üzeneteket, illetve a fogadók képernyőképet, másolatot készíthetnek belőlük, vagy újraoszthatják őket. Ne ossz meg veszélyes információt a Mastodon hálózaton!
+
IP címek és egyéb metaadatok: Bejelentkezéskor letároljuk a használt böngésződet és IP címedet. Minden rögzített munkamenet elérhető és visszavonható a beállítások között. Az utoljára rögzített IP címet maximum 12 hónapig tároljuk. Egyéb szerver logokat is megtarthatunk, melyek HTTP kérésenként is tárolhatják az IP címedet.
Mire használjuk az adataidat?
-
Bármely tőled begyűjtött adatot a következő célokra használhatjuk:
+
Bármely tőled begyűjtött adatot a következő célokra használhatjuk fel:
Mastodon alapfunkcióinak biztosítása: Csak akkor léphetsz kapcsolatba másokkal, ha be vagy jelentkezve. Pl. követhetsz másokat a saját, személyre szabott idővonaladon.
@@ -960,14 +949,14 @@ hu:
Mik az adatmegőrzési szabályaink?
-
Jóhiszeműen járunk el, hogy:
+
Mindent megteszünk, hogy:
-
A szerver logokat, melyek kérésenként tartalmazzák a felhasználó IP címét maximum 90 napig tartjuk meg.
-
A regisztrált felhasználók IP címeikkel összekötő adatokat maximum 12 hónapig tartjuk meg.
+
A szerver logokat, melyek kérésenként tartalmazzák a felhasználó IP címét maximum 90 napig tartsuk meg.
+
A regisztrált felhasználókat IP címeikkel összekötő adatokat maximum 12 hónapig tartsuk meg.
-
Kérhetsz archívot minden tárolt adatodról, tülkjeidről, média fájljaidról, profil- és háttér képedről.
+
Kérhetsz mentést minden tárolt adatodról, tülködről, média fájlodról, profil- és háttér képedről.
Bármikor visszaállíthatatlanul le is törölheted a fiókodat.
@@ -983,7 +972,7 @@ hu:
Átadunk bármilyen adatot harmadik személynek?
-
Az azonosításodra alkalmazható adatokat nem adjuk el, nem kereskedünk vele, nem adjuk át külső szereplőnek. Ez nem foglalja magába azon harmadik személyeket, aki az üzemeltetésben, felhasználók kiszolgálásban és a tevékenységünkben segítenek, de csak addig, amíg ők is elfogadják, hogy ezeket az adatokat bizalmasan kezelik. Akkor is átadhatjuk ezeket az adatokat, ha erre hitünk szerint törvény kötelez minket, ha betartatjuk az oldalunk szabályzatát vagy megvédjük a saját vagy mások személyiségi jogait, tulajdonát, biztonságát.
+
Az azonosításodra alkalmazható adatokat nem adjuk el, nem kereskedünk vele, nem adjuk át külső szereplőnek. Ez nem foglalja magában azon harmadik személyeket, aki az üzemeltetésben, felhasználók kiszolgálásban és a tevékenységünkben segítenek, de csak addig, amíg ők is elfogadják, hogy ezeket az adatokat bizalmasan kezelik. Akkor is átadhatjuk ezeket az adatokat, ha erre hitünk szerint törvény kötelez minket, ha betartatjuk az oldalunk szabályzatát vagy megvédjük a saját vagy mások személyiségi jogait, tulajdonát, biztonságát.
A nyilvános tartalmaidat más hálózatban lévő szerverek letölthetik. A nyilvános és csak követőknek szánt tülkjeid olyan szerverekre is elküldődnek, melyeken követőid vannak. A közvetlen üzenetek is átkerülnek a címzettek szervereire, ha ők más szerveren regisztráltak.
@@ -993,9 +982,9 @@ hu:
Az oldal gyerekek általi használata
-
Ha ez a szerver az EU-ban vagy EEA-ban van: Az oldalunk, szolgáltatásaink és termékeink mind 16 éven felülieket céloznak. Ha 16 évnél fiatalabb vagy, a GDPR (General Data Protection Regulation) értelmében kérlek ne használd ezt az oldalt!
+
Ha ez a szerver az EU-ban vagy EEA-ban található: Az oldalunk, szolgáltatásaink és termékeink mind 16 éven felülieket céloznak. Ha 16 évnél fiatalabb vagy, a GDPR (General Data Protection Regulation) értelmében kérlek ne használd ezt az oldalt!
-
Ha ez a szerver az USA-ban van: Az oldalunk, szolgáltatásaink és termékeink mind 13 éven felülieket céloznak. Ha 13 évnél fiatalabb vagy, a COPPA (Children's Online Privacy Protection Act) értelmében kérlek ne használd ezt az oldalt!
+
Ha ez a szerver az USA-ban található: Az oldalunk, szolgáltatásaink és termékeink mind 13 éven felülieket céloznak. Ha 13 évnél fiatalabb vagy, a COPPA (Children's Online Privacy Protection Act) értelmében kérlek ne használd ezt az oldalt!
A jogi előírások különbözhetnek ettől a világ egyéb tájain.
diff --git a/config/locales/id.yml b/config/locales/id.yml
index 43721b19b9..16098b1890 100644
--- a/config/locales/id.yml
+++ b/config/locales/id.yml
@@ -191,11 +191,6 @@ id:
title: Deskripsi situs tambahan
site_title: Judul Situs
title: Pengaturan situs
- subscriptions:
- confirmed: Dikonfirmasi
- expires_in: Kadaluarsa dalam
- last_delivery: Terakhir dikirim
- topic: Topik
title: Administrasi
application_mailer:
settings: 'Ubah pilihan email: %{link}'
diff --git a/config/locales/it.yml b/config/locales/it.yml
index 6dfe212d14..1df321752a 100644
--- a/config/locales/it.yml
+++ b/config/locales/it.yml
@@ -469,13 +469,6 @@ it:
no_status_selected: Nessun status è stato modificato perché nessuno era stato selezionato
title: Gli status dell'account
with_media: con media
- subscriptions:
- callback_url: URL Callback
- confirmed: Confermato
- expires_in: Scade in
- last_delivery: Ultima distribuzione
- title: WebSub
- topic: Argomento
tags:
accounts: Account
hidden: Nascosto
@@ -818,10 +811,6 @@ it:
reply:
proceed: Continua per rispondere
prompt: 'Vuoi rispondere a questo toot:'
- remote_unfollow:
- error: Errore
- title: Titolo
- unfollowed: Non più seguito
scheduled_statuses:
over_daily_limit: Hai superato il limite di %{limit} toot programmati per questo giorno
over_total_limit: Hai superato il limite di %{limit} toot programmati
@@ -885,7 +874,7 @@ it:
notifications: Notifiche
preferences: Preferenze
profile: Profilo
- relationships: Follows and followers
+ relationships: Follows e followers
two_factor_authentication: Autenticazione a due fattori
statuses:
attached:
diff --git a/config/locales/ja.yml b/config/locales/ja.yml
index d989d7d1de..d70bc0365f 100644
--- a/config/locales/ja.yml
+++ b/config/locales/ja.yml
@@ -463,13 +463,6 @@ ja:
no_status_selected: 何も選択されていないため、変更されていません
title: トゥート一覧
with_media: メディアあり
- subscriptions:
- callback_url: コールバックURL
- confirmed: 確認済み
- expires_in: 期限
- last_delivery: 最終配送
- title: WebSub
- topic: トピック
tags:
accounts: アカウント
hidden: 非表示
@@ -806,10 +799,6 @@ ja:
reply:
proceed: 返信する
prompt: '返信しようとしています:'
- remote_unfollow:
- error: エラー
- title: タイトル
- unfollowed: フォロー解除しました
scheduled_statuses:
over_daily_limit: その日予約できる投稿数 %{limit} を超えています
over_total_limit: 予約できる投稿数 %{limit} を超えています
diff --git a/config/locales/ka.yml b/config/locales/ka.yml
index 53057d8603..57dd0f5c02 100644
--- a/config/locales/ka.yml
+++ b/config/locales/ka.yml
@@ -368,13 +368,6 @@ ka:
no_status_selected: სატუსები არ შეცვლილა, რადგან არცერთი არ მონიშნულა
title: ანგარიშის სტატუსები
with_media: მედიით
- subscriptions:
- callback_url: ქოლბექ ურლ
- confirmed: დამოწმდა
- expires_in: ვადა გასდის
- last_delivery: ბოლო მიღება
- title: ვებ-საბი
- topic: სათაური
title: ადმინისტრაცია
admin_mailer:
new_report:
@@ -601,10 +594,6 @@ ka:
no_account_html: არ გაქვთ ანგარიში? შეგიძლიათ დარეგისტრირდეთ აქ
proceed: გააგრძელეთ გასაყოლად
prompt: 'თქვენ გაჰყვებით:'
- remote_unfollow:
- error: შეცდომა
- title: სათაური
- unfollowed: დადევნების შეწყვეტა
sessions:
activity: ბოლო აქტივობა
browser: ბრაუზერი
diff --git a/config/locales/kk.yml b/config/locales/kk.yml
index c6212c378f..a3651b1d30 100644
--- a/config/locales/kk.yml
+++ b/config/locales/kk.yml
@@ -436,13 +436,6 @@ kk:
no_status_selected: Бірде-бір статус өзгерген жоқ, себебі ештеңе таңдалмады
title: Аккаунт статустары
with_media: Медиамен
- subscriptions:
- callback_url: Callbаck URL
- confirmed: Confirmеd
- expires_in: Expirеs in
- last_delivery: Last dеlivery
- title: WеbSub
- topic: Tоpic
tags:
accounts: Accоunts
hidden: Hiddеn
@@ -726,10 +719,6 @@ kk:
reply:
proceed: Жауап жазу
prompt: 'Сіз мына жазбаға жауап жазасыз:'
- remote_unfollow:
- error: Қате
- title: Тақырыбы
- unfollowed: Жазылудан бас тартылды
scheduled_statuses:
over_daily_limit: Сіз бір күндік %{limit} жазба лимитін тауыстыңыз
over_total_limit: Сіз %{limit} жазба лимитін тауыстыңыз
diff --git a/config/locales/ko.yml b/config/locales/ko.yml
index 3f14d5df64..ec64972ed7 100644
--- a/config/locales/ko.yml
+++ b/config/locales/ko.yml
@@ -465,13 +465,6 @@ ko:
no_status_selected: 아무 것도 선택 되지 않아 아무 것도 바뀌지 않았습니다
title: 계정 툿
with_media: 미디어 있음
- subscriptions:
- callback_url: 콜백 URL
- confirmed: 확인됨
- expires_in: 기한
- last_delivery: 최종 발송
- title: WebSub
- topic: 토픽
tags:
accounts: 계정들
hidden: 숨겨짐
@@ -807,10 +800,6 @@ ko:
reply:
proceed: 답장 진행
prompt: '이 툿에 답장을 하려 합니다:'
- remote_unfollow:
- error: 에러
- title: 타이틀
- unfollowed: 언팔로우됨
scheduled_statuses:
over_daily_limit: 그 날짜에 대한 %{limit}개의 예약 툿 제한을 초과합니다
over_total_limit: 예약 툿 제한 %{limit}을 초과합니다
diff --git a/config/locales/lt.yml b/config/locales/lt.yml
index 2cf0b7c42b..087cbb582c 100644
--- a/config/locales/lt.yml
+++ b/config/locales/lt.yml
@@ -419,13 +419,6 @@ lt:
no_status_selected: Jokie statusai nebuvo pakeisti, nes niekas nepasirinkta
title: Paskyros statusai
with_media: Su medija
- subscriptions:
- callback_url: Atgalinė URL
- confirmed: Patvirtinta
- expires_in: Pasibaigia
- last_delivery: Paskutinis pristatymas
- title: WebSub protokolas
- topic: Tema
tags:
accounts: Paskyros
hidden: Paslėpti
@@ -672,10 +665,6 @@ lt:
reply:
proceed: Atsakyti
prompt: 'Jūs norite atsakyti šiam toot''ui:'
- remote_unfollow:
- error: Klaida
- title: Pavadinimas
- unfollowed: Nebesekama
scheduled_statuses:
over_daily_limit: Jūs pasieketė limitą (%{limit}) galimų toot'ų per dieną
over_total_limit: Jūs pasieketė %{limit} limitą galimų toot'ų
diff --git a/config/locales/nl.yml b/config/locales/nl.yml
index 78be7872d8..52c23de8f3 100644
--- a/config/locales/nl.yml
+++ b/config/locales/nl.yml
@@ -469,13 +469,6 @@ nl:
no_status_selected: Er werden geen toots gewijzigd, omdat er geen enkele werd geselecteerd
title: Toots van account
with_media: Met media
- subscriptions:
- callback_url: Callback-URL
- confirmed: Bevestigd
- expires_in: Verloopt over
- last_delivery: Laatste bezorging
- title: WebSub
- topic: Account
tags:
accounts: Accounts
hidden: Verborgen
@@ -816,10 +809,6 @@ nl:
reply:
proceed: Doorgaan met reageren
prompt: 'Je wilt op de volgende toot reageren:'
- remote_unfollow:
- error: Fout
- title: Titel
- unfollowed: Ontvolgd
scheduled_statuses:
over_daily_limit: Je hebt de limiet van %{limit} in te plannen toots voor die dag overschreden
over_total_limit: Je hebt de limiet van %{limit} in te plannen toots overschreden
diff --git a/config/locales/no.yml b/config/locales/no.yml
index d21dda6fba..fbf1383937 100644
--- a/config/locales/no.yml
+++ b/config/locales/no.yml
@@ -267,12 +267,6 @@
no_media: Ingen media
title: Kontostatuser
with_media: Med media
- subscriptions:
- callback_url: Callback-URL
- confirmed: Bekreftet
- expires_in: Utløper om
- last_delivery: Siste levering
- topic: Emne
title: Administrasjon
admin_mailer:
new_report:
diff --git a/config/locales/oc.yml b/config/locales/oc.yml
index 785caa4ecc..067c343b81 100644
--- a/config/locales/oc.yml
+++ b/config/locales/oc.yml
@@ -7,6 +7,7 @@ oc:
active_count_after: actius
active_footnote: Utilizaire actius per mes (UAM)
administered_by: 'Administrat per :'
+ api: API
apps: Aplicacions per mobil
apps_platforms: Utilizatz Mastodon d‘iOS, Android o d’autras plataforma estant
browse_directory: Navigatz per l’annuari de perfil e filtratz segon çò qu’aimatz
@@ -19,6 +20,7 @@ oc:
extended_description_html: |
Una bona plaça per las règlas
La descripcion longa es pas estada causida pel moment.
+ federation_hint_html: Amb un compte sus %{instance} poiretz sègre de personas de qualque siasque servidor Mastodon e encara mai.
generic_description: "%{domain} es un dels servidors del malhum"
get_apps: Ensajatz una aplicacion mobil
hosted_on: Mastodon albergat sus %{domain}
@@ -31,6 +33,7 @@ oc:
one: estatut
other: estatuts
status_count_before: qu’an escrich
+ tagline: Seguètz d’amics e trobatz-ne de nòus
terms: Condicions d’utilizacion
user_count_after:
one: utilizaire
@@ -62,8 +65,10 @@ oc:
posts_with_replies: Tuts e responsas
reserved_username: Aqueste nom d’utilizaire es reservat
roles:
+ admin: Admin
bot: Robòt
moderator: Moderador
+ unavailable: Perfil indisponible
unfollow: Quitar de sègre
admin:
account_actions:
@@ -76,7 +81,9 @@ oc:
destroyed_msg: Nòta de moderacion ben suprimida !
accounts:
approve: Aprovar
+ approve_all: O validar tot
are_you_sure: Sètz segur ?
+ avatar: Avatar
by_domain: Domeni
change_email:
changed_msg: Adreça corrèctament cambiada !
@@ -107,6 +114,7 @@ oc:
header: Bandièra
inbox_url: URL de recepcion
invited_by: Convidat per
+ ip: IP
joined: Venguèt
location:
all: Totes
@@ -126,6 +134,7 @@ oc:
moderation_notes: Nòtas de moderacion
most_recent_activity: Activitat mai recenta
most_recent_ip: IP mai recenta
+ no_account_selected: Cap de compte pas cambiat estant que cap èra pas seleccionat
no_limits_imposed: Cap de limit impausat
not_subscribed: Pas seguidor
outbox_url: URL Outbox
@@ -134,8 +143,11 @@ oc:
profile_url: URL del perfil
promote: Promòure
protocol: Protocòl
+ public: Public
push_subscription_expires: Fin de l’abonament PuSH
redownload: Actualizar lo perfil
+ reject: Regetar
+ reject_all: O regetar tot
remove_avatar: Supriir l’avatar
remove_header: Levar la bandièra
resend_confirmation:
@@ -145,7 +157,9 @@ oc:
reset: Reïnicializar
reset_password: Reïnicializar lo senhal
resubscribe: Se tornar abonar
+ role: Autorizacions
roles:
+ admin: Administrator
moderator: Moderador
staff: Personnal
user: Uitlizaire
@@ -160,6 +174,7 @@ oc:
statuses: Estatuts
subscribe: S’abonar
suspended: Suspendut
+ time_in_queue: En espèra a la fila %{time}
title: Comptes
unconfirmed_email: Adreça pas confirmada
undo_silenced: Levar lo silenci
@@ -167,6 +182,7 @@ oc:
unsubscribe: Se desabonar
username: Nom d’utilizaire
warn: Avisar
+ web: Web
action_logs:
actions:
assigned_to_self_report: "%{name} s’assignèt lo rapòrt %{target}"
@@ -211,6 +227,7 @@ oc:
destroyed_msg: Emoji ben suprimit !
disable: Desactivar
disabled_msg: Aqueste emoji es ben desactivat
+ emoji: Emoji
enable: Activar
enabled_msg: Aqueste emoji es ben activat
image_hint: PNG cap a 50Ko
@@ -233,6 +250,7 @@ oc:
feature_profile_directory: Annuari de perfils
feature_registrations: Inscripcions
feature_relay: Relai de federacion
+ feature_timeline_preview: Apercebut del flux d’actualitats
features: Foncionalitats
hidden_service: Federacion amb servicis amagats
open_reports: Senhalaments dobèrts
@@ -252,6 +270,7 @@ oc:
created_msg: Domeni blocat es a èsser tractat
destroyed_msg: Lo blocatge del domeni es estat levat
domain: Domeni
+ existing_domain_block_html: Impausèretz ja de limitas mai estrictas per %{name}, vos cal lo desblocard’en primièr.
new:
create: Crear blocatge
hint: Lo blocatge empacharà pas la creacion de compte dins la basa de donadas, mai aplicarà la moderacion sus aquestes comptes.
@@ -317,6 +336,8 @@ oc:
expired: Expirats
title: Filtre
title: Convits
+ pending_accounts:
+ title: Comptes en espèra (%{count})
relays:
add_new: Ajustar un nòu relai
delete: Suprimir
@@ -405,7 +426,9 @@ oc:
title: Autorizat amb invitacions
registrations_mode:
modes:
+ approved: Validacion necessària per s’inscriure
none: Degun pòt pas se marcar
+ open: Tot lo monde se pòt marcar
title: Mòdes d’inscripcion
show_known_fediverse_at_about_page:
desc_html: Un còp activat mostrarà los tuts de totes los fediverse dins l’apercebut. Autrament mostrarà pas que los tuts locals.
@@ -446,12 +469,6 @@ oc:
no_status_selected: Cap d’estatut pas cambiat estant que cap èra pas seleccionat
title: Estatuts del compte
with_media: Amb mèdia
- subscriptions:
- callback_url: URL de rapèl
- confirmed: Confirmat
- expires_in: S’acaba dins
- last_delivery: Darrièra distribucion
- topic: Subjècte
tags:
accounts: Comptes
hidden: Amagat
@@ -459,6 +476,7 @@ oc:
name: Etiqueta
title: Etiquetas
unhide: Aparéisser dins l’annuari
+ visible: Visible
title: Administracion
warning_presets:
add_new: N’ajustar un nòu
@@ -467,12 +485,22 @@ oc:
edit_preset: Modificar lo tèxt predefinit d’avertiment
title: Gerir los tèxtes predefinits
admin_mailer:
+ new_pending_account:
+ body: Los detalhs del nòu compte son çai-jos. Podètz validar o regetar aquesta demanda.
+ subject: Nòu compte per repassar sus %{instance} (%{username})
new_report:
body: "%{reporter} a senhalat %{target}"
body_remote: Qualqu’un de %{domain} senhalèt %{target}
subject: Novèl senhalament per %{instance} (#%{id})
+ appearance:
+ advanced_web_interface: Interfàcia web avançada
+ advanced_web_interface_hint: 'Se volètz utilizar la nautor complèta de l’ecran, l’interfàcia web avançada vos permet de configurar diferentas colomnas per mostrar tan d’informacions que volètz : Acuèlh, notificacions, flux d’actualitat, e d’autras listas e etiquetas.'
+ animations_and_accessibility: Animacion e accessibilitat
+ confirmation_dialogs: Fenèstras de confirmacion
+ sensitive_content: Contengut sensible
application_mailer:
notification_preferences: Cambiar las preferéncias de corrièl
+ salutation: "%{name},"
settings: 'Cambiar las preferéncias de corrièl : %{link}'
view: 'Veire :'
view_profile: Veire lo perfil
@@ -500,6 +528,9 @@ oc:
migrate_account: Mudar endacòm mai
migrate_account_html: Se volètz mandar los visitors d’aqueste compte a un autre, podètz o configurar aquí.
or_log_in_with: O autentificatz-vos amb
+ providers:
+ cas: CAS
+ saml: SAML
register: Se marcar
registration_closed: "%{instance} accepta pas de nòus membres"
resend_confirmation: Tornar mandar las instruccions de confirmacion
@@ -531,6 +562,7 @@ oc:
x_days: "%{count} jorns"
x_minutes: "%{count} min"
x_months: "%{count} meses"
+ x_seconds: "%{count}s"
deletes:
bad_password_msg: Ben ensajat pirata ! Senhal incorrècte
confirm_password: Picatz vòstre senhal actual per verificar vòstra identitat
@@ -561,6 +593,9 @@ oc:
content: Un quicomet a pas foncionat coma caliá.
title: Aquesta pagina es pas corrècta
noscript_html: Per utilizar l’aplicacion web de Mastodon, mercés d’activar JavaScript. O podètz utilizar una aplicacion per vòstra plataforma coma alernativa.
+ existing_username_validator:
+ not_found: impossible de trobar un utilizaire local amb aqueste nom d’utilizaire
+ not_found_multiple: impossible de trobar %{usernames}
exports:
archive_takeout:
date: Data
@@ -570,6 +605,7 @@ oc:
request: Demandar vòstre archiu
size: Talha
blocks: Personas que blocatz
+ csv: CSV
domain_blocks: Blocatge de domenis
follows: Personas que seguètz
lists: Listas
@@ -603,16 +639,31 @@ oc:
all: Tot
changes_saved_msg: Cambiaments ben realizats !
copy: Copiar
+ order_by: Triar per
save_changes: Salvar los cambiaments
validation_errors:
one: I a quicòm que truca ! Mercés de corregir l’error çai-jos
other: I a quicòm que truca ! Mercés de corregir las %{count} errors çai-jos
+ html_validator:
+ invalid_markup: 'conten un balisatge HTML invalid : %{error}'
identity_proofs:
+ active: Actiu
authorize: Òc, autorizar
authorize_connection_prompt: Autorizar aquesta connexion criptografica ?
+ errors:
+ failed: La connexion criptografica a fracassat. Ensajatz tornamai de %{provider} estant.
+ keybase:
+ invalid_token: Los getons Keybase son de hashes de signaturas e devon èsser de caractèrs 66 hex
+ verification_failed: Keybase reconeis pas aqueste geton coma signatura de l’utilizaire Keybase %{kb_username}. Ensajatz tornamai de Keybase estant.
+ wrong_user: Creacion impossibla de la pròva per %{proving} en estant connectat coma %{current}. Connectatz-vos coma %{proving} e ensajatz tornamai.
+ explanation_html: Aquí podètz connectar d’un biais criptografic vòstras identitats, coma un perfil Keybase. Aquò permet al monde de vos enviar de messatges chifrats e fisar al contengut que lor enviatz.
i_am_html: Soi %{username} a %{service}.
identity: Identitat
+ inactive: Inactiu
+ publicize_checkbox: 'E enviatz lo tut seguent :'
+ publicize_toot: 'Es provat ! Soi %{username} de %{service} : %{url}'
status: Estatut de verificacion
+ view_proof: Veire la pròva
imports:
modes:
merge: Fondre
@@ -698,11 +749,22 @@ oc:
body: "%{name} a tornat partejar vòstre estatut :"
subject: "%{name} a tornat partejar vòstre estatut"
title: Novèl partatge
+ number:
+ human:
+ decimal_units:
+ format: "%n%u"
+ units:
+ billion: B
+ million: M
+ quadrillion: Q
+ thousand: K
+ trillion: T
pagination:
newer: Mai recents
next: Seguent
older: Mai ancians
prev: Precedent
+ truncate: "…"
polls:
errors:
already_voted: Avètz ja votat per aqueste sondatge
@@ -715,13 +777,20 @@ oc:
too_many_options: pòt pas contenir mai de %{max} opcions
preferences:
other: Autre
+ posting_defaults: Valors per defaut de las publicacions
+ public_timelines: Fluxes d’actualitats publics
relationships:
activity: Activitat del compte
dormant: Inactiu
+ last_active: Darrièra activitat
+ most_recent: Mai recenta
moved: Mudat
mutual: Mutuala
primary: Pirmària
relationship: Relacion
+ remove_selected_domains: Levar totes los seguidors dels domenis seleccionats
+ remove_selected_followers: Levar los seguidors seleccionats
+ remove_selected_follows: Quitar de sègre las personas seleccionadas
status: Estat del compte
remote_follow:
acct: Picatz vòstre utilizaire@domeni que que volètz utilizar per sègre aqueste utilizaire
@@ -740,9 +809,6 @@ oc:
reply:
proceed: Contunhar per respondre
prompt: 'Volètz respondre a aqueste tut :'
- remote_unfollow:
- title: Títol
- unfollowed: Pas mai seguit
scheduled_statuses:
over_daily_limit: Avètz passat la limita de %{limit} tuts programats per aquel jorn
over_total_limit: Avètz passat la limita de %{limit} tuts programats
@@ -751,15 +817,47 @@ oc:
activity: Darrièra activitat
browser: Navigator
browsers:
+ alipay: Alipay
+ blackberry: Blackberry
+ chrome: Chrome
+ edge: Microsoft Edge
+ electron: Electron
+ firefox: Firefox
generic: Navigator desconegut
+ ie: Internet Explorer
+ micro_messenger: MicroMessenger
+ nokia: Nokia S40 Ovi Browser
+ opera: Opera
+ otter: Otter
+ phantom_js: PhantomJS
+ qq: QQ Browser
+ safari: Safari
+ uc_browser: UCBrowser
+ weibo: Weibo
current_session: Session en cors
description: "%{browser} sus %{platform}"
explanation: Aquí los navigators connectats a vòstre compte Mastodon.
+ ip: IP
platforms:
+ adobe_air: Adobe Air
+ android: Android
+ blackberry: Blackberry
+ chrome_os: ChromeOS
+ firefox_os: Firefox OS
+ ios: iOS
+ linux: Linux
+ mac: Mac
other: plataforma desconeguda
+ windows: Windows
+ windows_mobile: Windows Mobile
+ windows_phone: Windows Phone
revoke: Revocar
revoke_success: Session ben revocada
+ title: Sessions
settings:
+ account: Compte
+ account_settings: Paramètres de compte
+ appearance: Aparéncia
authorized_apps: Aplicacions autorizadas
back: Tornar a Mastodon
delete: Supression de compte
@@ -767,10 +865,13 @@ oc:
edit_profile: Modificar lo perfil
export: Exportar de donadas
featured_tags: Etiquetas en avant
+ identity_proofs: Pròvas d’identitat
import: Importar de donadas
+ import_and_export: Import e export
migrate: Migracion de compte
notifications: Notificacions
preferences: Preferéncias
+ profile: Perfil
relationships: Abonaments e seguidors
two_factor_authentication: Autentificacion en dos temps
statuses:
@@ -806,6 +907,7 @@ oc:
visibilities:
private: Seguidors solament
private_long: Mostrar pas qu’als seguidors
+ public: Public
public_long: Tot lo monde pòt veire
unlisted: Pas listat
unlisted_long: Tot lo monde pòt veire mai serà pas visible sul flux public
@@ -905,6 +1007,7 @@ oc:
time:
formats:
default: Lo %d %b de %Y a %Ho%M
+ month: "%b de %Y"
two_factor_authentication:
code_hint: Picatz lo còdi generat per vòstra aplicacion d’autentificacion per confirmar
description_html: S’activatz l’autentificacion two-factor, vos caldrà vòstre mobil per vos connectar perque generarà un geton per vos daissar dintrar.
diff --git a/config/locales/pl.yml b/config/locales/pl.yml
index 3285a26b64..9932f1c624 100644
--- a/config/locales/pl.yml
+++ b/config/locales/pl.yml
@@ -52,7 +52,7 @@ pl:
many: śledzących
one: śledzący
other: Śledzących
- following: Śledzonych
+ following: śledzonych
joined: Dołączył(a) %{date}
last_active: ostatnio aktywny(-a)
link_verified_on: Własność tego odnośnika została sprawdzona %{date}
@@ -481,13 +481,6 @@ pl:
no_status_selected: Żaden wpis nie został zmieniony, bo żaden nie został wybrany
title: Wpisy konta
with_media: Z zawartością multimedialną
- subscriptions:
- callback_url: URL zwrotny
- confirmed: Potwierdzone
- expires_in: Wygasa
- last_delivery: Ostatnio doręczono
- title: WebSub
- topic: Temat
tags:
accounts: Konta
hidden: Ukryte
@@ -839,10 +832,6 @@ pl:
reply:
proceed: Przejdź do dodawania odpowiedzi
prompt: 'Chcesz odpowiedzieć na ten wpis:'
- remote_unfollow:
- error: Błąd
- title: Tytuł
- unfollowed: Przestałeś(-aś) śledzić
scheduled_statuses:
over_daily_limit: Przekroczyłeś(-aś) limit %{limit} zaplanowanych wpisów na ten dzień
over_total_limit: Przekroczyłeś(-aś) limit %{limit} zaplanowanych wpisów
diff --git a/config/locales/pt-BR.yml b/config/locales/pt-BR.yml
index d75e91b8bc..e29191871e 100644
--- a/config/locales/pt-BR.yml
+++ b/config/locales/pt-BR.yml
@@ -451,12 +451,6 @@ pt-BR:
no_status_selected: Nenhum status foi modificado porque nenhum estava selecionado
title: Postagens da conta
with_media: Com mídia
- subscriptions:
- callback_url: URL de Callback
- confirmed: Confirmado
- expires_in: Expira em
- last_delivery: Última entrega
- topic: Tópico
tags:
accounts: Contas
hidden: Escondido
@@ -770,10 +764,6 @@ pt-BR:
reply:
proceed: Proceder para responder
prompt: 'Você quer responder à esse toot:'
- remote_unfollow:
- error: Erro
- title: Título
- unfollowed: Deixou de seguir
scheduled_statuses:
over_daily_limit: Você excedeu o limite de %{limit} toots planejados para esse dia
over_total_limit: Você excedeu o limite de %{limit} toots planejados
diff --git a/config/locales/pt.yml b/config/locales/pt.yml
index 9cd92f6bd8..41c399b7df 100644
--- a/config/locales/pt.yml
+++ b/config/locales/pt.yml
@@ -431,12 +431,6 @@ pt:
no_status_selected: Nenhum estado foi alterado porque nenhum foi selecionado
title: Estado das contas
with_media: Com media
- subscriptions:
- callback_url: URL de Callback
- confirmed: Confirmado
- expires_in: Expira em
- last_delivery: Última entrega
- topic: Tópico
tags:
accounts: Contas
hidden: Escondidas
@@ -707,10 +701,6 @@ pt:
reply:
proceed: Prosseguir com resposta
prompt: 'Queres responder a esta publicação:'
- remote_unfollow:
- error: Erro
- title: Título
- unfollowed: Não seguido
scheduled_statuses:
over_daily_limit: Excedeste o limite de %{limit} publicações agendadas para esse dia
over_total_limit: Tu excedeste o limite de %{limit} publicações agendadas
diff --git a/config/locales/ru.yml b/config/locales/ru.yml
index 7e336be984..83eb3089f5 100644
--- a/config/locales/ru.yml
+++ b/config/locales/ru.yml
@@ -478,13 +478,6 @@ ru:
no_status_selected: Не выбран ни один статус, ничего не изменено
title: Статусы аккаунта
with_media: С медиаконтентом
- subscriptions:
- callback_url: Callback URL
- confirmed: Подтверждено
- expires_in: Истекает через
- last_delivery: Последняя доставка
- title: WebSub
- topic: Тема
tags:
accounts: Аккаунты
hidden: Скрыты
@@ -714,8 +707,8 @@ ru:
many: "%{count} исп."
one: 1 исп
other: "%{count} исп"
- max_uses_prompt: Без лимита
- prompt: Генерируйте и делитесь ссылками с другими, чтобы предоставить им доступ к этому узлу
+ max_uses_prompt: Без ограничения
+ prompt: Создавайте и делитесь ссылками с другими, чтобы предоставить им доступом к этому узлу
table:
expires_at: Истекает
uses: Исп.
@@ -831,10 +824,6 @@ ru:
reply:
proceed: Ответить
prompt: 'Вы собираетесь ответить на этот статус:'
- remote_unfollow:
- error: Ошибка
- title: Заголовок
- unfollowed: Отписаны
scheduled_statuses:
over_daily_limit: Вы превысили лимит в %{limit} запланированных постов на указанный день
over_total_limit: Вы превысили лимит на %{limit} запланированных постов
diff --git a/config/locales/simple_form.co.yml b/config/locales/simple_form.co.yml
index 1f5dba43fb..d58e775289 100644
--- a/config/locales/simple_form.co.yml
+++ b/config/locales/simple_form.co.yml
@@ -34,6 +34,7 @@ co:
setting_hide_network: I vostri abbunati è abbunamenti ùn saranu micca mustrati nant’à u vostru prufile
setting_noindex: Tocca à u vostru prufile pubblicu è i vostri statuti
setting_show_application: L'applicazione chì voi utilizate per mandà statuti sarà affissata indè a vista ditagliata di quelli
+ setting_use_blurhash: I digradati blurhash sò basati nant'à i culori di u ritrattu piattatu ma senza i ditagli
username: U vostru cugnome sarà unicu nant'à %{domain}
whole_word: Quandu a parolla o a frasa sana hè alfanumerica, sarà applicata solu s'ella currisponde à a parolla sana
featured_tag:
@@ -109,6 +110,7 @@ co:
setting_system_font_ui: Pulizza di caratteri di u sistemu
setting_theme: Tema di u situ
setting_unfollow_modal: Mustrà una cunfirmazione per siguità qualch’unu
+ setting_use_blurhash: Vede digradati di culori per i media piattati
severity: Severità
type: Tippu d’impurtazione
username: Cugnome
diff --git a/config/locales/simple_form.cs.yml b/config/locales/simple_form.cs.yml
index 3bf74e9718..5191d77fe4 100644
--- a/config/locales/simple_form.cs.yml
+++ b/config/locales/simple_form.cs.yml
@@ -34,6 +34,7 @@ cs:
setting_hide_network: Koho sledujete a kdo sleduje vás nebude zobrazeno na vašem profilu
setting_noindex: Ovlivňuje váš veřejný profil a stránky tootů
setting_show_application: Aplikace, kterou používáte k psaní tootů, bude zobrazena v detailním zobrazení vašich tootů
+ setting_use_blurhash: Gradienty jsou založeny na barvách skryté grafiky, ale zakrývají jakékoliv detaily
username: Vaše uživatelské jméno bude na %{domain} unikátní
whole_word: Je-li klíčové slovo či fráze pouze alfanumerická, bude aplikována pouze, pokud se shoduje s celým slovem
featured_tag:
@@ -109,6 +110,7 @@ cs:
setting_system_font_ui: Použít výchozí písmo systému
setting_theme: Motiv stránky
setting_unfollow_modal: Zobrazovat před zrušením sledování potvrzovací okno
+ setting_use_blurhash: Zobrazit pro skrytá média barevné gradienty
severity: Přísnost
type: Typ importu
username: Uživatelské jméno
diff --git a/config/locales/simple_form.cy.yml b/config/locales/simple_form.cy.yml
index 023506f24f..9f4ef0708e 100644
--- a/config/locales/simple_form.cy.yml
+++ b/config/locales/simple_form.cy.yml
@@ -34,6 +34,7 @@ cy:
setting_hide_network: Ni fydd y rheini yr ydych yn eu dilyn a phwy sy'n eich dilyn chi yn cael ei ddangos ar eich proffil
setting_noindex: Mae hyn yn effeithio ar eich proffil cyhoeddus a'ch tudalennau statws
setting_show_application: Bydd y offer frydych yn defnyddio i dŵtio yn cael ei arddangos yn golwg manwl eich tŵtiau
+ setting_use_blurhash: Mae graddiannau wedi'u seilio ar liwiau'r delweddau cudd ond maent yn cuddio unrhyw fanylion
username: Bydd eich enw defnyddiwr yn unigryw ar %{domain}
whole_word: Os yw'r allweddair neu'r ymadrodd yn alffaniwmerig yn unig, mi fydd ond yn cael ei osod os yw'n cyfateb a'r gair cyfan
featured_tag:
@@ -109,6 +110,7 @@ cy:
setting_system_font_ui: Defnyddio ffont rhagosodedig y system
setting_theme: Thema'r wefan
setting_unfollow_modal: Dangos deialog cadarnhau cyn dad-ddilyn rhywun
+ setting_use_blurhash: Dangoswch raddiannau lliwgar ar gyfer cyfryngau cudd
severity: Difrifoldeb
type: Modd mewnforio
username: Enw defnyddiwr
diff --git a/config/locales/simple_form.de.yml b/config/locales/simple_form.de.yml
index 61e0f9740d..d070796426 100644
--- a/config/locales/simple_form.de.yml
+++ b/config/locales/simple_form.de.yml
@@ -34,6 +34,7 @@ de:
setting_hide_network: Wem du folgst und wer dir folgt, wird in deinem Profil nicht angezeigt
setting_noindex: Betrifft dein öffentliches Profil und deine Beiträge
setting_show_application: Die Anwendung die du nutzst wird in der detaillierten Ansicht deiner Beiträge angezeigt
+ setting_use_blurhash: Die Farbverläufe basieren auf den Farben der versteckten Medien, aber verstecken irgendwelche Details, die Reize auslösen könnten
username: Dein Profilname wird auf %{domain} einzigartig sein
whole_word: Wenn das Schlagwort nur aus Buchstaben und Zahlen besteht, wird es nur angewendet, wenn es dem ganzen Wort entspricht
featured_tag:
@@ -109,6 +110,7 @@ de:
setting_system_font_ui: Standardschriftart des Systems verwenden
setting_theme: Theme
setting_unfollow_modal: Bestätigungsdialog anzeigen, bevor jemandem entfolgt wird
+ setting_use_blurhash: Farbverlauf für versteckte Medien anzeigen
severity: Schweregrad
type: Art des Imports
username: Profilname
diff --git a/config/locales/simple_form.el.yml b/config/locales/simple_form.el.yml
index 67f3b64aa1..099c900a51 100644
--- a/config/locales/simple_form.el.yml
+++ b/config/locales/simple_form.el.yml
@@ -34,6 +34,7 @@ el:
setting_hide_network: Δε θα εμφανίζεται στο προφίλ σου ποιους ακολουθείς και ποιοι σε ακολουθούν
setting_noindex: Επηρεάζει το δημόσιο προφίλ και τις δημοσιεύσεις σου
setting_show_application: Η εφαρμογή που χρησιμοποιείς για να στέλνεις τα τουτ σου θα εμφανίζεται στις αναλυτικές λεπτομέρειες τους
+ setting_use_blurhash: Οι χρωματισμοί βασίζονται στα χρώματα του κρυμμένου πολυμέσου αλλά θολώνουν τις λεπτομέρειες
username: Το όνομα χρήστη σου θα είναι μοναδικό στο %{domain}
whole_word: Όταν η λέξη ή η φράση κλειδί είναι μόνο αλφαριθμητική, θα εφαρμοστεί μόνο αν ταιριάζει με ολόκληρη τη λέξη
featured_tag:
@@ -109,6 +110,7 @@ el:
setting_system_font_ui: Χρησιμοποίησε την προεπιλεγμένη γραμματοσειρά του συστήματος
setting_theme: Θέμα ιστότοπου
setting_unfollow_modal: Εμφάνιση ερώτησης επιβεβαίωσης πριν διακόψεις την παρακολούθηση κάποιου
+ setting_use_blurhash: Εμφάνιση χρωματισμών για τα κρυμμένα πολυμέσα
severity: Αυστηρότητα
type: Τύπος εισαγωγής
username: Όνομα χρηστη
diff --git a/config/locales/simple_form.es.yml b/config/locales/simple_form.es.yml
index 7b871e8ba0..2986cf091e 100644
--- a/config/locales/simple_form.es.yml
+++ b/config/locales/simple_form.es.yml
@@ -6,12 +6,16 @@ es:
text: Puede usar sintaxis de toots, como URLs, hashtags y menciones
admin_account_action:
send_email_notification: El usuario recibirá una explicación de lo que sucedió con respecto a su cuenta
+ text_html: Opcional. Puede usar sintaxis de toots. Puede añadir configuraciones predefinidas de advertencia para ahorrar tiempo
+ type_html: Elige qué hacer con %{acct}
+ warning_preset_id: Opcional. Aún puede añadir texto personalizado al final de la configuración predefinida
defaults:
autofollow: Los usuarios que se registren mediante la invitación te seguirán automáticamente
avatar: PNG, GIF o JPG. Máximo %{size}. Será escalado a %{dimensions}px
bot: Esta cuenta ejecuta principalmente acciones automatizadas y podría no ser monitorizada
context: Uno o múltiples contextos en los que debe aplicarse el filtro
digest: Solo enviado tras un largo periodo de inactividad y solo si has recibido mensajes personales durante tu ausencia
+ discoverable_html: El directorio permite a la gente encontrar cuentas basadas en intereses y actividad. Requiere al menos %{min_followers} seguidores
email: Se le enviará un correo de confirmación
fields: Puedes tener hasta 4 elementos mostrándose como una tabla en tu perfil
header: PNG, GIF o JPG. Máximo %{size}. Será escalado a %{dimensions}px
@@ -22,10 +26,19 @@ es:
password: Utilice al menos 8 caracteres
phrase: Se aplicará sin importar las mayúsculas o los avisos de contenido de un toot
scopes: Qué APIs de la aplicación tendrán acceso. Si seleccionas el alcance de nivel mas alto, no necesitas seleccionar las individuales.
+ setting_aggregate_reblogs: No mostrar nuevos retoots para los toots que han sido recientemente retooteados (sólo afecta a los retoots recibidos recientemente)
+ setting_default_sensitive: El contenido multimedia sensible está oculto por defecto y puede ser mostrado con un click
+ setting_display_media_default: Ocultar contenido multimedia marcado como sensible
+ setting_display_media_hide_all: Siempre ocultar todo el contenido multimedia
+ setting_display_media_show_all: Mostrar siempre contenido multimedia marcado como sensible
setting_hide_network: A quién sigues y quién te sigue no será mostrado en tu perfil
setting_noindex: Afecta a tu perfil público y páginas de estado
setting_show_application: La aplicación que utiliza usted para publicar toots se mostrará en la vista detallada de sus toots
+ setting_use_blurhash: Los gradientes se basan en los colores de las imágenes ocultas pero haciendo borrosos los detalles
+ username: Tu nombre de usuario será único en %{domain}
whole_word: Cuando la palabra clave o frase es solo alfanumérica, solo será aplicado si concuerda con toda la palabra
+ featured_tag:
+ name: 'Puede que quieras usar uno de estos:'
imports:
data: Archivo CSV exportado desde otra instancia de Mastodon
invite_request:
@@ -39,15 +52,21 @@ es:
fields:
name: Etiqueta
value: Contenido
+ account_warning_preset:
+ text: Texto predefinido
admin_account_action:
send_email_notification: Notificar al usuario por correo electrónico
text: Aviso personalizado
type: Acción
types:
disable: Deshabilitar
+ none: No hacer nada
silence: Silenciar
+ suspend: Suspender y eliminar de forma irreversible la información de la cuenta
+ warning_preset_id: Usar un aviso predeterminado
defaults:
autofollow: Invitar a seguir tu cuenta
+ avatar: Avatar
bot: Esta es una cuenta bot
chosen_languages: Filtrar idiomas
confirm_new_password: Confirmar nueva contraseña
@@ -55,6 +74,7 @@ es:
context: Filtrar contextos
current_password: Contraseña actual
data: Información
+ discoverable: Listar esta cuenta en el directorio
display_name: Nombre para mostrar
email: Dirección de correo electrónico
expires_in: Expirar tras
@@ -70,12 +90,19 @@ es:
otp_attempt: Código de dos factores
password: Contraseña
phrase: Palabra clave o frase
+ setting_advanced_layout: Habilitar interfaz web avanzada
+ setting_aggregate_reblogs: Agrupar retoots en las líneas de tiempo
setting_auto_play_gif: Reproducir automáticamente los GIFs animados
setting_boost_modal: Mostrar ventana de confirmación antes de un Retoot
setting_default_language: Idioma de publicación
setting_default_privacy: Privacidad de publicaciones
setting_default_sensitive: Marcar siempre imágenes como sensibles
setting_delete_modal: Mostrar diálogo de confirmación antes de borrar un toot
+ setting_display_media: Visualización multimedia
+ setting_display_media_default: Por defecto
+ setting_display_media_hide_all: Ocultar todo
+ setting_display_media_show_all: Mostrar todo
+ setting_expand_spoilers: Siempre expandir los toots marcados con advertencias de contenido
setting_hide_network: Ocultar tu red
setting_noindex: Excluirse del indexado de motores de búsqueda
setting_reduce_motion: Reducir el movimiento de las animaciones
@@ -83,11 +110,14 @@ es:
setting_system_font_ui: Utilizar la tipografía por defecto del sistema
setting_theme: Tema del sitio
setting_unfollow_modal: Mostrar diálogo de confirmación antes de dejar de seguir a alguien
+ setting_use_blurhash: Mostrar gradientes coloridos para contenido multimedia oculto
severity: Severidad
type: Importar tipo
username: Nombre de usuario
username_or_email: Usuario o Email
whole_word: Toda la palabra
+ featured_tag:
+ name: Etiqueta
interactions:
must_be_follower: Bloquear notificaciones de personas que no te siguen
must_be_following: Bloquear notificaciones de personas que no sigues
@@ -106,5 +136,6 @@ es:
'no': 'No'
recommended: Recomendado
required:
+ mark: "*"
text: necesario
'yes': Sí
diff --git a/config/locales/simple_form.eu.yml b/config/locales/simple_form.eu.yml
index acd5fd6d98..be3883fb0b 100644
--- a/config/locales/simple_form.eu.yml
+++ b/config/locales/simple_form.eu.yml
@@ -14,7 +14,7 @@ eu:
avatar: PNG, GIF edo JPG. Gehienez %{size}. %{dimensions}px neurrira eskalatuko da
bot: Kontu honek nagusiki automatizatutako ekintzak burutzen ditu eta agian ez du inork monitorizatzen
context: Iragazkia aplikatzeko testuinguru bat edo batzuk
- digest: Soilik jarduerarik gabeko epe luze bat eta gero, eta soilik ez zeudela mezu pertsonalen bat jaso baduzu
+ digest: Jarduerarik gabeko epe luze bat eta gero mezu pertsonalen bat jaso baduzu, besterik ez
discoverable_html: Direktorioak Jendea interesen eta jardueraren arabera aurkitzea ahalbidetzen du. Gutxienez %{min_followers} jarraitzaile behar dira bertan agertzeko
email: Baieztapen e-mail bat bidaliko zaizu
fields: 4 elementu bistaratu ditzakezu taula batean zure profilean
@@ -26,7 +26,7 @@ eu:
password: Erabili 8 karaktere gutxienez
phrase: Bat egingo du Maiuskula/minuskula kontuan hartu gabe eta edukiaren abisua kontuan hartu gabe
scopes: Zeintzuk API atzitu ditzakeen aplikazioak. Goi mailako arloa aukeratzen baduzu, ez dituzu azpikoak aukeratu behar.
- setting_aggregate_reblogs: Ez erakutsi buktzada berriak berriki bultzada jaso duten tootentzat (berriki jasotako bultzadei eragiten die besterik ez)
+ setting_aggregate_reblogs: Ez erakutsi bultzada berriak berriki bultzada jaso duten toot-entzat (berriki jasotako bultzadei eragiten die bakarrik)
setting_default_sensitive: Multimedia hunkigarria lehenetsita ezkutatzen da, eta sakatuz ikusi daiteke
setting_display_media_default: Ezkutatu hunkigarri gisa markatutako multimedia
setting_display_media_hide_all: Ezkutatu multimedia guztia beti
@@ -34,6 +34,7 @@ eu:
setting_hide_network: Nor jarraitzen duzun eta nork jarraitzen zaituen ez da bistaratuko zure profilean
setting_noindex: Zure profil publiko eta Toot-en orrietan eragina du
setting_show_application: Tootak bidaltzeko erabiltzen duzun aplikazioa zure tooten ikuspegi xehetsuan bistaratuko da
+ setting_use_blurhash: Gradienteak ezkutatutakoaren koloreetan oinarritzen dira, baina xehetasunak ezkutatzen dituzte
username: Zure erabiltzaile-izena bakana izango da %{domain} domeinuan
whole_word: Hitz eta esaldi gakoa alfanumerikoa denean, hitz osoarekin bat datorrenean besterik ez da aplikatuko
featured_tag:
@@ -109,6 +110,7 @@ eu:
setting_system_font_ui: Erabili sistemako tipografia lehenetsia
setting_theme: Gunearen gaia
setting_unfollow_modal: Erakutsi baieztapen elkarrizketa-koadroa inor jarraitzeari utzi aurretik
+ setting_use_blurhash: Erakutsi gradiente koloretsuak ezkutatutako multimediaren ordez
severity: Larritasuna
type: Inportazio mota
username: Erabiltzaile-izena
@@ -118,8 +120,8 @@ eu:
name: Traola
interactions:
must_be_follower: Blokeatu jarraitzaile ez direnen jakinarazpenak
- must_be_following: Blokeatu zuk jarraitzen ez dituzunen jakinarazpenak
- must_be_following_dm: Blokeatu zuk jarraitzen ez dituzunen mezu zuzenak
+ must_be_following: Blokeatu zuk jarraitzen ez dituzu horien jakinarazpenak
+ must_be_following_dm: Blokeatu zuk jarraitzen ez dituzun horien mezu zuzenak
invite_request:
text: Zergatik elkartu nahi duzu?
notification_emails:
diff --git a/config/locales/simple_form.gl.yml b/config/locales/simple_form.gl.yml
index 22389051fb..122481dcf0 100644
--- a/config/locales/simple_form.gl.yml
+++ b/config/locales/simple_form.gl.yml
@@ -34,6 +34,7 @@ gl:
setting_hide_network: Non se mostrará no seu perfil quen a segue e quen a está a seguir
setting_noindex: Afecta ao seu perfil público e páxinas de estado
setting_show_application: A aplicación que está a utilizar para enviar toots mostrarase na vista detallada do toot
+ setting_use_blurhash: Os gradientes toman as cores da imaxe oculta pero esborranchando todos os detalles
username: O seu nome de usuaria será único en %{domain}
whole_word: Se a chave ou frase de paso é só alfanumérica, só se aplicará se concorda a palabra completa
featured_tag:
@@ -109,6 +110,7 @@ gl:
setting_system_font_ui: Utilizar a tipografía por defecto do sistema
setting_theme: Decorado da instancia
setting_unfollow_modal: Solicitar confirmación antes de deixar de seguir alguén
+ setting_use_blurhash: Mostrar gradientes coloridos para medios ocultos
severity: Severidade
type: Tipo de importación
username: Nome de usuaria
diff --git a/config/locales/simple_form.ja.yml b/config/locales/simple_form.ja.yml
index dd7d9304d6..5d14fa4bf7 100644
--- a/config/locales/simple_form.ja.yml
+++ b/config/locales/simple_form.ja.yml
@@ -34,6 +34,7 @@ ja:
setting_hide_network: フォローとフォロワーの情報がプロフィールページで見られないようにします
setting_noindex: 公開プロフィールおよび各投稿ページに影響します
setting_show_application: トゥートするのに使用したアプリがトゥートの詳細ビューに表示されるようになります
+ setting_use_blurhash: ぼかしはメディアの色を元に生成されますが、細部は見えにくくなっています
username: あなたのユーザー名は %{domain} の中で重複していない必要があります
whole_word: キーワードまたはフレーズが英数字のみの場合、単語全体と一致する場合のみ適用されるようになります
featured_tag:
@@ -110,6 +111,7 @@ ja:
setting_system_font_ui: システムのデフォルトフォントを使う
setting_theme: サイトテーマ
setting_unfollow_modal: フォローを解除する前に確認ダイアログを表示する
+ setting_use_blurhash: 非表示のメディアを色付きのぼかしで表示する
severity: 重大性
type: インポートする項目
username: ユーザー名
diff --git a/config/locales/simple_form.oc.yml b/config/locales/simple_form.oc.yml
index e0bfcfef9c..9453375b17 100644
--- a/config/locales/simple_form.oc.yml
+++ b/config/locales/simple_form.oc.yml
@@ -27,12 +27,14 @@ oc:
phrase: Serà pres en compte que siá en majuscula o minuscula o dins un avertiment de contengut sensible
scopes: A quinas APIs poiràn accedir las aplicacions. Se seleccionatz un encastre de naut nivèl, fa pas mestièr de seleccionar los nivèls mai basses.
setting_aggregate_reblogs: Mostrar pas los nòus partatges que son estats partejats recentament (afecta pas que los nòus partatges recebuts)
+ setting_default_sensitive: Los mèdias sensibles son resconduts per defaut e se revelhan amb un clic
setting_display_media_default: Rescondre los mèdias marcats coma sensibles
setting_display_media_hide_all: Totjorn rescondre los mèdias
setting_display_media_show_all: Totjorn mostrar los mèdias marcats coma sensibles
setting_hide_network: Vòstre perfil mostrarà pas los que vos sègon e lo monde que seguètz
setting_noindex: Aquò es destinat a vòstre perfil public e vòstra pagina d’estatuts
setting_show_application: Lo nom de l’aplicacion qu’utilizatz per publicar serà mostrat dins la vista detalhada de vòstres tuts
+ setting_use_blurhash: Los degradats venon de las colors de l’imatge rescondut en enfoscar los detalhs
username: Vòstre nom d’utilizaire serà unic sus %{domain}
whole_word: Quand lo mot-clau o frasa es solament alfranumeric, serà pas qu’aplicat se correspond al mot complèt
featured_tag:
@@ -64,6 +66,7 @@ oc:
warning_preset_id: Utilizar un avertiment predefinit
defaults:
autofollow: Convidar a sègre vòstre compte
+ avatar: Avatar
bot: Aquò es lo compte a un robòt
chosen_languages: Filtrar las lengas
confirm_new_password: Confirmacion del nòu senhal
@@ -83,9 +86,11 @@ oc:
locked: Far venir lo compte privat
max_uses: Limit d’utilizacions
new_password: Nòu senhal
+ note: Bio
otp_attempt: Còdi Two-factor
password: Senhal
phrase: Senhal o frasa
+ setting_advanced_layout: Activar l’interfàcia web avançada
setting_aggregate_reblogs: Agropar los partatges dins lo flux d’actualitat
setting_auto_play_gif: Lectura automatica dels GIFS animats
setting_boost_modal: Mostrar una fenèstra de confirmacion abans de partejar un estatut
@@ -105,6 +110,7 @@ oc:
setting_system_font_ui: Utilizar la polissa del sistèma
setting_theme: Tèma del site
setting_unfollow_modal: Mostrar una confirmacion abans de quitar de sègre qualqu’un
+ setting_use_blurhash: Mostrar los degradats colorats pels mèdias resconduts
severity: Severitat
type: Tipe d’impòrt
username: Nom d’utilizaire
@@ -128,6 +134,8 @@ oc:
reblog: Enviar un corrièl quand qualqu’un tòrna partejar vòstre estatut
report: Enviar un corrièl pels nòus senhalaments
'no': Non
+ recommended: Recomandat
required:
+ mark: "*"
text: requesit
'yes': Òc
diff --git a/config/locales/simple_form.pl.yml b/config/locales/simple_form.pl.yml
index b74bbc2f54..6a9cf13eb8 100644
--- a/config/locales/simple_form.pl.yml
+++ b/config/locales/simple_form.pl.yml
@@ -35,6 +35,7 @@ pl:
setting_noindex: Wpływa na widoczność strony profilu i Twoich wpisów
setting_show_application: W informacjach o wpisie będzie widoczna informacja o aplikacji, z której został wysłany
setting_skin: Zmienia wygląd używanej odmiany Mastodona
+ setting_use_blurhash: Gradienty są oparte na kolorach ukrywanej zawartości, ale uniewidaczniają wszystkie szczegóły
username: Twoja nazwa użytkownika będzie niepowtarzalna na %{domain}
whole_word: Jeśli słowo lub fraza składa się jedynie z liter lub cyfr, filtr będzie zastosowany tylko do pełnych wystąpień
featured_tag:
@@ -111,6 +112,7 @@ pl:
setting_skin: Motyw
setting_system_font_ui: Używaj domyślnej czcionki systemu
setting_unfollow_modal: Pytaj o potwierdzenie przed cofnięciem śledzenia
+ setting_use_blurhash: Pokazuj kolorowe gradienty dla ukrytej zawartości multimedialnej
severity: Priorytet
type: Importowane dane
username: Nazwa użytkownika
diff --git a/config/locales/simple_form.ru.yml b/config/locales/simple_form.ru.yml
index 26a73c3c6d..fcc1c2827a 100644
--- a/config/locales/simple_form.ru.yml
+++ b/config/locales/simple_form.ru.yml
@@ -10,7 +10,7 @@ ru:
type_html: Выберите, что делать с аккаунтом %{acct}
warning_preset_id: Необязательно. Вы можете добавить собственный текст в конце шаблона
defaults:
- autofollow: Люди, пришедшие по этому приглашению автоматически будут подписаны на Вас
+ autofollow: Люди, пришедшие по этому приглашению, автоматически будут подписаны на вас
avatar: PNG, GIF или JPG. Максимально %{size}. Будет уменьшено до %{dimensions}px
bot: Этот аккаунт обычно выполяет автоматизированные действия и может не просматриваться владельцем
context: Один или несколько контекстов, к которым должны быть применены фильтры
@@ -64,7 +64,7 @@ ru:
suspend: Заблокировать и безвозвратно удалить все данные аккаунта
warning_preset_id: Использовать шаблон
defaults:
- autofollow: Пригласите подписаться на Ваш аккаунт
+ autofollow: С подпиской на ваш аккаунт
avatar: Аватар
bot: Это аккаунт бота
chosen_languages: Фильтр языков
@@ -83,7 +83,7 @@ ru:
irreversible: Удалять, а не скрывать
locale: Язык интерфейса
locked: Сделать аккаунт закрытым
- max_uses: Макс. число использований
+ max_uses: Максимальное число использований
new_password: Новый пароль
note: О Вас
otp_attempt: Двухфакторный код
diff --git a/config/locales/simple_form.sk.yml b/config/locales/simple_form.sk.yml
index 8470f79391..4ee251b262 100644
--- a/config/locales/simple_form.sk.yml
+++ b/config/locales/simple_form.sk.yml
@@ -109,6 +109,7 @@ sk:
setting_system_font_ui: Použi základné systémové písmo
setting_theme: Vzhľad webu
setting_unfollow_modal: Vyžaduj potvrdenie pred skončením sledovania iného užívateľa
+ setting_use_blurhash: Ukáž farebné prechody pre skryté médiá
severity: Závažnosť
type: Typ importu
username: Prezývka
@@ -134,5 +135,6 @@ sk:
'no': Nie
recommended: Odporúčané
required:
+ mark: "*"
text: povinné
'yes': Áno
diff --git a/config/locales/simple_form.th.yml b/config/locales/simple_form.th.yml
index 9d6b75ed0d..33a3c5a3ab 100644
--- a/config/locales/simple_form.th.yml
+++ b/config/locales/simple_form.th.yml
@@ -34,6 +34,7 @@ th:
setting_hide_network: จะไม่แสดงผู้ที่คุณติดตามและผู้ที่ติดตามคุณในโปรไฟล์ของคุณ
setting_noindex: มีผลต่อโปรไฟล์สาธารณะและหน้าสถานะของคุณ
setting_show_application: จะแสดงแอปพลิเคชันที่คุณใช้เพื่อโพสต์ในมุมมองโดยละเอียดของโพสต์ของคุณ
+ setting_use_blurhash: การไล่ระดับสีอิงตามสีของภาพที่ซ่อนอยู่แต่ทำให้รายละเอียดใด ๆ คลุมเครือ
username: ชื่อผู้ใช้ของคุณจะไม่ซ้ำกันบน %{domain}
whole_word: เมื่อคำสำคัญหรือวลีมีแค่ตัวอักษรและตัวเลข จะถูกใช้หากตรงกันทั้งคำเท่านั้น
featured_tag:
@@ -109,6 +110,7 @@ th:
setting_system_font_ui: ใช้แบบอักษรเริ่มต้นของระบบ
setting_theme: ชุดรูปแบบไซต์
setting_unfollow_modal: แสดงกล่องโต้ตอบการยืนยันก่อนเลิกติดตามใครสักคน
+ setting_use_blurhash: แสดงการไล่ระดับสีที่มีสีสันสำหรับสื่อที่ซ่อนอยู่
severity: ความรุนแรง
type: ชนิดการนำเข้า
username: ชื่อผู้ใช้
diff --git a/config/locales/simple_form.zh-CN.yml b/config/locales/simple_form.zh-CN.yml
index b781deb32b..c62e57a518 100644
--- a/config/locales/simple_form.zh-CN.yml
+++ b/config/locales/simple_form.zh-CN.yml
@@ -15,7 +15,7 @@ zh-CN:
bot: 来自这个帐户的绝大多数操作都是自动进行的,并且可能无人监控
context: 过滤器的应用场景
digest: 仅在你长时间未登录,且收到了私信时发送
- discoverable_html: 目录 让大家能根据兴趣和活动寻找用户。需要至少 %{min_followers} 位关注者
+ discoverable_html: 用户目录 让大家能根据兴趣和活动寻找用户。需要至少 %{min_followers} 位关注者
email: 我们会向你发送一封确认邮件
fields: 这将会在个人资料页上以表格的形式展示,最多 4 个项目
header: 文件大小限制 %{size},只支持 PNG、GIF 或 JPG 格式。图片分辨率将会压缩至 %{dimensions}px
@@ -34,6 +34,7 @@ zh-CN:
setting_hide_network: 你关注的人和关注你的人将不会在你的个人资料页上展示
setting_noindex: 此设置会影响到你的公开个人资料以及嘟文页面
setting_show_application: 你用来发表嘟文的应用程序将会在你嘟文的详细内容中显示
+ setting_use_blurhash: 渐变是基于模糊后的隐藏内容生成的
username: 你的用户名在 %{domain} 上是独特的
whole_word: 如果关键词只包含字母和数字,就只会在整个词被匹配时才会套用
featured_tag:
@@ -73,7 +74,7 @@ zh-CN:
context: 过滤器场景
current_password: 当前密码
data: 数据文件
- discoverable: 在本站用户资料目录中列出此账户
+ discoverable: 在本站用户目录中收录此账户
display_name: 昵称
email: 电子邮件地址
expires_in: 失效时间
@@ -109,6 +110,7 @@ zh-CN:
setting_system_font_ui: 使用系统默认字体
setting_theme: 站点主题
setting_unfollow_modal: 在取消关注前询问我
+ setting_use_blurhash: 将隐藏媒体显示为彩色渐变
severity: 级别
type: 导入数据类型
username: 用户名
diff --git a/config/locales/sk.yml b/config/locales/sk.yml
index 75a43e322f..5b0bbdef45 100644
--- a/config/locales/sk.yml
+++ b/config/locales/sk.yml
@@ -301,7 +301,7 @@ sk:
affected_accounts:
few: "%{count} účtov v databázi ovplyvnených"
many: "%{count} účtov v databázi ovplyvnených"
- one: Jeden účet v databázi ovplyvnený
+ one: 1 účet v databázi ovplyvnený
other: "%{count} účty v databázi ovplyvnené"
retroactive:
silence: Zruš stíšenie všetkých momentálne utíšených účtov z tejto domény
@@ -481,13 +481,6 @@ sk:
no_status_selected: Žiadne príspevky neboli zmenené, keďže si žiadne nemal/a zvolené
title: Príspevky na účte
with_media: S médiami
- subscriptions:
- callback_url: Zdrojová adresa URL
- confirmed: Potvrdené
- expires_in: Vyprší do
- last_delivery: Posledné doručenie
- title: WebSub
- topic: Téma
tags:
accounts: Účty
hidden: Skryté
@@ -513,6 +506,7 @@ sk:
subject: Nové hlásenie pre %{instance} (#%{id})
appearance:
advanced_web_interface: Pokročilé webové rozhranie
+ advanced_web_interface_hint: 'Ak chceš využiť celkovú šírku tvojej obrazovky, pokročilé webové rozhranie ti umožňuje nastaviť mnoho rôznych stĺpcov, aby si videl/a toľko informácií naraz, koľko chceš: Domov, oboznámenia, federovanú časovú os, a ľubovolný počet zoznamov, či haštagov.'
animations_and_accessibility: Animácie a prístupnosť
confirmation_dialogs: Potvrdzovacie dialógy
sensitive_content: Chúlostivý obsah
@@ -657,12 +651,19 @@ sk:
copy: Kopíruj
order_by: Zoraď podľa
save_changes: Ulož zmeny
+ validation_errors:
+ few: Niečo ešte nieje celkom v poriadku! Prosím skontroluj %{count} chýb uvedených nižšie
+ many: Niečo ešte nieje celkom v poriadku! Prosím skontroluj %{count} chýb uvedených nižšie
+ one: Niečo ešte nieje celkom v poriadku! Prosím skontroluj chybu uvedenú nižšie
+ other: Niečo ešte nieje celkom v poriadku! Prosím skontroluj %{count} chyby uvedené nižšie
identity_proofs:
active: Aktívne
authorize: Áno, povoľ
authorize_connection_prompt: Povoliť toto kryptografické prepojenie?
errors:
failed: Kryptografické prepojenie sa nepodarilo. Prosím skús to znova z %{provider}.
+ keybase:
+ verification_failed: Keybase nerozpoznáva tento token ako podpis od Keybase užívateľa menom %{kb_username}. Prosím skús to znova cez Keybase.
i_am_html: Na %{service} som %{username}.
identity: Identita
inactive: Neaktívne
@@ -768,6 +769,7 @@ sk:
too_many_options: nemôže zahŕňať viac ako %{max} položiek
preferences:
other: Ostatné
+ posting_defaults: Východiskové nastavenia príspevkov
public_timelines: Verejné časové osi
relationships:
activity: Aktivita účtu
@@ -778,6 +780,7 @@ sk:
mutual: Spoločné
primary: Hlavné
relationship: Vzťah
+ remove_selected_domains: Vymaž všetkých následovateľov z vybraných domén
remove_selected_followers: Odstráň vybraných následovatrľov
remove_selected_follows: Prestaň sledovať vybraných užívateľov
status: Stav účtu
@@ -798,10 +801,6 @@ sk:
reply:
proceed: Pokračuj odpovedaním
prompt: 'Chceš odpovedať na tento príspevok:'
- remote_unfollow:
- error: Chyba
- title: Názov
- unfollowed: Už nesleduješ
scheduled_statuses:
over_daily_limit: Prekročil/a si denný limit %{limit} predplánovaných príspevkov
over_total_limit: Prekročil/a si limit %{limit} predplánovaných príspevkov
diff --git a/config/locales/sl.yml b/config/locales/sl.yml
index 85e167ca9d..ff6c5851af 100644
--- a/config/locales/sl.yml
+++ b/config/locales/sl.yml
@@ -1,22 +1,33 @@
---
sl:
about:
- about_hashtag_html: To so javni tuti, označeni z #%{hashtag}. Z njimi se lahko povežete, če imate račun kjerkoli v fediversu.
+ about_hashtag_html: To so javni tuti, označeni z #%{hashtag}. Z njimi se lahko povežete, če imate račun kjerkoli v fediverse-u.
about_mastodon_html: Mastodon je socialno omrežje, ki temelji na odprtih spletnih protokolih in prosti ter odprtokodni programski opremi. Je decentraliziran, kot e-pošta.
about_this: O Mastodonu
+ active_count_after: dejaven
+ active_footnote: Aktivni mesečni uporabniki (AMU)
administered_by: 'Upravlja:'
+ api: API
apps: Mobilne aplikacije
+ apps_platforms: Uporabljajte Mastodon iz iOS, Android ali iz drugih platform
+ browse_directory: Brskajte po imeniku profilov in filtriranje po interesih
+ browse_public_posts: Brskajte javnih objav v živo na Mastodonu
contact: Kontakt
contact_missing: Ni nastavljeno
contact_unavailable: Ni na voljo
+ discover_users: Odkrijte uporabnike
documentation: Dokumentacija
extended_description_html: |
Dober prostor za pravila
Razširjen opis še ni bil nastavljen.
+ federation_hint_html: Z računom na %{instance} boste lahko spremljali ljudi na kateremkoli Mastodon strežniku.
generic_description: "%{domain} je en strežnik v omrežju"
+ get_apps: Poskusite mobilno aplikacijo
hosted_on: Mastodon gostuje na %{domain}
- learn_more: Spoznaj več
- privacy_policy: Politika zasebnosti
+ learn_more: Nauči se več
+ privacy_policy: Pravilnik o zasebnosti
+ see_whats_happening: Poglejte, kaj se dogaja
+ server_stats: 'Statistika strežnika:'
source_code: Izvorna koda
status_count_after:
few: stanja
@@ -24,12 +35,13 @@ sl:
other: stanj
two: stanja
status_count_before: Ki so avtorji
+ tagline: Sledite prijateljem in odkrijte nove
terms: Pogoji storitve
user_count_after:
few: uporabniki
one: uporabnik
other: uporabnikov
- two: uporabniki
+ two: uporabnika
user_count_before: Dom za
what_is_mastodon: Kaj je Mastodon?
accounts:
@@ -38,56 +50,61 @@ sl:
followers:
few: Sledilci
one: Sledilec
- other: Sledilci
- two: Sledilci
+ other: Sledilcev
+ two: Sledilca
following: Sledim
joined: Se je pridružil na %{date}
- last_active: zadnji aktivni
+ last_active: zadnja dejavnost
link_verified_on: Lastništvo te povezave je bilo preverjeno na %{date}
- media: Medij
+ media: Mediji
moved_html: "%{name} se je prestavil na %{new_profile_link}:"
- network_hidden: Te informacije niso na voljo
- nothing_here: Nič ni tukaj!
+ network_hidden: Ta informacija ni na voljo
+ nothing_here: Tukaj ni ničesar!
people_followed_by: Ljudje, ki jim sledi %{name}
people_who_follow: Ljudje, ki sledijo %{name}
pin_errors:
following: Verjetno že sledite osebi, ki jo želite potrditi
posts:
- few: Trob
- one: Trob
- other: Trob
- two: Trob
- posts_tab_heading: Trobi
+ few: Tuti
+ one: Tut
+ other: Tutov
+ two: Tuta
+ posts_tab_heading: Tuti
posts_with_replies: Tuti in odgovori
reserved_username: Uporabniško ime je zasedeno
roles:
admin: Skrbnik
bot: Robot
+ moderator: Mod
+ unavailable: Profil ni na voljo
unfollow: Prenehaj slediti
admin:
account_actions:
action: Izvedi dejanje
- title: Izvedi moderirano dejanje %{acct}
+ title: Izvedi moderirano dejanje za %{acct}
account_moderation_notes:
create: Pusti opombo
- created_msg: Uspešno ustvarjena opomba moderiranja!
+ created_msg: Moderirana opomba je uspešno ustvarjena!
delete: Izbriši
destroyed_msg: Moderirana opomba je uspešno uničena!
accounts:
- are_you_sure: Ali si prepričan?
+ approve: Odobri
+ approve_all: Odobri vse
+ are_you_sure: Ali ste prepričani?
+ avatar: Podoba
by_domain: Domena
change_email:
changed_msg: E-pošta računa je uspešno spremenjena!
- current_email: Trenutna E-pošta
- label: Spremeni E-pošto
- new_email: Nova E-pošta
- submit: Spremeni E-pošto
- title: Spremeni E-pošto za %{username}
+ current_email: Trenutna e-pošta
+ label: Spremeni e-pošto
+ new_email: Nova e-pošta
+ submit: Spremeni e-pošto
+ title: Spremeni e-pošto za %{username}
confirm: Potrdi
confirmed: Potrjeno
confirming: Potrjujem
deleted: Izbrisano
- demote: Ponižaj
+ demote: Degradiraj
disable: Onemogoči
disable_two_factor_authentication: Onemogoči 2FA
disabled: Onemogočeno
@@ -95,44 +112,50 @@ sl:
domain: Domena
edit: Uredi
email: E-pošta
- email_status: Stanje E-pošte
+ email_status: Stanje e-pošte
enable: Omogoči
enabled: Omogočeno
- feed_url: URL vir
+ feed_url: URL vira
followers: Sledilci
- followers_url: URL sledilci
+ followers_url: URL sledilcev
follows: Sledi
header: Glava
- inbox_url: URl v mapi "Prejeto"
+ inbox_url: URL mape "Prejeto"
invited_by: Povabljen od
+ ip: IP
joined: Pridružil
location:
all: Vse
- local: Lokalno
+ local: Lokalni
remote: Oddaljeni
title: Lokacija
login_status: Stanje prijave
- media_attachments: Medijske priloge
+ media_attachments: Predstavnostne priloge
memorialize: Spremenite v spomin
moderation:
active: Dejaven
all: Vse
+ pending: Na čakanju
silenced: Utišan
suspended: Suspendiran
title: Moderiranje
moderation_notes: Opombe moderiranja
- most_recent_activity: Zadnja aktivnost
+ most_recent_activity: Zadnja dejavnost
most_recent_ip: Zadnji IP
+ no_account_selected: Noben račun ni bil spremenjen, ker ni bil izbran noben
no_limits_imposed: Brez omejitev
- not_subscribed: Ni naročeno
- outbox_url: URl za pošiljanje
- perform_full_suspension: Začasno ustavi
+ not_subscribed: Ni naročen
+ outbox_url: URL za pošiljanje
+ pending: Čakanje na pregled
+ perform_full_suspension: Suspendiraj
profile_url: URL profila
- promote: Spodbujanje
+ promote: Promoviraj
protocol: Protokol
public: Javen
push_subscription_expires: Naročnina PuSH preteče
redownload: Osveži profil
+ reject: Zavrni
+ reject_all: Zavrni vse
remove_avatar: Odstrani podobo
remove_header: Odstrani glavo
resend_confirmation:
@@ -145,9 +168,11 @@ sl:
role: Dovoljenja
roles:
admin: Skrbnik
+ moderator: Moderator
staff: Osebje
user: Uporabnik
- search: Poišči
+ salmon_url: URL lososa
+ search: Iskanje
shared_inbox_url: URL mape "Prejeto v skupni rabi"
show:
created_reports: Narejene prijave
@@ -157,6 +182,7 @@ sl:
statuses: Stanja
subscribe: Naroči
suspended: Suspendiran
+ time_in_queue: Čakanje v vrsti %{time}
title: Računi
unconfirmed_email: Nepotrjena e-pošta
undo_silenced: Razveljavi utišanje
@@ -171,27 +197,27 @@ sl:
change_email_user: "%{name} je spremenil naslov e-pošte uporabnika %{target}"
confirm_user: "%{name} je potrdil naslov e-pošte uporabnika %{target}"
create_account_warning: "%{name} je poslal opozorilo %{target}"
- create_custom_emoji: "%{name} je poslal nove emotikone %{target}"
+ create_custom_emoji: "%{name} je posodobil emotikone %{target}"
create_domain_block: "%{name} je blokiral domeno %{target}"
create_email_domain_block: "%{name} je dal na črni seznam e-pošto domene %{target}"
demote_user: "%{name} je degradiral uporabnika %{target}"
- destroy_custom_emoji: "%{name} je uničil emotikon %{target}"
+ destroy_custom_emoji: "%{name} je uničil emotikone %{target}"
destroy_domain_block: "%{name} je odblokiral domeno %{target}"
destroy_email_domain_block: "%{name} je dal na beli seznam e-pošto domene %{target}"
destroy_status: "%{name} je odstranil stanje od %{target}"
disable_2fa_user: "%{name} je onemogočil dvofaktorsko zahtevo za uporabnika %{target}"
- disable_custom_emoji: "%{name} je onemogočil emotikon %{target}"
+ disable_custom_emoji: "%{name} je onemogočil emotikone %{target}"
disable_user: "%{name} je onemogočil prijavo za uporabnika %{target}"
- enable_custom_emoji: "%{name} je omogočil emotikon %{target}"
+ enable_custom_emoji: "%{name} je omogočil emotikone %{target}"
enable_user: "%{name} je omogočil prijavo za uporabnika %{target}"
memorialize_account: "%{name} je spremenil račun od %{target} v stran spominov"
- promote_user: "%{name} je spodbudil uporabnika %{target}"
+ promote_user: "%{name} je promoviral uporabnika %{target}"
remove_avatar_user: "%{name} je odstranil podobo od %{target}"
reopen_report: "%{name} je ponovno odprl prijavo %{target}"
reset_password_user: "%{name} je ponastavil geslo od uporabnika %{target}"
resolve_report: "%{name} je razrešil prijavo %{target}"
silence_account: "%{name} je utišal račun od %{target}"
- suspend_account: "%{name} je začasno ustavil račun od %{target}"
+ suspend_account: "%{name} je suspendiral račun od %{target}"
unassigned_report: "%{name} je nedodeljeno prijavil %{target}"
unsilence_account: "%{name} je preklical utišanje računa od %{target}"
unsuspend_account: "%{name} je aktiviral račun od %{target}"
@@ -201,9 +227,9 @@ sl:
title: Dnevnik revizije
custom_emojis:
by_domain: Domena
- copied_msg: Lokalna kopija emotikona je bila uspešno ustvarjena
+ copied_msg: Lokalna kopija emotikonov je bila uspešno ustvarjena
copy: Kopiraj
- copy_failed_msg: Lokalne kopije emotikona ni bilo mogoče ustvariti
+ copy_failed_msg: Lokalne kopije emotikonov ni bilo mogoče ustvariti
created_msg: Emotikon je uspešno ustvarjen!
delete: Izbriši
destroyed_msg: Emotikon je uspešno uničen!
@@ -225,13 +251,14 @@ sl:
updated_msg: Emotikon je uspešno posodobljen!
upload: Pošlji
dashboard:
- backlog: Zaostala opravila
+ backlog: zaostala opravila
config: Nastavitve
feature_deletions: Brisanje računov
- feature_invites: Poveza povabil
- feature_profile_directory: Mapa profila
+ feature_invites: Povezave povabil
+ feature_profile_directory: Imenik profilov
feature_registrations: Registracije
feature_relay: Rele federacije
+ feature_timeline_preview: Predogled časovnice
features: Zmožnosti
hidden_service: Federacija s skritimi storitvami
open_reports: odprte prijave
@@ -241,7 +268,7 @@ sl:
software: Programska oprema
space: Uporaba prostora
title: Nadzorna plošča
- total_users: Skupaj uporabnikov
+ total_users: skupaj uporabnikov
trends: Trendi
week_interactions: interakcije ta teden
week_users_active: aktivni ta teden
@@ -251,12 +278,13 @@ sl:
created_msg: Domenski blok se sedaj obdeluje
destroyed_msg: Domenski blok je bil razveljavljen
domain: Domena
+ existing_domain_block_html: Uvedli ste strožje omejitve za %{name}, sedaj ga morate najprej odblokirati.
new:
create: Ustvari blok
hint: Domenski blok ne bo preprečil ustvarjanja vnosov računov v zbirko podatkov, ampak bo retroaktivno in samodejno uporabil posebne metode moderiranja na teh računih.
severity:
desc_html: "Utišaj bo vse objave računa naredil nevidne vsem, ki jih ne sledijo. Suspendiraj bo odstranil vso vsebino, medije in podatke profila računa. Uporabi nič, če želite le zavrniti predstavnostne datoteke."
- noop: Nič
+ noop: Brez
silence: Utišaj
suspend: Suspendiraj
title: Nov domenski blok
@@ -271,13 +299,13 @@ sl:
suspend: suspendirani
show:
affected_accounts:
- few: "%{count} računov v bazi podatkov so prizadeti"
+ few: "%{count} računi v bazi podatkov so prizadeti"
one: En račun v bazi podatkov je prizadet
- other: "%{count} računov v bazi podatkov so prizadeti"
- two: "%{count} računov v bazi podatkov so prizadeti"
+ other: "%{count} računov v bazi podatkov je prizadetih"
+ two: "%{count} računa v bazi podatkov so prizadeta"
retroactive:
silence: Prekliči utišanje za vse obstoječe račune iz te domene
- suspend: Odsuspendiraj vse obstoječe račune iz te domene
+ suspend: Aktiviraj vse obstoječe račune iz te domene
title: Razveljavi domenski blok za %{domain}
undo: Razveljavi
undo: Razveljavi domenski blok
@@ -290,17 +318,18 @@ sl:
new:
create: Dodaj domeno
title: Nov vnos e-pošte na črni seznam
- title: Črni seznam e-pošte
+ title: Črni seznam e-pošt
followers:
back_to_account: Nazaj na račun
title: Sledilci od %{acct}
instances:
+ by_domain: Domena
delivery_available: Na voljo je dostava
known_accounts:
- few: "%{count} znanih računov"
+ few: "%{count} znani računi"
one: "%{count} znan račun"
other: "%{count} znanih računov"
- two: "%{count} znanih računov"
+ two: "%{count} znana računa"
moderation:
all: Vse
limited: Omejeno
@@ -317,15 +346,18 @@ sl:
all: Vse
available: Razpoložljivo
expired: Potekel
+ title: Filter
title: Povabila
+ pending_accounts:
+ title: "(%{count}) računov na čakanju"
relays:
add_new: Dodaj nov rele
delete: Izbriši
- description_html: "Rele federacije je posredniški strežnik, ki si izmenjuje velike količine javnih trobov med strežniki, ki so se naročili in objavili na njem. Majhnim in srednjim strežnikom lahko pomaga pri odkrivanju vsebine iz sistema fediverse, kar bi sicer zahtevalo, da lokalni uporabniki ročno sledijo druge osebe na oddaljenih strežnikih."
+ description_html: "Rele federacije je posredniški strežnik, ki si izmenjuje velike količine javnih tutov med strežniki, ki so se naročili in objavili na njem. Majhnim in srednjim strežnikom lahko pomaga pri odkrivanju vsebine iz sistema fediverse, kar bi sicer zahtevalo, da lokalni uporabniki ročno sledijo druge osebe na oddaljenih strežnikih."
disable: Onemogoči
disabled: Onemogočeno
enable: Omogoči
- enable_hint: Ko je omogočen, se bo vaš strežnik naročil na vse javne trobe iz tega releja in začel pošiljati javne trobe tega strežnika.
+ enable_hint: Ko je omogočen, se bo vaš strežnik naročil na vse javne tute iz tega releja in začel pošiljati javne tute tega strežnika.
enabled: Omogočeno
inbox_url: URL releja
pending: Čakanje na odobritev releja
@@ -345,7 +377,7 @@ sl:
assign_to_self: Dodeli meni
assigned: Dodeljen moderator
comment:
- none: Nič
+ none: Brez
created_at: Prijavljeno
mark_as_resolved: Označi kot rešeno
mark_as_unresolved: Označi kot nerešeno
@@ -359,19 +391,19 @@ sl:
report: 'Prijavi #%{id}'
reported_account: Prijavljeni račun
reported_by: Prijavljen od
- resolved: Razrešeno
+ resolved: Razrešeni
resolved_msg: Prijava je uspešno razrešena!
status: Stanje
title: Prijave
- unassign: Odstopi
- unresolved: Nerešeno
- updated_at: Posodobljen
+ unassign: Odstopljeni
+ unresolved: Nerešeni
+ updated_at: Posodobljeni
settings:
activity_api_enabled:
desc_html: Številke lokalno objavljenih stanj, aktivnih uporabnikov in novih registracij na tedenskih seznamih
title: Objavi združeno statistiko o dejavnosti uporabnikov
bootstrap_timeline_accounts:
- desc_html: Več uporabniških imen ločite z vejico. Deluje samo na lokalnih in odklenjenih računih. Privzeto, ko je prazno, pri vseh lokalnih skrbnikih.
+ desc_html: Več uporabniških imen ločite z vejico. Deluje samo na lokalnih in odklenjenih računih. Privzeto, ko je prazno, je pri vseh lokalnih skrbnikih.
title: Privzeta sledenja za nove uporabnike
contact_information:
email: Poslovna e-pošta
@@ -379,21 +411,382 @@ sl:
custom_css:
desc_html: Spremeni videz z naloženim CSS na vsaki strani
title: CSS po meri
+ hero:
+ desc_html: Prikazano na sprednji strani. Priporoča se vsaj 600x100px. Ko ni nastavljen, se vrne na sličico strežnika
+ title: Slika junaka
+ mascot:
+ desc_html: Prikazano na več straneh. Priporočena je najmanj 293 × 205 px. Ko ni nastavljen, se vrne na privzeto maskoto
+ title: Slika maskote
+ peers_api_enabled:
+ desc_html: Domene, na katere je ta strežnik naletel na fediverse-u
+ title: Objavi seznam odkritih strežnikov
+ preview_sensitive_media:
+ desc_html: Predogledi povezav na drugih spletiščih bodo prikazali sličico, tudi če je medij označen kot občutljiv
+ title: Prikaži občutljive medije v predogledih OpenGraph
+ profile_directory:
+ desc_html: Dovoli uporabnikom, da jih lahko odkrijejo
+ title: Omogoči imenik profilov
+ registrations:
+ closed_message:
+ desc_html: Prikazano na prvi strani, ko so registracije zaprte. Lahko uporabite oznake HTML
+ title: Sporočilo o zaprti registraciji
+ deletion:
+ desc_html: Dovoli vsakomur, da izbriše svoj račun
+ title: Odpri brisanje računa
+ min_invite_role:
+ disabled: Nihče
+ title: Dovoli vabila od
+ registrations_mode:
+ modes:
+ approved: Potrebna je odobritev za prijavo
+ none: Nihče se ne more prijaviti
+ open: Vsakdo se lahko prijavi
+ title: Način registracije
+ show_known_fediverse_at_about_page:
+ desc_html: Ko preklopite, bo prikazal tute vseh znanih fediverse-ov v predogledu. V nasprotnem primeru bodo prikazani samo lokalni tuti.
+ title: Pokaži znane fediverse-e v predogledu časovnice
+ show_staff_badge:
+ desc_html: Prikaži značko osebja na uporabniški strani
+ title: Prikaži značko osebja
+ site_description:
+ desc_html: Uvodni odstavek na API-ju. Opišite, zakaj je ta Mastodon strežnik poseben in karkoli pomembnega. Lahko uporabite HTML oznake, zlasti <a> in <em>.
+ title: Opis strežnika
+ site_description_extended:
+ desc_html: Dober kraj za vaš kodeks ravnanja, pravila, smernice in druge stvari, ki ločujejo vaš strežnik. Lahko uporabite oznake HTML
+ title: Razširjene informacije po meri
+ site_short_description:
+ desc_html: Prikazano v stranski vrstici in metaoznakah. V enem odstavku opišite, kaj je Mastodon in kaj naredi ta strežnik poseben.
+ title: Kratek opis strežnika
+ site_terms:
+ desc_html: Lahko napišete svojo pravilnik o zasebnosti, pogoje storitve ali druge pravne dokumente. Lahko uporabite oznake HTML
+ title: Pogoji storitve po meri
+ site_title: Ime strežnika
+ thumbnail:
+ desc_html: Uporablja se za predogled prek OpenGrapha in API-ja. Priporočamo 1200x630px
+ title: Sličica strežnika
+ timeline_preview:
+ desc_html: Prikaži javno časovnico na ciljni strani
+ title: Predogled časovnice
+ title: Nastavitve strani
+ statuses:
+ back_to_account: Nazaj na stran računa
+ batch:
+ delete: Izbriši
+ nsfw_off: Označi, da ni občutljivo
+ nsfw_on: Označi, kot občutljivo
+ failed_to_execute: Ni bilo mogoče izvesti
+ media:
+ title: Mediji
+ no_media: Ni medijev
+ no_status_selected: Nobeno stanje ni bilo spremenjeno, ker ni bilo izbrano nobeno
+ title: Stanja računa
+ with_media: Z mediji
+ tags:
+ accounts: Računi
+ hidden: Skriti
+ hide: Skrij iz imenika
+ name: Ključnik
+ title: Ključniki
+ unhide: Prikaži v imeniku
+ visible: Vidni
+ title: Upravljanje
+ warning_presets:
+ add_new: Dodaj novo
+ delete: Izbriši
+ edit: Uredi
+ edit_preset: Uredi prednastavitev opozoril
+ title: Upravljaj prednastavitev opozoril
+ admin_mailer:
+ new_pending_account:
+ body: Podrobnosti o novem računu so navedene spodaj. To aplikacijo lahko odobrite ali zavrnete.
+ subject: Nov račun za pregled na %{instance} (%{username})
+ new_report:
+ body: "%{reporter} je prijavil %{target}"
+ body_remote: Nekdo iz %{domain} je prijavil %{target}
+ subject: Nove prijave za %{instance} (#%{id})
+ appearance:
+ advanced_web_interface: Napredni spletni vmesnik
+ advanced_web_interface_hint: 'Če želite uporabiti celotno širino zaslona, vam napredni spletni vmesnik omogoča, da si nastavite več različnih stolpcev in da si hkrati ogledate toliko informacij, kot želite: domačo stran, obvestila, združeno časovnico, poljubno število seznamov in ključnikov.'
+ animations_and_accessibility: Animacije in dostopnost
+ confirmation_dialogs: Potrditvena okna
+ sensitive_content: Občutljiva vsebina
+ application_mailer:
+ notification_preferences: Spremenite e-poštne nastavitve
+ salutation: "%{name},"
+ settings: 'Spremenite e-poštne nastavitve: %{link}'
+ view: 'Pogled:'
+ view_profile: Ogled profila
+ view_status: Ogled stanja
+ applications:
+ created: Aplikacija je bila uspešno ustvarjena
+ destroyed: Aplikacija je bila uspešno izbrisana
+ invalid_url: Navedeni URL je neveljaven
+ regenerate_token: Obnovite dostopni žeton
+ token_regenerated: Dostopni žeton je bil uspešno regeneriran
+ warning: Bodite zelo previdni s temi podatki. Nikoli jih ne delite z nikomer!
+ your_token: Vaš dostopni žeton
+ auth:
+ apply_for_account: Zahtevajte povabilo
+ change_password: Geslo
+ checkbox_agreement_html: Strinjam se s pravili strežnika in pogoji storitve
+ confirm_email: Potrdi e-pošto
+ delete_account: Izbriši račun
+ delete_account_html: Če želite izbrisati svoj račun, lahko nadaljujete tukaj. Prosili vas bomo za potrditev.
+ didnt_get_confirmation: Niste prejeli navodil za potrditev?
+ forgot_password: Ste pozabili svoje geslo?
+ invalid_reset_password_token: Žeton za ponastavitev gesla je neveljaven ali je potekel. Zahtevajte novo.
+ login: Prijava
+ logout: Odjava
+ migrate_account: Premakni se na drug račun
+ migrate_account_html: Če želite ta račun preusmeriti na drugega, ga lahko nastavite tukaj.
+ or_log_in_with: Ali se prijavite z
+ providers:
+ cas: CAS
+ saml: SAML
+ register: Vpis
+ registration_closed: "%{instance} ne sprejema novih članov"
+ resend_confirmation: Ponovno pošlji navodila za potrditev
+ reset_password: Ponastavi geslo
+ security: Varnost
+ set_new_password: Nastavi novo geslo
+ trouble_logging_in: Težave pri prijavi?
+ authorize_follow:
+ already_following: Temu računu že sledite
+ error: Na žalost je prišlo do napake pri iskanju oddaljenega računa
+ follow: Sledi
+ follow_request: 'Prošnjo za sledenje se poslali:'
+ following: 'Uspeh! Zdaj sledite:'
+ post_follow:
+ close: Lahko pa tudi zaprete to okno.
+ return: Prikaži uporabnikov profil
+ web: Pojdi na splet
+ title: Sledi %{acct}
+ datetime:
+ distance_in_words:
+ about_x_hours: "%{count}h"
+ about_x_months: "%{count}mo"
+ about_x_years: "%{count}y"
+ almost_x_years: "%{count}y"
+ half_a_minute: Pravkar
+ less_than_x_minutes: "%{count}m"
+ less_than_x_seconds: Pravkar
+ over_x_years: "%{count}y"
+ x_days: "%{count}d"
+ x_minutes: "%{count}m"
+ x_months: "%{count}mo"
+ x_seconds: "%{count}s"
+ deletes:
+ bad_password_msg: Lep poskus, hekerji! napačno geslo
+ confirm_password: Vnesite svoje trenutno geslo, da potrdite svojo identiteto
+ description_html: S tem boste trajno, nepovratno odstranili vsebino iz vašega računa in jo deaktivirali. Vaše uporabniško ime bo ostalo rezervirano za preprečevanje prihodnjih lažnih predstav.
+ proceed: Izbriši račun
+ success_msg: Vaš račun je bil uspešno izbrisan
+ warning_html: Zagotovljeno je samo brisanje vsebine iz tega strežnika. Vsebina, ki je široko razširjena, bo verjetno pustila sledi. Strežniki brez povezave in strežniki, ki so se odjavili od vaših posodobitev, ne bodo posodabljali svojih podatkovnih baz.
+ warning_title: Razširjena razpoložljivost vsebine
+ directories:
+ directory: Imenik profilov
+ enabled: Trenutno ste navedeni v imeniku.
+ enabled_but_waiting: Vključili ste, da ste navedeni v imeniku, vendar še nimate najmanjšega števila sledilcev (%{min_followers}), da bi vas prikazalo.
+ explanation: Odkrijte uporabnike glede na njihove interese
+ explore_mastodon: Razišči %{title}
+ how_to_enable: Trenutno niste vključeni v imenik. Spodaj se lahko vključite. Uporabite ključnike v vaši biografiji, da boste navedeni pod specifične ključnike!
+ people:
+ few: "%{count} osebe"
+ one: "%{count} oseba"
+ other: "%{count} oseb"
+ two: "%{count} osebi"
errors:
- '403': You don't have permission to view this page.
- '404': The page you are looking for isn't here.
- '410': The page you were looking for doesn't exist here anymore.
- '422':
- '429': Throttled
- '500':
+ '403': Nimate dovoljenja za ogled te strani.
+ '404': Iskana stran ne obstaja.
+ '410': Iskana stran ne obstaja več.
+ '422':
+ content: Varnostno preverjanje ni uspelo. Ali blokirate piškotke?
+ title: Varnostno preverjanje je spodletelo
+ '429': Omejeno
+ '500':
+ content: Žal nam je, toda na našem koncu je prišlo do napake.
+ title: Ta stran ni pravilna
+ noscript_html: Če želite uporabljati spletno aplikacijo Mastodon, omogočite JavaScript. Druga možnost je, da za svojo platformo poskusite eno od lastnih aplikacij za Mastodon.
+ existing_username_validator:
+ not_found: s tem uporabniškim imenom ni bilo mogoče najti lokalnega uporabnika
+ not_found_multiple: ni bilo mogoče najti %{usernames}
+ exports:
+ archive_takeout:
+ date: Datum
+ download: Prenesi svoj arhiv
+ hint_html: Zahtevate lahko arhiv vaših tutov in naloženih medijev. Izvoženi podatki bodo v formatu ActivityPub, ki ga bo mogoče brati s katerokoli skladno programsko opremo. Arhiv lahko zahtevate vsakih 7 dni.
+ in_progress: Prevajanje arhiva...
+ request: Zahtevajte svoj arhiv
+ size: Velikost
+ blocks: Blokirate
+ csv: CSV
+ domain_blocks: Bloki domene
+ follows: Sledite
+ lists: Seznami
+ mutes: Utišate
+ storage: Shranjeni mediji
+ featured_tags:
+ add_new: Dodaj novo
+ errors:
+ limit: Ste že dodali največje število ključnikov
+ filters:
+ contexts:
+ home: Domača časovnica
+ notifications: Obvestila
+ public: Javne časovnice
+ thread: Pogovori
+ edit:
+ title: Uredite filter
+ errors:
+ invalid_context: Ne vsebuje nobenega ali vsebuje neveljaven kontekst
+ invalid_irreversible: Nepovratno filtriranje deluje le v kontekstu doma ali obvestil
+ index:
+ delete: Izbriši
+ title: Filtri
+ new:
+ title: Dodaj nov filter
+ footer:
+ developers: Razvijalci
+ more: Več…
+ resources: Viri
+ generic:
+ all: Vse
+ changes_saved_msg: Spremembe so uspešno shranjene!
+ copy: Kopiraj
+ order_by: Razvrsti po
+ save_changes: Shrani spremembe
+ validation_errors:
+ few: Nekaj še ni čisto v redu! Spodaj si oglejte %{count} napake
+ one: Nekaj še ni čisto v redu! Spodaj si oglejte napako
+ other: Nekaj še ni čisto v redu! Spodaj si oglejte %{count} napak
+ two: Nekaj še ni čisto v redu! Spodaj si oglejte %{count} napaki
+ html_validator:
+ invalid_markup: 'vsebuje neveljavno oznako HTML: %{error}'
+ identity_proofs:
+ active: Dejaven
+ authorize: Da, odobri
+ authorize_connection_prompt: Odobrite to kriptografsko povezavo?
+ errors:
+ failed: Kriptografska povezava ni uspela. Poskusite znova od %{provider}.
+ keybase:
+ invalid_token: Žetoni Keybase so algoritem podpisov in morajo biti sestavljeni iz 66 heksadecimalnih znakov
+ verification_failed: Keybase ne prepozna tega žetona kot podpis uporabnika %{kb_username}. Poskusite znova s Keybase-om.
+ wrong_user: Dokler se prijavite kot %{current}, ni mogoče ustvariti dokazila za %{proving}. Prijavite se kot %{proving} in poskusite znova.
+ explanation_html: Tukaj lahko kriptografsko povežete druge identitete, na primer profil Keybase. To omogoča drugim, da vam pošljejo šifrirana sporočila in zaupate vsebino, ki ste jo poslali.
+ i_am_html: Jaz sem %{username} na %{service}.
+ identity: Identiteta
+ inactive: Neaktiven
+ publicize_checkbox: 'In to tutnite:'
+ publicize_toot: 'Dokazano je! Jaz sem %{username} na %{service}: %{url}'
+ status: Stanje preverjanja
+ view_proof: Oglejte si dokaz
+ imports:
+ modes:
+ merge: Združi
+ merge_long: Ohrani obstoječe zapise in dodaj nove
+ overwrite: Prepiši
+ overwrite_long: Zamenjaj trenutne zapise z novimi
+ preface: Podatke, ki ste jih izvozili iz drugega strežnika, lahko uvozite. Na primer seznam oseb, ki jih spremljate ali blokirate.
+ success: Vaši podatki so bili uspešno naloženi in bodo zdaj pravočasno obdelani
+ types:
+ blocking: Seznam blokiranih
+ domain_blocking: Seznam blokiranih domen
+ following: Seznam uporabnikov, katerim sledite
+ muting: Seznam utišanih
+ upload: Pošlji
+ in_memoriam_html: V spomin.
invites:
+ delete: Onemogoči
+ expired: Poteklo
expires_in:
- '1800': 30 minutes
- '21600': 6 hours
- '3600': 1 hour
- '43200': 12 hours
- '604800': 1 week
- '86400': 1 day
+ '1800': 30 minut
+ '21600': 6 ur
+ '3600': 1 ura
+ '43200': 12 ur
+ '604800': 1 teden
+ '86400': 1 dan
+ expires_in_prompt: Nikoli
+ generate: Ustvari
+ invited_by: 'Povabil/a vas je:'
+ max_uses:
+ few: "%{count} uporabe"
+ one: 1 uporaba
+ other: "%{count} uporab"
+ two: "%{count} uporabi"
+ max_uses_prompt: Brez omejitve
+ prompt: Ustvarite in delite povezave z drugimi, da omogočite dostop do tega strežnika
+ table:
+ expires_at: Poteče
+ uses: Uporabe
+ title: Povabite ljudi
+ lists:
+ errors:
+ limit: Dosegli ste največje število seznamov
+ media_attachments:
+ validations:
+ images_and_video: Videoposnetka ni mogoče priložiti stanju, ki že vsebuje slike
+ too_many: Ni možno priložiti več kot 4 datoteke
+ migrations:
+ acct: username@domain novega računa
+ currently_redirecting: 'Vaš profil je preusmerjen na:'
+ proceed: Shrani
+ updated_msg: Nastavitev selitve računa je bila uspešno posodobljena!
+ moderation:
+ title: Moderiranje
+ notification_mailer:
+ digest:
+ action: Prikaži vsa obvestila
+ body: Tukaj je kratek povzetek sporočil, ki ste jih zamudili od vašega zadnjega obiska v %{since}
+ mention: "%{name} vas je omenil/a v:"
+ new_followers_summary:
+ few: Prav tako ste pridobili %{count} nove sledilce, ko ste bili odsotni! Juhu!
+ one: Prav tako ste pridobili enega novega sledilca, ko ste bili odsotni! Juhu!
+ other: Prav tako ste pridobili %{count} novih sledilcev, ko ste bili odsotni! Juhu!
+ two: Prav tako ste pridobili %{count} nova sledilca, ko ste bili odsotni! Juhu!
+ subject:
+ few: "%{count} nova obvestila od vašega zadnjega obiska \U0001F418"
+ one: "1 novo obvestilo od vašega zadnjega obiska \U0001F418"
+ other: "%{count} novih obvestil od vašega zadnjega obiska \U0001F418"
+ two: "%{count} novi obvestili od vašega zadnjega obiska \U0001F418"
+ title: V vaši odsotnosti...
+ favourite:
+ body: "%{name} je vzljubil/a vaše stanje:"
+ subject: "%{name} je vzljubil/a vaše stanje"
+ title: Novo priljubljeno
+ follow:
+ body: "%{name} vam sedaj sledi!"
+ subject: "%{name} vam sedaj sledi"
+ title: Novi sledilec
+ follow_request:
+ action: Upravljajte s prošnjami za sledenje
+ body: "%{name} vas je prosil/a za sledenje"
+ subject: 'Čakajoči sledilec/ka: %{name}'
+ title: Nova prošnja za sledenje
+ mention:
+ action: Odgovori
+ body: "%{name} vas je omenil/a v:"
+ subject: "%{name} vas je omenil/a"
+ title: Nova omemba
+ reblog:
+ body: "%{name} je spodbudil/a vaše stanje:"
+ subject: "%{name} je spodbudil/a vaše stanje"
+ title: Nova spodbuda
+ number:
+ human:
+ decimal_units:
+ format: "%n%u"
+ units:
+ billion: B
+ million: M
+ quadrillion: Q
+ thousand: K
+ trillion: T
+ pagination:
+ newer: Novejše
+ next: Naprej
+ older: Starejše
+ prev: Nazaj
+ truncate: "…"
statuses:
pin_errors:
ownership: Trob nekoga drugega ne more biti pripet
diff --git a/config/locales/sq.yml b/config/locales/sq.yml
index 6cab033321..cbe2256469 100644
--- a/config/locales/sq.yml
+++ b/config/locales/sq.yml
@@ -423,12 +423,6 @@ sq:
no_status_selected: S’u ndryshua ndonjë gjendje, ngaqë s’u përzgjodh ndonjë e tillë
title: Gjendje llogarish
with_media: Me media
- subscriptions:
- callback_url: URL Callback-u
- confirmed: U ripohua
- expires_in: Skadon më
- last_delivery: Dorëzimi e fundit
- topic: Temë
tags:
accounts: Llogari
hidden: Fshehur
@@ -686,10 +680,6 @@ sq:
reply:
proceed: Ripohoni përgjigjen
prompt: 'Doni t’i përgjigjeni këtij mesazhi:'
- remote_unfollow:
- error: Gabim
- title: Titull
- unfollowed: U hoq ndjekja
scheduled_statuses:
over_daily_limit: Keni tejkaluar kufirin e %{limit} mesazheve të planifikuara për atë ditë
over_total_limit: Keni tejkaluar kufirin prej %{limit} mesazhesh të planifikuara
diff --git a/config/locales/sr-Latn.yml b/config/locales/sr-Latn.yml
index 3310716e0f..6530d4c762 100644
--- a/config/locales/sr-Latn.yml
+++ b/config/locales/sr-Latn.yml
@@ -263,10 +263,6 @@ sr-Latn:
no_media: Bez multimedije
title: Statusi naloga
with_media: Sa multimedijom
- subscriptions:
- confirmed: Potvrđeno
- expires_in: Ističe za
- last_delivery: Poslednja dostava
title: Administracija
admin_mailer:
new_report:
diff --git a/config/locales/sr.yml b/config/locales/sr.yml
index 1555fb235d..88db0c4f45 100644
--- a/config/locales/sr.yml
+++ b/config/locales/sr.yml
@@ -440,10 +440,6 @@ sr:
no_status_selected: Ниједан статус није промењен јер ниједан није изабран
title: Статуси налога
with_media: Са мултимедијом
- subscriptions:
- confirmed: Потврђено
- expires_in: Истиче за
- last_delivery: Последња достава
tags:
accounts: Налози
hidden: Скривено
@@ -693,10 +689,6 @@ sr:
reply:
proceed: Наставите да бисте одговорили
prompt: 'Желите да одговорите на ову трубу:'
- remote_unfollow:
- error: Грешка
- title: Наслов
- unfollowed: Отпраћени
scheduled_statuses:
over_daily_limit: Прекорачили сте границу од %{limit} планираних труба за тај дан
over_total_limit: Прекорачили сте границу од %{limit} планираних труба
diff --git a/config/locales/sv.yml b/config/locales/sv.yml
index d3d0cb888d..c123e2889e 100644
--- a/config/locales/sv.yml
+++ b/config/locales/sv.yml
@@ -313,12 +313,6 @@ sv:
no_media: Ingen media
title: Kontostatus
with_media: med media
- subscriptions:
- callback_url: Återanrop URL
- confirmed: Bekräftad
- expires_in: Utgår om
- last_delivery: Sista leverans
- topic: Ämne
admin_mailer:
new_report:
body: "%{reporter} har rapporterat %{target}"
@@ -513,10 +507,6 @@ sv:
missing_resource: Det gick inte att hitta den begärda omdirigeringsadressen för ditt konto
proceed: Fortsätt för att följa
prompt: 'Du kommer att följa:'
- remote_unfollow:
- error: Fel
- title: Titel
- unfollowed: Slutade följa
sessions:
activity: Senaste aktivitet
browser: Webbläsare
diff --git a/config/locales/th.yml b/config/locales/th.yml
index 7a16bc2f32..a009e4ebbd 100644
--- a/config/locales/th.yml
+++ b/config/locales/th.yml
@@ -335,13 +335,6 @@ th:
title: สื่อ
no_media: ไม่มีสื่อ
title: สถานะบัญชี
- subscriptions:
- callback_url: URL เรียกกลับ
- confirmed: ยืนยันแล้ว
- expires_in: หมดอายุภายใน
- last_delivery: ส่งล่าสุด
- title: WebSub
- topic: หัวข้อ
tags:
accounts: บัญชี
hidden: ซ่อนอยู่
@@ -360,6 +353,7 @@ th:
appearance:
advanced_web_interface: ส่วนติดต่อเว็บขั้นสูง
animations_and_accessibility: ภาพเคลื่อนไหวและการช่วยการเข้าถึง
+ confirmation_dialogs: กล่องโต้ตอบการยืนยัน
sensitive_content: เนื้อหาที่ละเอียดอ่อน
application_mailer:
notification_preferences: เปลี่ยนการกำหนดลักษณะอีเมล
@@ -537,6 +531,7 @@ th:
prev: ก่อนหน้า
truncate: "…"
preferences:
+ other: อื่น ๆ
posting_defaults: ค่าเริ่มต้นการโพสต์
public_timelines: เส้นเวลาสาธารณะ
relationships:
@@ -562,10 +557,6 @@ th:
reply:
proceed: ดำเนินการต่อเพื่อตอบกลับ
prompt: 'คุณต้องการตอบกลับโพสต์นี้:'
- remote_unfollow:
- error: ข้อผิดพลาด
- title: ชื่อเรื่อง
- unfollowed: เลิกติดตามแล้ว
sessions:
activity: กิจกรรมล่าสุด
browser: เบราว์เซอร์
diff --git a/config/locales/tr.yml b/config/locales/tr.yml
index 3113e7a08f..5929e1e071 100644
--- a/config/locales/tr.yml
+++ b/config/locales/tr.yml
@@ -207,12 +207,6 @@ tr:
title: Sunucu hakkında detaylı bilgi
site_title: Site başlığı
title: Site Ayarları
- subscriptions:
- callback_url: Callback linki
- confirmed: Onaylandı
- expires_in: Bitiş Tarihi
- last_delivery: Son gönderim
- topic: Konu
tags:
accounts: Hesaplar
name: Etiketler
diff --git a/config/locales/uk.yml b/config/locales/uk.yml
index e027b6baee..c2d422474d 100644
--- a/config/locales/uk.yml
+++ b/config/locales/uk.yml
@@ -349,11 +349,6 @@ uk:
no_media: Немає медіа
title: Статуси аккаунтів
with_media: З медіа
- subscriptions:
- confirmed: Підтверджено
- expires_in: Спливає через
- last_delivery: Остання доставка
- topic: Тема
title: Адміністрування
admin_mailer:
new_report:
@@ -569,10 +564,6 @@ uk:
no_account_html: Не маєте аккаунту? Не біда, ви можете зареєструватися
proceed: Перейти до підписки
prompt: 'Ви хочете підписатися на:'
- remote_unfollow:
- error: Помилка
- title: Заголовок
- unfollowed: Відписані
sessions:
activity: Остання активність
browser: Браузер
diff --git a/config/locales/zh-CN.yml b/config/locales/zh-CN.yml
index 0c9b291ad3..42ab59d506 100644
--- a/config/locales/zh-CN.yml
+++ b/config/locales/zh-CN.yml
@@ -10,7 +10,7 @@ zh-CN:
api: API
apps: 移动应用
apps_platforms: 在 iOS、Android 和其他平台上使用 Mastodon
- browse_directory: 浏览用户资料目录并按兴趣筛选
+ browse_directory: 浏览用户目录并按兴趣筛选
browse_public_posts: 浏览 Mastodon 上公共嘟文的实时信息流
contact: 联系方式
contact_missing: 未设定
@@ -32,7 +32,7 @@ zh-CN:
status_count_after:
other: 条嘟文
status_count_before: 他们共嘟出了
- tagline: 关注朋友并发现新朋友
+ tagline: 关注并发现新朋友
terms: 使用条款
user_count_after:
other: 位用户
@@ -243,9 +243,9 @@ zh-CN:
config: 服务器配置
feature_deletions: 帐户删除
feature_invites: 邀请链接
- feature_profile_directory: 用户资料目录
+ feature_profile_directory: 用户目录
feature_registrations: 公开注册
- feature_relay: 同步中继
+ feature_relay: 中继服务器
feature_timeline_preview: 时间轴预览
features: 功能
hidden_service: 匿名服务连通性
@@ -333,9 +333,9 @@ zh-CN:
pending_accounts:
title: 待处理的帐户 (%{count})
relays:
- add_new: 添加新的中继
+ add_new: 订阅新的中继
delete: 删除
- description_html: "同步中继是一种中间服务器,各实例可以通过订阅中继和向中继推送信息的方式来大量交换公开嘟文。它可以帮助中小型实例发现网络中的内容,而无需本地用户手动关注其他远程实例上的用户。"
+ description_html: "中继服务器是一个信息统合服务器,各服务器可以通过订阅中继服务器和向中继服务器推送信息来交换大量公开嘟文。它可以帮助中小型服务器发现联邦宇宙中的其他服务器的内容,而无需本站用户手动关注其他远程服务器上的用户。"
disable: 禁用
disabled: 已禁用
enable: 启用
@@ -400,14 +400,14 @@ zh-CN:
desc_html: 用于在首页展示。推荐分辨率 293×205px 以上。未指定的情况下将使用默认吉祥物。
title: 吉祥物图像
peers_api_enabled:
- desc_html: 截至目前本实例在网络中已发现的域名
+ desc_html: 截至目前本服务器在联邦宇宙中已发现的域名
title: 公开已知实例的列表
preview_sensitive_media:
desc_html: 始终在站外链接预览中展示缩略图,无论媒体内容是否标记为敏感
title: 在 OpenGraph 预览中显示敏感媒体内容
profile_directory:
- desc_html: 允许用户可被发现
- title: 启用用户资料目录
+ desc_html: 允许用户被发现
+ title: 启用用户目录
registrations:
closed_message:
desc_html: 本站关闭注册期间的提示信息。可以使用 HTML 标签
@@ -463,20 +463,13 @@ zh-CN:
no_status_selected: 因为没有嘟文被选中,所以没有更改
title: 帐户嘟文
with_media: 含有媒体文件
- subscriptions:
- callback_url: 回调 URL
- confirmed: 已确认
- expires_in: 失效时间
- last_delivery: 最后一次接收数据的时间
- title: WebSub
- topic: 话题
tags:
accounts: 帐户
hidden: 隐藏
- hide: 从目录隐藏
+ hide: 从用户目录中隐藏
name: 话题标签
title: 话题标签
- unhide: 在目录中显示
+ unhide: 在用户目录中显示
visible: 可见
title: 管理
warning_presets:
@@ -573,12 +566,12 @@ zh-CN:
warning_html: 我们只能保证本服务器上的内容将会被彻底删除。对于已经被广泛传播的内容,它们在本服务器以外的某些地方可能仍然可见。此外,失去连接的服务器以及停止接收订阅的服务器所存储的数据亦无法删除。
warning_title: 关于已传播的内容的警告
directories:
- directory: 用户资料目录
- enabled: 您目前已被列入目录中。
- enabled_but_waiting: 您已选择列入目录,但是您没有达到关注者数量下限 (%{min_followers} 名) 。
+ directory: 用户目录
+ enabled: 您已被收录在用户目录中。
+ enabled_but_waiting: 你已选择将账号收录到用户目录中,但是你的关注者不足 (%{min_followers}) 人 。
explanation: 根据兴趣发现用户
explore_mastodon: 探索 %{title}
- how_to_enable: 您目前没有选择选择列入到目录中。您可以在下面选择列入。可以在个人简介中加上话题标签,话题标签也会显示在用户资料目录里!
+ how_to_enable: 您目前没有被收录到用户目录中。您可以在下面选择收录。在个人简介中加上话题标签后,话题标签也会显示在用户目录上!
people:
other: "%{count} 人"
errors:
@@ -748,6 +741,7 @@ zh-CN:
number:
human:
decimal_units:
+ format: "%n%u"
units:
billion: B
million: M
@@ -759,6 +753,7 @@ zh-CN:
next: 下一页
older: 更早
prev: 上一页
+ truncate: "…"
polls:
errors:
already_voted: 你已经在这里投过票了
@@ -803,10 +798,6 @@ zh-CN:
reply:
proceed: 确认回复
prompt: 您想要回复此嘟文:
- remote_unfollow:
- error: 错误
- title: 标题
- unfollowed: 已取消关注
scheduled_statuses:
over_daily_limit: 您已超出每日定时嘟文的上限(%{limit} 条)
over_total_limit: 您已超出定时嘟文的上限(%{limit} 条)
@@ -870,7 +861,7 @@ zh-CN:
notifications: 通知
preferences: 首选项
profile: 个人资料
- relationships: 正在关注以及关注者
+ relationships: 关注管理
two_factor_authentication: 双重认证
statuses:
attached:
@@ -910,6 +901,87 @@ zh-CN:
reblogged: 转嘟
sensitive_content: 敏感内容
terms:
+ body_html: |
+
title: "%{instance} 使用条款和隐私权政策"
themes:
contrast: Mastodon(高对比度)
@@ -945,7 +1017,7 @@ zh-CN:
disable: 虽然您的帐户被冻结,您的帐户数据仍然完整;但是您无法在解锁前执行任何操作。
silence: 当您的帐户受限时,只有已经关注过你的人才会这台服务器上看到你的嘟文,并且您会被排除在各种公共列表之外。但是,其他人仍然可以手动关注你。
suspend: 您的帐户已被封禁,所有的嘟文和您上传的媒体文件都已经从该服务器和您的关注者的服务器上删除并且不可恢复。
- review_server_policies: 审阅服务器条款
+ review_server_policies: 查看服务器政策
subject:
disable: 您的帐户 %{acct} 已被冻结
none: 对 %{acct} 的警告
diff --git a/config/locales/zh-HK.yml b/config/locales/zh-HK.yml
index 25e7475a88..520771da4a 100644
--- a/config/locales/zh-HK.yml
+++ b/config/locales/zh-HK.yml
@@ -327,13 +327,6 @@ zh-HK:
no_media: 不含媒體檔案
title: 帳戶文章
with_media: 含有媒體檔案
- subscriptions:
- callback_url: 回傳 URL
- confirmed: 確定
- expires_in: 期限
- last_delivery: 資料最後送抵時間
- title: PuSH 訂閱
- topic: 所訂閱資源
title: 管理
admin_mailer:
new_report:
@@ -524,10 +517,6 @@ zh-HK:
missing_resource: 無法找到你用戶的轉接網址
proceed: 下一步
prompt: 你希望關注︰
- remote_unfollow:
- error: 錯誤
- title: 標題
- unfollowed: 取消關注
sessions:
activity: 最近活動
browser: 瀏覽器
diff --git a/config/locales/zh-TW.yml b/config/locales/zh-TW.yml
index d3dcf5133f..801ea7cead 100644
--- a/config/locales/zh-TW.yml
+++ b/config/locales/zh-TW.yml
@@ -401,13 +401,6 @@ zh-TW:
no_media: 不含媒體檔案
title: 帳戶嘟文
with_media: 含有媒體檔案
- subscriptions:
- callback_url: 回傳網址
- confirmed: 已確認
- expires_in: 期限
- last_delivery: 最後遞送
- title: WebSub 訂閱
- topic: 主題
title: 管理介面
admin_mailer:
new_report:
@@ -587,10 +580,6 @@ zh-TW:
missing_resource: 無法找到資源
proceed: 下一步
prompt: '您希望關注:'
- remote_unfollow:
- error: 錯誤
- title: 標題
- unfollowed: 取消關注
sessions:
activity: 最近活動
browser: 瀏覽器
diff --git a/config/navigation.rb b/config/navigation.rb
index e8494ddc25..52d41f72f9 100644
--- a/config/navigation.rb
+++ b/config/navigation.rb
@@ -54,7 +54,6 @@ SimpleNavigation::Configuration.run do |navigation|
s.item :settings, safe_join([fa_icon('cogs fw'), t('admin.settings.title')]), edit_admin_settings_url, if: -> { current_user.admin? }, highlights_on: %r{/admin/settings}
s.item :custom_emojis, safe_join([fa_icon('smile-o fw'), t('admin.custom_emojis.title')]), admin_custom_emojis_url, highlights_on: %r{/admin/custom_emojis}
s.item :relays, safe_join([fa_icon('exchange fw'), t('admin.relays.title')]), admin_relays_url, if: -> { current_user.admin? }, highlights_on: %r{/admin/relays}
- s.item :subscriptions, safe_join([fa_icon('paper-plane-o fw'), t('admin.subscriptions.title')]), admin_subscriptions_url, if: -> { current_user.admin? }
s.item :sidekiq, safe_join([fa_icon('diamond fw'), 'Sidekiq']), sidekiq_url, link_html: { target: 'sidekiq' }, if: -> { current_user.admin? }
s.item :pghero, safe_join([fa_icon('database fw'), 'PgHero']), pghero_url, link_html: { target: 'pghero' }, if: -> { current_user.admin? }
end
diff --git a/config/routes.rb b/config/routes.rb
index 1b88fe5e3e..66be635a51 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -28,6 +28,10 @@ Rails.application.routes.draw do
get 'intent', to: 'intents#show'
get 'custom.css', to: 'custom_css#show', as: :custom_css
+ resource :instance_actor, path: 'actor', only: [:show] do
+ resource :inbox, only: [:create], module: :activitypub
+ end
+
devise_scope :user do
get '/invite/:invite_code', to: 'auth/registrations#new', as: :public_invite
match '/auth/finish_signup' => 'auth/confirmations#finish_signup', via: [:get, :patch], as: :finish_signup
@@ -45,12 +49,6 @@ Rails.application.routes.draw do
get '/authorize_follow', to: redirect { |_, request| "/authorize_interaction?#{request.params.to_query}" }
resources :accounts, path: 'users', only: [:show], param: :username do
- resources :stream_entries, path: 'updates', only: [:show] do
- member do
- get :embed
- end
- end
-
get :remote_follow, to: 'remote_follow#new'
post :remote_follow, to: 'remote_follow#create'
@@ -58,8 +56,9 @@ Rails.application.routes.draw do
member do
get :activity
get :embed
- get :replies
end
+
+ resources :replies, only: [:index], module: :activitypub
end
resources :followers, only: [:index], controller: :follower_accounts
@@ -148,15 +147,12 @@ Rails.application.routes.draw do
get '/public', to: 'public_timelines#show', as: :public_timeline
get '/media_proxy/:id/(*any)', to: 'media_proxy#show', as: :media_proxy
- # Remote follow
- resource :remote_unfollow, only: [:create]
resource :authorize_interaction, only: [:show, :create]
resource :share, only: [:show, :create]
namespace :admin do
get '/dashboard', to: 'dashboard#index'
- resources :subscriptions, only: [:index]
resources :domain_blocks, only: [:new, :create, :show, :destroy]
resources :email_domain_blocks, only: [:index, :new, :create, :destroy]
resources :action_logs, only: [:index]
@@ -193,8 +189,6 @@ Rails.application.routes.draw do
resources :accounts, only: [:index, :show] do
member do
- post :subscribe
- post :unsubscribe
post :enable
post :unsilence
post :unsuspend
@@ -259,16 +253,6 @@ Rails.application.routes.draw do
get '/admin', to: redirect('/admin/dashboard', status: 302)
namespace :api do
- # PubSubHubbub outgoing subscriptions
- resources :subscriptions, only: [:show]
- post '/subscriptions/:id', to: 'subscriptions#update'
-
- # PubSubHubbub incoming subscriptions
- post '/push', to: 'push#update', as: :push
-
- # Salmon
- post '/salmon/:id', to: 'salmon#update', as: :salmon
-
# OEmbed
get '/oembed', to: 'oembed#show', as: :oembed
@@ -324,7 +308,6 @@ Rails.application.routes.draw do
get '/search', to: 'search#index', as: :search
- resources :follows, only: [:create]
resources :media, only: [:create, :update]
resources :blocks, only: [:index]
resources :mutes, only: [:index] do
diff --git a/config/settings.yml b/config/settings.yml
index bc97f650b6..328a25a5ad 100644
--- a/config/settings.yml
+++ b/config/settings.yml
@@ -68,6 +68,7 @@ defaults: &defaults
show_reblogs_in_public_timelines: false
show_replies_in_public_timelines: false
default_content_type: 'text/plain'
+ spam_check_enabled: true
development:
<<: *defaults
diff --git a/config/sidekiq.yml b/config/sidekiq.yml
index 0ec1742abf..5c652792c6 100644
--- a/config/sidekiq.yml
+++ b/config/sidekiq.yml
@@ -9,9 +9,6 @@
scheduled_statuses_scheduler:
every: '5m'
class: Scheduler::ScheduledStatusesScheduler
- subscriptions_scheduler:
- cron: '<%= Random.rand(0..59) %> <%= Random.rand(4..6) %> * * *'
- class: Scheduler::SubscriptionsScheduler
media_cleanup_scheduler:
cron: '<%= Random.rand(0..59) %> <%= Random.rand(3..5) %> * * *'
class: Scheduler::MediaCleanupScheduler
@@ -30,6 +27,9 @@
ip_cleanup_scheduler:
cron: '<%= Random.rand(0..59) %> <%= Random.rand(3..5) %> * * *'
class: Scheduler::IpCleanupScheduler
+ preview_cards_cleanup_scheduler:
+ cron: '<%= Random.rand(0..59) %> <%= Random.rand(3..5) %> * * *'
+ class: Scheduler::PreviewCardsCleanupScheduler
email_scheduler:
cron: '0 10 * * 2'
class: Scheduler::EmailScheduler
diff --git a/db/migrate/20180528141303_fix_accounts_unique_index.rb b/db/migrate/20180528141303_fix_accounts_unique_index.rb
index bd4e158b7e..bbbf28d817 100644
--- a/db/migrate/20180528141303_fix_accounts_unique_index.rb
+++ b/db/migrate/20180528141303_fix_accounts_unique_index.rb
@@ -12,6 +12,11 @@ class FixAccountsUniqueIndex < ActiveRecord::Migration[5.2]
end
end
+ class StreamEntry < ApplicationRecord
+ # Dummy class, to make migration possible across version changes
+ belongs_to :account, inverse_of: :stream_entries
+ end
+
disable_ddl_transaction!
def up
diff --git a/db/migrate/20190701022101_add_trust_level_to_accounts.rb b/db/migrate/20190701022101_add_trust_level_to_accounts.rb
new file mode 100644
index 0000000000..917486d2ed
--- /dev/null
+++ b/db/migrate/20190701022101_add_trust_level_to_accounts.rb
@@ -0,0 +1,5 @@
+class AddTrustLevelToAccounts < ActiveRecord::Migration[5.2]
+ def change
+ add_column :accounts, :trust_level, :integer
+ end
+end
diff --git a/db/migrate/20190715164535_add_instance_actor.rb b/db/migrate/20190715164535_add_instance_actor.rb
new file mode 100644
index 0000000000..a26d549493
--- /dev/null
+++ b/db/migrate/20190715164535_add_instance_actor.rb
@@ -0,0 +1,9 @@
+class AddInstanceActor < ActiveRecord::Migration[5.2]
+ def up
+ Account.create!(id: -99, actor_type: 'Application', locked: true, username: Rails.configuration.x.local_domain)
+ end
+
+ def down
+ Account.find_by(id: -99, actor_type: 'Application').destroy!
+ end
+end
diff --git a/db/post_migrate/20190706233204_drop_stream_entries.rb b/db/post_migrate/20190706233204_drop_stream_entries.rb
new file mode 100644
index 0000000000..1fecece055
--- /dev/null
+++ b/db/post_migrate/20190706233204_drop_stream_entries.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+class DropStreamEntries < ActiveRecord::Migration[5.2]
+ disable_ddl_transaction!
+
+ def up
+ drop_table :stream_entries
+ end
+
+ def down
+ raise ActiveRecord::IrreversibleMigration
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 2e7af9b787..1600878477 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 2019_06_27_222826) do
+ActiveRecord::Schema.define(version: 2019_07_15_164535) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -148,6 +148,7 @@ ActiveRecord::Schema.define(version: 2019_06_27_222826) do
t.string "also_known_as", array: true
t.datetime "silenced_at"
t.datetime "suspended_at"
+ t.integer "trust_level"
t.index "(((setweight(to_tsvector('simple'::regconfig, (display_name)::text), 'A'::\"char\") || setweight(to_tsvector('simple'::regconfig, (username)::text), 'B'::\"char\")) || setweight(to_tsvector('simple'::regconfig, (COALESCE(domain, ''::character varying))::text), 'C'::\"char\")))", name: "search_index", using: :gin
t.index "lower((username)::text), lower((domain)::text)", name: "index_accounts_on_username_and_domain_lower", unique: true
t.index ["moved_to_account_id"], name: "index_accounts_on_moved_to_account_id"
@@ -660,17 +661,6 @@ ActiveRecord::Schema.define(version: 2019_06_27_222826) do
t.index ["tag_id", "status_id"], name: "index_statuses_tags_on_tag_id_and_status_id", unique: true
end
- create_table "stream_entries", force: :cascade do |t|
- t.bigint "activity_id"
- t.string "activity_type"
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.boolean "hidden", default: false, null: false
- t.bigint "account_id"
- t.index ["account_id", "activity_type", "id"], name: "index_stream_entries_on_account_id_and_activity_type_and_id"
- t.index ["activity_id", "activity_type"], name: "index_stream_entries_on_activity_id_and_activity_type"
- end
-
create_table "subscriptions", force: :cascade do |t|
t.string "callback_url", default: "", null: false
t.string "secret"
@@ -846,7 +836,6 @@ ActiveRecord::Schema.define(version: 2019_06_27_222826) do
add_foreign_key "statuses", "statuses", column: "reblog_of_id", on_delete: :cascade
add_foreign_key "statuses_tags", "statuses", on_delete: :cascade
add_foreign_key "statuses_tags", "tags", name: "fk_3081861e21", on_delete: :cascade
- add_foreign_key "stream_entries", "accounts", name: "fk_5659b17554", on_delete: :cascade
add_foreign_key "subscriptions", "accounts", name: "fk_9847d1cbb5", on_delete: :cascade
add_foreign_key "tombstones", "accounts", on_delete: :cascade
add_foreign_key "user_invite_requests", "users", on_delete: :cascade
diff --git a/db/seeds.rb b/db/seeds.rb
index 9a6e9dd78e..5f43fbac8b 100644
--- a/db/seeds.rb
+++ b/db/seeds.rb
@@ -1,7 +1,9 @@
Doorkeeper::Application.create!(name: 'Web', superapp: true, redirect_uri: Doorkeeper.configuration.native_redirect_uri, scopes: 'read write follow')
+domain = ENV['LOCAL_DOMAIN'] || Rails.configuration.x.local_domain
+Account.create!(id: -99, actor_type: 'Application', locked: true, username: domain)
+
if Rails.env.development?
- domain = ENV['LOCAL_DOMAIN'] || Rails.configuration.x.local_domain
admin = Account.where(username: 'admin').first_or_initialize(username: 'admin')
admin.save(validate: false)
User.where(email: "admin@#{domain}").first_or_initialize(email: "admin@#{domain}", password: 'mastodonadmin', password_confirmation: 'mastodonadmin', confirmed_at: Time.now.utc, admin: true, account: admin, agreement: true, approved: true).save!
diff --git a/docker-compose.yml b/docker-compose.yml
index f3fe6cfd0b..7406849663 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -38,7 +38,7 @@ services:
image: tootsuite/mastodon
restart: always
env_file: .env.production
- command: bash -c "rm -f /mastodon/tmp/pids/server.pid; bundle exec rails s -p 3000 -b '0.0.0.0'"
+ command: bash -c "rm -f /mastodon/tmp/pids/server.pid; bundle exec rails s -p 3000"
networks:
- external_network
- internal_network
@@ -58,7 +58,7 @@ services:
image: tootsuite/mastodon
restart: always
env_file: .env.production
- command: BIND=0.0.0.0 node ./streaming
+ command: node ./streaming
networks:
- external_network
- internal_network
diff --git a/spec/controllers/accounts_controller_spec.rb b/spec/controllers/accounts_controller_spec.rb
index b728d719f9..3d2a0665da 100644
--- a/spec/controllers/accounts_controller_spec.rb
+++ b/spec/controllers/accounts_controller_spec.rb
@@ -48,37 +48,6 @@ RSpec.describe AccountsController, type: :controller do
end
end
- context 'atom' do
- let(:format) { 'atom' }
- let(:content_type) { 'application/atom+xml' }
-
- shared_examples 'responsed streams' do
- it 'assigns @entries' do
- entries = assigns(:entries).to_a
- expect(entries.size).to eq expected_statuses.size
- entries.each.zip(expected_statuses.each) do |entry, expected_status|
- expect(entry.status).to eq expected_status
- end
- end
- end
-
- include_examples 'responses'
-
- context 'without max_id nor since_id' do
- let(:expected_statuses) { [status7, status6, status5, status4, status3, status2, status1] }
-
- include_examples 'responsed streams'
- end
-
- context 'with max_id and since_id' do
- let(:max_id) { status4.stream_entry.id }
- let(:since_id) { status1.stream_entry.id }
- let(:expected_statuses) { [status3, status2] }
-
- include_examples 'responsed streams'
- end
- end
-
context 'activitystreams2' do
let(:format) { 'json' }
let(:content_type) { 'application/activity+json' }
diff --git a/spec/controllers/activitypub/inboxes_controller_spec.rb b/spec/controllers/activitypub/inboxes_controller_spec.rb
index eab4b8c3e6..a9ee754900 100644
--- a/spec/controllers/activitypub/inboxes_controller_spec.rb
+++ b/spec/controllers/activitypub/inboxes_controller_spec.rb
@@ -4,7 +4,7 @@ require 'rails_helper'
RSpec.describe ActivityPub::InboxesController, type: :controller do
describe 'POST #create' do
- context 'if signed_request_account' do
+ context 'with signed_request_account' do
it 'returns 202' do
allow(controller).to receive(:signed_request_account) do
Fabricate(:account)
@@ -15,7 +15,7 @@ RSpec.describe ActivityPub::InboxesController, type: :controller do
end
end
- context 'not signed_request_account' do
+ context 'without signed_request_account' do
it 'returns 401' do
allow(controller).to receive(:signed_request_account) do
false
diff --git a/spec/controllers/admin/accounts_controller_spec.rb b/spec/controllers/admin/accounts_controller_spec.rb
index a348ab3d75..608606ff90 100644
--- a/spec/controllers/admin/accounts_controller_spec.rb
+++ b/spec/controllers/admin/accounts_controller_spec.rb
@@ -75,44 +75,6 @@ RSpec.describe Admin::AccountsController, type: :controller do
end
end
- describe 'POST #subscribe' do
- subject { post :subscribe, params: { id: account.id } }
-
- let(:current_user) { Fabricate(:user, admin: admin) }
- let(:account) { Fabricate(:account) }
-
- context 'when user is admin' do
- let(:admin) { true }
-
- it { is_expected.to redirect_to admin_account_path(account.id) }
- end
-
- context 'when user is not admin' do
- let(:admin) { false }
-
- it { is_expected.to have_http_status :forbidden }
- end
- end
-
- describe 'POST #unsubscribe' do
- subject { post :unsubscribe, params: { id: account.id } }
-
- let(:current_user) { Fabricate(:user, admin: admin) }
- let(:account) { Fabricate(:account) }
-
- context 'when user is admin' do
- let(:admin) { true }
-
- it { is_expected.to redirect_to admin_account_path(account.id) }
- end
-
- context 'when user is not admin' do
- let(:admin) { false }
-
- it { is_expected.to have_http_status :forbidden }
- end
- end
-
describe 'POST #memorialize' do
subject { post :memorialize, params: { id: account.id } }
diff --git a/spec/controllers/admin/subscriptions_controller_spec.rb b/spec/controllers/admin/subscriptions_controller_spec.rb
deleted file mode 100644
index 967152abe3..0000000000
--- a/spec/controllers/admin/subscriptions_controller_spec.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-# frozen_string_literal: true
-require 'rails_helper'
-
-RSpec.describe Admin::SubscriptionsController, type: :controller do
- render_views
-
- describe 'GET #index' do
- around do |example|
- default_per_page = Subscription.default_per_page
- Subscription.paginates_per 1
- example.run
- Subscription.paginates_per default_per_page
- end
-
- before do
- sign_in Fabricate(:user, admin: true), scope: :user
- end
-
- it 'renders subscriptions' do
- Fabricate(:subscription)
- specified = Fabricate(:subscription)
-
- get :index
-
- subscriptions = assigns(:subscriptions)
- expect(subscriptions.count).to eq 1
- expect(subscriptions[0]).to eq specified
-
- expect(response).to have_http_status(200)
- end
- end
-end
diff --git a/spec/controllers/api/oembed_controller_spec.rb b/spec/controllers/api/oembed_controller_spec.rb
index 7fee15a353..b9082bde1e 100644
--- a/spec/controllers/api/oembed_controller_spec.rb
+++ b/spec/controllers/api/oembed_controller_spec.rb
@@ -9,7 +9,7 @@ RSpec.describe Api::OEmbedController, type: :controller do
describe 'GET #show' do
before do
request.host = Rails.configuration.x.local_domain
- get :show, params: { url: account_stream_entry_url(alice, status.stream_entry) }, format: :json
+ get :show, params: { url: short_account_status_url(alice, status) }, format: :json
end
it 'returns http success' do
diff --git a/spec/controllers/api/push_controller_spec.rb b/spec/controllers/api/push_controller_spec.rb
deleted file mode 100644
index d769d8554f..0000000000
--- a/spec/controllers/api/push_controller_spec.rb
+++ /dev/null
@@ -1,59 +0,0 @@
-require 'rails_helper'
-
-RSpec.describe Api::PushController, type: :controller do
- describe 'POST #update' do
- context 'with hub.mode=subscribe' do
- it 'creates a subscription' do
- service = double(call: ['', 202])
- allow(Pubsubhubbub::SubscribeService).to receive(:new).and_return(service)
- account = Fabricate(:account)
- account_topic_url = "https://#{Rails.configuration.x.local_domain}/users/#{account.username}.atom"
- post :update, params: {
- 'hub.mode' => 'subscribe',
- 'hub.topic' => account_topic_url,
- 'hub.callback' => 'https://callback.host/api',
- 'hub.lease_seconds' => '3600',
- 'hub.secret' => 'as1234df',
- }
-
- expect(service).to have_received(:call).with(
- account,
- 'https://callback.host/api',
- 'as1234df',
- '3600',
- nil
- )
- expect(response).to have_http_status(202)
- end
- end
-
- context 'with hub.mode=unsubscribe' do
- it 'unsubscribes the account' do
- service = double(call: ['', 202])
- allow(Pubsubhubbub::UnsubscribeService).to receive(:new).and_return(service)
- account = Fabricate(:account)
- account_topic_url = "https://#{Rails.configuration.x.local_domain}/users/#{account.username}.atom"
- post :update, params: {
- 'hub.mode' => 'unsubscribe',
- 'hub.topic' => account_topic_url,
- 'hub.callback' => 'https://callback.host/api',
- }
-
- expect(service).to have_received(:call).with(
- account,
- 'https://callback.host/api',
- )
- expect(response).to have_http_status(202)
- end
- end
-
- context 'with unknown mode' do
- it 'returns an unknown mode error' do
- post :update, params: { 'hub.mode' => 'fake' }
-
- expect(response).to have_http_status(422)
- expect(response.body).to match(/Unknown mode/)
- end
- end
- end
-end
diff --git a/spec/controllers/api/salmon_controller_spec.rb b/spec/controllers/api/salmon_controller_spec.rb
deleted file mode 100644
index 235a29af00..0000000000
--- a/spec/controllers/api/salmon_controller_spec.rb
+++ /dev/null
@@ -1,65 +0,0 @@
-require 'rails_helper'
-
-RSpec.describe Api::SalmonController, type: :controller do
- render_views
-
- let(:account) { Fabricate(:user, account: Fabricate(:account, username: 'catsrgr8')).account }
-
- before do
- stub_request(:get, "https://quitter.no/.well-known/host-meta").to_return(request_fixture('.host-meta.txt'))
- stub_request(:get, "https://quitter.no/.well-known/webfinger?resource=acct:gargron@quitter.no").to_return(request_fixture('webfinger.txt'))
- stub_request(:get, "https://quitter.no/api/statuses/user_timeline/7477.atom").to_return(request_fixture('feed.txt'))
- stub_request(:get, "https://quitter.no/avatar/7477-300-20160211190340.png").to_return(request_fixture('avatar.txt'))
- end
-
- describe 'POST #update' do
- context 'with valid post data' do
- before do
- post :update, params: { id: account.id }, body: File.read(Rails.root.join('spec', 'fixtures', 'salmon', 'mention.xml'))
- end
-
- it 'contains XML in the request body' do
- expect(request.body.read).to be_a String
- end
-
- it 'returns http success' do
- expect(response).to have_http_status(202)
- end
-
- it 'creates remote account' do
- expect(Account.find_by(username: 'gargron', domain: 'quitter.no')).to_not be_nil
- end
-
- it 'creates status' do
- expect(Status.find_by(uri: 'tag:quitter.no,2016-03-20:noticeId=1276923:objectType=note')).to_not be_nil
- end
-
- it 'creates mention for target account' do
- expect(account.mentions.count).to eq 1
- end
- end
-
- context 'with empty post data' do
- before do
- post :update, params: { id: account.id }, body: ''
- end
-
- it 'returns http client error' do
- expect(response).to have_http_status(400)
- end
- end
-
- context 'with invalid post data' do
- before do
- service = double(call: false)
- allow(VerifySalmonService).to receive(:new).and_return(service)
-
- post :update, params: { id: account.id }, body: File.read(Rails.root.join('spec', 'fixtures', 'salmon', 'mention.xml'))
- end
-
- it 'returns http client error' do
- expect(response).to have_http_status(401)
- end
- end
- end
-end
diff --git a/spec/controllers/api/subscriptions_controller_spec.rb b/spec/controllers/api/subscriptions_controller_spec.rb
deleted file mode 100644
index 7a4252fe67..0000000000
--- a/spec/controllers/api/subscriptions_controller_spec.rb
+++ /dev/null
@@ -1,68 +0,0 @@
-require 'rails_helper'
-
-RSpec.describe Api::SubscriptionsController, type: :controller do
- render_views
-
- let(:account) { Fabricate(:account, username: 'gargron', domain: 'quitter.no', remote_url: 'topic_url', secret: 'abc') }
-
- describe 'GET #show' do
- context 'with valid subscription' do
- before do
- get :show, params: { :id => account.id, 'hub.topic' => 'topic_url', 'hub.challenge' => '456', 'hub.lease_seconds' => "#{86400 * 30}" }
- end
-
- it 'returns http success' do
- expect(response).to have_http_status(200)
- end
-
- it 'echoes back the challenge' do
- expect(response.body).to match '456'
- end
- end
-
- context 'with invalid subscription' do
- before do
- expect_any_instance_of(Account).to receive_message_chain(:subscription, :valid?).and_return(false)
- get :show, params: { :id => account.id }
- end
-
- it 'returns http success' do
- expect(response).to have_http_status(404)
- end
- end
- end
-
- describe 'POST #update' do
- let(:feed) { File.read(Rails.root.join('spec', 'fixtures', 'push', 'feed.atom')) }
-
- before do
- stub_request(:post, "https://quitter.no/main/push/hub").to_return(:status => 200, :body => "", :headers => {})
- stub_request(:get, "https://quitter.no/avatar/7477-300-20160211190340.png").to_return(request_fixture('avatar.txt'))
- stub_request(:get, "https://quitter.no/notice/1269244").to_return(status: 404)
- stub_request(:get, "https://quitter.no/notice/1265331").to_return(status: 404)
- stub_request(:get, "https://community.highlandarrow.com/notice/54411").to_return(status: 404)
- stub_request(:get, "https://community.highlandarrow.com/notice/53857").to_return(status: 404)
- stub_request(:get, "https://community.highlandarrow.com/notice/51852").to_return(status: 404)
- stub_request(:get, "https://social.umeahackerspace.se/notice/424348").to_return(status: 404)
- stub_request(:get, "https://community.highlandarrow.com/notice/50467").to_return(status: 404)
- stub_request(:get, "https://quitter.no/notice/1243309").to_return(status: 404)
- stub_request(:get, "https://quitter.no/user/7477").to_return(status: 404)
- stub_request(:any, "https://community.highlandarrow.com/user/1").to_return(status: 404)
- stub_request(:any, "https://social.umeahackerspace.se/user/2").to_return(status: 404)
- stub_request(:any, "https://gs.kawa-kun.com/user/2").to_return(status: 404)
- stub_request(:any, "https://mastodon.social/users/Gargron").to_return(status: 404)
-
- request.env['HTTP_X_HUB_SIGNATURE'] = "sha1=#{OpenSSL::HMAC.hexdigest('sha1', 'abc', feed)}"
-
- post :update, params: { id: account.id }, body: feed
- end
-
- it 'returns http success' do
- expect(response).to have_http_status(200)
- end
-
- it 'creates statuses for feed' do
- expect(account.statuses.count).to_not eq 0
- end
- end
-end
diff --git a/spec/controllers/api/v1/follows_controller_spec.rb b/spec/controllers/api/v1/follows_controller_spec.rb
deleted file mode 100644
index 089e0fe5ec..0000000000
--- a/spec/controllers/api/v1/follows_controller_spec.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-require 'rails_helper'
-
-RSpec.describe Api::V1::FollowsController, type: :controller do
- render_views
-
- let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }
- let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'write:follows') }
-
- before do
- allow(controller).to receive(:doorkeeper_token) { token }
- end
-
- describe 'POST #create' do
- before do
- stub_request(:get, "https://quitter.no/.well-known/host-meta").to_return(request_fixture('.host-meta.txt'))
- stub_request(:get, "https://quitter.no/.well-known/webfinger?resource=acct:gargron@quitter.no").to_return(request_fixture('webfinger.txt'))
- stub_request(:head, "https://quitter.no/api/statuses/user_timeline/7477.atom").to_return(:status => 405, :body => "", :headers => {})
- stub_request(:get, "https://quitter.no/api/statuses/user_timeline/7477.atom").to_return(request_fixture('feed.txt'))
- stub_request(:get, "https://quitter.no/avatar/7477-300-20160211190340.png").to_return(request_fixture('avatar.txt'))
- stub_request(:post, "https://quitter.no/main/push/hub").to_return(:status => 200, :body => "", :headers => {})
- stub_request(:post, "https://quitter.no/main/salmon/user/7477").to_return(:status => 200, :body => "", :headers => {})
-
- post :create, params: { uri: 'gargron@quitter.no' }
- end
-
- it 'returns http success' do
- expect(response).to have_http_status(200)
- end
-
- it 'creates account for remote user' do
- expect(Account.find_by(username: 'gargron', domain: 'quitter.no')).to_not be_nil
- end
-
- it 'creates a follow relation between user and remote user' do
- expect(user.account.following?(Account.find_by(username: 'gargron', domain: 'quitter.no'))).to be true
- end
-
- it 'sends a salmon slap to the remote user' do
- expect(a_request(:post, "https://quitter.no/main/salmon/user/7477")).to have_been_made
- end
-
- it 'subscribes to remote hub' do
- expect(a_request(:post, "https://quitter.no/main/push/hub")).to have_been_made
- end
-
- it 'returns http success if already following, too' do
- post :create, params: { uri: 'gargron@quitter.no' }
- expect(response).to have_http_status(200)
- end
- end
-end
diff --git a/spec/controllers/application_controller_spec.rb b/spec/controllers/application_controller_spec.rb
index ea443b80cb..99015c82d7 100644
--- a/spec/controllers/application_controller_spec.rb
+++ b/spec/controllers/application_controller_spec.rb
@@ -364,9 +364,5 @@ describe ApplicationController, type: :controller do
context 'Status' do
include_examples 'cacheable', :status, Status
end
-
- context 'StreamEntry' do
- include_examples 'receives :with_includes', :stream_entry, StreamEntry
- end
end
end
diff --git a/spec/controllers/concerns/account_controller_concern_spec.rb b/spec/controllers/concerns/account_controller_concern_spec.rb
index ea2b4a2a1d..7ea214a7d3 100644
--- a/spec/controllers/concerns/account_controller_concern_spec.rb
+++ b/spec/controllers/concerns/account_controller_concern_spec.rb
@@ -41,7 +41,7 @@ describe ApplicationController, type: :controller do
it 'sets link headers' do
account = Fabricate(:account, username: 'username', user: Fabricate(:user))
get 'success', params: { account_username: 'username' }
- expect(response.headers['Link'].to_s).to eq '; rel="lrdd"; type="application/xrd+xml", ; rel="alternate"; type="application/atom+xml", ; rel="alternate"; type="application/activity+json"'
+ expect(response.headers['Link'].to_s).to eq '; rel="lrdd"; type="application/jrd+json", ; rel="alternate"; type="application/activity+json"'
end
it 'returns http success' do
diff --git a/spec/controllers/concerns/signature_verification_spec.rb b/spec/controllers/concerns/signature_verification_spec.rb
index 7206900971..1fa19f54d7 100644
--- a/spec/controllers/concerns/signature_verification_spec.rb
+++ b/spec/controllers/concerns/signature_verification_spec.rb
@@ -38,7 +38,7 @@ describe ApplicationController, type: :controller do
end
context 'with signature header' do
- let!(:author) { Fabricate(:account) }
+ let!(:author) { Fabricate(:account, domain: 'example.com', uri: 'https://example.com/actor') }
context 'without body' do
before do
diff --git a/spec/controllers/remote_unfollows_controller_spec.rb b/spec/controllers/remote_unfollows_controller_spec.rb
deleted file mode 100644
index a1a55ede0b..0000000000
--- a/spec/controllers/remote_unfollows_controller_spec.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-# frozen_string_literal: true
-
-require 'rails_helper'
-
-describe RemoteUnfollowsController do
- render_views
-
- describe '#create' do
- subject { post :create, params: { acct: acct } }
-
- let(:current_user) { Fabricate(:user, account: current_account) }
- let(:current_account) { Fabricate(:account) }
- let(:remote_account) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox')).account }
- before do
- sign_in current_user
- current_account.follow!(remote_account)
- stub_request(:post, 'http://example.com/inbox') { { status: 200 } }
- end
-
- context 'when successfully unfollow remote account' do
- let(:acct) { "acct:#{remote_account.username}@#{remote_account.domain}" }
-
- it do
- is_expected.to render_template :success
- expect(current_account.following?(remote_account)).to be false
- end
- end
-
- context 'when fails to unfollow remote account' do
- let(:acct) { "acct:#{remote_account.username + '_test'}@#{remote_account.domain}" }
-
- it do
- is_expected.to render_template :error
- expect(current_account.following?(remote_account)).to be true
- end
- end
- end
-end
diff --git a/spec/controllers/statuses_controller_spec.rb b/spec/controllers/statuses_controller_spec.rb
index 1bb6636c60..6905dae10e 100644
--- a/spec/controllers/statuses_controller_spec.rb
+++ b/spec/controllers/statuses_controller_spec.rb
@@ -55,18 +55,6 @@ describe StatusesController do
expect(assigns(:status)).to eq status
end
- it 'assigns @stream_entry' do
- status = Fabricate(:status)
- get :show, params: { account_username: status.account.username, id: status.id }
- expect(assigns(:stream_entry)).to eq status.stream_entry
- end
-
- it 'assigns @type' do
- status = Fabricate(:status)
- get :show, params: { account_username: status.account.username, id: status.id }
- expect(assigns(:type)).to eq 'status'
- end
-
it 'assigns @ancestors for ancestors of the status if it is a reply' do
ancestor = Fabricate(:status)
status = Fabricate(:status, in_reply_to_id: ancestor.id)
@@ -104,7 +92,7 @@ describe StatusesController do
end
it 'assigns @max_descendant_thread_id for the last thread if it is hitting the status limit' do
- stub_const 'StatusesController::DESCENDANTS_LIMIT', 1
+ stub_const 'StatusControllerConcern::DESCENDANTS_LIMIT', 1
status = Fabricate(:status)
child = Fabricate(:status, in_reply_to_id: status.id)
@@ -115,7 +103,7 @@ describe StatusesController do
end
it 'assigns @descendant_threads for threads with :next_status key if they are hitting the depth limit' do
- stub_const 'StatusesController::DESCENDANTS_DEPTH_LIMIT', 2
+ stub_const 'StatusControllerConcern::DESCENDANTS_DEPTH_LIMIT', 2
status = Fabricate(:status)
child0 = Fabricate(:status, in_reply_to_id: status.id)
child1 = Fabricate(:status, in_reply_to_id: child0.id)
@@ -135,10 +123,10 @@ describe StatusesController do
expect(response).to have_http_status(200)
end
- it 'renders stream_entries/show' do
+ it 'renders statuses/show' do
status = Fabricate(:status)
get :show, params: { account_username: status.account.username, id: status.id }
- expect(response).to render_template 'stream_entries/show'
+ expect(response).to render_template 'statuses/show'
end
end
end
diff --git a/spec/controllers/stream_entries_controller_spec.rb b/spec/controllers/stream_entries_controller_spec.rb
deleted file mode 100644
index eb7fdf9d78..0000000000
--- a/spec/controllers/stream_entries_controller_spec.rb
+++ /dev/null
@@ -1,95 +0,0 @@
-require 'rails_helper'
-
-RSpec.describe StreamEntriesController, type: :controller do
- render_views
-
- shared_examples 'before_action' do |route|
- context 'when account is not suspended and stream_entry is available' do
- it 'assigns instance variables' do
- status = Fabricate(:status)
-
- get route, params: { account_username: status.account.username, id: status.stream_entry.id }
-
- expect(assigns(:account)).to eq status.account
- expect(assigns(:stream_entry)).to eq status.stream_entry
- expect(assigns(:type)).to eq 'status'
- end
-
- it 'sets Link headers' do
- alice = Fabricate(:account, username: 'alice')
- status = Fabricate(:status, account: alice)
-
- get route, params: { account_username: alice.username, id: status.stream_entry.id }
-
- expect(response.headers['Link'].to_s).to eq "; rel=\"alternate\"; type=\"application/atom+xml\", ; rel=\"alternate\"; type=\"application/activity+json\""
- end
- end
-
- context 'when account is suspended' do
- it 'returns http status 410' do
- account = Fabricate(:account, suspended: true)
- status = Fabricate(:status, account: account)
-
- get route, params: { account_username: account.username, id: status.stream_entry.id }
-
- expect(response).to have_http_status(410)
- end
- end
-
- context 'when activity is nil' do
- it 'raises ActiveRecord::RecordNotFound' do
- account = Fabricate(:account)
- stream_entry = Fabricate.build(:stream_entry, account: account, activity: nil, activity_type: 'Status')
- stream_entry.save!(validate: false)
-
- get route, params: { account_username: account.username, id: stream_entry.id }
-
- expect(response).to have_http_status(404)
- end
- end
-
- context 'when it is hidden and it is not permitted' do
- it 'raises ActiveRecord::RecordNotFound' do
- status = Fabricate(:status)
- user = Fabricate(:user)
- status.account.block!(user.account)
- status.stream_entry.update!(hidden: true)
-
- sign_in(user)
- get route, params: { account_username: status.account.username, id: status.stream_entry.id }
-
- expect(response).to have_http_status(404)
- end
- end
- end
-
- describe 'GET #show' do
- include_examples 'before_action', :show
-
- it 'redirects to status page' do
- status = Fabricate(:status)
-
- get :show, params: { account_username: status.account.username, id: status.stream_entry.id }
-
- expect(response).to redirect_to(short_account_status_url(status.account, status))
- end
-
- it 'returns http success with Atom' do
- status = Fabricate(:status)
- get :show, params: { account_username: status.account.username, id: status.stream_entry.id }, format: 'atom'
- expect(response).to have_http_status(200)
- end
- end
-
- describe 'GET #embed' do
- include_examples 'before_action', :embed
-
- it 'redirects to new embed page' do
- status = Fabricate(:status)
-
- get :embed, params: { account_username: status.account.username, id: status.stream_entry.id }
-
- expect(response).to redirect_to(embed_short_account_status_url(status.account, status))
- end
- end
-end
diff --git a/spec/fabricators/stream_entry_fabricator.rb b/spec/fabricators/stream_entry_fabricator.rb
deleted file mode 100644
index f33822c7c5..0000000000
--- a/spec/fabricators/stream_entry_fabricator.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-Fabricator(:stream_entry) do
- account
- activity { Fabricate(:status) }
- hidden { [true, false].sample }
-end
diff --git a/spec/fixtures/requests/webfinger.txt b/spec/fixtures/requests/webfinger.txt
index edb8a2dbb5..f337ecae6f 100644
--- a/spec/fixtures/requests/webfinger.txt
+++ b/spec/fixtures/requests/webfinger.txt
@@ -8,4 +8,4 @@ Access-Control-Allow-Origin: *
Vary: Accept-Encoding,Cookie
Strict-Transport-Security: max-age=31536000; includeSubdomains;
-{"subject":"acct:gargron@quitter.no","aliases":["https:\/\/quitter.no\/user\/7477","https:\/\/quitter.no\/gargron","https:\/\/quitter.no\/index.php\/user\/7477","https:\/\/quitter.no\/index.php\/gargron"],"links":[{"rel":"http:\/\/webfinger.net\/rel\/profile-page","type":"text\/html","href":"https:\/\/quitter.no\/gargron"},{"rel":"http:\/\/gmpg.org\/xfn\/11","type":"text\/html","href":"https:\/\/quitter.no\/gargron"},{"rel":"describedby","type":"application\/rdf+xml","href":"https:\/\/quitter.no\/gargron\/foaf"},{"rel":"http:\/\/apinamespace.org\/atom","type":"application\/atomsvc+xml","href":"https:\/\/quitter.no\/api\/statusnet\/app\/service\/gargron.xml"},{"rel":"http:\/\/apinamespace.org\/twitter","href":"https:\/\/quitter.no\/api\/"},{"rel":"http:\/\/specs.openid.net\/auth\/2.0\/provider","href":"https:\/\/quitter.no\/gargron"},{"rel":"http:\/\/schemas.google.com\/g\/2010#updates-from","type":"application\/atom+xml","href":"https:\/\/quitter.no\/api\/statuses\/user_timeline\/7477.atom"},{"rel":"magic-public-key","href":"data:application\/magic-public-key,RSA.1ZBkHTavLvxH3FzlKv4O6WtlILKRFfNami3_Rcu8EuogtXSYiS-bB6hElZfUCSHbC4uLemOA34PEhz__CDMozax1iI_t8dzjDnh1x0iFSup7pSfW9iXk_WU3Dm74yWWW2jildY41vWgrEstuQ1dJ8vVFfSJ9T_tO4c-T9y8vDI8=.AQAB"},{"rel":"salmon","href":"https:\/\/quitter.no\/main\/salmon\/user\/7477"},{"rel":"http:\/\/salmon-protocol.org\/ns\/salmon-replies","href":"https:\/\/quitter.no\/main\/salmon\/user\/7477"},{"rel":"http:\/\/salmon-protocol.org\/ns\/salmon-mention","href":"https:\/\/quitter.no\/main\/salmon\/user\/7477"},{"rel":"http:\/\/ostatus.org\/schema\/1.0\/subscribe","template":"https:\/\/quitter.no\/main\/ostatussub?profile={uri}"}]}
\ No newline at end of file
+{"subject":"acct:gargron@quitter.no","aliases":["https:\/\/quitter.no\/user\/7477","https:\/\/quitter.no\/gargron","https:\/\/quitter.no\/index.php\/user\/7477","https:\/\/quitter.no\/index.php\/gargron"],"links":[{"rel":"http:\/\/webfinger.net\/rel\/profile-page","type":"text\/html","href":"https:\/\/quitter.no\/gargron"},{"rel":"http:\/\/gmpg.org\/xfn\/11","type":"text\/html","href":"https:\/\/quitter.no\/gargron"},{"rel":"describedby","type":"application\/rdf+xml","href":"https:\/\/quitter.no\/gargron\/foaf"},{"rel":"http:\/\/apinamespace.org\/atom","type":"application\/atomsvc+xml","href":"https:\/\/quitter.no\/api\/statusnet\/app\/service\/gargron.xml"},{"rel":"http:\/\/apinamespace.org\/twitter","href":"https:\/\/quitter.no\/api\/"},{"rel":"http:\/\/specs.openid.net\/auth\/2.0\/provider","href":"https:\/\/quitter.no\/gargron"},{"rel":"http:\/\/schemas.google.com\/g\/2010#updates-from","type":"application\/atom+xml","href":"https:\/\/quitter.no\/api\/statuses\/user_timeline\/7477.atom"},{"rel":"magic-public-key","href":"data:application\/magic-public-key,RSA.1ZBkHTavLvxH3FzlKv4O6WtlILKRFfNami3_Rcu8EuogtXSYiS-bB6hElZfUCSHbC4uLemOA34PEhz__CDMozax1iI_t8dzjDnh1x0iFSup7pSfW9iXk_WU3Dm74yWWW2jildY41vWgrEstuQ1dJ8vVFfSJ9T_tO4c-T9y8vDI8=.AQAB"},{"rel":"salmon","href":"https:\/\/quitter.no\/main\/salmon\/user\/7477"},{"rel":"http:\/\/salmon-protocol.org\/ns\/salmon-replies","href":"https:\/\/quitter.no\/main\/salmon\/user\/7477"},{"rel":"http:\/\/salmon-protocol.org\/ns\/salmon-mention","href":"https:\/\/quitter.no\/main\/salmon\/user\/7477"},{"rel":"http:\/\/ostatus.org\/schema\/1.0\/subscribe","template":"https:\/\/quitter.no\/main\/ostatussub?profile={uri}"}]}
diff --git a/spec/helpers/admin/account_moderation_notes_helper_spec.rb b/spec/helpers/admin/account_moderation_notes_helper_spec.rb
index c07f6c4b88..ddfe8b46f9 100644
--- a/spec/helpers/admin/account_moderation_notes_helper_spec.rb
+++ b/spec/helpers/admin/account_moderation_notes_helper_spec.rb
@@ -3,7 +3,7 @@
require 'rails_helper'
RSpec.describe Admin::AccountModerationNotesHelper, type: :helper do
- include StreamEntriesHelper
+ include StatusesHelper
describe '#admin_account_link_to' do
context 'account is nil' do
diff --git a/spec/helpers/stream_entries_helper_spec.rb b/spec/helpers/statuses_helper_spec.rb
similarity index 94%
rename from spec/helpers/stream_entries_helper_spec.rb
rename to spec/helpers/statuses_helper_spec.rb
index 845b9974ea..510955a2ff 100644
--- a/spec/helpers/stream_entries_helper_spec.rb
+++ b/spec/helpers/statuses_helper_spec.rb
@@ -1,6 +1,6 @@
require 'rails_helper'
-RSpec.describe StreamEntriesHelper, type: :helper do
+RSpec.describe StatusesHelper, type: :helper do
describe '#display_name' do
it 'uses the display name when it exists' do
account = Account.new(display_name: "Display", username: "Username")
@@ -70,13 +70,13 @@ RSpec.describe StreamEntriesHelper, type: :helper do
end
def set_not_embedded_view
- params[:controller] = "not_#{StreamEntriesHelper::EMBEDDED_CONTROLLER}"
- params[:action] = "not_#{StreamEntriesHelper::EMBEDDED_ACTION}"
+ params[:controller] = "not_#{StatusesHelper::EMBEDDED_CONTROLLER}"
+ params[:action] = "not_#{StatusesHelper::EMBEDDED_ACTION}"
end
def set_embedded_view
- params[:controller] = StreamEntriesHelper::EMBEDDED_CONTROLLER
- params[:action] = StreamEntriesHelper::EMBEDDED_ACTION
+ params[:controller] = StatusesHelper::EMBEDDED_CONTROLLER
+ params[:action] = StatusesHelper::EMBEDDED_ACTION
end
describe '#style_classes' do
diff --git a/spec/lib/activitypub/tag_manager_spec.rb b/spec/lib/activitypub/tag_manager_spec.rb
index 6d246629e7..1c5c6f0edd 100644
--- a/spec/lib/activitypub/tag_manager_spec.rb
+++ b/spec/lib/activitypub/tag_manager_spec.rb
@@ -143,12 +143,6 @@ RSpec.describe ActivityPub::TagManager do
expect(subject.uri_to_resource(OStatus::TagManager.instance.uri_for(status), Status)).to eq status
end
- it 'returns the local status for OStatus StreamEntry URL' do
- status = Fabricate(:status)
- stream_entry_url = account_stream_entry_url(status.account, status.stream_entry)
- expect(subject.uri_to_resource(stream_entry_url, Status)).to eq status
- end
-
it 'returns the remote status by matching URI without fragment part' do
status = Fabricate(:status, uri: 'https://example.com/123')
expect(subject.uri_to_resource('https://example.com/123#456', Status)).to eq status
diff --git a/spec/lib/language_detector_spec.rb b/spec/lib/language_detector_spec.rb
index 0cb70605ad..b7ba0f6c4f 100644
--- a/spec/lib/language_detector_spec.rb
+++ b/spec/lib/language_detector_spec.rb
@@ -32,11 +32,11 @@ describe LanguageDetector do
expect(result).to eq 'Our website is and also'
end
- it 'strips #hashtags from strings before detection' do
- string = 'Hey look at all the #animals and #fish'
+ it 'converts #hashtags back to normal text before detection' do
+ string = 'Hey look at all the #animals and #FishAndChips'
result = described_class.instance.send(:prepare_text, string)
- expect(result).to eq 'Hey look at all the and'
+ expect(result).to eq 'Hey look at all the animals and fish and chips'
end
end
diff --git a/spec/lib/ostatus/atom_serializer_spec.rb b/spec/lib/ostatus/atom_serializer_spec.rb
deleted file mode 100644
index 891871c1c7..0000000000
--- a/spec/lib/ostatus/atom_serializer_spec.rb
+++ /dev/null
@@ -1,1560 +0,0 @@
-require 'rails_helper'
-
-RSpec.describe OStatus::AtomSerializer do
- shared_examples 'follow request salmon' do
- it 'appends author element with account' do
- account = Fabricate(:account, domain: nil, username: 'username')
- follow_request = Fabricate(:follow_request, account: account)
-
- follow_request_salmon = serialize(follow_request)
-
- expect(follow_request_salmon.author.id.text).to eq 'https://cb6e6126.ngrok.io/users/username'
- end
-
- it 'appends activity:object-type element with activity type' do
- follow_request = Fabricate(:follow_request)
-
- follow_request_salmon = serialize(follow_request)
-
- object_type = follow_request_salmon.nodes.find { |node| node.name == 'activity:object-type' }
- expect(object_type.text).to eq OStatus::TagManager::TYPES[:activity]
- end
-
- it 'appends activity:verb element with request_friend type' do
- follow_request = Fabricate(:follow_request)
-
- follow_request_salmon = serialize(follow_request)
-
- verb = follow_request_salmon.nodes.find { |node| node.name == 'activity:verb' }
- expect(verb.text).to eq OStatus::TagManager::VERBS[:request_friend]
- end
-
- it 'appends activity:object with target account' do
- target_account = Fabricate(:account, domain: 'domain.test', uri: 'https://domain.test/id')
- follow_request = Fabricate(:follow_request, target_account: target_account)
-
- follow_request_salmon = serialize(follow_request)
-
- object = follow_request_salmon.nodes.find { |node| node.name == 'activity:object' }
- expect(object.id.text).to eq 'https://domain.test/id'
- end
- end
-
- shared_examples 'namespaces' do
- it 'adds namespaces' do
- element = serialize
-
- expect(element['xmlns']).to eq OStatus::TagManager::XMLNS
- expect(element['xmlns:thr']).to eq OStatus::TagManager::THR_XMLNS
- expect(element['xmlns:activity']).to eq OStatus::TagManager::AS_XMLNS
- expect(element['xmlns:poco']).to eq OStatus::TagManager::POCO_XMLNS
- expect(element['xmlns:media']).to eq OStatus::TagManager::MEDIA_XMLNS
- expect(element['xmlns:ostatus']).to eq OStatus::TagManager::OS_XMLNS
- expect(element['xmlns:mastodon']).to eq OStatus::TagManager::MTDN_XMLNS
- end
- end
-
- shared_examples 'no namespaces' do
- it 'does not add namespaces' do
- expect(serialize['xmlns']).to eq nil
- end
- end
-
- shared_examples 'status attributes' do
- it 'appends summary element with spoiler text if present' do
- status = Fabricate(:status, language: :ca, spoiler_text: 'spoiler text')
-
- element = serialize(status)
-
- summary = element.summary
- expect(summary['xml:lang']).to eq 'ca'
- expect(summary.text).to eq 'spoiler text'
- end
-
- it 'does not append summary element with spoiler text if not present' do
- status = Fabricate(:status, spoiler_text: '')
- element = serialize(status)
- element.nodes.each { |node| expect(node.name).not_to eq 'summary' }
- end
-
- it 'appends content element with formatted status' do
- status = Fabricate(:status, language: :ca, text: 'text')
-
- element = serialize(status)
-
- content = element.content
- expect(content[:type]).to eq 'html'
- expect(content['xml:lang']).to eq 'ca'
- expect(content.text).to eq '
text
'
- end
-
- it 'appends link elements for mentioned accounts' do
- account = Fabricate(:account, username: 'username')
- status = Fabricate(:status)
- Fabricate(:mention, account: account, status: status)
-
- element = serialize(status)
-
- mentioned = element.nodes.find do |node|
- node.name == 'link' &&
- node[:rel] == 'mentioned' &&
- node['ostatus:object-type'] == OStatus::TagManager::TYPES[:person]
- end
-
- expect(mentioned[:href]).to eq 'https://cb6e6126.ngrok.io/users/username'
- end
-
- it 'appends link elements for emojis' do
- Fabricate(:custom_emoji)
-
- status = Fabricate(:status, text: ':coolcat:')
- element = serialize(status)
- emoji = element.nodes.find { |node| node.name == 'link' && node[:rel] == 'emoji' }
-
- expect(emoji[:name]).to eq 'coolcat'
- expect(emoji[:href]).to_not be_blank
- end
- end
-
- describe 'render' do
- it 'returns XML with emojis' do
- element = Ox::Element.new('tag')
- element << '💩'
- xml = OStatus::AtomSerializer.render(element)
-
- expect(xml).to eq "\n💩\n"
- end
-
- it 'returns XML, stripping invalid characters like \b and \v' do
- element = Ox::Element.new('tag')
- element << "im l33t\b haxo\b\vr"
- xml = OStatus::AtomSerializer.render(element)
-
- expect(xml).to eq "\nim l33t haxor\n"
- end
- end
-
- describe '#author' do
- context 'when note is present' do
- it 'appends poco:note element with note for local account' do
- account = Fabricate(:account, domain: nil, note: '