mirror of
https://github.com/mastodon/mastodon.git
synced 2025-09-05 17:31:12 +00:00
Merge branch 'main' into feature/require-mfa-by-admin
This commit is contained in:
commit
bdf102df4e
|
@ -6,10 +6,6 @@
|
|||
# Note that changes in the inspected code, or installation of new
|
||||
# versions of RuboCop, may require this file to be generated again.
|
||||
|
||||
Lint/NonLocalExitFromIterator:
|
||||
Exclude:
|
||||
- 'app/helpers/json_ld_helper.rb'
|
||||
|
||||
# Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes.
|
||||
Metrics/AbcSize:
|
||||
Max: 82
|
||||
|
|
|
@ -468,7 +468,7 @@ GEM
|
|||
hashie (>= 3.4.6)
|
||||
rack (>= 2.2.3)
|
||||
rack-protection
|
||||
omniauth-cas (3.0.1)
|
||||
omniauth-cas (3.0.2)
|
||||
addressable (~> 2.8)
|
||||
nokogiri (~> 1.12)
|
||||
omniauth (~> 2.1)
|
||||
|
@ -860,7 +860,7 @@ GEM
|
|||
stoplight (4.1.1)
|
||||
redlock (~> 1.0)
|
||||
stringio (3.1.7)
|
||||
strong_migrations (2.4.0)
|
||||
strong_migrations (2.5.0)
|
||||
activerecord (>= 7.1)
|
||||
swd (2.0.3)
|
||||
activesupport (>= 3)
|
||||
|
|
|
@ -22,7 +22,7 @@ class Settings::Migration::RedirectsController < Settings::BaseController
|
|||
end
|
||||
|
||||
def destroy
|
||||
if current_account.moved_to_account_id.present?
|
||||
if current_account.moved?
|
||||
current_account.update!(moved_to_account: nil)
|
||||
ActivityPub::UpdateDistributionWorker.perform_async(current_account.id)
|
||||
end
|
||||
|
|
|
@ -65,12 +65,12 @@ module FormattingHelper
|
|||
end
|
||||
|
||||
def rss_content_preroll(status)
|
||||
if status.spoiler_text?
|
||||
safe_join [
|
||||
tag.p { spoiler_with_warning(status) },
|
||||
tag.hr,
|
||||
]
|
||||
end
|
||||
return unless status.spoiler_text?
|
||||
|
||||
safe_join [
|
||||
tag.p { spoiler_with_warning(status) },
|
||||
tag.hr,
|
||||
]
|
||||
end
|
||||
|
||||
def spoiler_with_warning(status)
|
||||
|
@ -81,10 +81,10 @@ module FormattingHelper
|
|||
end
|
||||
|
||||
def rss_content_postroll(status)
|
||||
if status.preloadable_poll
|
||||
tag.p do
|
||||
poll_option_tags(status)
|
||||
end
|
||||
return unless status.preloadable_poll
|
||||
|
||||
tag.p do
|
||||
poll_option_tags(status)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -134,7 +134,7 @@ module JsonLdHelper
|
|||
patch_for_forwarding!(value, compacted_value)
|
||||
elsif value.is_a?(Array)
|
||||
compacted_value = [compacted_value] unless compacted_value.is_a?(Array)
|
||||
return if value.size != compacted_value.size
|
||||
return nil if value.size != compacted_value.size
|
||||
|
||||
compacted[key] = value.zip(compacted_value).map do |v, vc|
|
||||
if v.is_a?(Hash) && vc.is_a?(Hash)
|
||||
|
|
|
@ -24,24 +24,24 @@ module ThemeHelper
|
|||
end
|
||||
|
||||
def custom_stylesheet
|
||||
if active_custom_stylesheet.present?
|
||||
stylesheet_link_tag(
|
||||
custom_css_path(active_custom_stylesheet),
|
||||
host: root_url,
|
||||
media: :all,
|
||||
skip_pipeline: true
|
||||
)
|
||||
end
|
||||
return if active_custom_stylesheet.blank?
|
||||
|
||||
stylesheet_link_tag(
|
||||
custom_css_path(active_custom_stylesheet),
|
||||
host: root_url,
|
||||
media: :all,
|
||||
skip_pipeline: true
|
||||
)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def active_custom_stylesheet
|
||||
if cached_custom_css_digest.present?
|
||||
[:custom, cached_custom_css_digest.to_s.first(8)]
|
||||
.compact_blank
|
||||
.join('-')
|
||||
end
|
||||
return if cached_custom_css_digest.blank?
|
||||
|
||||
[:custom, cached_custom_css_digest.to_s.first(8)]
|
||||
.compact_blank
|
||||
.join('-')
|
||||
end
|
||||
|
||||
def cached_custom_css_digest
|
||||
|
|
|
@ -48,13 +48,13 @@ class TranslateButton extends PureComponent {
|
|||
|
||||
return (
|
||||
<div className='translate-button'>
|
||||
<div className='translate-button__meta'>
|
||||
<FormattedMessage id='status.translated_from_with' defaultMessage='Translated from {lang} using {provider}' values={{ lang: languageName, provider }} />
|
||||
</div>
|
||||
|
||||
<button className='link-button' onClick={onClick}>
|
||||
<FormattedMessage id='status.show_original' defaultMessage='Show original' />
|
||||
</button>
|
||||
|
||||
<div className='translate-button__meta'>
|
||||
<FormattedMessage id='status.translated_from_with' defaultMessage='Translated from {lang} using {provider}' values={{ lang: languageName, provider }} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -110,7 +110,7 @@
|
|||
"announcement.announcement": "إعلان",
|
||||
"annual_report.summary.archetype.booster": "The cool-hunter",
|
||||
"annual_report.summary.archetype.lurker": "المتصفح الصامت",
|
||||
"annual_report.summary.archetype.oracle": "حكيم",
|
||||
"annual_report.summary.archetype.oracle": "الحكيم",
|
||||
"annual_report.summary.archetype.pollster": "مستطلع للرأي",
|
||||
"annual_report.summary.archetype.replier": "الفراشة الاجتماعية",
|
||||
"annual_report.summary.followers.followers": "المُتابِعُون",
|
||||
|
@ -845,6 +845,7 @@
|
|||
"status.bookmark": "أضفه إلى الفواصل المرجعية",
|
||||
"status.cancel_reblog_private": "إلغاء إعادة النشر",
|
||||
"status.cannot_reblog": "لا يمكن إعادة نشر هذا المنشور",
|
||||
"status.context.load_new_replies": "الردود الجديدة المتاحة",
|
||||
"status.continued_thread": "تكملة للخيط",
|
||||
"status.copy": "انسخ رابط الرسالة",
|
||||
"status.delete": "احذف",
|
||||
|
|
|
@ -324,7 +324,7 @@
|
|||
"empty_column.follow_requests": "Du har endnu ingen følgeanmodninger. Når du modtager én, vil den dukke op her.",
|
||||
"empty_column.followed_tags": "Ingen hashtags følges endnu. Når det sker, vil de fremgå her.",
|
||||
"empty_column.hashtag": "Der er intet med dette hashtag endnu.",
|
||||
"empty_column.home": "Din hjemmetidslinje er tom! Følg nogle personer, for at fylde den op.",
|
||||
"empty_column.home": "Din hjem-tidslinje er tom! Følg nogle personer, for at fylde den op.",
|
||||
"empty_column.list": "Der er ikke noget på denne liste endnu. Når medlemmer af denne liste udgiver nye indlæg, vil de blive vist her.",
|
||||
"empty_column.mutes": "Du har endnu ikke skjult nogle brugere.",
|
||||
"empty_column.notification_requests": "Alt er klar! Der er intet her. Når der modtages nye notifikationer, fremgår de her jævnfør dine indstillinger.",
|
||||
|
@ -476,7 +476,7 @@
|
|||
"keyboard_shortcuts.favourites": "Åbn favoritlisten",
|
||||
"keyboard_shortcuts.federated": "Åbn fødereret tidslinje",
|
||||
"keyboard_shortcuts.heading": "Tastaturgenveje",
|
||||
"keyboard_shortcuts.home": "Åbn hjemmetidslinje",
|
||||
"keyboard_shortcuts.home": "Åbn hjem-tidslinje",
|
||||
"keyboard_shortcuts.hotkey": "Hurtigtast",
|
||||
"keyboard_shortcuts.legend": "Vis dette symbol",
|
||||
"keyboard_shortcuts.local": "Åbn lokal tidslinje",
|
||||
|
@ -518,7 +518,7 @@
|
|||
"lists.done": "Færdig",
|
||||
"lists.edit": "Redigér liste",
|
||||
"lists.exclusive": "Skjul medlemmer i Hjem",
|
||||
"lists.exclusive_hint": "Er nogen er på denne liste, skjul personen i hjemme-feeds for at undgå at se vedkommendes indlæg to gange.",
|
||||
"lists.exclusive_hint": "Hvis nogen er på denne liste, så skjul dem i hjem-feed for at undgå at se deres indlæg to gange.",
|
||||
"lists.find_users_to_add": "Find brugere at tilføje",
|
||||
"lists.list_members_count": "{count, plural, one {# medlem} other {# medlemmer}}",
|
||||
"lists.list_name": "Listetitel",
|
||||
|
@ -792,7 +792,7 @@
|
|||
"report.thanks.title": "Ønsker ikke at se dette?",
|
||||
"report.thanks.title_actionable": "Tak for anmeldelsen, der vil blive set nærmere på dette.",
|
||||
"report.unfollow": "Følg ikke længere @{name}",
|
||||
"report.unfollow_explanation": "Du følger denne konto. For ikke længere at se vedkommendes indlæg i din hjemmestrøm, kan du stoppe med at følge dem.",
|
||||
"report.unfollow_explanation": "Du følger denne konto. Hvis du ikke længere vil se vedkommendes indlæg i dit hjem-feed, så stop med at følge dem.",
|
||||
"report_notification.attached_statuses": "{count, plural, one {{count} indlæg} other {{count} indlæg}} vedhæftet",
|
||||
"report_notification.categories.legal": "Juridisk",
|
||||
"report_notification.categories.legal_sentence": "ikke-tilladt indhold",
|
||||
|
|
|
@ -43,7 +43,7 @@
|
|||
"account.followers": "Follower",
|
||||
"account.followers.empty": "Diesem Profil folgt noch niemand.",
|
||||
"account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Follower}}",
|
||||
"account.followers_you_know_counter": "{counter} Follower kennst Du",
|
||||
"account.followers_you_know_counter": "{counter} bekannt",
|
||||
"account.following": "Folge ich",
|
||||
"account.following_counter": "{count, plural, one {{counter} Folge ich} other {{counter} Folge ich}}",
|
||||
"account.follows.empty": "Dieses Profil folgt noch niemandem.",
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"about.blocks": "Moderated servers",
|
||||
"about.contact": "Contact:",
|
||||
"about.default_locale": "Default",
|
||||
"about.default_locale": "Varsayılan",
|
||||
"about.disclaimer": "Mastodon is free, open-source software, and a trademark of Mastodon gGmbH.",
|
||||
"about.domain_blocks.no_reason_available": "Reason not available",
|
||||
"about.domain_blocks.preamble": "Mastodon generally allows you to view content from and interact with users from any other server in the Fediverse. These are the exceptions that have been made on this particular server.",
|
||||
|
@ -9,11 +9,11 @@
|
|||
"about.domain_blocks.silenced.title": "Limited",
|
||||
"about.domain_blocks.suspended.explanation": "No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.",
|
||||
"about.domain_blocks.suspended.title": "Suspended",
|
||||
"about.language_label": "Language",
|
||||
"about.language_label": "Dil",
|
||||
"about.not_available": "This information has not been made available on this server.",
|
||||
"about.powered_by": "Decentralised social media powered by {mastodon}",
|
||||
"about.rules": "Server rules",
|
||||
"account.account_note_header": "Personal note",
|
||||
"account.account_note_header": "Kişisel not",
|
||||
"account.add_or_remove_from_list": "Add or Remove from lists",
|
||||
"account.badges.bot": "Automated",
|
||||
"account.badges.group": "Group",
|
||||
|
@ -845,6 +845,8 @@
|
|||
"status.bookmark": "Bookmark",
|
||||
"status.cancel_reblog_private": "Unboost",
|
||||
"status.cannot_reblog": "This post cannot be boosted",
|
||||
"status.context.load_new_replies": "Yeni yanıtlar geldi.",
|
||||
"status.context.loading": "Daha fazla yanıt kontrol ediliyor",
|
||||
"status.continued_thread": "Continued thread",
|
||||
"status.copy": "Copy link to status",
|
||||
"status.delete": "Delete",
|
||||
|
|
|
@ -292,6 +292,7 @@
|
|||
"emoji_button.search_results": "Paieškos rezultatai",
|
||||
"emoji_button.symbols": "Simboliai",
|
||||
"emoji_button.travel": "Kelionės ir vietos",
|
||||
"empty_column.account_featured_other.unknown": "Ši paskyra dar nieko neparodė.",
|
||||
"empty_column.account_hides_collections": "Šis (-i) naudotojas (-a) pasirinko nepadaryti šią informaciją prieinamą.",
|
||||
"empty_column.account_suspended": "Paskyra pristabdyta.",
|
||||
"empty_column.account_timeline": "Nėra čia įrašų.",
|
||||
|
@ -794,6 +795,8 @@
|
|||
"status.bookmark": "Pridėti į žymės",
|
||||
"status.cancel_reblog_private": "Nebepasidalinti",
|
||||
"status.cannot_reblog": "Šis įrašas negali būti pakeltas.",
|
||||
"status.context.load_new_replies": "Yra naujų atsakymų",
|
||||
"status.context.loading": "Tikrinama dėl daugiau atsakymų",
|
||||
"status.continued_thread": "Tęsiama gijoje",
|
||||
"status.copy": "Kopijuoti nuorodą į įrašą",
|
||||
"status.delete": "Ištrinti",
|
||||
|
|
|
@ -845,6 +845,8 @@
|
|||
"status.bookmark": "冊籤",
|
||||
"status.cancel_reblog_private": "取消轉送",
|
||||
"status.cannot_reblog": "Tsit篇PO文bē當轉送",
|
||||
"status.context.load_new_replies": "有新ê回應",
|
||||
"status.context.loading": "Leh檢查其他ê回應",
|
||||
"status.continued_thread": "接續ê討論線",
|
||||
"status.copy": "Khóo-pih PO文ê連結",
|
||||
"status.delete": "Thâi掉",
|
||||
|
|
|
@ -27,6 +27,8 @@
|
|||
"account.edit_profile": "Upraviť profil",
|
||||
"account.enable_notifications": "Zapnúť upozornenia na príspevky od @{name}",
|
||||
"account.endorse": "Zobraziť na vlastnom profile",
|
||||
"account.familiar_followers_one": "Nasledovanie od {name1}",
|
||||
"account.familiar_followers_two": "Nasledovanie od {name1} a {name2}",
|
||||
"account.featured": "Zviditeľnené",
|
||||
"account.featured.accounts": "Profily",
|
||||
"account.featured.hashtags": "Hashtagy",
|
||||
|
|
|
@ -845,6 +845,8 @@
|
|||
"status.bookmark": "Yer işareti ekle",
|
||||
"status.cancel_reblog_private": "Yeniden paylaşımı geri al",
|
||||
"status.cannot_reblog": "Bu gönderi yeniden paylaşılamaz",
|
||||
"status.context.load_new_replies": "Yeni yanıtlar mevcut",
|
||||
"status.context.loading": "Daha fazla yanıt için kontrol ediliyor",
|
||||
"status.continued_thread": "Devam eden akış",
|
||||
"status.copy": "Gönderi bağlantısını kopyala",
|
||||
"status.delete": "Sil",
|
||||
|
|
|
@ -301,6 +301,9 @@
|
|||
"emoji_button.search_results": "搜索结果",
|
||||
"emoji_button.symbols": "符号",
|
||||
"emoji_button.travel": "旅行与地点",
|
||||
"empty_column.account_featured.me": "你尚未设置任何精选。你知道吗?你也可以将自己最常使用的话题标签,甚至是好友的帐号,在你的个人主页上设为精选。",
|
||||
"empty_column.account_featured.other": "{acct} 尚未设置任何精选。你知道吗?你也可以将自己最常使用的话题标签,甚至是好友的帐号,在你的个人主页上设为精选。",
|
||||
"empty_column.account_featured_other.unknown": "该用户尚未设置任何精选。",
|
||||
"empty_column.account_hides_collections": "该用户选择不公开此信息",
|
||||
"empty_column.account_suspended": "账号已被停用",
|
||||
"empty_column.account_timeline": "这里没有嘟文!",
|
||||
|
@ -402,8 +405,10 @@
|
|||
"hashtag.counter_by_accounts": "{count, plural,other {{counter} 人讨论}}",
|
||||
"hashtag.counter_by_uses": "{count, plural, other {{counter} 条嘟文}}",
|
||||
"hashtag.counter_by_uses_today": "今日 {count, plural, other {{counter} 条嘟文}}",
|
||||
"hashtag.feature": "设为精选",
|
||||
"hashtag.follow": "关注话题",
|
||||
"hashtag.mute": "停止提醒 #{hashtag}",
|
||||
"hashtag.unfeature": "取消精选",
|
||||
"hashtag.unfollow": "取消关注话题",
|
||||
"hashtags.and_other": "… 和另外 {count, plural, other {# 个话题}}",
|
||||
"hints.profiles.followers_may_be_missing": "该账号的关注者列表可能没有完全显示。",
|
||||
|
@ -558,6 +563,7 @@
|
|||
"navigation_bar.preferences": "偏好设置",
|
||||
"navigation_bar.privacy_and_reach": "隐私与可达性",
|
||||
"navigation_bar.search": "搜索",
|
||||
"navigation_bar.search_trends": "搜索/热门趋势",
|
||||
"navigation_panel.collapse_lists": "收起菜单列表",
|
||||
"navigation_panel.expand_lists": "展开菜单列表",
|
||||
"not_signed_in_indicator.not_signed_in": "你需要登录才能访问此资源。",
|
||||
|
@ -786,6 +792,7 @@
|
|||
"report_notification.categories.violation": "违反规则",
|
||||
"report_notification.categories.violation_sentence": "违反规则",
|
||||
"report_notification.open": "打开举报",
|
||||
"search.clear": "清空搜索内容",
|
||||
"search.no_recent_searches": "无最近搜索",
|
||||
"search.placeholder": "搜索",
|
||||
"search.quick_action.account_search": "包含 {x} 的账号",
|
||||
|
@ -827,6 +834,8 @@
|
|||
"status.bookmark": "添加到书签",
|
||||
"status.cancel_reblog_private": "取消转嘟",
|
||||
"status.cannot_reblog": "不能转嘟这条嘟文",
|
||||
"status.context.load_new_replies": "有新回复",
|
||||
"status.context.loading": "正在检查更多回复",
|
||||
"status.continued_thread": "上接嘟文串",
|
||||
"status.copy": "复制嘟文链接",
|
||||
"status.delete": "删除",
|
||||
|
@ -854,8 +863,10 @@
|
|||
"status.pin": "在个人资料页面置顶",
|
||||
"status.quote_error.filtered": "已根据你的筛选器过滤",
|
||||
"status.quote_error.not_found": "无法显示这篇贴文。",
|
||||
"status.quote_error.pending_approval": "此嘟文正在等待原作者批准。",
|
||||
"status.quote_error.rejected": "由于原作者不允许引用转发,无法显示这篇贴文。",
|
||||
"status.quote_error.removed": "该帖子已被作者删除。",
|
||||
"status.quote_error.unauthorized": "你无权查看此嘟文,因此无法显示。",
|
||||
"status.quote_post_author": "{name} 的嘟文",
|
||||
"status.read_more": "查看更多",
|
||||
"status.reblog": "转嘟",
|
||||
|
|
|
@ -65,4 +65,16 @@ class Admin::Metrics::Dimension::BaseDimension
|
|||
def canonicalized_params
|
||||
params.to_h.to_a.sort_by { |k, _v| k.to_s }.map { |k, v| "#{k}=#{v}" }.join(';')
|
||||
end
|
||||
|
||||
def earliest_status_id
|
||||
snowflake_id(@start_at.beginning_of_day)
|
||||
end
|
||||
|
||||
def latest_status_id
|
||||
snowflake_id(@end_at.end_of_day)
|
||||
end
|
||||
|
||||
def snowflake_id(datetime)
|
||||
Mastodon::Snowflake.id_at(datetime, with_random: false)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -19,7 +19,7 @@ class Admin::Metrics::Dimension::InstanceLanguagesDimension < Admin::Metrics::Di
|
|||
end
|
||||
|
||||
def sql_array
|
||||
[sql_query_string, { domain: params[:domain], earliest_status_id: earliest_status_id, latest_status_id: latest_status_id, limit: @limit }]
|
||||
[sql_query_string, { domain: params[:domain], earliest_status_id:, latest_status_id:, limit: @limit }]
|
||||
end
|
||||
|
||||
def sql_query_string
|
||||
|
@ -36,14 +36,6 @@ class Admin::Metrics::Dimension::InstanceLanguagesDimension < Admin::Metrics::Di
|
|||
SQL
|
||||
end
|
||||
|
||||
def earliest_status_id
|
||||
Mastodon::Snowflake.id_at(@start_at.beginning_of_day, with_random: false)
|
||||
end
|
||||
|
||||
def latest_status_id
|
||||
Mastodon::Snowflake.id_at(@end_at.end_of_day, with_random: false)
|
||||
end
|
||||
|
||||
def params
|
||||
@params.permit(:domain)
|
||||
end
|
||||
|
|
|
@ -14,7 +14,7 @@ class Admin::Metrics::Dimension::ServersDimension < Admin::Metrics::Dimension::B
|
|||
end
|
||||
|
||||
def sql_array
|
||||
[sql_query_string, { earliest_status_id: earliest_status_id, latest_status_id: latest_status_id, limit: @limit }]
|
||||
[sql_query_string, { earliest_status_id:, latest_status_id:, limit: @limit }]
|
||||
end
|
||||
|
||||
def sql_query_string
|
||||
|
@ -28,12 +28,4 @@ class Admin::Metrics::Dimension::ServersDimension < Admin::Metrics::Dimension::B
|
|||
LIMIT :limit
|
||||
SQL
|
||||
end
|
||||
|
||||
def earliest_status_id
|
||||
Mastodon::Snowflake.id_at(@start_at.beginning_of_day, with_random: false)
|
||||
end
|
||||
|
||||
def latest_status_id
|
||||
Mastodon::Snowflake.id_at(@end_at.end_of_day, with_random: false)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -19,7 +19,7 @@ class Admin::Metrics::Dimension::TagLanguagesDimension < Admin::Metrics::Dimensi
|
|||
end
|
||||
|
||||
def sql_array
|
||||
[sql_query_string, { tag_id: tag_id, earliest_status_id: earliest_status_id, latest_status_id: latest_status_id, limit: @limit }]
|
||||
[sql_query_string, { tag_id: tag_id, earliest_status_id:, latest_status_id:, limit: @limit }]
|
||||
end
|
||||
|
||||
def sql_query_string
|
||||
|
@ -39,14 +39,6 @@ class Admin::Metrics::Dimension::TagLanguagesDimension < Admin::Metrics::Dimensi
|
|||
params[:id]
|
||||
end
|
||||
|
||||
def earliest_status_id
|
||||
Mastodon::Snowflake.id_at(@start_at.beginning_of_day, with_random: false)
|
||||
end
|
||||
|
||||
def latest_status_id
|
||||
Mastodon::Snowflake.id_at(@end_at.end_of_day, with_random: false)
|
||||
end
|
||||
|
||||
def params
|
||||
@params.permit(:id)
|
||||
end
|
||||
|
|
|
@ -18,7 +18,7 @@ class Admin::Metrics::Dimension::TagServersDimension < Admin::Metrics::Dimension
|
|||
end
|
||||
|
||||
def sql_array
|
||||
[sql_query_string, { tag_id: tag_id, earliest_status_id: earliest_status_id, latest_status_id: latest_status_id, limit: @limit }]
|
||||
[sql_query_string, { tag_id: tag_id, earliest_status_id:, latest_status_id:, limit: @limit }]
|
||||
end
|
||||
|
||||
def sql_query_string
|
||||
|
@ -39,14 +39,6 @@ class Admin::Metrics::Dimension::TagServersDimension < Admin::Metrics::Dimension
|
|||
params[:id]
|
||||
end
|
||||
|
||||
def earliest_status_id
|
||||
Mastodon::Snowflake.id_at(@start_at.beginning_of_day, with_random: false)
|
||||
end
|
||||
|
||||
def latest_status_id
|
||||
Mastodon::Snowflake.id_at(@end_at.end_of_day, with_random: false)
|
||||
end
|
||||
|
||||
def params
|
||||
@params.permit(:id)
|
||||
end
|
||||
|
|
|
@ -104,4 +104,16 @@ class Admin::Metrics::Measure::BaseMeasure
|
|||
def canonicalized_params
|
||||
params.to_h.to_a.sort_by { |k, _v| k.to_s }.map { |k, v| "#{k}=#{v}" }.join(';')
|
||||
end
|
||||
|
||||
def earliest_status_id
|
||||
snowflake_id(@start_at.beginning_of_day)
|
||||
end
|
||||
|
||||
def latest_status_id
|
||||
snowflake_id(@end_at.end_of_day)
|
||||
end
|
||||
|
||||
def snowflake_id(datetime)
|
||||
Mastodon::Snowflake.id_at(datetime, with_random: false)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -28,7 +28,7 @@ class Admin::Metrics::Measure::InstanceStatusesMeasure < Admin::Metrics::Measure
|
|||
end
|
||||
|
||||
def sql_array
|
||||
[sql_query_string, { start_at: @start_at, end_at: @end_at, domain: params[:domain], earliest_status_id: earliest_status_id, latest_status_id: latest_status_id }]
|
||||
[sql_query_string, { start_at: @start_at, end_at: @end_at, domain: params[:domain], earliest_status_id:, latest_status_id: }]
|
||||
end
|
||||
|
||||
def sql_query_string
|
||||
|
@ -50,14 +50,6 @@ class Admin::Metrics::Measure::InstanceStatusesMeasure < Admin::Metrics::Measure
|
|||
SQL
|
||||
end
|
||||
|
||||
def earliest_status_id
|
||||
Mastodon::Snowflake.id_at(@start_at.beginning_of_day, with_random: false)
|
||||
end
|
||||
|
||||
def latest_status_id
|
||||
Mastodon::Snowflake.id_at(@end_at.end_of_day, with_random: false)
|
||||
end
|
||||
|
||||
def params
|
||||
@params.permit(:domain, :include_subdomains)
|
||||
end
|
||||
|
|
|
@ -22,7 +22,7 @@ class Admin::Metrics::Measure::TagServersMeasure < Admin::Metrics::Measure::Base
|
|||
end
|
||||
|
||||
def sql_array
|
||||
[sql_query_string, { start_at: @start_at, end_at: @end_at, tag_id: tag.id, earliest_status_id: earliest_status_id, latest_status_id: latest_status_id }]
|
||||
[sql_query_string, { start_at: @start_at, end_at: @end_at, tag_id: tag.id, earliest_status_id:, latest_status_id: }]
|
||||
end
|
||||
|
||||
def sql_query_string
|
||||
|
@ -45,14 +45,6 @@ class Admin::Metrics::Measure::TagServersMeasure < Admin::Metrics::Measure::Base
|
|||
SQL
|
||||
end
|
||||
|
||||
def earliest_status_id
|
||||
Mastodon::Snowflake.id_at(@start_at.beginning_of_day, with_random: false)
|
||||
end
|
||||
|
||||
def latest_status_id
|
||||
Mastodon::Snowflake.id_at(@end_at.end_of_day, with_random: false)
|
||||
end
|
||||
|
||||
def tag
|
||||
@tag ||= Tag.find(params[:id])
|
||||
end
|
||||
|
|
|
@ -84,22 +84,18 @@ class Webfinger
|
|||
|
||||
def body_from_host_meta
|
||||
host_meta_request.perform do |res|
|
||||
if res.code == 200
|
||||
body_from_webfinger(url_from_template(res.body_with_limit), use_fallback: false)
|
||||
else
|
||||
raise Webfinger::Error, "Request for #{@uri} returned HTTP #{res.code}"
|
||||
end
|
||||
raise Webfinger::Error, "Request for #{@uri} returned HTTP #{res.code}" unless res.code == 200
|
||||
|
||||
body_from_webfinger(url_from_template(res.body_with_limit), use_fallback: false)
|
||||
end
|
||||
end
|
||||
|
||||
def url_from_template(str)
|
||||
link = Nokogiri::XML(str).at_xpath('//xmlns:Link[@rel="lrdd"]')
|
||||
|
||||
if link.present?
|
||||
link['template'].gsub('{uri}', @uri)
|
||||
else
|
||||
raise Webfinger::Error, "Request for #{@uri} returned host-meta without link to Webfinger"
|
||||
end
|
||||
raise Webfinger::Error, "Request for #{@uri} returned host-meta without link to Webfinger" if link.blank?
|
||||
|
||||
link['template'].gsub('{uri}', @uri)
|
||||
rescue Nokogiri::XML::XPath::SyntaxError
|
||||
raise Webfinger::Error, "Invalid XML encountered in host-meta for #{@uri}"
|
||||
end
|
||||
|
|
|
@ -54,11 +54,9 @@ class WebfingerResource
|
|||
end
|
||||
|
||||
def username_from_acct
|
||||
if domain_matches_local?
|
||||
local_username
|
||||
else
|
||||
raise ActiveRecord::RecordNotFound
|
||||
end
|
||||
raise ActiveRecord::RecordNotFound unless domain_matches_local?
|
||||
|
||||
local_username
|
||||
end
|
||||
|
||||
def split_acct
|
||||
|
|
|
@ -74,7 +74,7 @@ class AccountMigration < ApplicationRecord
|
|||
errors.add(:acct, I18n.t('migrations.errors.not_found'))
|
||||
else
|
||||
errors.add(:acct, I18n.t('migrations.errors.missing_also_known_as')) unless target_account.also_known_as.include?(ActivityPub::TagManager.instance.uri_for(account))
|
||||
errors.add(:acct, I18n.t('migrations.errors.already_moved')) if account.moved_to_account_id.present? && account.moved_to_account_id == target_account.id
|
||||
errors.add(:acct, I18n.t('migrations.errors.already_moved')) if account.moved? && account.moved_to_account_id == target_account.id
|
||||
errors.add(:acct, I18n.t('migrations.errors.move_to_self')) if account.id == target_account.id
|
||||
end
|
||||
end
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
#
|
||||
|
||||
class AnnouncementReaction < ApplicationRecord
|
||||
before_validation :set_custom_emoji
|
||||
before_validation :set_custom_emoji, if: :name?
|
||||
after_commit :queue_publish
|
||||
|
||||
belongs_to :account
|
||||
|
@ -27,7 +27,7 @@ class AnnouncementReaction < ApplicationRecord
|
|||
private
|
||||
|
||||
def set_custom_emoji
|
||||
self.custom_emoji = CustomEmoji.local.enabled.find_by(shortcode: name) if name.present?
|
||||
self.custom_emoji = CustomEmoji.local.enabled.find_by(shortcode: name)
|
||||
end
|
||||
|
||||
def queue_publish
|
||||
|
|
|
@ -3,12 +3,8 @@
|
|||
module RateLimitable
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
def rate_limit=(value)
|
||||
@rate_limit = value
|
||||
end
|
||||
|
||||
def rate_limit?
|
||||
@rate_limit
|
||||
included do
|
||||
attribute :rate_limit, :boolean, default: false
|
||||
end
|
||||
|
||||
def rate_limiter(by, options = {})
|
||||
|
|
|
@ -37,7 +37,7 @@ class FollowRequest < ApplicationRecord
|
|||
if account.local?
|
||||
ListAccount.where(follow_request: self).update_all(follow_request_id: nil, follow_id: follow.id)
|
||||
MergeWorker.perform_async(target_account.id, account.id, 'home')
|
||||
MergeWorker.push_bulk(List.where(account: account).joins(:list_accounts).where(list_accounts: { account_id: target_account.id }).pluck(:id)) do |list_id|
|
||||
MergeWorker.push_bulk(account.owned_lists.with_list_account(target_account).pluck(:id)) do |list_id|
|
||||
[target_account.id, list_id, 'list']
|
||||
end
|
||||
end
|
||||
|
|
|
@ -40,7 +40,7 @@ class Form::Redirect
|
|||
if target_account.nil?
|
||||
errors.add(:acct, I18n.t('migrations.errors.not_found'))
|
||||
else
|
||||
errors.add(:acct, I18n.t('migrations.errors.already_moved')) if account.moved_to_account_id.present? && account.moved_to_account_id == target_account.id
|
||||
errors.add(:acct, I18n.t('migrations.errors.already_moved')) if account.moved? && account.moved_to_account_id == target_account.id
|
||||
errors.add(:acct, I18n.t('migrations.errors.move_to_self')) if account.id == target_account.id
|
||||
end
|
||||
end
|
||||
|
|
|
@ -32,6 +32,8 @@ class List < ApplicationRecord
|
|||
|
||||
before_destroy :clean_feed_manager
|
||||
|
||||
scope :with_list_account, ->(account) { joins(:list_accounts).where(list_accounts: { account: }) }
|
||||
|
||||
private
|
||||
|
||||
def validate_account_lists_limit
|
||||
|
|
|
@ -170,10 +170,9 @@ class PreviewCard < ApplicationRecord
|
|||
private
|
||||
|
||||
def serialized_authors
|
||||
if author_name? || author_url? || author_account_id?
|
||||
PreviewCard::Author
|
||||
.new(self)
|
||||
end
|
||||
return unless author_name? || author_url? || author_account_id?
|
||||
|
||||
PreviewCard::Author.new(self)
|
||||
end
|
||||
|
||||
def extract_dimensions
|
||||
|
|
|
@ -164,9 +164,10 @@ class Tag < ApplicationRecord
|
|||
end
|
||||
|
||||
def validate_display_name_change
|
||||
unless HashtagNormalizer.new.normalize(display_name).casecmp(name).zero?
|
||||
errors.add(:display_name,
|
||||
I18n.t('tags.does_not_match_previous_name'))
|
||||
end
|
||||
errors.add(:display_name, I18n.t('tags.does_not_match_previous_name')) unless display_name_matches_name?
|
||||
end
|
||||
|
||||
def display_name_matches_name?
|
||||
HashtagNormalizer.new.normalize(display_name).casecmp(name).zero?
|
||||
end
|
||||
end
|
||||
|
|
|
@ -466,16 +466,17 @@ class User < ApplicationRecord
|
|||
|
||||
yield
|
||||
|
||||
if new_user
|
||||
# Avoid extremely unlikely race condition when approving and confirming
|
||||
# the user at the same time
|
||||
reload unless approved?
|
||||
after_confirmation_tasks if new_user
|
||||
end
|
||||
|
||||
if approved?
|
||||
prepare_new_user!
|
||||
else
|
||||
notify_staff_about_pending_account!
|
||||
end
|
||||
def after_confirmation_tasks
|
||||
# Handle condition when approving and confirming a user at the same time
|
||||
reload unless approved?
|
||||
|
||||
if approved?
|
||||
prepare_new_user!
|
||||
else
|
||||
notify_staff_about_pending_account!
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -539,10 +540,10 @@ class User < ApplicationRecord
|
|||
|
||||
def regenerate_feed!
|
||||
home_feed = HomeFeed.new(account)
|
||||
unless home_feed.regenerating?
|
||||
home_feed.regeneration_in_progress!
|
||||
RegenerationWorker.perform_async(account_id)
|
||||
end
|
||||
return if home_feed.regenerating?
|
||||
|
||||
home_feed.regeneration_in_progress!
|
||||
RegenerationWorker.perform_async(account_id)
|
||||
end
|
||||
|
||||
def needs_feed_update?
|
||||
|
|
|
@ -19,17 +19,22 @@ class WorkerBatch
|
|||
redis.hset(key, { 'async_refresh_key' => async_refresh_key, 'threshold' => threshold })
|
||||
end
|
||||
|
||||
def within
|
||||
raise NoBlockGivenError unless block_given?
|
||||
|
||||
begin
|
||||
Thread.current[:batch] = self
|
||||
yield
|
||||
ensure
|
||||
Thread.current[:batch] = nil
|
||||
end
|
||||
end
|
||||
|
||||
# Add jobs to the batch. Usually when the batch is created.
|
||||
# @param [Array<String>] jids
|
||||
def add_jobs(jids)
|
||||
if jids.blank?
|
||||
async_refresh_key = redis.hget(key, 'async_refresh_key')
|
||||
|
||||
if async_refresh_key.present?
|
||||
async_refresh = AsyncRefresh.new(async_refresh_key)
|
||||
async_refresh.finish!
|
||||
end
|
||||
|
||||
finish!
|
||||
return
|
||||
end
|
||||
|
||||
|
@ -55,8 +60,23 @@ class WorkerBatch
|
|||
if async_refresh_key.present?
|
||||
async_refresh = AsyncRefresh.new(async_refresh_key)
|
||||
async_refresh.increment_result_count(by: 1)
|
||||
async_refresh.finish! if pending.zero? || processed >= threshold.to_f * (processed + pending)
|
||||
end
|
||||
|
||||
if pending.zero? || processed >= (threshold || 1.0).to_f * (processed + pending)
|
||||
async_refresh&.finish!
|
||||
cleanup
|
||||
end
|
||||
end
|
||||
|
||||
def finish!
|
||||
async_refresh_key = redis.hget(key, 'async_refresh_key')
|
||||
|
||||
if async_refresh_key.present?
|
||||
async_refresh = AsyncRefresh.new(async_refresh_key)
|
||||
async_refresh.finish!
|
||||
end
|
||||
|
||||
cleanup
|
||||
end
|
||||
|
||||
# Get pending jobs.
|
||||
|
@ -76,4 +96,8 @@ class WorkerBatch
|
|||
def key(suffix = nil)
|
||||
"worker_batch:#{@id}#{":#{suffix}" if suffix}"
|
||||
end
|
||||
|
||||
def cleanup
|
||||
redis.del(key, key('jobs'))
|
||||
end
|
||||
end
|
||||
|
|
|
@ -17,7 +17,12 @@ class ActivityPub::FetchRepliesService < BaseService
|
|||
|
||||
batch = WorkerBatch.new
|
||||
batch.connect(async_refresh_key) if async_refresh_key.present?
|
||||
batch.add_jobs(FetchReplyWorker.push_bulk(@items) { |reply_uri| [reply_uri, { 'request_id' => request_id, 'batch_id' => batch.id }] })
|
||||
batch.finish! if @items.empty?
|
||||
batch.within do
|
||||
FetchReplyWorker.push_bulk(@items) do |reply_uri|
|
||||
[reply_uri, { 'request_id' => request_id, 'batch_id' => batch.id }]
|
||||
end
|
||||
end
|
||||
|
||||
[@items, n_pages]
|
||||
end
|
||||
|
|
|
@ -82,7 +82,7 @@ class FollowService < BaseService
|
|||
|
||||
LocalNotificationWorker.perform_async(@target_account.id, follow.id, follow.class.name, 'follow')
|
||||
MergeWorker.perform_async(@target_account.id, @source_account.id, 'home')
|
||||
MergeWorker.push_bulk(List.where(account: @source_account).joins(:list_accounts).where(list_accounts: { account_id: @target_account.id }).pluck(:id)) do |list_id|
|
||||
MergeWorker.push_bulk(@source_account.owned_lists.with_list_account(@target_account).pluck(:id)) do |list_id|
|
||||
[@target_account.id, list_id, 'list']
|
||||
end
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ class UnfollowService < BaseService
|
|||
|
||||
unless @options[:skip_unmerge]
|
||||
UnmergeWorker.perform_async(@target_account.id, @source_account.id, 'home')
|
||||
UnmergeWorker.push_bulk(List.where(account: @source_account).joins(:list_accounts).where(list_accounts: { account_id: @target_account.id }).pluck(:list_id)) do |list_id|
|
||||
UnmergeWorker.push_bulk(@source_account.owned_lists.with_list_account(@target_account).pluck(:list_id)) do |list_id|
|
||||
[@target_account.id, list_id, 'list']
|
||||
end
|
||||
end
|
||||
|
|
|
@ -9,7 +9,7 @@ class UnmuteService < BaseService
|
|||
if account.following?(target_account)
|
||||
MergeWorker.perform_async(target_account.id, account.id, 'home')
|
||||
|
||||
MergeWorker.push_bulk(List.where(account: account).joins(:list_accounts).where(list_accounts: { account_id: target_account.id }).pluck(:id)) do |list_id|
|
||||
MergeWorker.push_bulk(account.owned_lists.with_list_account(target_account).pluck(:id)) do |list_id|
|
||||
[target_account.id, list_id, 'list']
|
||||
end
|
||||
end
|
||||
|
|
|
@ -30,9 +30,9 @@
|
|||
= t('admin.accounts.suspended')
|
||||
- elsif account.silenced?
|
||||
= t('admin.accounts.silenced')
|
||||
- elsif account.local? && account.user&.disabled?
|
||||
- elsif account.local? && account.user_disabled?
|
||||
= t('admin.accounts.disabled')
|
||||
- elsif account.local? && !account.user&.confirmed?
|
||||
- elsif account.local? && !account.user_confirmed?
|
||||
= t('admin.accounts.confirming')
|
||||
- elsif account.local? && !account.user_approved?
|
||||
= t('admin.accounts.pending')
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
%tr
|
||||
%th= t('admin.accounts.email_status')
|
||||
%td
|
||||
- if account.user&.confirmed?
|
||||
- if account.user_confirmed?
|
||||
= t('admin.accounts.confirmed')
|
||||
- else
|
||||
= t('admin.accounts.confirming')
|
||||
|
|
|
@ -42,7 +42,7 @@
|
|||
%span.red= t('admin.accounts.suspended')
|
||||
- elsif target_account.silenced?
|
||||
%span.red= t('admin.accounts.silenced')
|
||||
- elsif target_account.user&.disabled?
|
||||
- elsif target_account.user_disabled?
|
||||
%span.red= t('admin.accounts.disabled')
|
||||
- else
|
||||
%span.neutral= t('admin.accounts.no_limits_imposed')
|
||||
|
|
|
@ -81,7 +81,7 @@ class MoveWorker
|
|||
|
||||
def copy_account_notes!
|
||||
AccountNote.where(target_account: @source_account).find_each do |note|
|
||||
text = I18n.with_locale(note.account.user&.locale.presence || I18n.default_locale) do
|
||||
text = I18n.with_locale(note.account.user_locale.presence || I18n.default_locale) do
|
||||
I18n.t('move_handler.copy_account_note_text', acct: @source_account.acct)
|
||||
end
|
||||
|
||||
|
@ -104,7 +104,7 @@ class MoveWorker
|
|||
|
||||
def carry_blocks_over!
|
||||
@source_account.blocked_by_relationships.where(account: Account.local).find_each do |block|
|
||||
unless block.account.blocking?(@target_account) || block.account.following?(@target_account)
|
||||
unless skip_block_move?(block)
|
||||
BlockService.new.call(block.account, @target_account)
|
||||
add_account_note_if_needed!(block.account, 'move_handler.carry_blocks_over_text')
|
||||
end
|
||||
|
@ -115,7 +115,7 @@ class MoveWorker
|
|||
|
||||
def carry_mutes_over!
|
||||
@source_account.muted_by_relationships.where(account: Account.local).find_each do |mute|
|
||||
MuteService.new.call(mute.account, @target_account, notifications: mute.hide_notifications) unless mute.account.muting?(@target_account) || mute.account.following?(@target_account)
|
||||
MuteService.new.call(mute.account, @target_account, notifications: mute.hide_notifications) unless skip_mute_move?(mute)
|
||||
add_account_note_if_needed!(mute.account, 'move_handler.carry_mutes_over_text')
|
||||
rescue => e
|
||||
@deferred_error = e
|
||||
|
@ -123,11 +123,19 @@ class MoveWorker
|
|||
end
|
||||
|
||||
def add_account_note_if_needed!(account, id)
|
||||
unless AccountNote.exists?(account: account, target_account: @target_account)
|
||||
text = I18n.with_locale(account.user&.locale.presence || I18n.default_locale) do
|
||||
I18n.t(id, acct: @source_account.acct)
|
||||
end
|
||||
AccountNote.create!(account: account, target_account: @target_account, comment: text)
|
||||
return if AccountNote.exists?(account: account, target_account: @target_account)
|
||||
|
||||
text = I18n.with_locale(account.user_locale.presence || I18n.default_locale) do
|
||||
I18n.t(id, acct: @source_account.acct)
|
||||
end
|
||||
AccountNote.create!(account: account, target_account: @target_account, comment: text)
|
||||
end
|
||||
|
||||
def skip_mute_move?(mute)
|
||||
mute.account.muting?(@target_account) || mute.account.following?(@target_account)
|
||||
end
|
||||
|
||||
def skip_block_move?(block)
|
||||
block.account.blocking?(@target_account) || block.account.following?(@target_account)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -9,7 +9,7 @@ class PublishScheduledStatusWorker
|
|||
scheduled_status = ScheduledStatus.find(scheduled_status_id)
|
||||
scheduled_status.destroy!
|
||||
|
||||
return true if scheduled_status.account.user.disabled?
|
||||
return true if scheduled_status.account.user_disabled?
|
||||
|
||||
PostStatusService.new.call(
|
||||
scheduled_status.account,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../../lib/mastodon/sidekiq_middleware'
|
||||
require_relative '../../lib/mastodon/worker_batch_middleware'
|
||||
|
||||
Sidekiq.configure_server do |config|
|
||||
config.redis = REDIS_CONFIGURATION.sidekiq
|
||||
|
@ -72,14 +73,12 @@ Sidekiq.configure_server do |config|
|
|||
|
||||
config.server_middleware do |chain|
|
||||
chain.add Mastodon::SidekiqMiddleware
|
||||
end
|
||||
|
||||
config.server_middleware do |chain|
|
||||
chain.add SidekiqUniqueJobs::Middleware::Server
|
||||
end
|
||||
|
||||
config.client_middleware do |chain|
|
||||
chain.add SidekiqUniqueJobs::Middleware::Client
|
||||
chain.add Mastodon::WorkerBatchMiddleware
|
||||
end
|
||||
|
||||
config.on(:startup) do
|
||||
|
@ -105,6 +104,7 @@ Sidekiq.configure_client do |config|
|
|||
|
||||
config.client_middleware do |chain|
|
||||
chain.add SidekiqUniqueJobs::Middleware::Client
|
||||
chain.add Mastodon::WorkerBatchMiddleware
|
||||
end
|
||||
|
||||
config.logger.level = Logger.const_get(ENV.fetch('RAILS_LOG_LEVEL', 'info').upcase.to_s)
|
||||
|
|
|
@ -560,6 +560,8 @@ br:
|
|||
one: "%{count} skeudenn"
|
||||
other: "%{count} skeudenn"
|
||||
two: "%{count} skeudenn"
|
||||
errors:
|
||||
quoted_status_not_found: War a seblant, n'eus ket eus an embannadenn emaoc'h o klask menegiñ.
|
||||
pin_errors:
|
||||
ownership: N'hallit ket spilhennañ embannadurioù ar re all
|
||||
quote_policies:
|
||||
|
|
|
@ -1870,6 +1870,7 @@ ca:
|
|||
edited_at_html: Editat %{date}
|
||||
errors:
|
||||
in_reply_not_found: El tut al qual intentes respondre sembla que no existeix.
|
||||
quoted_status_not_found: Sembla que la publicació que vols citar no existeix.
|
||||
over_character_limit: Límit de caràcters de %{max} superat
|
||||
pin_errors:
|
||||
direct: Els tuts que només són visibles per als usuaris mencionats no poden ser fixats
|
||||
|
|
|
@ -1958,6 +1958,7 @@ cs:
|
|||
edited_at_html: Upraven %{date}
|
||||
errors:
|
||||
in_reply_not_found: Příspěvek, na který se pokoušíte odpovědět, neexistuje.
|
||||
quoted_status_not_found: Zdá se, že příspěvek, který se pokoušíte citovat neexistuje.
|
||||
over_character_limit: byl překročen limit %{max} znaků
|
||||
pin_errors:
|
||||
direct: Příspěvky viditelné pouze zmíněným uživatelům nelze připnout
|
||||
|
|
|
@ -2043,6 +2043,7 @@ cy:
|
|||
edited_at_html: Wedi'i olygu %{date}
|
||||
errors:
|
||||
in_reply_not_found: Nid yw'n ymddangos bod y postiad rydych chi'n ceisio ei ateb yn bodoli.
|
||||
quoted_status_not_found: Nid yw'n ymddangos bod y postiad rydych chi'n ceisio'i ddyfynnu yn bodoli.
|
||||
over_character_limit: wedi mynd y tu hwnt i'r terfyn nodau o %{max}
|
||||
pin_errors:
|
||||
direct: Nid oes modd pinio postiadau sy'n weladwy i ddefnyddwyr a grybwyllwyd yn unig
|
||||
|
|
|
@ -1394,7 +1394,7 @@ da:
|
|||
filters:
|
||||
contexts:
|
||||
account: Profiler
|
||||
home: Hjemmetidslinje
|
||||
home: Hjem og lister
|
||||
notifications: Notifikationer
|
||||
public: Offentlig tidslinje
|
||||
thread: Samtaler
|
||||
|
@ -1872,6 +1872,7 @@ da:
|
|||
edited_at_html: Redigeret %{date}
|
||||
errors:
|
||||
in_reply_not_found: Indlægget, der forsøges besvaret, ser ikke ud til at eksistere.
|
||||
quoted_status_not_found: Indlægget, du forsøger at citere, ser ikke ud til at eksistere.
|
||||
over_character_limit: grænsen på %{max} tegn overskredet
|
||||
pin_errors:
|
||||
direct: Indlæg, som kun kan ses af omtalte brugere, kan ikke fastgøres
|
||||
|
|
|
@ -1872,6 +1872,7 @@ de:
|
|||
edited_at_html: 'Bearbeitet: %{date}'
|
||||
errors:
|
||||
in_reply_not_found: Der Beitrag, auf den du antworten möchtest, scheint nicht zu existieren.
|
||||
quoted_status_not_found: Der Beitrag, den du zitieren möchtest, scheint nicht zu existieren.
|
||||
over_character_limit: Begrenzung von %{max} Zeichen überschritten
|
||||
pin_errors:
|
||||
direct: Beiträge, die nur für erwähnte Profile sichtbar sind, können nicht angeheftet werden
|
||||
|
|
|
@ -1872,6 +1872,7 @@ el:
|
|||
edited_at_html: Επεξεργάστηκε στις %{date}
|
||||
errors:
|
||||
in_reply_not_found: Η ανάρτηση στην οποία προσπαθείς να απαντήσεις δεν φαίνεται να υπάρχει.
|
||||
quoted_status_not_found: Η ανάρτηση την οποία προσπαθείς να παραθέσεις δεν φαίνεται να υπάρχει.
|
||||
over_character_limit: υπέρβαση μέγιστου ορίου %{max} χαρακτήρων
|
||||
pin_errors:
|
||||
direct: Αναρτήσεις που είναι ορατές μόνο στους αναφερόμενους χρήστες δεν μπορούν να καρφιτσωθούν
|
||||
|
|
|
@ -1872,6 +1872,7 @@ es-AR:
|
|||
edited_at_html: Editado el %{date}
|
||||
errors:
|
||||
in_reply_not_found: El mensaje al que intentás responder no existe.
|
||||
quoted_status_not_found: El mensaje al que intentás citar parece que no existe.
|
||||
over_character_limit: se excedió el límite de %{max} caracteres
|
||||
pin_errors:
|
||||
direct: Los mensajes que sólo son visibles para los usuarios mencionados no pueden ser fijados
|
||||
|
|
|
@ -1872,6 +1872,7 @@ es-MX:
|
|||
edited_at_html: Editado %{date}
|
||||
errors:
|
||||
in_reply_not_found: La publicación a la que estás intentando responder no existe.
|
||||
quoted_status_not_found: La publicación que intentas citar no parece existir.
|
||||
over_character_limit: Límite de caracteres de %{max} superado
|
||||
pin_errors:
|
||||
direct: Las publicaciones que son visibles solo para los usuarios mencionados no pueden fijarse
|
||||
|
|
|
@ -1872,6 +1872,7 @@ es:
|
|||
edited_at_html: Editado %{date}
|
||||
errors:
|
||||
in_reply_not_found: La publicación a la que intentas responder no existe.
|
||||
quoted_status_not_found: La publicación que estás intentando citar no existe.
|
||||
over_character_limit: Límite de caracteres de %{max} superado
|
||||
pin_errors:
|
||||
direct: Las publicaciones que son visibles solo para los usuarios mencionados no pueden fijarse
|
||||
|
|
|
@ -1872,6 +1872,7 @@ fo:
|
|||
edited_at_html: Rættað %{date}
|
||||
errors:
|
||||
in_reply_not_found: Posturin, sum tú roynir at svara, sýnist ikki at finnast.
|
||||
quoted_status_not_found: Posturin, sum tú roynir at sitera, sýnist ikki at finnast.
|
||||
over_character_limit: mesta tal av teknum, %{max}, rokkið
|
||||
pin_errors:
|
||||
direct: Postar, sum einans eru sjónligir hjá nevndum brúkarum, kunnu ikki festast
|
||||
|
|
|
@ -1872,6 +1872,7 @@ gl:
|
|||
edited_at_html: Editado %{date}
|
||||
errors:
|
||||
in_reply_not_found: A publicación á que tentas responder semella que non existe.
|
||||
quoted_status_not_found: Parece que a publicación que intentas citar non existe.
|
||||
over_character_limit: Excedeu o límite de caracteres %{max}
|
||||
pin_errors:
|
||||
direct: As publicacións que só son visibles para as usuarias mencionadas non se poden fixar
|
||||
|
|
|
@ -1957,7 +1957,8 @@ he:
|
|||
two: 'מכיל את התגיות האסורות: %{tags}'
|
||||
edited_at_html: נערך ב-%{date}
|
||||
errors:
|
||||
in_reply_not_found: נראה שההודעה שאת/ה מנסה להגיב לה לא קיימת.
|
||||
in_reply_not_found: נראה שההודעה שנסית להגיב לה לא קיימת.
|
||||
quoted_status_not_found: נראה שההודעה שנסית לצטט לא קיימת.
|
||||
over_character_limit: חריגה מגבול התווים של %{max}
|
||||
pin_errors:
|
||||
direct: לא ניתן לקבע הודעות שנראותן מוגבלת למכותבים בלבד
|
||||
|
|
|
@ -1872,6 +1872,7 @@ hu:
|
|||
edited_at_html: 'Szerkesztve: %{date}'
|
||||
errors:
|
||||
in_reply_not_found: Már nem létezik az a bejegyzés, melyre válaszolni szeretnél.
|
||||
quoted_status_not_found: Már nem létezik az a bejegyzés, amelyből idézni szeretnél.
|
||||
over_character_limit: túllépted a maximális %{max} karakteres keretet
|
||||
pin_errors:
|
||||
direct: A csak a megemlített felhasználók számára látható bejegyzések nem tűzhetők ki
|
||||
|
|
|
@ -1876,6 +1876,7 @@ is:
|
|||
edited_at_html: Breytt %{date}
|
||||
errors:
|
||||
in_reply_not_found: Færslan sem þú ert að reyna að svara að er líklega ekki til.
|
||||
quoted_status_not_found: Færslan sem þú ert að reyna að vitna í virðist ekki vera til.
|
||||
over_character_limit: hámarksfjölda stafa (%{max}) náð
|
||||
pin_errors:
|
||||
direct: Ekki er hægt að festa færslur sem einungis eru sýnilegar þeim notendum sem minnst er á
|
||||
|
|
|
@ -912,6 +912,10 @@ lt:
|
|||
your_appeal_rejected: Tavo apeliacija buvo atmesta
|
||||
edit_profile:
|
||||
hint_html: "<strong>Tinkink tai, ką žmonės mato tavo viešame profilyje ir šalia įrašų.</strong> Kiti žmonės labiau linkę sekti atgal ir bendrauti su tavimi, jei tavo profilis yra užpildytas ir turi profilio nuotrauką."
|
||||
emoji_styles:
|
||||
auto: Automatinis
|
||||
native: Vietiniai
|
||||
twemoji: Tvejaustukai
|
||||
errors:
|
||||
'403': Jūs neturie prieigos matyti šiam puslapiui.
|
||||
'404': Puslapis nerastas.
|
||||
|
@ -1183,6 +1187,8 @@ lt:
|
|||
other: "%{count} vaizdų"
|
||||
boosted_from_html: Pakelta iš %{acct_link}
|
||||
content_warning: 'Turinio įspėjimas: %{warning}'
|
||||
errors:
|
||||
quoted_status_not_found: Įrašas, kurį bandote cituoti, atrodo, neegzistuoja.
|
||||
over_character_limit: pasiektas %{max} simbolių limitas
|
||||
pin_errors:
|
||||
limit: Jūs jau prisegėte maksimalų toot'ų skaičų
|
||||
|
|
|
@ -97,7 +97,7 @@ nan:
|
|||
silenced: 受限制
|
||||
suspended: 權限中止ah
|
||||
title: 管理
|
||||
moderation_notes: 管理ê註釋
|
||||
moderation_notes: 管理ê筆記
|
||||
most_recent_activity: 最近ê活動時間
|
||||
most_recent_ip: 最近ê IP
|
||||
no_account_selected: 因為無揀任何口座,所以lóng無改變
|
||||
|
@ -245,7 +245,7 @@ nan:
|
|||
create_announcement_html: "%{name} kā公告 %{target} 建立ah"
|
||||
create_canonical_email_block_html: "%{name} kā hash是 %{target} ê電子phue封鎖ah"
|
||||
create_custom_emoji_html: "%{name} kā 新ê emoji %{target} 傳上去ah"
|
||||
create_domain_allow_html: "%{name} 允准 %{target} 域名加入聯邦宇宙"
|
||||
create_domain_allow_html: "%{name} 允准 %{target} 域名加入聯邦"
|
||||
create_domain_block_html: "%{name} 封鎖域名 %{target}"
|
||||
create_email_domain_block_html: "%{name} kā 電子phue域名 %{target} 封鎖ah"
|
||||
create_ip_block_html: "%{name} 建立 IP %{target} ê規則"
|
||||
|
@ -256,7 +256,7 @@ nan:
|
|||
destroy_announcement_html: "%{name} kā公告 %{target} thâi掉ah"
|
||||
destroy_canonical_email_block_html: "%{name} kā hash是 %{target} ê電子phue取消封鎖ah"
|
||||
destroy_custom_emoji_html: "%{name} kā 新ê emoji %{target} thâi掉ah"
|
||||
destroy_domain_allow_html: "%{name} 無允准 %{target} 域名加入聯邦宇宙"
|
||||
destroy_domain_allow_html: "%{name} 無允准 %{target} 域名加入聯邦"
|
||||
destroy_domain_block_html: "%{name} 取消封鎖域名 %{target}"
|
||||
destroy_email_domain_block_html: "%{name} kā 電子phue域名 %{target} 取消封鎖ah"
|
||||
destroy_instance_html: "%{name} 清除域名 %{target}"
|
||||
|
@ -531,16 +531,111 @@ nan:
|
|||
content_policies:
|
||||
comment: 內部ê筆記
|
||||
description_html: Lí ē當定義用tī所有tuì tsit ê域名kap伊ê子域名來ê口座ê內容政策。
|
||||
limited_federation_mode_description_html: Lí通選擇kám beh允准tsit ê域名加入聯邦。
|
||||
policies:
|
||||
reject_media: 拒絕媒體
|
||||
reject_reports: 拒絕檢舉
|
||||
silence: 限制
|
||||
suspend: 中止權限
|
||||
policy: 政策
|
||||
reason: 公開ê理由
|
||||
title: 內容政策
|
||||
dashboard:
|
||||
instance_accounts_dimension: 上tsē lâng跟tuè ê口座
|
||||
instance_accounts_measure: 儲存ê口座
|
||||
instance_followers_measure: lán tī hia ê跟tuè者
|
||||
instance_follows_measure: in tī tsia ê跟tuè者
|
||||
instance_languages_dimension: Tsia̍p用ê語言
|
||||
instance_media_attachments_measure: 儲存ê媒體附件
|
||||
instance_reports_measure: 關係in ê檢舉
|
||||
instance_statuses_measure: 儲存ê PO文
|
||||
delivery:
|
||||
all: 全部
|
||||
clear: 清寄送ê錯誤
|
||||
failing: 失敗
|
||||
restart: 重頭啟動寄送
|
||||
stop: 停止寄送
|
||||
unavailable: Bē當用
|
||||
delivery_available: 通寄送
|
||||
delivery_error_days: 寄送錯誤ê日數
|
||||
delivery_error_hint: Nā連續 %{count} kang bē當寄送,就ē自動標做bē當寄送。
|
||||
destroyed_msg: Tuì %{domain} 來ê資料,teh排隊beh thâi掉。
|
||||
empty: Tshuē無域名。
|
||||
known_accounts:
|
||||
other: "%{count} ê知影ê口座"
|
||||
moderation:
|
||||
all: 全部
|
||||
limited: 受限制
|
||||
title: 管理
|
||||
moderation_notes:
|
||||
create: 加添管理筆記
|
||||
created_msg: 站臺ê管理記錄成功建立!
|
||||
description_html: 檢視á是替別ê管理者kap未來ê家己留筆記
|
||||
destroyed_msg: 站臺ê管理記錄成功thâi掉!
|
||||
placeholder: 關係本站、行ê行動,á是其他通幫tsān lí未來管本站ê資訊。
|
||||
title: 管理ê筆記
|
||||
private_comment: 私人評論
|
||||
public_comment: 公開ê評論
|
||||
purge: 清除
|
||||
purge_description_html: Nā lí想講tsit ê域名ē永永斷線,ē當tuì儲存內底thâi掉uì tsit ê域名來ê所有口座記錄kap相關資料。Huân-sè ē開點á時間。
|
||||
title: 聯邦
|
||||
total_blocked_by_us: Hōo lán封鎖
|
||||
total_followed_by_them: Hōo in跟tuè
|
||||
total_followed_by_us: Hōo lán跟tuè
|
||||
total_reported: 關係in ê檢舉
|
||||
total_storage: 媒體ê附件
|
||||
totals_time_period_hint_html: 下kha顯示ê總計包含ta̍k時ê資料。
|
||||
unknown_instance: 佇本服務器,現tsú時iáu無tsit ê域名ê記錄。
|
||||
invites:
|
||||
deactivate_all: Lóng停用
|
||||
filter:
|
||||
all: 全部
|
||||
available: 通用ê
|
||||
expired: 過期ê
|
||||
title: 過濾器
|
||||
title: 邀請
|
||||
ip_blocks:
|
||||
add_new: 建立規則
|
||||
created_msg: 成功加添新ê IP規則
|
||||
delete: Thâi掉
|
||||
expires_in:
|
||||
'1209600': 2 禮拜
|
||||
'15778476': 6個月
|
||||
'2629746': 1 個月
|
||||
'31556952': 1 年
|
||||
'86400': 1 kang
|
||||
'94670856': 3 年
|
||||
new:
|
||||
title: 建立新ê IP規則
|
||||
no_ip_block_selected: 因為無揀任何IP規則,所以lóng無改變
|
||||
title: IP規則
|
||||
relationships:
|
||||
title: "%{acct} ê關係"
|
||||
relays:
|
||||
add_new: 加添新ê中繼
|
||||
delete: Thâi掉
|
||||
description_html: "<strong>聯邦ê中繼站</strong> 是中lâng ê服侍器,ē tī訂koh公開kàu hit ê中繼站ê服侍器之間,交換tsē-tsē ê 公開PO文。<strong>中繼站通幫tsān小型kap中型服侍器tuì聯邦宇宙發現內容</strong>,本地ê用者免手動跟tuè遠距離ê服侍器ê別lâng。"
|
||||
disable: 停止使用
|
||||
disabled: 停止使用ê
|
||||
enable: 啟用
|
||||
enable_hint: Lí ê服侍器tsi̍t-ē啟動,ē訂tuì tsit ê中繼逐ê公開PO文,mā ē開始送tsit ê服侍器ê公開PO文kàu hia。
|
||||
enabled: 啟用ê
|
||||
inbox_url: 中繼 URL
|
||||
pending: Teh等中繼站允准
|
||||
save_and_enable: 儲存koh啟用
|
||||
setup: 設定中繼ê連結
|
||||
signatures_not_enabled: Nā啟用安全模式á是受限ê聯邦模式,中繼可能buē-tàng正常運作
|
||||
status: 狀態
|
||||
title: 中繼
|
||||
report_notes:
|
||||
created_msg: 檢舉記錄成功建立!
|
||||
destroyed_msg: 檢舉記錄成功thâi掉!
|
||||
reports:
|
||||
account:
|
||||
notes:
|
||||
other: "%{count} 篇筆記"
|
||||
action_log: 審查日誌
|
||||
action_taken_by: 操作由
|
||||
statuses:
|
||||
language: 語言
|
||||
trends:
|
||||
|
|
|
@ -1872,6 +1872,7 @@ nl:
|
|||
edited_at_html: Bewerkt op %{date}
|
||||
errors:
|
||||
in_reply_not_found: Het bericht waarop je probeert te reageren lijkt niet te bestaan.
|
||||
quoted_status_not_found: Het bericht die je probeert te citeren lijkt niet te bestaan.
|
||||
over_character_limit: Limiet van %{max} tekens overschreden
|
||||
pin_errors:
|
||||
direct: Berichten die alleen zichtbaar zijn voor vermelde gebruikers, kunnen niet worden vastgezet
|
||||
|
|
|
@ -1872,6 +1872,7 @@ pt-PT:
|
|||
edited_at_html: Editado em %{date}
|
||||
errors:
|
||||
in_reply_not_found: A publicação a que estás a tentar responder parece não existir.
|
||||
quoted_status_not_found: A publicação que está a tentar citar parece não existir.
|
||||
over_character_limit: limite de caracteres %{max} excedido
|
||||
pin_errors:
|
||||
direct: As publicações que só são visíveis para os utilizadores mencionados não podem ser fixadas
|
||||
|
|
|
@ -1352,7 +1352,7 @@ ru:
|
|||
edit_profile:
|
||||
basic_information: Основные данные
|
||||
hint_html: "<strong>Здесь вы можете изменить всё то, что будет отображаться в вашем публичном профиле и рядом с вашими постами.</strong> На вас будут чаще подписываться и с вами будут чаще взаимодействовать, если у вас будет заполнен профиль и добавлено фото профиля."
|
||||
other: Прочее
|
||||
other: Разное
|
||||
emoji_styles:
|
||||
auto: Автоматически
|
||||
native: Как в системе
|
||||
|
@ -1630,19 +1630,19 @@ ru:
|
|||
media_attachments:
|
||||
validations:
|
||||
images_and_video: Нельзя добавить видео к посту с изображениями
|
||||
not_found: Медиа %{ids} не найдено или уже прикреплено к другому сообщению
|
||||
not_ready: Не удаётся прикрепить файлы, обработка которых не завершена. Повторите попытку чуть позже!
|
||||
too_many: Нельзя добавить более 4 файлов
|
||||
not_found: Медиа %{ids} не найдены или уже прикреплены к другому посту
|
||||
not_ready: Обработка некоторых прикреплённых файлов ещё не окончена. Подождите немного и попробуйте снова!
|
||||
too_many: Можно прикрепить не более 4 файлов
|
||||
migrations:
|
||||
acct: имя@домен новой учётной записи
|
||||
acct: Куда
|
||||
cancel: Отменить переезд
|
||||
cancel_explanation: Отмена перенаправления повторно активирует текущую учётную запись, но не вернёт обратно подписчиков, которые были перемещены на другую.
|
||||
cancelled_msg: Переезд был успешно отменён.
|
||||
cancel_explanation: После отмены перенаправления ваша текущая учётная запись снова станет активна, но ранее перенесённые подписчики не будут возвращены.
|
||||
cancelled_msg: Переезд отменён.
|
||||
errors:
|
||||
already_moved: это та же учётная запись, на которую вы мигрировали
|
||||
missing_also_known_as: не ссылается на эту учетную запись
|
||||
already_moved: не может быть той учётной записью, куда уже настроен переезд
|
||||
missing_also_known_as: должна быть связанной учётной записью
|
||||
move_to_self: не может быть текущей учётной записью
|
||||
not_found: не удалось найти
|
||||
not_found: не найдена
|
||||
on_cooldown: Вы пока не можете переезжать
|
||||
followers_count: Подписчиков на момент переезда
|
||||
incoming_migrations: Переезд со старой учётной записи
|
||||
|
@ -1650,25 +1650,25 @@ ru:
|
|||
moved_msg: Теперь ваша учётная запись перенаправляет к %{acct}, туда же перемещаются подписчики.
|
||||
not_redirecting: Для вашей учётной записи пока не настроено перенаправление.
|
||||
on_cooldown: Вы уже недавно переносили свою учётную запись. Эта возможность будет снова доступна через %{count} дн.
|
||||
past_migrations: Прошлые переезды
|
||||
past_migrations: История переездов
|
||||
proceed_with_move: Перенести подписчиков
|
||||
redirected_msg: Ваша учётная запись теперь перенаправляется на %{acct}.
|
||||
redirecting_to: Ваша учётная запись перенаправляет к %{acct}.
|
||||
set_redirect: Настроить перенаправление
|
||||
warning:
|
||||
backreference_required: Новая учётная запись должна быть сначала настроена так, чтоб ссылаться на текущую
|
||||
before: 'Прежде чем продолжить, внимательно прочитайте следующую информацию:'
|
||||
cooldown: После переезда наступает период, в течение которого вы не сможете ещё раз переехать
|
||||
backreference_required: Текущая учётная запись сначала должна быть добавлена как связанная в настройках новой учётной записи
|
||||
before: 'Внимательно ознакомьтесь со следующими замечаниями перед тем как продолжить:'
|
||||
cooldown: После переезда наступит период ожидания, в течение которого переезд будет невозможен
|
||||
disabled_account: Вашу текущую учётная запись впоследствии нельзя будет больше использовать. При этом, у вас будет доступ к экспорту данных, а также к повторной активации учётной записи.
|
||||
followers: Это действие перенесёт всех ваших подписчиков с текущей учётной записи на новую
|
||||
only_redirect_html: Или же вы можете <a href="%{path}">просто настроить перенаправление в ваш профиль</a>.
|
||||
followers: В результате переезда все ваши подписчики будут перенесены с текущей учётной записи на новую
|
||||
only_redirect_html: Также вы можете <a href="%{path}">настроить перенаправление без переноса подписчиков</a>.
|
||||
other_data: Никакие другие данные не будут автоматически перенесены
|
||||
redirect: Профиль этой учётной записи будет обновлён с заметкой о перенаправлении, а также исключён из поиска
|
||||
redirect: Профиль текущей учётной записи будет исключён из поиска, а в нём появится объявление о переезде
|
||||
moderation:
|
||||
title: Модерация
|
||||
move_handler:
|
||||
carry_blocks_over_text: Этот пользователь переехал с учётной записи %{acct}, которую вы заблокировали.
|
||||
carry_mutes_over_text: Этот пользователь перешёл с учётной записи %{acct}, которую вы игнорируете.
|
||||
carry_mutes_over_text: Этот пользователь переехал с учётной записи %{acct}, которую вы игнорируете.
|
||||
copy_account_note_text: 'Этот пользователь переехал с %{acct}, вот ваша предыдущая заметка о нём:'
|
||||
navigation:
|
||||
toggle_menu: Переключить меню
|
||||
|
@ -1717,8 +1717,9 @@ ru:
|
|||
billion: млрд
|
||||
million: млн
|
||||
quadrillion: квадрлн
|
||||
thousand: тыс
|
||||
thousand: тыс.
|
||||
trillion: трлн
|
||||
unit: ''
|
||||
otp_authentication:
|
||||
code_hint: Для подтверждения введите код, сгенерированный приложением-аутентификатором
|
||||
description_html: Подключив <strong>двуфакторную авторизацию</strong>, для входа в свою учётную запись вам будет необходим смартфон и приложение-аутентификатор на нём, которое будет генерировать специальные временные коды. Без этих кодов войти в учётную запись не получиться, даже если все данные верны, что существенно увеличивает безопасность вашей учётной записи.
|
||||
|
@ -1728,32 +1729,32 @@ ru:
|
|||
setup: Настроить
|
||||
wrong_code: Введенный код недействителен! Время сервера и время устройства правильно?
|
||||
pagination:
|
||||
newer: Новее
|
||||
next: След
|
||||
older: Старше
|
||||
prev: Пред
|
||||
newer: Позже
|
||||
next: Вперёд
|
||||
older: Раньше
|
||||
prev: Назад
|
||||
truncate: "…"
|
||||
polls:
|
||||
errors:
|
||||
already_voted: Вы уже голосовали в этом опросе
|
||||
already_voted: Вы уже проголосовали в этом опросе
|
||||
duplicate_options: не должны повторяться
|
||||
duration_too_long: слишком велика
|
||||
duration_too_short: слишком мала
|
||||
expired: Опрос уже завершился
|
||||
invalid_choice: Выбранного варианта голосования не существует
|
||||
expired: Этот опрос уже завершился
|
||||
invalid_choice: Выбранного вами варианта ответа не существует
|
||||
over_character_limit: не должны превышать %{max} символов
|
||||
self_vote: Вы не можете голосовать в своих опросах
|
||||
too_few_options: должны содержать не меньше двух опций
|
||||
too_many_options: должны ограничиваться максимум %{max} опциями
|
||||
preferences:
|
||||
other: Остальное
|
||||
posting_defaults: Настройки отправки по умолчанию
|
||||
other: Разное
|
||||
posting_defaults: Предустановки для новых постов
|
||||
public_timelines: Публичные ленты
|
||||
privacy:
|
||||
hint_html: "<strong>Настройте, как вы хотите, чтобы ваш профиль и ваши сообщения были найдены.</strong> Различные функции в Mastodon могут помочь вам охватить более широкую аудиторию, если они включены. Уделите время изучению этих настроек, чтобы убедиться, что они подходят для вашего случая использования."
|
||||
privacy: Конфиденциальность
|
||||
privacy: Приватность
|
||||
privacy_hint_html: Определите, какую информацию вы хотите раскрыть в интересах других. Люди находят интересные профили и приложения, просматривая список подписчиков других людей и узнавая, из каких приложений они публикуют свои сообщения, но вы можете предпочесть скрыть это.
|
||||
reach: Охват
|
||||
reach: Видимость
|
||||
reach_hint_html: Укажите, хотите ли вы, чтобы новые люди обнаруживали вас и могли следить за вами. Хотите ли вы, чтобы ваши сообщения появлялись на экране Обзора? Хотите ли вы, чтобы другие люди видели вас в своих рекомендациях? Хотите ли вы автоматически принимать всех новых подписчиков или иметь возможность детально контролировать каждого из них?
|
||||
search: Поиск
|
||||
search_hint_html: Определите, как вас могут найти. Хотите ли вы, чтобы люди находили вас по тому, о чём вы публично писали? Хотите ли вы, чтобы люди за пределами Mastodon находили ваш профиль при поиске в Интернете? Следует помнить, что полное исключение из всех поисковых систем не может быть гарантировано для публичной информации.
|
||||
|
|
|
@ -9,7 +9,7 @@ da:
|
|||
fields: Din hjemmeside, dine pronominer, din alder, eller hvad du har lyst til.
|
||||
indexable: Dine offentlige indlæg vil kunne vises i Mastodon-søgeresultater. Folk, som har interageret med dem, vil kunne finde dem uanset.
|
||||
note: 'Du kan @omtale andre personer eller #hashtags.'
|
||||
show_collections: Folk vil ikke kunne tjekke dine Følger og Følgere. Folk, du selv følger, vil stadig kunne se dette.
|
||||
show_collections: Folk vil kunne se, hvem du følger, og hvem der følger dig. Personer, som du følger, vil kunne se, at du følger dem.
|
||||
unlocked: Man vil kunne følges af folk uden først at godkende dem. Ønsker man at gennemgå Følg-anmodninger og individuelt acceptere/afvise nye følgere, så fjern markeringen.
|
||||
account_alias:
|
||||
acct: Angiv brugernavn@domain for den konto, hvorfra du vil flytte
|
||||
|
@ -75,7 +75,7 @@ da:
|
|||
featured_tag:
|
||||
name: 'Her er nogle af dine hyppigst brugte hashtags:'
|
||||
filters:
|
||||
action: Vælg handlingen til eksekvering, når et indlæg matcher filteret
|
||||
action: Vælg, hvilken handling, der skal udføres, når et indlæg matcher filteret
|
||||
actions:
|
||||
blur: Skjul medier bag en advarsel, uden at skjule selve teksten
|
||||
hide: Skjul det filtrerede indhold fuldstændigt og gør, som om det ikke eksisterer
|
||||
|
|
|
@ -60,6 +60,7 @@ lt:
|
|||
setting_display_media_default: Slėpti mediją, pažymėtą kaip jautrią
|
||||
setting_display_media_hide_all: Visada slėpti mediją
|
||||
setting_display_media_show_all: Visada rodyti mediją
|
||||
setting_emoji_style: Kaip rodyti emodžius. „Auto“ bandys naudoti vietinius jaustukus, bet senesnėse naršyklėse grįš prie Tvejaustukų.
|
||||
setting_system_scrollbars_ui: Taikoma tik darbalaukio naršyklėms, karkasiniais „Safari“ ir „Chrome“.
|
||||
setting_use_blurhash: Gradientai pagrįsti paslėptų vizualizacijų spalvomis, bet užgožia bet kokias detales.
|
||||
setting_use_pending_items: Slėpti laiko skalės naujienas po paspaudimo, vietoj automatinio srauto slinkimo.
|
||||
|
@ -120,6 +121,11 @@ lt:
|
|||
min_age: Neturėtų būti žemiau mažiausio amžiaus, reikalaujamo pagal jūsų jurisdikcijos įstatymus.
|
||||
user:
|
||||
chosen_languages: Kai pažymėta, viešose laiko skalėse bus rodomi tik įrašai pasirinktomis kalbomis.
|
||||
date_of_birth:
|
||||
few: Turime įsitikinti, kad esate bent %{count} norint naudotis %{domain}. Mes to neišsaugosime.
|
||||
many: Turime įsitikinti, kad esate bent %{count} norint naudotis %{domain}. Mes to neišsaugosime.
|
||||
one: Turime įsitikinti, kad esate bent %{count} norint naudotis %{domain}. Mes to neišsaugosime.
|
||||
other: Turime įsitikinti, kad esate bent %{count} norint naudotis %{domain}. Mes to neišsaugosime.
|
||||
role: Vaidmuo valdo, kokius leidimus naudotojas turi.
|
||||
labels:
|
||||
account:
|
||||
|
@ -162,6 +168,7 @@ lt:
|
|||
setting_display_media: Medijos rodymas
|
||||
setting_display_media_hide_all: Slėpti viską
|
||||
setting_display_media_show_all: Rodyti viską
|
||||
setting_emoji_style: Jaustuko stilius
|
||||
setting_expand_spoilers: Visada išplėsti įrašus, pažymėtus turinio įspėjimais
|
||||
setting_hide_network: Slėpti savo socialinę diagramą
|
||||
setting_missing_alt_text_modal: Rodyti patvirtinimo dialogo langą prieš skelbiant mediją be alternatyvaus teksto.
|
||||
|
|
|
@ -1872,6 +1872,7 @@ tr:
|
|||
edited_at_html: "%{date} tarihinde düzenlendi"
|
||||
errors:
|
||||
in_reply_not_found: Yanıtlamaya çalıştığınız durum yok gibi görünüyor.
|
||||
quoted_status_not_found: Alıntılamaya çalıştığınız gönderi mevcut görünmüyor.
|
||||
over_character_limit: "%{max} karakter limiti aşıldı"
|
||||
pin_errors:
|
||||
direct: Sadece değinilen kullanıcıların görebileceği gönderiler üstte tutulamaz
|
||||
|
|
|
@ -1846,6 +1846,7 @@ uk:
|
|||
edited_at_html: Відредаговано %{date}
|
||||
errors:
|
||||
in_reply_not_found: Допису, на який ви намагаєтеся відповісти, не існує.
|
||||
quoted_status_not_found: Повідомлення, яке ви намагаєтеся цитувати, не існує.
|
||||
over_character_limit: перевищено ліміт символів %{max}
|
||||
pin_errors:
|
||||
direct: Не можливо прикріпити дописи, які видимі лише згаданим користувачам
|
||||
|
|
|
@ -1829,6 +1829,7 @@ vi:
|
|||
edited_at_html: Sửa %{date}
|
||||
errors:
|
||||
in_reply_not_found: Bạn đang trả lời một tút không còn tồn tại.
|
||||
quoted_status_not_found: Bạn đang trích dẫn một tút không còn tồn tại.
|
||||
over_character_limit: vượt quá giới hạn %{max} ký tự
|
||||
pin_errors:
|
||||
direct: Không thể ghim những tút nhắn riêng
|
||||
|
|
|
@ -1830,7 +1830,8 @@ zh-TW:
|
|||
other: 含有不得使用的標籤: %{tags}
|
||||
edited_at_html: 編輯於 %{date}
|
||||
errors:
|
||||
in_reply_not_found: 您嘗試回覆的嘟文看起來不存在。
|
||||
in_reply_not_found: 您嘗試回覆之嘟文似乎不存在。
|
||||
quoted_status_not_found: 您嘗試引用之嘟文似乎不存在。
|
||||
over_character_limit: 已超過 %{max} 字的限制
|
||||
pin_errors:
|
||||
direct: 無法釘選只有僅提及使用者可見之嘟文
|
||||
|
|
|
@ -7,7 +7,17 @@ if Rails.env.development?
|
|||
admin = Account.where(username: 'admin').first_or_initialize(username: 'admin')
|
||||
admin.save(validate: false)
|
||||
|
||||
user = User.where(email: "admin@#{domain}").first_or_initialize(email: "admin@#{domain}", password: 'mastodonadmin', password_confirmation: 'mastodonadmin', confirmed_at: Time.now.utc, role: UserRole.find_by(name: 'Owner'), account: admin, agreement: true, approved: true)
|
||||
user = User.where(email: "admin@#{domain}").first_or_initialize(
|
||||
email: "admin@#{domain}",
|
||||
password: 'mastodonadmin',
|
||||
password_confirmation: 'mastodonadmin',
|
||||
confirmed_at: Time.now.utc,
|
||||
role: UserRole.find_by(name: 'Owner'),
|
||||
account: admin,
|
||||
agreement: true,
|
||||
approved: true,
|
||||
bypass_registration_checks: true
|
||||
)
|
||||
user.save!
|
||||
user.approve!
|
||||
end
|
||||
|
|
11
lib/mastodon/worker_batch_middleware.rb
Normal file
11
lib/mastodon/worker_batch_middleware.rb
Normal file
|
@ -0,0 +1,11 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Mastodon::WorkerBatchMiddleware
|
||||
def call(_worker, msg, _queue, _redis_pool = nil)
|
||||
if (batch = Thread.current[:batch])
|
||||
batch.add_jobs([msg['jid']])
|
||||
end
|
||||
|
||||
yield
|
||||
end
|
||||
end
|
|
@ -180,6 +180,14 @@ RSpec.describe JsonLdHelper do
|
|||
expect(compacted.dig('object', 'tag', 0, 'href')).to eq ['foo']
|
||||
expect(safe_for_forwarding?(json, compacted)).to be true
|
||||
end
|
||||
|
||||
context 'when array size mismatch exists' do
|
||||
subject { helper.patch_for_forwarding!(json, alternate) }
|
||||
|
||||
let(:alternate) { json.merge('to' => %w(one two three)) }
|
||||
|
||||
it { is_expected.to be_nil }
|
||||
end
|
||||
end
|
||||
|
||||
describe 'safe_for_forwarding?' do
|
||||
|
|
|
@ -4,15 +4,15 @@ require 'rails_helper'
|
|||
|
||||
RSpec.describe Webfinger do
|
||||
describe 'self link' do
|
||||
subject { described_class.new('acct:alice@example.com').perform }
|
||||
|
||||
context 'when self link is specified with type application/activity+json' do
|
||||
let!(:webfinger) { { subject: 'acct:alice@example.com', links: [{ rel: 'self', href: 'https://example.com/alice', type: 'application/activity+json' }] } }
|
||||
|
||||
it 'correctly parses the response' do
|
||||
stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' })
|
||||
|
||||
response = described_class.new('acct:alice@example.com').perform
|
||||
|
||||
expect(response.self_link_href).to eq 'https://example.com/alice'
|
||||
expect(subject.self_link_href).to eq 'https://example.com/alice'
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -22,9 +22,7 @@ RSpec.describe Webfinger do
|
|||
it 'correctly parses the response' do
|
||||
stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' })
|
||||
|
||||
response = described_class.new('acct:alice@example.com').perform
|
||||
|
||||
expect(response.self_link_href).to eq 'https://example.com/alice'
|
||||
expect(subject.self_link_href).to eq 'https://example.com/alice'
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -34,7 +32,45 @@ RSpec.describe Webfinger do
|
|||
it 'raises an error' do
|
||||
stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' })
|
||||
|
||||
expect { described_class.new('acct:alice@example.com').perform }.to raise_error(Webfinger::Error)
|
||||
expect { subject }
|
||||
.to raise_error(Webfinger::Error)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when webfinger fails and host meta is used' do
|
||||
before { stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(status: 404) }
|
||||
|
||||
context 'when host meta succeeds' do
|
||||
let(:host_meta) do
|
||||
<<~XML
|
||||
<?xml version="1.0"?>
|
||||
<XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0">
|
||||
<Link rel="lrdd" type="application/xrd+xml" template="https://example.com/.well-known/nonStandardWebfinger?resource={uri}"/>
|
||||
</XRD>
|
||||
XML
|
||||
end
|
||||
let(:webfinger) { { subject: 'acct:alice@example.com', links: [{ rel: 'self', href: 'https://example.com/alice-from-NS', type: 'application/activity+json' }] } }
|
||||
|
||||
before do
|
||||
stub_request(:get, 'https://example.com/.well-known/host-meta').to_return(body: host_meta, headers: { 'Content-Type': 'application/jrd+json' })
|
||||
stub_request(:get, 'https://example.com/.well-known/nonStandardWebfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' })
|
||||
end
|
||||
|
||||
it 'uses host meta details' do
|
||||
expect(subject.self_link_href)
|
||||
.to eq 'https://example.com/alice-from-NS'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when host meta fails' do
|
||||
before do
|
||||
stub_request(:get, 'https://example.com/.well-known/host-meta').to_return(status: 500)
|
||||
end
|
||||
|
||||
it 'raises error' do
|
||||
expect { subject }
|
||||
.to raise_error(Webfinger::Error)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
63
spec/models/announcement_reaction_spec.rb
Normal file
63
spec/models/announcement_reaction_spec.rb
Normal file
|
@ -0,0 +1,63 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe AnnouncementReaction do
|
||||
describe 'Associations' do
|
||||
it { is_expected.to belong_to(:account) }
|
||||
it { is_expected.to belong_to(:announcement).inverse_of(:announcement_reactions) }
|
||||
it { is_expected.to belong_to(:custom_emoji).optional }
|
||||
end
|
||||
|
||||
describe 'Validations' do
|
||||
subject { Fabricate.build :announcement_reaction }
|
||||
|
||||
it { is_expected.to validate_presence_of(:name) }
|
||||
it { is_expected.to allow_values('😀').for(:name) }
|
||||
it { is_expected.to_not allow_values('INVALID').for(:name) }
|
||||
|
||||
context 'when reaction limit is reached' do
|
||||
subject { Fabricate.build :announcement_reaction, announcement: announcement_reaction.announcement }
|
||||
|
||||
let(:announcement_reaction) { Fabricate :announcement_reaction, name: '😊' }
|
||||
|
||||
before { stub_const 'ReactionValidator::LIMIT', 1 }
|
||||
|
||||
it { is_expected.to_not allow_values('😀').for(:name).against(:base) }
|
||||
end
|
||||
end
|
||||
|
||||
describe 'Callbacks' do
|
||||
describe 'Setting custom emoji association' do
|
||||
subject { Fabricate.build :announcement_reaction, name: }
|
||||
|
||||
context 'when name is missing' do
|
||||
let(:name) { '' }
|
||||
|
||||
it 'does not set association' do
|
||||
expect { subject.valid? }
|
||||
.to not_change(subject, :custom_emoji).from(be_blank)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when name matches a custom emoji shortcode' do
|
||||
let(:name) { 'custom' }
|
||||
let!(:custom_emoji) { Fabricate :custom_emoji, shortcode: 'custom' }
|
||||
|
||||
it 'sets association' do
|
||||
expect { subject.valid? }
|
||||
.to change(subject, :custom_emoji).from(be_blank).to(custom_emoji)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when name does not match a custom emoji' do
|
||||
let(:name) { 'custom' }
|
||||
|
||||
it 'does not set association' do
|
||||
expect { subject.valid? }
|
||||
.to not_change(subject, :custom_emoji).from(be_blank)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -28,4 +28,26 @@ RSpec.describe List do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'Scopes' do
|
||||
describe '.with_list_account' do
|
||||
let(:alice) { Fabricate :account }
|
||||
let(:bob) { Fabricate :account }
|
||||
let(:list) { Fabricate :list }
|
||||
let(:other_list) { Fabricate :list }
|
||||
|
||||
before do
|
||||
Fabricate :follow, account: list.account, target_account: alice
|
||||
Fabricate :follow, account: other_list.account, target_account: bob
|
||||
Fabricate :list_account, list: list, account: alice
|
||||
Fabricate :list_account, list: other_list, account: bob
|
||||
end
|
||||
|
||||
it 'returns lists connected to the account' do
|
||||
expect(described_class.with_list_account(alice))
|
||||
.to include(list)
|
||||
.and not_include(other_list)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -17,6 +17,7 @@ RSpec.describe Tag do
|
|||
subject { Fabricate :tag, name: 'original' }
|
||||
|
||||
it { is_expected.to_not allow_value('changed').for(:name).with_message(previous_name_error_message) }
|
||||
it { is_expected.to allow_value('ORIGINAL').for(:name) }
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -31,6 +32,7 @@ RSpec.describe Tag do
|
|||
subject { Fabricate :tag, name: 'original', display_name: 'OriginalDisplayName' }
|
||||
|
||||
it { is_expected.to_not allow_value('ChangedDisplayName').for(:display_name).with_message(previous_name_error_message) }
|
||||
it { is_expected.to allow_value('ORIGINAL').for(:display_name) }
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -13791,8 +13791,8 @@ __metadata:
|
|||
linkType: hard
|
||||
|
||||
"vite-plugin-pwa@npm:^1.0.0":
|
||||
version: 1.0.1
|
||||
resolution: "vite-plugin-pwa@npm:1.0.1"
|
||||
version: 1.0.2
|
||||
resolution: "vite-plugin-pwa@npm:1.0.2"
|
||||
dependencies:
|
||||
debug: "npm:^4.3.6"
|
||||
pretty-bytes: "npm:^6.1.1"
|
||||
|
@ -13807,7 +13807,7 @@ __metadata:
|
|||
peerDependenciesMeta:
|
||||
"@vite-pwa/assets-generator":
|
||||
optional: true
|
||||
checksum: 10c0/ceca04df97877ca97eb30805207d4826bd6340796194c9015afeefeb781931bf9019a630c5a0bdaa6dffcada11ce1fdf8595ac48a08d751dff81601aa0c7db38
|
||||
checksum: 10c0/e4f2f4dfff843ee2585a0d89e74187168ba20da77cd0d127ce7ad7eebcf5a68b2bf09000afb6bb86d43a2034fea9f568cd6db2a2d4b47a72e175d999a5e07eb1
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user