From 24611d8deb8eb31e3af1aa2035aab29fbd4510f9 Mon Sep 17 00:00:00 2001 From: luzi82 Date: Mon, 2 Apr 2018 18:11:37 +0800 Subject: [PATCH 01/12] i18n: update zh-HK translation (#7004) * i18n: update zh-HK translation * i18n: update zh-HK translation * i18n-tasks normalize --- app/javascript/mastodon/locales/zh-HK.json | 172 ++++++++++----------- config/locales/simple_form.zh-HK.yml | 2 + config/locales/zh-HK.yml | 31 +++- 3 files changed, 118 insertions(+), 87 deletions(-) diff --git a/app/javascript/mastodon/locales/zh-HK.json b/app/javascript/mastodon/locales/zh-HK.json index 0504a8c7a..1cbc9f1c5 100644 --- a/app/javascript/mastodon/locales/zh-HK.json +++ b/app/javascript/mastodon/locales/zh-HK.json @@ -1,36 +1,36 @@ { "account.block": "封鎖 @{name}", "account.block_domain": "隱藏來自 {domain} 的一切文章", - "account.blocked": "Blocked", - "account.direct": "Direct Message @{name}", + "account.blocked": "封鎖", + "account.direct": "私訊 @{name}", "account.disclaimer_full": "下列資料不一定完整。", - "account.domain_blocked": "Domain hidden", + "account.domain_blocked": "服務站被隱藏", "account.edit_profile": "修改個人資料", "account.follow": "關注", "account.followers": "關注的人", "account.follows": "正關注", "account.follows_you": "關注你", - "account.hide_reblogs": "Hide boosts from @{name}", + "account.hide_reblogs": "隱藏 @{name} 的轉推", "account.media": "媒體", "account.mention": "提及 @{name}", - "account.moved_to": "{name} has moved to:", + "account.moved_to": "{name} 已經遷移到:", "account.mute": "將 @{name} 靜音", - "account.mute_notifications": "Mute notifications from @{name}", - "account.muted": "Muted", + "account.mute_notifications": "將來自 @{name} 的通知靜音", + "account.muted": "靜音", "account.posts": "文章", - "account.posts_with_replies": "Toots with replies", + "account.posts_with_replies": "包含回覆的文章", "account.report": "舉報 @{name}", "account.requested": "等候審批", "account.share": "分享 @{name} 的個人資料", - "account.show_reblogs": "Show boosts from @{name}", + "account.show_reblogs": "顯示 @{name} 的推文", "account.unblock": "解除對 @{name} 的封鎖", "account.unblock_domain": "不再隱藏 {domain}", "account.unfollow": "取消關注", "account.unmute": "取消 @{name} 的靜音", - "account.unmute_notifications": "Unmute notifications from @{name}", + "account.unmute_notifications": "取消來自 @{name} 通知的靜音", "account.view_full_profile": "查看完整資料", - "alert.unexpected.message": "An unexpected error occurred.", - "alert.unexpected.title": "Oops!", + "alert.unexpected.message": "發生不可預期的錯誤。", + "alert.unexpected.title": "噢!", "boost_modal.combo": "如你想在下次路過這顯示,請按{combo},", "bundle_column_error.body": "加載本組件出錯。", "bundle_column_error.retry": "重試", @@ -40,11 +40,11 @@ "bundle_modal_error.retry": "重試", "column.blocks": "封鎖用戶", "column.community": "本站時間軸", - "column.domain_blocks": "Hidden domains", + "column.domain_blocks": "隱藏的服務站", "column.favourites": "最愛的文章", "column.follow_requests": "關注請求", "column.home": "主頁", - "column.lists": "Lists", + "column.lists": "列表", "column.mutes": "靜音名單", "column.notifications": "通知", "column.pins": "置頂文章", @@ -58,25 +58,25 @@ "column_header.unpin": "取下", "column_subheading.navigation": "瀏覽", "column_subheading.settings": "設定", - "compose_form.direct_message_warning": "This toot will only be visible to all the mentioned users.", - "compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.", + "compose_form.direct_message_warning": "這文章只有被提及的用戶才可以看到。", + "compose_form.hashtag_warning": "這文章因為不是公開,所以不會被標籤搜索。只有公開的文章才會被標籤搜索。", "compose_form.lock_disclaimer": "你的用戶狀態為「{locked}」,任何人都能立即關注你,然後看到「只有關注者能看」的文章。", "compose_form.lock_disclaimer.lock": "公共", "compose_form.placeholder": "你在想甚麼?", "compose_form.publish": "發文", "compose_form.publish_loud": "{publish}!", - "compose_form.sensitive.marked": "Media is marked as sensitive", - "compose_form.sensitive.unmarked": "Media is not marked as sensitive", - "compose_form.spoiler.marked": "Text is hidden behind warning", - "compose_form.spoiler.unmarked": "Text is not hidden", + "compose_form.sensitive.marked": "媒體被標示為敏感", + "compose_form.sensitive.unmarked": "媒體沒有被標示為敏感", + "compose_form.spoiler.marked": "文字被警告隱藏", + "compose_form.spoiler.unmarked": "文字沒有被隱藏", "compose_form.spoiler_placeholder": "敏感警告訊息", "confirmation_modal.cancel": "取消", "confirmations.block.confirm": "封鎖", "confirmations.block.message": "你確定要封鎖{name}嗎?", "confirmations.delete.confirm": "刪除", "confirmations.delete.message": "你確定要刪除{name}嗎?", - "confirmations.delete_list.confirm": "Delete", - "confirmations.delete_list.message": "Are you sure you want to permanently delete this list?", + "confirmations.delete_list.confirm": "刪除", + "confirmations.delete_list.message": "你確定要永久刪除這列表嗎?", "confirmations.domain_block.confirm": "隱藏整個網站", "confirmations.domain_block.message": "你真的真的確定要隱藏整個 {domain} ?多數情況下,比較推薦封鎖或靜音幾個特定目標就好。", "confirmations.mute.confirm": "靜音", @@ -86,7 +86,7 @@ "embed.instructions": "要內嵌此文章,請將以下代碼貼進你的網站。", "embed.preview": "看上去會是這樣:", "emoji_button.activity": "活動", - "emoji_button.custom": "Custom", + "emoji_button.custom": "自訂", "emoji_button.flags": "旗幟", "emoji_button.food": "飲飲食食", "emoji_button.label": "加入表情符號", @@ -94,9 +94,9 @@ "emoji_button.not_found": "No emojos!! (╯°□°)╯︵ ┻━┻", "emoji_button.objects": "物品", "emoji_button.people": "人物", - "emoji_button.recent": "Frequently used", + "emoji_button.recent": "常用", "emoji_button.search": "搜尋…", - "emoji_button.search_results": "Search results", + "emoji_button.search_results": "搜尋結果", "emoji_button.symbols": "符號", "emoji_button.travel": "旅遊景物", "empty_column.community": "本站時間軸暫時未有內容,快文章來搶頭香啊!", @@ -119,48 +119,48 @@ "home.column_settings.show_reblogs": "顯示被轉推的文章", "home.column_settings.show_replies": "顯示回應文章", "home.settings": "欄位設定", - "keyboard_shortcuts.back": "to navigate back", - "keyboard_shortcuts.boost": "to boost", - "keyboard_shortcuts.column": "to focus a status in one of the columns", - "keyboard_shortcuts.compose": "to focus the compose textarea", - "keyboard_shortcuts.description": "Description", - "keyboard_shortcuts.down": "to move down in the list", - "keyboard_shortcuts.enter": "to open status", - "keyboard_shortcuts.favourite": "to favourite", - "keyboard_shortcuts.heading": "Keyboard Shortcuts", - "keyboard_shortcuts.hotkey": "Hotkey", - "keyboard_shortcuts.legend": "to display this legend", - "keyboard_shortcuts.mention": "to mention author", - "keyboard_shortcuts.reply": "to reply", - "keyboard_shortcuts.search": "to focus search", - "keyboard_shortcuts.toot": "to start a brand new toot", - "keyboard_shortcuts.unfocus": "to un-focus compose textarea/search", - "keyboard_shortcuts.up": "to move up in the list", + "keyboard_shortcuts.back": "後退", + "keyboard_shortcuts.boost": "轉推", + "keyboard_shortcuts.column": "把標示移動到其中一列", + "keyboard_shortcuts.compose": "把標示移動到文字輸入區", + "keyboard_shortcuts.description": "描述", + "keyboard_shortcuts.down": "在列表往下移動", + "keyboard_shortcuts.enter": "打開文章", + "keyboard_shortcuts.favourite": "收藏", + "keyboard_shortcuts.heading": "鍵盤快速鍵", + "keyboard_shortcuts.hotkey": "快速鍵", + "keyboard_shortcuts.legend": "顯示這個說明", + "keyboard_shortcuts.mention": "提及作者", + "keyboard_shortcuts.reply": "回覆", + "keyboard_shortcuts.search": "把標示移動到搜索", + "keyboard_shortcuts.toot": "新的推文", + "keyboard_shortcuts.unfocus": "把標示移離文字輸入和搜索", + "keyboard_shortcuts.up": "在列表往上移動", "lightbox.close": "關閉", "lightbox.next": "繼續", "lightbox.previous": "回退", - "lists.account.add": "Add to list", - "lists.account.remove": "Remove from list", - "lists.delete": "Delete list", - "lists.edit": "Edit list", - "lists.new.create": "Add list", - "lists.new.title_placeholder": "New list title", - "lists.search": "Search among people you follow", - "lists.subheading": "Your lists", + "lists.account.add": "新增到列表", + "lists.account.remove": "從列表刪除", + "lists.delete": "刪除列表", + "lists.edit": "編輯列表", + "lists.new.create": "新增列表", + "lists.new.title_placeholder": "新列表標題", + "lists.search": "從你關注的用戶中搜索", + "lists.subheading": "列表", "loading_indicator.label": "載入中...", "media_gallery.toggle_visible": "打開或關上", "missing_indicator.label": "找不到內容", - "missing_indicator.sublabel": "This resource could not be found", - "mute_modal.hide_notifications": "Hide notifications from this user?", + "missing_indicator.sublabel": "無法找到內容", + "mute_modal.hide_notifications": "隱藏來自這用戶的通知嗎?", "navigation_bar.blocks": "被你封鎖的用戶", "navigation_bar.community_timeline": "本站時間軸", - "navigation_bar.domain_blocks": "Hidden domains", + "navigation_bar.domain_blocks": "隱藏的服務站", "navigation_bar.edit_profile": "修改個人資料", "navigation_bar.favourites": "最愛的內容", "navigation_bar.follow_requests": "關注請求", "navigation_bar.info": "關於本服務站", - "navigation_bar.keyboard_shortcuts": "Keyboard shortcuts", - "navigation_bar.lists": "Lists", + "navigation_bar.keyboard_shortcuts": "鍵盤快速鍵", + "navigation_bar.lists": "列表", "navigation_bar.logout": "登出", "navigation_bar.mutes": "被你靜音的用戶", "navigation_bar.pins": "置頂文章", @@ -187,8 +187,8 @@ "onboarding.page_four.home": "「主頁」顯示你所關注用戶的文章", "onboarding.page_four.notifications": "「通知」欄顯示你和其他人的互動。", "onboarding.page_one.federation": "Mastodon(萬象社交)是由一批獨立網站組成的龐大網絡,我們將這些獨立又互連網站稱為「服務站」(instance)", - "onboarding.page_one.full_handle": "Your full handle", - "onboarding.page_one.handle_hint": "This is what you would tell your friends to search for.", + "onboarding.page_one.full_handle": "你的帳號全名", + "onboarding.page_one.handle_hint": "朋友可以從這個帳號全名找到你", "onboarding.page_one.welcome": "歡迎使用 Mastodon(萬象社交)", "onboarding.page_six.admin": "你服務站的管理員是{admin}", "onboarding.page_six.almost_done": "差不多了……", @@ -211,33 +211,33 @@ "privacy.public.short": "公共", "privacy.unlisted.long": "公開,但不在公共時間軸顯示", "privacy.unlisted.short": "公開", - "regeneration_indicator.label": "Loading…", - "regeneration_indicator.sublabel": "Your home feed is being prepared!", - "relative_time.days": "{number}d", - "relative_time.hours": "{number}h", - "relative_time.just_now": "now", - "relative_time.minutes": "{number}m", - "relative_time.seconds": "{number}s", + "regeneration_indicator.label": "載入中……", + "regeneration_indicator.sublabel": "你的主頁時間軸正在準備中!", + "relative_time.days": "{number}日", + "relative_time.hours": "{number}小時", + "relative_time.just_now": "剛剛", + "relative_time.minutes": "{number}分鐘", + "relative_time.seconds": "{number}秒", "reply_indicator.cancel": "取消", - "report.forward": "Forward to {target}", - "report.forward_hint": "The account is from another server. Send an anonymized copy of the report there as well?", - "report.hint": "The report will be sent to your instance moderators. You can provide an explanation of why you are reporting this account below:", + "report.forward": "轉寄到 {target}", + "report.forward_hint": "這個帳戶屬於其他服務站。要向該服務站發送匿名的舉報訊息嗎?", + "report.hint": "這訊息會發送到你服務站的管理員。你可以提供舉報這個帳戶的理由:", "report.placeholder": "額外訊息", "report.submit": "提交", "report.target": "舉報", "search.placeholder": "搜尋", - "search_popout.search_format": "Advanced search format", - "search_popout.tips.full_text": "Simple text returns statuses you have written, favourited, boosted, or have been mentioned in, as well as matching usernames, display names, and hashtags.", - "search_popout.tips.hashtag": "hashtag", - "search_popout.tips.status": "status", - "search_popout.tips.text": "Simple text returns matching display names, usernames and hashtags", - "search_popout.tips.user": "user", - "search_results.accounts": "People", - "search_results.hashtags": "Hashtags", - "search_results.statuses": "Toots", + "search_popout.search_format": "高級搜索格式", + "search_popout.tips.full_text": "輸入簡單的文字,搜索由你發放、收藏、轉推和提及你的文章,以及符合的用戶名稱,帳號名稱和標籤。", + "search_popout.tips.hashtag": "標籤", + "search_popout.tips.status": "文章", + "search_popout.tips.text": "輸入簡單的文字,搜索符合的用戶名稱,帳號名稱和標籤。", + "search_popout.tips.user": "用戶", + "search_results.accounts": "使用者", + "search_results.hashtags": "標籤", + "search_results.statuses": "文章", "search_results.total": "{count, number} 項結果", "standalone.public_title": "站點一瞥…", - "status.block": "Block @{name}", + "status.block": "封鎖 @{name}", "status.cannot_reblog": "這篇文章無法被轉推", "status.delete": "刪除", "status.embed": "鑲嵌", @@ -245,12 +245,12 @@ "status.load_more": "載入更多", "status.media_hidden": "隱藏媒體內容", "status.mention": "提及 @{name}", - "status.more": "More", - "status.mute": "Mute @{name}", + "status.more": "更多", + "status.mute": "把 @{name} 靜音", "status.mute_conversation": "靜音對話", "status.open": "展開文章", "status.pin": "置頂到資料頁", - "status.pinned": "Pinned toot", + "status.pinned": "置頂文章", "status.reblog": "轉推", "status.reblogged_by": "{name} 轉推", "status.reply": "回應", @@ -258,22 +258,22 @@ "status.report": "舉報 @{name}", "status.sensitive_toggle": "點擊顯示", "status.sensitive_warning": "敏感內容", - "status.share": "Share", + "status.share": "分享", "status.show_less": "減少顯示", - "status.show_less_all": "Show less for all", + "status.show_less_all": "減少顯示這類文章", "status.show_more": "顯示更多", - "status.show_more_all": "Show more for all", + "status.show_more_all": "顯示更多這類文章", "status.unmute_conversation": "解禁對話", "status.unpin": "解除置頂", "tabs_bar.federated_timeline": "跨站", "tabs_bar.home": "主頁", "tabs_bar.local_timeline": "本站", "tabs_bar.notifications": "通知", - "ui.beforeunload": "Your draft will be lost if you leave Mastodon.", + "ui.beforeunload": "如果你現在離開 Mastodon,你的草稿內容將會被丟棄。", "upload_area.title": "將檔案拖放至此上載", "upload_button.label": "上載媒體檔案", - "upload_form.description": "Describe for the visually impaired", - "upload_form.focus": "Crop", + "upload_form.description": "為視覺障礙人士添加文字說明", + "upload_form.focus": "裁切", "upload_form.undo": "還原", "upload_progress.label": "上載中……", "video.close": "關閉影片", diff --git a/config/locales/simple_form.zh-HK.yml b/config/locales/simple_form.zh-HK.yml index 01ba61fdf..da0292a90 100644 --- a/config/locales/simple_form.zh-HK.yml +++ b/config/locales/simple_form.zh-HK.yml @@ -41,6 +41,7 @@ zh-HK: setting_default_privacy: 文章預設為 setting_default_sensitive: 預設我的內容為敏感內容 setting_delete_modal: 刪推前詢問我 + setting_display_sensitive_media: 預設我的媒體為敏感內容 setting_noindex: 阻止搜尋引擎檢索 setting_reduce_motion: 減低動畫效果 setting_system_font_ui: 使用系統預設字型 @@ -49,6 +50,7 @@ zh-HK: severity: 等級 type: 匯入資料類型 username: 用戶名稱 + username_or_email: 用戶名稱或電郵 interactions: must_be_follower: 隱藏沒有關注你的用戶的通知 must_be_following: 隱藏你不關注的用戶的通知 diff --git a/config/locales/zh-HK.yml b/config/locales/zh-HK.yml index cc1cade1e..5c1feabfc 100644 --- a/config/locales/zh-HK.yml +++ b/config/locales/zh-HK.yml @@ -101,7 +101,7 @@ zh-HK: most_recent: 按時間 title: 排序 outbox_url: 寄件箱(Outbox)URL - perform_full_suspension: 實行完全暫停 + perform_full_suspension: 完全停權 profile_url: 個人檔案 URL promote: 升任 protocol: 協議 @@ -272,6 +272,9 @@ zh-HK: contact_information: email: 輸入一個公開的電郵地址 username: 輸入用戶名稱 + hero: + desc_html: 在首頁顯示。推薦最小 600x100px。如果留空,就會默認為服務站縮圖。 + title: 主題圖片 peers_api_enabled: desc_html: 現時本服務站在網絡中已發現的域名 title: 公開已知服務站的列表 @@ -288,6 +291,9 @@ zh-HK: open: desc_html: 允許所有人建立帳戶 title: 開放註冊 + show_known_fediverse_at_about_page: + desc_html: 如果開啟,就會在時間軸預覽顯示跨站文章,否則就只會顯示本站文章。 + title: 在時間軸預覽顯示跨站文章 show_staff_badge: desc_html: 在個人資料頁上顯示管理人員標誌 title: 顯示管理人員標誌 @@ -352,6 +358,8 @@ zh-HK: your_token: token auth: agreement_html: 登記即表示你同意遵守本服務站的規則使用條款。 + change_password: 密碼 + confirm_email: 確認電郵 delete_account: 刪除帳戶 delete_account_html: 如果你想刪除你的帳戶,請點擊這裡繼續。你需要確認你的操作。 didnt_get_confirmation: 沒有收到確認指示電郵? @@ -361,7 +369,13 @@ zh-HK: logout: 登出 migrate_account: 轉移到另一個帳號 migrate_account_html: 想要將這個帳號指向另一個帳號可到這裡設定。 + or: 或 + or_log_in_with: 或登入於 + providers: + cas: CAS + saml: SAML register: 登記 + register_elsewhere: 在其他服務站登記 resend_confirmation: 重發確認指示電郵 reset_password: 重設密碼 security: 登入資訊 @@ -411,6 +425,13 @@ zh-HK: title: 這個頁面有問題 noscript_html: 使用 Mastodon 網頁版應用需要啟用 JavaScript。你也可以選擇適用於你的平台的 Mastodon 應用。 exports: + archive_takeout: + date: 日期 + download: 下載檔案 + hint_html: 你可以下載包含你的文章和媒體的檔案。資料以 ActivityPub 格式儲存,可用於相容的軟體。 + in_progress: 檔案製作中... + request: 下載檔案 + size: 檔案大小 blocks: 被你封鎖的用戶 csv: CSV follows: 你所關注的用戶 @@ -524,7 +545,9 @@ zh-HK: trillion: T unit: '' pagination: + newer: 較新 next: 下一頁 + older: 較舊 prev: 上一頁 truncate: "……" preferences: @@ -606,6 +629,11 @@ zh-HK: two_factor_authentication: 雙重認證 your_apps: 你的應用程式 statuses: + attached: + description: 附件: %{attached} + image: "%{count} 張圖片" + video: "%{count} 段影片" + content_warning: 'Content warning: %{warning}' open_in_web: 開啟網頁 over_character_limit: 超過了 %{max} 字的限制 pin_errors: @@ -670,4 +698,5 @@ zh-HK: users: invalid_email: 電郵地址格式不正確 invalid_otp_token: 雙重認證確認碼不正確 + seamless_external_login: 由於你是從外部系統登入,所以不能設定密碼和電郵。 signed_in_as: 目前登入的帳戶: From b04f73ce664b1f2c8f863b53ba8ff8fa0f0b330f Mon Sep 17 00:00:00 2001 From: Evgeny Petrov Date: Mon, 2 Apr 2018 13:49:06 +0300 Subject: [PATCH 02/12] Russian language updated (#7005) * Russian language updated * Small fixes for RU language * bundle exec i18n-tasks normalize --- app/javascript/mastodon/locales/ru.json | 30 +++++++------- config/locales/doorkeeper.ru.yml | 2 +- config/locales/ru.yml | 54 ++++++++++++++++++++++--- config/locales/simple_form.ru.yml | 4 +- 4 files changed, 67 insertions(+), 23 deletions(-) diff --git a/app/javascript/mastodon/locales/ru.json b/app/javascript/mastodon/locales/ru.json index 15959092c..8616ef98f 100644 --- a/app/javascript/mastodon/locales/ru.json +++ b/app/javascript/mastodon/locales/ru.json @@ -1,10 +1,10 @@ { "account.block": "Блокировать", "account.block_domain": "Блокировать все с {domain}", - "account.blocked": "Blocked", - "account.direct": "Direct Message @{name}", + "account.blocked": "Заблокирован(а)", + "account.direct": "Написать @{name}", "account.disclaimer_full": "Нижеуказанная информация может не полностью отражать профиль пользователя.", - "account.domain_blocked": "Domain hidden", + "account.domain_blocked": "Домен скрыт", "account.edit_profile": "Изменить профиль", "account.follow": "Подписаться", "account.followers": "Подписаны", @@ -16,9 +16,9 @@ "account.moved_to": "Ищите {name} здесь:", "account.mute": "Заглушить", "account.mute_notifications": "Скрыть уведомления от @{name}", - "account.muted": "Muted", + "account.muted": "Приглушён", "account.posts": "Посты", - "account.posts_with_replies": "Toots with replies", + "account.posts_with_replies": "Посты с ответами", "account.report": "Пожаловаться", "account.requested": "Ожидает подтверждения", "account.share": "Поделиться профилем @{name}", @@ -29,8 +29,8 @@ "account.unmute": "Снять глушение", "account.unmute_notifications": "Показывать уведомления от @{name}", "account.view_full_profile": "Показать полный профиль", - "alert.unexpected.message": "An unexpected error occurred.", - "alert.unexpected.title": "Oops!", + "alert.unexpected.message": "Что-то пошло не так.", + "alert.unexpected.title": "Ой!", "boost_modal.combo": "Нажмите {combo}, чтобы пропустить это в следующий раз", "bundle_column_error.body": "Что-то пошло не так при загрузке этого компонента.", "bundle_column_error.retry": "Попробовать снова", @@ -40,7 +40,7 @@ "bundle_modal_error.retry": "Попробовать снова", "column.blocks": "Список блокировки", "column.community": "Локальная лента", - "column.domain_blocks": "Hidden domains", + "column.domain_blocks": "Скрытые домены", "column.favourites": "Понравившееся", "column.follow_requests": "Запросы на подписку", "column.home": "Главная", @@ -65,10 +65,10 @@ "compose_form.placeholder": "О чем Вы думаете?", "compose_form.publish": "Трубить", "compose_form.publish_loud": "{publish}!", - "compose_form.sensitive.marked": "Media is marked as sensitive", - "compose_form.sensitive.unmarked": "Media is not marked as sensitive", - "compose_form.spoiler.marked": "Text is hidden behind warning", - "compose_form.spoiler.unmarked": "Text is not hidden", + "compose_form.sensitive.marked": "Медиафайлы не отмечены как чувствительные", + "compose_form.sensitive.unmarked": "Медиафайлы не отмечены как чувствительные", + "compose_form.spoiler.marked": "Текст скрыт за предупреждением", + "compose_form.spoiler.unmarked": "Текст не скрыт", "compose_form.spoiler_placeholder": "Напишите свое предупреждение здесь", "confirmation_modal.cancel": "Отмена", "confirmations.block.confirm": "Заблокировать", @@ -154,7 +154,7 @@ "mute_modal.hide_notifications": "Убрать уведомления от этого пользователя?", "navigation_bar.blocks": "Список блокировки", "navigation_bar.community_timeline": "Локальная лента", - "navigation_bar.domain_blocks": "Hidden domains", + "navigation_bar.domain_blocks": "Скрытые домены", "navigation_bar.edit_profile": "Изменить профиль", "navigation_bar.favourites": "Понравившееся", "navigation_bar.follow_requests": "Запросы на подписку", @@ -221,13 +221,13 @@ "reply_indicator.cancel": "Отмена", "report.forward": "Forward to {target}", "report.forward_hint": "The account is from another server. Send an anonymized copy of the report there as well?", - "report.hint": "The report will be sent to your instance moderators. You can provide an explanation of why you are reporting this account below:", + "report.hint": "Жалоба будет отправлена модераторам Вашего сервера. Вы также можете указать подробную причину жалобы ниже:", "report.placeholder": "Комментарий", "report.submit": "Отправить", "report.target": "Жалуемся на", "search.placeholder": "Поиск", "search_popout.search_format": "Продвинутый формат поиска", - "search_popout.tips.full_text": "Simple text returns statuses you have written, favourited, boosted, or have been mentioned in, as well as matching usernames, display names, and hashtags.", + "search_popout.tips.full_text": "Возвращает посты, которые Вы написали, отметили как 'избранное', продвинули или в которых были упомянуты, а также содержащие юзернейм, имя и хэштеги.", "search_popout.tips.hashtag": "хэштег", "search_popout.tips.status": "статус", "search_popout.tips.text": "Простой ввод текста покажет совпадающие имена пользователей, отображаемые имена и хэштеги", diff --git a/config/locales/doorkeeper.ru.yml b/config/locales/doorkeeper.ru.yml index 05c3d971c..28c0ff0bd 100644 --- a/config/locales/doorkeeper.ru.yml +++ b/config/locales/doorkeeper.ru.yml @@ -39,7 +39,7 @@ ru: callback_url: Callback URL delete: Удалить name: Название - new: Новое Приложение + new: Новое приложение scopes: Права show: Показывать title: Ваши приложения diff --git a/config/locales/ru.yml b/config/locales/ru.yml index 81af42556..108ca33e9 100644 --- a/config/locales/ru.yml +++ b/config/locales/ru.yml @@ -48,7 +48,7 @@ ru: reserved_username: Имя пользователя зарезервировано roles: admin: Администратор - moderator: Мод + moderator: Модератор unfollow: Отписаться admin: account_moderation_notes: @@ -217,7 +217,7 @@ ru: title: Снять блокировку с домена %{domain} undo: Отменить title: Доменные блокировки - undo: Отемнить + undo: Отменить email_domain_blocks: add_new: Добавить новую created_msg: Доменная блокировка еmail успешно создана @@ -275,6 +275,9 @@ ru: contact_information: email: Введите публичный e-mail username: Введите имя пользователя + hero: + desc_html: Отображается на главной странице. Рекомендуется разрешение не менее 600х100px. Если не установлено, используется изображение узла + title: Баннер узла peers_api_enabled: desc_html: Домены, которые были замечены этим узлом среди всей федерации title: Публикация списка обнаруженных узлов @@ -291,6 +294,9 @@ ru: open: desc_html: Позволяет любому создавать аккаунт title: Открыть регистрацию + show_known_fediverse_at_about_page: + desc_html: Если включено, показывает посты со всех известных узлов в предпросмотре ленты. В противном случае отображаются только локальные посты. + title: Показывать известные узлы в предпросмотре ленты show_staff_badge: desc_html: Показывать метку персонала на странице пользователя title: Показывать метку персонала @@ -308,7 +314,7 @@ ru: desc_html: Используется для предпросмотра с помощью OpenGraph и API. Рекомендуется разрешение 1200x630px title: Картинка узла timeline_preview: - desc_html: Показывать публичную ленту на целевой странице + desc_html: Показывать публичную ленту на приветственной странице title: Предпросмотр ленты title: Настройки сайта statuses: @@ -368,13 +374,17 @@ ru: migrate_account_html: Если Вы хотите перенести этот аккаунт на другой, вы можете сделать это здесь. or: или or_log_in_with: Или войти с помощью + providers: + cas: CAS + saml: SAML register: Зарегистрироваться - register_elsewhere: Зарегистрироваться на другом сервере + register_elsewhere: Зарегистрироваться на другом узле resend_confirmation: Повторить отправку инструкции для подтверждения reset_password: Сбросить пароль - security: Изменить пароль + security: Безопасность set_new_password: Задать новый пароль authorize_follow: + already_following: Вы уже подписаны на этот аккаунт error: К сожалению, при поиске удаленного аккаунта возникла ошибка follow: Подписаться follow_request: 'Вы отправили запрос на подписку:' @@ -467,10 +477,13 @@ ru: '21600': 6 часов '3600': 1 час '43200': 12 часов + '604800': 1 неделю '86400': 1 день expires_in_prompt: Никогда generate: Сгенерировать max_uses: + few: "%{count} исп." + many: "%{count} исп." one: 1 исп. other: "%{count} исп." max_uses_prompt: Без лимита @@ -514,11 +527,13 @@ ru: favourite: body: 'Ваш статус понравился %{name}:' subject: "%{name} понравился Ваш статус" + title: Понравившийся статус follow: body: "%{name} теперь подписан(а) на Вас!" subject: "%{name} теперь подписан(а) на Вас" title: Новый подписчик follow_request: + action: Управление запросами на подписку body: "%{name} запросил Вас о подписке" subject: "%{name} хочет подписаться на Вас" title: Новый запрос о подписке @@ -587,6 +602,7 @@ ru: micro_messenger: MicroMessenger nokia: Nokia S40 Ovi Browser opera: Opera + otter: Otter phantom_js: PhantomJS qq: QQ Browser safari: Safari @@ -628,6 +644,19 @@ ru: two_factor_authentication: Двухфакторная аутентификация your_apps: Ваши приложения statuses: + attached: + description: 'Вложение: %{attached}' + image: + few: "%{count} изображения" + many: "%{count} изображений" + one: "%{count} изображение" + other: "%{count} изображений" + video: + few: "%{count} видео" + many: "%{count} видео" + one: "%{count} видео" + other: "%{count} видео" + content_warning: 'Спойлер: %{warning}' open_in_web: Открыть в WWW over_character_limit: превышен лимит символов (%{max}) pin_errors: @@ -636,6 +665,7 @@ ru: private: Нельзя закрепить непубличный статус reblog: Нельзя закрепить продвинутый статус show_more: Подробнее + title: '%{name}: "%{quote}"' visibilities: private: Для подписчиков private_long: Показывать только подписчикам @@ -717,12 +747,24 @@ ru: title: Вынос архива welcome: edit_profile_action: Настроить профиль + edit_profile_step: Вы можете настроить свой профиль, загрузив аватар, обложку, сменив имя и много чего ещё. Если Вы хотите фильтровать подписчиков до того, как они смогут на Вас подписаться, Вы можете закрыть свой аккаунт. + explanation: Несколько советов для новичков final_action: Начать постить + final_step: 'Начните постить! Ваши публичные посты могут видеть другие, например, в локальной ленте или по хэштегам, даже если у Вас нет подписчиков. Вы также можете поздороваться с остальными и представиться, используя хэштек #приветствие.' + full_handle: Ваше обращение + full_handle_hint: То, что Вы хотите сообщить своим друзьям, чтобы они могли написать Вам или подписаться с другого узла. review_preferences_action: Изменить настройки - subject: Добро пожаловать на Mastodon + review_preferences_step: Проверьте все настройки, например, какие письма Вы хотите получать или уровень приватности статусов по умолчанию. Если Вы не страдаете морской болезнь, можете включить автовоспроизведение GIF. + subject: Добро пожаловать в Mastodon + tip_bridge_html: Если Вы пришли из Twitter, можете поискать своих друзей в Mastodon, используя приложение-мост. Но это работает только если они тоже использовали это приложение! + tip_federated_timeline: В глобальной ленте отображается сеть Mastodon. Но в ней показаны посты только от людей, на которых подписаны Вы и Ваши соседи, поэтому лента может быть неполной. + tip_following: По умолчанию Вы подписаны на администратора(-ов) Вашего узла. Чтобы найти других интересных людей, проверьте локальную и глобальную ленты. + tip_local_timeline: В локальной ленте показаны посты от людей с %{instance}. Это Ваши непосредственные соседи! + tip_mobile_webapp: Если Ваш мобильный браузер предлагает добавить иконку Mastodon на домашний экран, то Вы можете получать push-уведомления. Прямо как полноценное приложение! tips: Советы title: Добро пожаловать на борт, %{name}! users: invalid_email: Введенный e-mail неверен invalid_otp_token: Введен неверный код + seamless_external_login: Вы залогинены через сторонний сервис, поэтому настройки e-mail и пароля недоступны. signed_in_as: 'Выполнен вход под именем:' diff --git a/config/locales/simple_form.ru.yml b/config/locales/simple_form.ru.yml index 5c4df2189..b8ee5892d 100644 --- a/config/locales/simple_form.ru.yml +++ b/config/locales/simple_form.ru.yml @@ -38,7 +38,7 @@ ru: filtered_languages: Фильтруемые языки header: Заголовок locale: Язык - locked: Сделать аккаунт приватным + locked: Сделать аккаунт закрытым max_uses: Макс. число использований new_password: Новый пароль note: О Вас @@ -49,6 +49,7 @@ ru: setting_default_privacy: Видимость постов setting_default_sensitive: Всегда отмечать медиаконтент как чувствительный setting_delete_modal: Показывать диалог подтверждения перед удалением + setting_display_sensitive_media: Всегда показывать медиаконтент, отмеченный как чувствительный setting_noindex: Отказаться от индексации в поисковых машинах setting_reduce_motion: Уменьшить движение в анимации setting_system_font_ui: Использовать шрифт системы по умолчанию @@ -57,6 +58,7 @@ ru: severity: Строгость type: Тип импорта username: Имя пользователя + username_or_email: Имя пользователя или e-mail interactions: must_be_follower: Заблокировать уведомления не от подписчиков must_be_following: Заблокировать уведомления от людей, на которых Вы не подписаны From 3f51c6efaac0a0705d363e021951b0dd6b071a28 Mon Sep 17 00:00:00 2001 From: Yamagishi Kazutoshi Date: Mon, 2 Apr 2018 20:43:30 +0900 Subject: [PATCH 03/12] Weblate translations (2018-04-02) (#7007) * Translated using Weblate (Galician) Currently translated at 100.0% (587 of 587 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/gl/ * Translated using Weblate (Dutch) Currently translated at 100.0% (587 of 587 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/nl/ * Translated using Weblate (Catalan) Currently translated at 100.0% (587 of 587 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/ca/ * Translated using Weblate (Arabic) Currently translated at 76.4% (449 of 587 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/ar/ * Translated using Weblate (Japanese) Currently translated at 99.8% (586 of 587 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/ja/ * Translated using Weblate (Slovak) Currently translated at 92.3% (542 of 587 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/sk/ * Translated using Weblate (Slovak) Currently translated at 92.3% (542 of 587 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/sk/ * Translated using Weblate (Slovak) Currently translated at 100.0% (58 of 58 strings) Translation: Mastodon/Preferences Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/simple_form/sk/ * Translated using Weblate (Polish) Currently translated at 98.9% (581 of 587 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/pl/ * Translated using Weblate (French) Currently translated at 99.6% (585 of 587 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/fr/ * Translated using Weblate (Portuguese (Brazil)) Currently translated at 99.8% (586 of 587 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/pt_BR/ * Translated using Weblate (Catalan) Currently translated at 100.0% (280 of 280 strings) Translation: Mastodon/React Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/ca/ * Translated using Weblate (Persian) Currently translated at 100.0% (75 of 75 strings) Translation: Mastodon/Doorkeeper Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/doorkeeper/fa/ * Translated using Weblate (Persian) Currently translated at 100.0% (280 of 280 strings) Translation: Mastodon/React Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/fa/ * Translated using Weblate (French) Currently translated at 100.0% (280 of 280 strings) Translation: Mastodon/React Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/fr/ * Translated using Weblate (Japanese) Currently translated at 99.8% (586 of 587 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/ja/ * Translated using Weblate (Japanese) Currently translated at 99.8% (586 of 587 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/ja/ * Translated using Weblate (Slovak) Currently translated at 100.0% (280 of 280 strings) Translation: Mastodon/React Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/sk/ * Translated using Weblate (Chinese (Traditional)) Currently translated at 100.0% (280 of 280 strings) Translation: Mastodon/React Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/zh_Hant/ * Translated using Weblate (Chinese (Traditional)) Currently translated at 100.0% (62 of 62 strings) Translation: Mastodon/Devise Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/devise/zh_Hant/ * Translated using Weblate (Chinese (Traditional)) Currently translated at 100.0% (75 of 75 strings) Translation: Mastodon/Doorkeeper Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/doorkeeper/zh_Hant/ * Translated using Weblate (Chinese (Traditional)) Currently translated at 100.0% (62 of 62 strings) Translation: Mastodon/Devise Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/devise/zh_Hant/ * Translated using Weblate (Esperanto) Currently translated at 100.0% (587 of 587 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/eo/ * Translated using Weblate (Esperanto) Currently translated at 100.0% (280 of 280 strings) Translation: Mastodon/React Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/eo/ * Translated using Weblate (Chinese (Traditional)) Currently translated at 100.0% (75 of 75 strings) Translation: Mastodon/Doorkeeper Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/doorkeeper/zh_Hant/ * Translated using Weblate (Arabic) Currently translated at 76.6% (450 of 587 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/ar/ * Translated using Weblate (Esperanto) Currently translated at 100.0% (587 of 587 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/eo/ * Translated using Weblate (Esperanto) Currently translated at 100.0% (280 of 280 strings) Translation: Mastodon/React Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/eo/ * Translated using Weblate (Slovak) Currently translated at 92.6% (544 of 587 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/sk/ * Translated using Weblate (Slovak) Currently translated at 100.0% (75 of 75 strings) Translation: Mastodon/Doorkeeper Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/doorkeeper/sk/ * Translated using Weblate (Arabic) Currently translated at 82.9% (487 of 587 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/ar/ * Translated using Weblate (Arabic) Currently translated at 98.6% (74 of 75 strings) Translation: Mastodon/Doorkeeper Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/doorkeeper/ar/ * Translated using Weblate (Slovak) Currently translated at 93.6% (550 of 587 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/sk/ * Translated using Weblate (Slovak) Currently translated at 95.4% (560 of 587 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/sk/ * Translated using Weblate (Japanese) Currently translated at 100.0% (280 of 280 strings) Translation: Mastodon/React Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/ja/ * Translated using Weblate (Indonesian) Currently translated at 100.0% (75 of 75 strings) Translation: Mastodon/Doorkeeper Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/doorkeeper/id/ * Translated using Weblate (Korean) Currently translated at 100.0% (58 of 58 strings) Translation: Mastodon/Preferences Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/simple_form/ko/ * Translated using Weblate (Korean) Currently translated at 99.8% (586 of 587 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/ko/ * Translated using Weblate (Korean) Currently translated at 100.0% (280 of 280 strings) Translation: Mastodon/React Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/ko/ * Translated using Weblate (Esperanto) Currently translated at 100.0% (280 of 280 strings) Translation: Mastodon/React Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/eo/ * Translated using Weblate (Arabic) Currently translated at 82.9% (487 of 587 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/ar/ * Translated using Weblate (Arabic) Currently translated at 99.2% (278 of 280 strings) Translation: Mastodon/React Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/ar/ * Translated using Weblate (Arabic) Currently translated at 87.3% (513 of 587 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/ar/ * Translated using Weblate (Arabic) Currently translated at 99.6% (279 of 280 strings) Translation: Mastodon/React Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/ar/ * bundle exec i18n-tasks normalize && yarn manage:translations * revert --- app/javascript/mastodon/locales/ar.json | 6 +- app/javascript/mastodon/locales/ca.json | 2 +- app/javascript/mastodon/locales/eo.json | 18 ++--- app/javascript/mastodon/locales/fa.json | 10 +-- app/javascript/mastodon/locales/fr.json | 42 ++++++------ app/javascript/mastodon/locales/ja.json | 2 +- app/javascript/mastodon/locales/ko.json | 4 +- app/javascript/mastodon/locales/sk.json | 8 +-- app/javascript/mastodon/locales/zh-TW.json | 4 +- config/locales/ar.yml | 79 +++++++++++++++++++++- config/locales/devise.zh-TW.yml | 25 ++++++- config/locales/doorkeeper.ar.yml | 5 ++ config/locales/doorkeeper.fa.yml | 16 ++--- config/locales/doorkeeper.id.yml | 4 ++ config/locales/doorkeeper.sk.yml | 4 +- config/locales/doorkeeper.zh-TW.yml | 14 ++-- config/locales/eo.yml | 13 +++- config/locales/ja.yml | 4 +- config/locales/ko.yml | 16 +++++ config/locales/simple_form.ko.yml | 2 + config/locales/sk.yml | 24 +++++++ 21 files changed, 233 insertions(+), 69 deletions(-) diff --git a/app/javascript/mastodon/locales/ar.json b/app/javascript/mastodon/locales/ar.json index 3078b5b8c..34e34411f 100644 --- a/app/javascript/mastodon/locales/ar.json +++ b/app/javascript/mastodon/locales/ar.json @@ -2,7 +2,7 @@ "account.block": "حظر @{name}", "account.block_domain": "إخفاء كل شيئ قادم من إسم النطاق {domain}", "account.blocked": "محظور", - "account.direct": "Direct Message @{name}", + "account.direct": "Direct message @{name}", "account.disclaimer_full": "قد لا تعكس المعلومات أدناه الملف الشخصي الكامل للمستخدم.", "account.domain_blocked": "النطاق مخفي", "account.edit_profile": "تعديل الملف الشخصي", @@ -66,7 +66,7 @@ "compose_form.publish": "بوّق", "compose_form.publish_loud": "{publish}!", "compose_form.sensitive.marked": "لقد تم تحديد هذه الصورة كحساسة", - "compose_form.sensitive.unmarked": "Media is not marked as sensitive", + "compose_form.sensitive.unmarked": "لم يتم تحديد الصورة كحساسة", "compose_form.spoiler.marked": "إنّ النص مخفي وراء تحذير", "compose_form.spoiler.unmarked": "النص غير مخفي", "compose_form.spoiler_placeholder": "تنبيه عن المحتوى", @@ -221,7 +221,7 @@ "reply_indicator.cancel": "إلغاء", "report.forward": "التحويل إلى {target}", "report.forward_hint": "هذا الحساب ينتمي إلى خادوم آخَر. هل تودّ إرسال نسخة مجهولة مِن التقرير إلى هنالك أيضًا ؟", - "report.hint": "The report will be sent to your instance moderators. You can provide an explanation of why you are reporting this account below:", + "report.hint": "سوف يتم إرسال التقرير إلى مُشرِفي مثيل خادومكم. بإمكانك الإدلاء بشرح عن سبب الإبلاغ عن الحساب أسفله :", "report.placeholder": "تعليقات إضافية", "report.submit": "إرسال", "report.target": "إبلاغ", diff --git a/app/javascript/mastodon/locales/ca.json b/app/javascript/mastodon/locales/ca.json index ec5a8a1d6..b7f95a664 100644 --- a/app/javascript/mastodon/locales/ca.json +++ b/app/javascript/mastodon/locales/ca.json @@ -2,7 +2,7 @@ "account.block": "Bloca @{name}", "account.block_domain": "Amaga-ho tot de {domain}", "account.blocked": "Bloquejat", - "account.direct": "Direct Message @{name}", + "account.direct": "Direct message @{name}", "account.disclaimer_full": "La informació següent pot reflectir incompleta el perfil de l'usuari.", "account.domain_blocked": "Domini ocult", "account.edit_profile": "Edita el perfil", diff --git a/app/javascript/mastodon/locales/eo.json b/app/javascript/mastodon/locales/eo.json index 82b749417..6dee6e544 100644 --- a/app/javascript/mastodon/locales/eo.json +++ b/app/javascript/mastodon/locales/eo.json @@ -2,7 +2,7 @@ "account.block": "Bloki @{name}", "account.block_domain": "Kaŝi ĉion de {domain}", "account.blocked": "Blokita", - "account.direct": "Direct Message @{name}", + "account.direct": "Direct message @{name}", "account.disclaimer_full": "Subaj informoj povas reflekti la profilon de la uzanto nekomplete.", "account.domain_blocked": "Domajno kaŝita", "account.edit_profile": "Redakti profilon", @@ -17,8 +17,8 @@ "account.mute": "Silentigi @{name}", "account.mute_notifications": "Silentigi sciigojn el @{name}", "account.muted": "Silentigita", - "account.posts": "Mesaĝoj", - "account.posts_with_replies": "Mesaĝoj kun respondoj", + "account.posts": "Tootoj", + "account.posts_with_replies": "Kun respondoj", "account.report": "Signali @{name}", "account.requested": "Atendo de aprobo. Alklaku por nuligi peton de sekvado", "account.share": "Diskonigi la profilon de @{name}", @@ -65,10 +65,10 @@ "compose_form.placeholder": "Pri kio vi pensas?", "compose_form.publish": "Hup", "compose_form.publish_loud": "{publish}!", - "compose_form.sensitive.marked": "Media is marked as sensitive", - "compose_form.sensitive.unmarked": "Media is not marked as sensitive", - "compose_form.spoiler.marked": "Text is hidden behind warning", - "compose_form.spoiler.unmarked": "Text is not hidden", + "compose_form.sensitive.marked": "Aŭdovidaĵo markita tikla", + "compose_form.sensitive.unmarked": "Aŭdovidaĵo ne markita tikla", + "compose_form.spoiler.marked": "Teksto kaŝita malantaŭ averto", + "compose_form.spoiler.unmarked": "Teksto ne kaŝita", "compose_form.spoiler_placeholder": "Skribu vian averton ĉi tie", "confirmation_modal.cancel": "Nuligi", "confirmations.block.confirm": "Bloki", @@ -260,9 +260,9 @@ "status.sensitive_warning": "Tikla enhavo", "status.share": "Diskonigi", "status.show_less": "Malgrandigi", - "status.show_less_all": "Show less for all", + "status.show_less_all": "Malgrandigi ĉiujn", "status.show_more": "Grandigi", - "status.show_more_all": "Show more for all", + "status.show_more_all": "Grandigi ĉiujn", "status.unmute_conversation": "Malsilentigi konversacion", "status.unpin": "Depingli de profilo", "tabs_bar.federated_timeline": "Fratara tempolinio", diff --git a/app/javascript/mastodon/locales/fa.json b/app/javascript/mastodon/locales/fa.json index 4b64ca353..61cdcd00a 100644 --- a/app/javascript/mastodon/locales/fa.json +++ b/app/javascript/mastodon/locales/fa.json @@ -1,10 +1,10 @@ { "account.block": "مسدودسازی @{name}", "account.block_domain": "پنهان‌سازی همه چیز از سرور {domain}", - "account.blocked": "Blocked", - "account.direct": "Direct Message @{name}", + "account.blocked": "مسدودشده", + "account.direct": "Direct message @{name}", "account.disclaimer_full": "اطلاعات زیر ممکن است نمایهٔ این کاربر را به تمامی نشان ندهد.", - "account.domain_blocked": "Domain hidden", + "account.domain_blocked": "دامین پنهان‌شده", "account.edit_profile": "ویرایش نمایه", "account.follow": "پی بگیرید", "account.followers": "پیگیران", @@ -16,9 +16,9 @@ "account.moved_to": "{name} منتقل شده است به:", "account.mute": "بی‌صدا کردن @{name}", "account.mute_notifications": "بی‌صداکردن اعلان‌ها از طرف @{name}", - "account.muted": "Muted", + "account.muted": "بی‌صداشده", "account.posts": "نوشته‌ها", - "account.posts_with_replies": "Toots with replies", + "account.posts_with_replies": "نوشته‌ها و پاسخ‌ها", "account.report": "گزارش @{name}", "account.requested": "در انتظار پذیرش", "account.share": "هم‌رسانی نمایهٔ @{name}", diff --git a/app/javascript/mastodon/locales/fr.json b/app/javascript/mastodon/locales/fr.json index 58e6ad54d..57c55c9bd 100644 --- a/app/javascript/mastodon/locales/fr.json +++ b/app/javascript/mastodon/locales/fr.json @@ -2,7 +2,7 @@ "account.block": "Bloquer @{name}", "account.block_domain": "Tout masquer venant de {domain}", "account.blocked": "Bloqué", - "account.direct": "Direct Message @{name}", + "account.direct": "Direct message @{name}", "account.disclaimer_full": "Les données ci-dessous peuvent ne pas refléter ce profil dans sa totalité.", "account.domain_blocked": "Domaine caché", "account.edit_profile": "Modifier le profil", @@ -20,7 +20,7 @@ "account.posts": "Pouets", "account.posts_with_replies": "Pouets avec réponses", "account.report": "Signaler", - "account.requested": "Invitation envoyée", + "account.requested": "En attente d'approbation. Cliquez pour annuler la requête", "account.share": "Partager le profil de @{name}", "account.show_reblogs": "Afficher les partages de @{name}", "account.unblock": "Débloquer", @@ -88,7 +88,7 @@ "emoji_button.activity": "Activités", "emoji_button.custom": "Personnalisés", "emoji_button.flags": "Drapeaux", - "emoji_button.food": "Boire et manger", + "emoji_button.food": "Nourriture & Boisson", "emoji_button.label": "Insérer un émoji", "emoji_button.nature": "Nature", "emoji_button.not_found": "Pas d'emojis !! (╯°□°)╯︵ ┻━┻", @@ -98,14 +98,14 @@ "emoji_button.search": "Recherche…", "emoji_button.search_results": "Résultats de la recherche", "emoji_button.symbols": "Symboles", - "emoji_button.travel": "Lieux et voyages", + "emoji_button.travel": "Lieux & Voyages", "empty_column.community": "Le fil public local est vide. Écrivez donc quelque chose pour le remplir !", "empty_column.hashtag": "Il n’y a encore aucun contenu associé à ce hashtag.", - "empty_column.home": "Vous ne suivez encore personne. Visitez {public} ou bien utilisez la recherche pour vous connecter à d’autres utilisateur⋅ice⋅s.", + "empty_column.home": "Vous ne suivez encore personne. Visitez {public} ou bien utilisez la recherche pour vous connecter à d’autres personnes.", "empty_column.home.public_timeline": "le fil public", "empty_column.list": "Il n'y a rien dans cette liste pour l'instant. Dès que des personnes de cette liste publierons de nouveaux statuts, ils apparaîtront ici.", - "empty_column.notifications": "Vous n’avez pas encore de notification. Interagissez avec d’autres utilisateur⋅ice⋅s pour débuter la conversation.", - "empty_column.public": "Il n’y a rien ici ! Écrivez quelque chose publiquement, ou bien suivez manuellement des utilisateur⋅ice·s d’autres instances pour remplir le fil public", + "empty_column.notifications": "Vous n’avez pas encore de notification. Interagissez avec d’autres personnes pour débuter la conversation.", + "empty_column.public": "Il n’y a rien ici ! Écrivez quelque chose publiquement, ou bien suivez manuellement des personnes d’autres instances pour remplir le fil public", "follow_request.authorize": "Accepter", "follow_request.reject": "Rejeter", "getting_started.appsshort": "Applications", @@ -122,9 +122,9 @@ "keyboard_shortcuts.back": "revenir en arrière", "keyboard_shortcuts.boost": "partager", "keyboard_shortcuts.column": "focaliser un statut dans l'une des colonnes", - "keyboard_shortcuts.compose": "pour centrer la zone de redaction", + "keyboard_shortcuts.compose": "pour centrer la zone de rédaction", "keyboard_shortcuts.description": "Description", - "keyboard_shortcuts.down": "descendre dans la liste", + "keyboard_shortcuts.down": "pour descendre dans la liste", "keyboard_shortcuts.enter": "pour ouvrir le statut", "keyboard_shortcuts.favourite": "vers les favoris", "keyboard_shortcuts.heading": "Raccourcis clavier", @@ -151,7 +151,7 @@ "media_gallery.toggle_visible": "Modifier la visibilité", "missing_indicator.label": "Non trouvé", "missing_indicator.sublabel": "Ressource introuvable", - "mute_modal.hide_notifications": "Masquer les notifications de cet utilisateur ?", + "mute_modal.hide_notifications": "Masquer les notifications de cette personne ?", "navigation_bar.blocks": "Comptes bloqués", "navigation_bar.community_timeline": "Fil public local", "navigation_bar.domain_blocks": "Hidden domains", @@ -170,7 +170,7 @@ "notification.follow": "{name} vous suit", "notification.mention": "{name} vous a mentionné⋅e :", "notification.reblog": "{name} a partagé votre statut :", - "notifications.clear": "Nettoyer", + "notifications.clear": "Nettoyer les notifications", "notifications.clear_confirmation": "Voulez-vous vraiment supprimer toutes vos notifications ?", "notifications.column_settings.alert": "Notifications locales", "notifications.column_settings.favourite": "Favoris :", @@ -183,12 +183,12 @@ "notifications.column_settings.sound": "Émettre un son", "onboarding.done": "Effectué", "onboarding.next": "Suivant", - "onboarding.page_five.public_timelines": "Le fil public global affiche les posts de tou⋅te⋅s les utilisateur⋅ice⋅s suivi⋅es par les membres de {domain}. Le fil public local est identique mais se limite aux utilisateur⋅ice⋅s de {domain}.", - "onboarding.page_four.home": "L’Accueil affiche les posts de tou⋅te·s les utilisateur⋅ice·s que vous suivez.", - "onboarding.page_four.notifications": "Les Notifications vous informent lorsque quelqu’un interagit avec vous.", - "onboarding.page_one.federation": "Mastodon est un réseau social qui appartient à tou⋅te⋅s.", - "onboarding.page_one.full_handle": "Votre pleine maîtrise", - "onboarding.page_one.handle_hint": "C'est ce que vous diriez à vos amis de rechercher.", + "onboarding.page_five.public_timelines": "Le fil public global affiche les messages de toutes les personnes suivies par les membres de {domain}. Le fil public local est identique mais se limite aux membres de {domain}.", + "onboarding.page_four.home": "L’Accueil affiche les messages des personnes que vous suivez.", + "onboarding.page_four.notifications": "La colonne de notification vous avertit lors d'une interaction avec vous.", + "onboarding.page_one.federation": "Mastodon est un réseau de serveurs indépendants qui se joignent pour former un réseau social plus vaste. Nous appelons ces serveurs des instances.", + "onboarding.page_one.full_handle": "Votre identifiant complet", + "onboarding.page_one.handle_hint": "C'est ce que vos amis devront rechercher.", "onboarding.page_one.welcome": "Bienvenue sur Mastodon !", "onboarding.page_six.admin": "L’administrateur⋅ice de votre instance est {admin}.", "onboarding.page_six.almost_done": "Nous y sommes presque…", @@ -199,7 +199,7 @@ "onboarding.page_six.read_guidelines": "S’il vous plaît, n’oubliez pas de lire les {guidelines} !", "onboarding.page_six.various_app": "applications mobiles", "onboarding.page_three.profile": "Modifiez votre profil pour changer votre avatar, votre description ainsi que votre nom. Vous y trouverez également d’autres préférences.", - "onboarding.page_three.search": "Utilisez la barre de recherche pour trouver des utilisateur⋅ice⋅s et regarder des hashtags tels que {illustration} et {introductions}. Pour trouver quelqu’un qui n’est pas sur cette instance, utilisez son nom d’utilisateur⋅ice complet.", + "onboarding.page_three.search": "Utilisez la barre de recherche pour trouver des utilisateur⋅ice⋅s ou regardez des hashtags tels que {illustration} et {introductions}. Pour trouver quelqu’un qui n’est pas sur cette instance, utilisez son identifiant complet.", "onboarding.page_two.compose": "Écrivez depuis la colonne de composition. Vous pouvez ajouter des images, changer les réglages de confidentialité, et ajouter des avertissements de contenu (Content Warning) grâce aux icônes en dessous.", "onboarding.skip": "Passer", "privacy.change": "Ajuster la confidentialité du message", @@ -227,16 +227,16 @@ "report.target": "Signalement", "search.placeholder": "Rechercher", "search_popout.search_format": "Recherche avancée", - "search_popout.tips.full_text": "Les textes simples retournent les pouets que vous avez écris, mis en favori, épinglés, ou ayant été mentionnés, ainsi que les noms d'utilisateurs, les noms affichés, et les hashtags correspondant.", + "search_popout.tips.full_text": "Les textes simples retournent les pouets que vous avez écris, mis en favori, épinglés, ou ayant été mentionnés, ainsi que les identifiants, les noms affichés, et les hashtags des personnes et messages correspondant.", "search_popout.tips.hashtag": "hashtag", "search_popout.tips.status": "statuts", - "search_popout.tips.text": "Un texte simple renvoie les noms affichés, les noms d’utilisateur⋅ice et les hashtags correspondants", + "search_popout.tips.text": "Un texte simple renvoie les noms affichés, les identifiants et les hashtags correspondants", "search_popout.tips.user": "utilisateur⋅ice", "search_results.accounts": "Personnes", "search_results.hashtags": "Hashtags", "search_results.statuses": "Pouets", "search_results.total": "{count, number} {count, plural, one {résultat} other {résultats}}", - "standalone.public_title": "Jeter un coup d’œil…", + "standalone.public_title": "Un aperçu …", "status.block": "Block @{name}", "status.cannot_reblog": "Cette publication ne peut être boostée", "status.delete": "Effacer", diff --git a/app/javascript/mastodon/locales/ja.json b/app/javascript/mastodon/locales/ja.json index 80a13a9bf..432517716 100644 --- a/app/javascript/mastodon/locales/ja.json +++ b/app/javascript/mastodon/locales/ja.json @@ -27,7 +27,7 @@ "account.unblock_domain": "{domain}を表示", "account.unfollow": "フォロー解除", "account.unmute": "@{name}さんのミュートを解除", - "account.unmute_notifications": "@{name}さんからの通知を受け取る", + "account.unmute_notifications": "@{name}さんからの通知を受け取るようにする", "account.view_full_profile": "全ての情報を見る", "alert.unexpected.message": "不明なエラーが発生しました", "alert.unexpected.title": "エラー", diff --git a/app/javascript/mastodon/locales/ko.json b/app/javascript/mastodon/locales/ko.json index 449df42b8..89fde8966 100644 --- a/app/javascript/mastodon/locales/ko.json +++ b/app/javascript/mastodon/locales/ko.json @@ -2,7 +2,7 @@ "account.block": "@{name}을 차단", "account.block_domain": "{domain} 전체를 숨김", "account.blocked": "차단 됨", - "account.direct": "Direct Message @{name}", + "account.direct": "Direct message @{name}", "account.disclaimer_full": "여기 있는 정보는 유저의 프로파일을 정확히 반영하지 못 할 수도 있습니다.", "account.domain_blocked": "도메인 숨겨짐", "account.edit_profile": "프로필 편집", @@ -17,7 +17,7 @@ "account.mute": "@{name} 뮤트", "account.mute_notifications": "@{name}의 알림을 뮤트", "account.muted": "뮤트 됨", - "account.posts": "게시물", + "account.posts": "툿", "account.posts_with_replies": "툿과 답장", "account.report": "@{name} 신고", "account.requested": "승인 대기 중. 클릭해서 취소하기", diff --git a/app/javascript/mastodon/locales/sk.json b/app/javascript/mastodon/locales/sk.json index 7bfae0302..925b46df6 100644 --- a/app/javascript/mastodon/locales/sk.json +++ b/app/javascript/mastodon/locales/sk.json @@ -2,7 +2,7 @@ "account.block": "Blokovať @{name}", "account.block_domain": "Ukryť všetko z {domain}", "account.blocked": "Blokovaný/á", - "account.direct": "Direct Message @{name}", + "account.direct": "Direct message @{name}", "account.disclaimer_full": "Inofrmácie nižšie nemusia byť úplným odrazom uživateľovho účtu.", "account.domain_blocked": "Doména ukrytá", "account.edit_profile": "Upraviť profil", @@ -42,12 +42,12 @@ "column.community": "Lokálna časová os", "column.domain_blocks": "Hidden domains", "column.favourites": "Obľúbené", - "column.follow_requests": "Žiadosti o sledovaní", + "column.follow_requests": "Žiadosti o sledovanie", "column.home": "Domov", "column.lists": "Zoznamy", "column.mutes": "Ignorovaní užívatelia", "column.notifications": "Notifikácie", - "column.pins": "Pripnuté toots", + "column.pins": "Pripnuté tooty", "column.public": "Federovaná časová os", "column_back_button.label": "Späť", "column_header.hide_settings": "Skryť nastavenia", @@ -163,7 +163,7 @@ "navigation_bar.lists": "Zoznamy", "navigation_bar.logout": "Odhlásiť", "navigation_bar.mutes": "Ignorovaní užívatelia", - "navigation_bar.pins": "Pripnuté toots", + "navigation_bar.pins": "Pripnuté tooty", "navigation_bar.preferences": "Voľby", "navigation_bar.public_timeline": "Federovaná časová os", "notification.favourite": "{name} sa páči tvoj status", diff --git a/app/javascript/mastodon/locales/zh-TW.json b/app/javascript/mastodon/locales/zh-TW.json index fab7ecf06..c7925829f 100644 --- a/app/javascript/mastodon/locales/zh-TW.json +++ b/app/javascript/mastodon/locales/zh-TW.json @@ -2,7 +2,7 @@ "account.block": "封鎖 @{name}", "account.block_domain": "隱藏來自 {domain} 的一切貼文", "account.blocked": "Blocked", - "account.direct": "Direct Message @{name}", + "account.direct": "Direct message @{name}", "account.disclaimer_full": "下列資料不一定完整。", "account.domain_blocked": "Domain hidden", "account.edit_profile": "編輯用者資訊", @@ -103,7 +103,7 @@ "empty_column.hashtag": "這個主題標籤下什麼都沒有。", "empty_column.home": "你還沒關注任何人。造訪{public}或利用搜尋功能找到其他用者。", "empty_column.home.public_timeline": "公開時間軸", - "empty_column.list": "There is nothing in this list yet.", + "empty_column.list": "此份清單尚未有東西。當此清單的成員貼出了新的狀態時,它們就會出現在這裡。", "empty_column.notifications": "還沒有任何通知。和別的使用者互動來開始對話。", "empty_column.public": "這裡什麼都沒有!公開寫些什麼,或是關注其他副本的使用者。", "follow_request.authorize": "授權", diff --git a/config/locales/ar.yml b/config/locales/ar.yml index 25ca302d6..c316a2fa5 100644 --- a/config/locales/ar.yml +++ b/config/locales/ar.yml @@ -119,6 +119,7 @@ ar: user: مستخدِم salmon_url: عنوان رابط سالمون Salmon search: البحث + shared_inbox_url: رابط الصندوق المُشترَك للبريد الوارد show: created_reports: البلاغات التي أنشأها هذا الحساب report: التقرير @@ -140,14 +141,23 @@ ar: create_email_domain_block: "%{name} قد قام بحظر نطاق البريد الإلكتروني %{target}" demote_user: "%{name} قد قام بإنزال الرتبة الوظيفية لـ %{target}" destroy_domain_block: "%{name} قام بإلغاء الحجب عن النطاق %{target}" + destroy_email_domain_block: قام %{name} بإضافة نطاق البريد الإلكتروني %{target} إلى اللائحة البيضاء + destroy_status: لقد قام %{name} بحذف منشور %{target} disable_2fa_user: "%{name} لقد قام بتعطيل ميزة المصادقة بخطوتين للمستخدم %{target}" disable_custom_emoji: "%{name} قام بتعطيل الإيموجي %{target}" disable_user: "%{name} لقد قام بتعطيل تسجيل الدخول للمستخدِم %{target}" enable_custom_emoji: "%{name} قام بتنشيط الإيموجي %{target}" enable_user: "%{name} لقد قام بتنشيط تسجيل الدخول للمستخدِم %{target}" + memorialize_account: لقد قام %{name} بتحويل حساب %{target} إلى صفحة تذكارية promote_user: "%{name} قام بترقية المستخدم %{target}" reset_password_user: "%{name} لقد قام بإعادة تعيين الكلمة السرية الخاصة بـ %{target}" + resolve_report: قام %{name} بإلغاء التقرير المُرسَل مِن طرف %{target} + silence_account: لقد قام %{name} بكتم حساب %{target} + suspend_account: لقد قام %{name} بتعليق حساب %{target} + unsilence_account: لقد قام %{name} بإلغاء الكتم عن حساب %{target} + unsuspend_account: لقد قام %{name} بإلغاء التعليق المفروض على حساب %{target} update_custom_emoji: "%{name} قام بتحديث الإيموجي %{target}" + update_status: لقد قام %{name} بتحديث منشور %{target} title: سِجلّ التفتيش و المعاينة custom_emojis: by_domain: النطاق @@ -163,35 +173,54 @@ ar: enable: تفعيل enabled_msg: تم تنشيط ذاك الإيموجي بنجاح image_hint: ملف PNG إلى غاية حجم 50 ك.ب + listed: مُدرَج new: title: إضافة إيموجي خاص جديد + overwrite: إعادة الكتابة shortcode: الترميز المُصَغّر shortcode_hint: على الأقل حرفين، و فقط رموز أبجدية عددية و أسطر سفلية title: الإيموجي الخاصة + unlisted: غير مدرج update_failed_msg: تعذرت عملية تحذيث ذاك الإيموجي updated_msg: تم تحديث الإيموجي بنجاح ! upload: رفع domain_blocks: add_new: إضافة نطاق جديد + created_msg: إنّ حجب النطاق حيز التشغيل + destroyed_msg: تم إلغاء الحجب المفروض على النطاق domain: النطاق new: create: إنشاء حظر severity: noop: لا شيء silence: كتم + suspend: تعليق title: حجب نطاق جديد reject_media: رفض ملفات الوسائط severities: noop: لا شيء + silence: إخفاء أو كتم + suspend: تعليق + severity: الشدة show: + affected_accounts: + other: هناك %{count} حسابات في قاعدة البيانات متأثرة بذلك + retroactive: + silence: إلغاء الكتم عن كافة الحسابات المتواجدة على هذا النطاق + suspend: إلغاء التعليق المفروض على كافة حسابات هذا النطاق title: رفع حظر النطاق عن %{domain} undo: إلغاء + title: حظر النطاقات undo: إلغاء email_domain_blocks: + add_new: إضافة + created_msg: لقد دخل حظر نطاق البريد الإلكتروني حيّز الخدمة delete: حذف + destroyed_msg: تم حذف نطاق البريد الإلكتروني من اللائحة السوداء بنجاح domain: النطاق new: create: إضافة نطاق + title: إضافة نطاق بريد جديد إلى اللائحة السوداء title: القائمة السوداء للبريد الإلكتروني instances: account_count: الحسابات المعروفة @@ -214,27 +243,52 @@ ar: none: لا شيء delete: حذف id: معرّف ID + mark_as_resolved: إعتبار التقرير كمحلول nsfw: + 'false': الكشف عن الصور 'true': إخفاء الوسائط المرفقة + report: 'التقرير #%{id}' report_contents: المحتويات + reported_account: حساب مُبلّغ عنه reported_by: أبلغ عنه من طرف + resolved: معالجة + silence_account: كتم و إخفاء الحساب status: الحالة + suspend_account: فرض تعليق على الحساب + target: الهدف title: التقارير + unresolved: غير معالجة view: عرض settings: + activity_api_enabled: + desc_html: عدد المنشورات المحلية و المستخدمين النشطين و التسجيلات الأسبوعية الجديدة + bootstrap_timeline_accounts: + title: الإشتراكات الإفتراضية للمستخدمين الجدد contact_information: email: البريد الإلكتروني المهني username: الإتصال بالمستخدِم + hero: + title: الصورة الرأسية + peers_api_enabled: + desc_html: أسماء النطاقات التي إلتقى بها مثيل الخادوم على البيئة الموحَّدة فيديفرس + title: نشر عدد مثيلات الخوادم التي تم مصادفتها registrations: closed_message: title: رسالة التسجيلات المقفلة deletion: desc_html: السماح لأي مستخدم إغلاق حسابه + title: السماح بحذف الحسابات + min_invite_role: + disabled: لا أحد open: desc_html: السماح للجميع بإنشاء حساب title: فتح التسجيل + show_known_fediverse_at_about_page: + title: إظهار الفيديفرس الموحَّد في خيط المُعايَنة site_description: title: وصف مثيل الخادوم + site_description_extended: + title: الوصف المُفصّل للموقع site_terms: title: شروط الخدمة المخصصة site_title: إسم مثيل الخادم @@ -242,11 +296,14 @@ ar: title: الصورة الرمزية المصغرة لمثيل الخادوم timeline_preview: desc_html: عرض الخيط العمومي على صفحة الإستقبال + title: مُعاينة الخيط العام title: إعدادات الموقع statuses: back_to_account: العودة إلى صفحة الحساب batch: delete: حذف + execute: تفعيل + failed_to_execute: خطأ في التفعيل media: hide: إخفاء الوسائط show: إظهار الوسائط @@ -256,8 +313,13 @@ ar: subscriptions: confirmed: مؤكَّد expires_in: تنتهي مدة صلاحيتها في + last_delivery: آخر إيداع + title: WebSub topic: الموضوع title: الإدارة + admin_mailer: + new_report: + body: قام %{reporter} بالإبلاغ عن %{target} application_mailer: notification_preferences: تعديل خيارات البريد الإلكتروني salutation: "%{name}،" @@ -270,6 +332,7 @@ ar: destroyed: تم حذف التطبيق بنجاح invalid_url: إن الرابط المقدم غير صالح regenerate_token: إعادة توليد رمز النفاذ + warning: كن حذرا مع هذه البيانات. لا تقم أبدا بمشاركتها مع الآخَرين ! your_token: رمز نفاذك auth: agreement_html: بقبولك التسجيل فإنك تُصرِّح قبول قواعد مثيل الخادوم و شروط الخدمة التي نوفرها لك. @@ -283,11 +346,13 @@ ar: logout: خروج migrate_account: الإنتقال إلى حساب آخر migrate_account_html: إن كنت ترغب في تحويل هذا الحساب نحو حساب آخَر، يُمكِنُك إعداده هنا. + or: أو or_log_in_with: أو قم بتسجيل الدخول بواسطة providers: cas: CAS saml: SAML register: إنشاء حساب + register_elsewhere: التسجيل على خادوم آخَر resend_confirmation: إعادة إرسال تعليمات التأكيد reset_password: إعادة تعيين كلمة المرور security: الهوية @@ -296,6 +361,7 @@ ar: error: يا للأسف، وقع هناك خطأ إثر عملية البحث عن الحساب عن بعد follow: إتبع follow_request: 'لقد قمت بإرسال طلب متابعة إلى :' + following: 'مرحى ! أنت الآن تتبع :' post_follow: close: أو يمكنك إغلاق هذه النافذة. return: العودة إلى الملف الشخصي للمستخدم @@ -324,18 +390,24 @@ ar: '403': ليس لك الصلاحيات الكافية لعرض هذه الصفحة. '404': إنّ الصفحة التي تبحث عنها لا وجود لها أصلا. '410': إنّ الصفحة التي تبحث عنها لم تعد موجودة. + '422': + content: فشل التحقق الآمن. ربما منعتَ كعكات الكوكيز ؟ + title: فشِل التحقق الآمن '500': content: نحن متأسفون، لقد حدث خطأ ما مِن جانبنا. title: هذه الصفحة خاطئة exports: archive_takeout: + date: التاريخ download: تنزيل نسخة لحسابك hint_html: بإمكانك طلب نسخة كاملة لـ كافة تبويقاتك و الوسائط التي قمت بنشرها. البيانات المُصدَّرة ستكون محفوظة على شكل نسق ActivityPub و باستطاعتك قراءتها بأي برنامج يدعم هذا النسق. in_progress: عملية جمع نسخة لبيانات حسابك جارية … request: طلب نسخة لحسابك + size: الحجم blocks: قمت بحظر csv: CSV follows: أنت تتبع + mutes: قُمتَ بكتم storage: ذاكرة التخزين followers: domain: النطاق @@ -368,9 +440,14 @@ ar: '86400': يوم واحد expires_in_prompt: أبدا generate: توليد + max_uses: + one: إستعمال واحد + other: "%{count} استخدامات" max_uses_prompt: بلا حدود + prompt: توليد و مشاركة روابط للسماح للآخَرين بالنفاذ إلى مثيل الخادوم هذا table: expires_at: تنتهي مدة صلاحيتها في + uses: يستخدِم title: دعوة أشخاص landing_strip_html: "%{name} هو أحد مُستخدِمي %{link_to_root_path}. بإمكانك متابعته أو التواصل معه إن كنت تملك حسابًا أيا كان على البيئة الموحَّدة فيديفرس." landing_strip_signup_html: إن كنت لا تملك واحدا، يمكنك التسجيل مِن هنا. @@ -433,7 +510,7 @@ ar: next: التالي older: الأقدَم prev: السابق - truncate: "…" + truncate: و preferences: languages: اللغات other: إعدادات أخرى diff --git a/config/locales/devise.zh-TW.yml b/config/locales/devise.zh-TW.yml index e627653f1..976e96be2 100644 --- a/config/locales/devise.zh-TW.yml +++ b/config/locales/devise.zh-TW.yml @@ -2,7 +2,7 @@ zh-TW: devise: confirmations: - confirmed: 信箱驗證成功 + confirmed: 您的電子郵件地址確認成功。 send_instructions: 您將會在幾分鐘內收到驗證信。 send_paranoid_instructions: 如果您的電子信箱已經存在於我們的資料庫,您將會在幾分鐘內收到信,確認您電子信箱的指示。 failure: @@ -10,18 +10,39 @@ zh-TW: inactive: 您的帳號尚未啟用。 invalid: 不正確的 %{authentication_keys} 或密碼。 last_attempt: 若您再次嘗試失敗,我們將鎖定您的帳號,以策安全。 - locked: 您的帳號已被鎖定 + locked: 您的帳號已被鎖定。 not_found_in_database: 不正確的 %{authentication_keys} 或密碼。 timeout: 您的登入階段已經逾期,請重新登入以繼續使用。 unauthenticated: 您必須先登入或註冊,以繼續使用。 unconfirmed: 您必須先完成信箱驗證,以繼續使用。 mailer: confirmation_instructions: + action: 驗證電子郵件地址 + explanation: 您已經在 %{host} 上以此電子郵件地址建立了一個帳號。您距離啟用它只剩一次點擊之遙了。如果這不是你,請忽略此電子郵件。 + extra_html: 同時也請看看該實體的規則我們的服務條款。 subject: 'Mastodon: 信箱驗證' + title: 驗證電子郵件地址 + email_changed: + explanation: 您帳號的電子郵件地址被變更為: + extra: 如果您並未變更您的電子郵件,那麼很有可能是某人取得了您帳號的存取權限。請立刻變更您的密碼,或是若您的帳號已被鎖定,請聯絡所使用實體的管理員。 + subject: Mastodon 電子郵件變更 + title: 新電子郵件地址 password_change: + explanation: 您帳號的密碼已變更。 + extra: 如果您並未變更您的密碼,那麼很有可能是某人取得了您帳號的存取權限。請立刻變更您的密碼,或是若您的帳號已被鎖定,請聯絡所使用實體的管理員。 subject: 'Mastodon: 更改密碼' + title: 密碼已變更 + reconfirmation_instructions: + explanation: 確認新的電子郵件地址以變更您的電子郵件。 + extra: 若此次變更不是由您開啟的,請忽略這個電子郵件。Mastodon 帳號的電子郵件地址在您存取上面的連結前不會變更。 + subject: Mastodon:%{instance} 的確認電子郵件 + title: 驗證電子郵件地址 reset_password_instructions: + action: 變更密碼 + explanation: 您為您的帳號請求了一個新密碼。 + extra: 若您並未請求這個,請忽略此電子郵件。您的密碼在您存取上面的連結並建立一個新的之前不會變更。 subject: 'Mastodon: 重設密碼' + title: 重設密碼 unlock_instructions: subject: 'Mastodon: 帳號解鎖' omniauth_callbacks: diff --git a/config/locales/doorkeeper.ar.yml b/config/locales/doorkeeper.ar.yml index d13c22386..5586b8dc8 100644 --- a/config/locales/doorkeeper.ar.yml +++ b/config/locales/doorkeeper.ar.yml @@ -79,12 +79,17 @@ ar: messages: access_denied: لقد رفض مالك المَورِدِ أو تصريح السيرفر طلبك. invalid_client: فشلت المصادقة مع العميل لأنه العميل مجهول أو لغياب المصادقة ضمن العميل أو أنّ أسلوب المصادقة غير مدعومة. + invalid_grant: إنّ التصريح المقدَّم غير صالح، سواء انتهت مدة صلاحيته أو تم إلغاؤه أو أنه لا يتطابق مع عنوان إعادة التحويل في طلب التصريح أو أنّ هذا التصريح قد تم تقديمه لعميل آخر. invalid_redirect_uri: إنّ عنوان إعادة التحويل غير صالح. + invalid_request: إنّ هذا الطلب يستلزم مؤشرا أو يحمل قيمة مُعامِل غير مدعومة أو فيه خلل ما. + invalid_resource_owner: إنّ المُعرِّفات التي قدّمها صاحب المورِد غير صحيحة أو أنه لا وجود لصاحب المورِد invalid_scope: المجال المطلوب غير صحيح أو مجهول أو مُعبَّر عنه بشكل خاطئ. invalid_token: expired: إنتهت فترة صلاحيته رمز المصادقة revoked: تم إبطال رمز المصادقة unknown: رمز المصادقة غير صالح + resource_owner_authenticator_not_configured: لقد أخفقت عملية البحث عن صاحب المَورِد لغياب الضبط في Doorkeeper.configure.resource_owner_authenticator. + server_error: لقد صادفَ خادوم التصريحات ضروفا غير مواتية، الأمر الذي مَنَعه مِن مواصلة دراسة الطلب. temporarily_unavailable: تعذر على خادم التفويض معالجة الطلب و ذلك بسبب زيادة مؤقتة في التحميل أو عملية صيانة مبرمجة على الخادم. unauthorized_client: لا يصرح للعميل بتنفيذ هذا الطلب باستخدام هذه الطريقة. unsupported_grant_type: هذا النوع من منح التصريح غير معتمد في خادم الترخيص. diff --git a/config/locales/doorkeeper.fa.yml b/config/locales/doorkeeper.fa.yml index 6a4be575e..f3db862ca 100644 --- a/config/locales/doorkeeper.fa.yml +++ b/config/locales/doorkeeper.fa.yml @@ -3,19 +3,19 @@ fa: activerecord: attributes: doorkeeper/application: - name: Application name - redirect_uri: Redirect URI - scopes: Scopes - website: Application website + name: نام برنامه + redirect_uri: نشانی تغییرمسیر + scopes: محدوده + website: وبگاه برنامه errors: models: doorkeeper/application: attributes: redirect_uri: - fragment_present: cannot contain a fragment. - invalid_uri: must be a valid URI. - relative_uri: must be an absolute URI. - secured_uri: must be an HTTPS/SSL URI. + fragment_present: نمی‌تواند چندتکه باشد. + invalid_uri: باید یک نشانی معتبر باشد. + relative_uri: باید یک نشانی مطلق باشد. + secured_uri: باید یک نشانی HTTPS/SSL باشد. doorkeeper: applications: buttons: diff --git a/config/locales/doorkeeper.id.yml b/config/locales/doorkeeper.id.yml index 6db797c87..0a99b86c0 100644 --- a/config/locales/doorkeeper.id.yml +++ b/config/locales/doorkeeper.id.yml @@ -35,9 +35,13 @@ id: redirect_uri: Gunakan satu baris per URI scopes: Pisahkan scope dengan spasi. Biarkan kosong jika ingin menggunakan scope default. index: + application: Aplikasi callback_url: URL Callback + delete: Hapus name: Nama new: Aplikasi baru + scopes: Cakupan + show: Tampilkan title: Aplikasi anda new: title: Aplikasi Baru diff --git a/config/locales/doorkeeper.sk.yml b/config/locales/doorkeeper.sk.yml index b8fd281f7..7a285eb4f 100644 --- a/config/locales/doorkeeper.sk.yml +++ b/config/locales/doorkeeper.sk.yml @@ -19,7 +19,7 @@ sk: doorkeeper: applications: buttons: - authorize: Autorizovať + authorize: Overiť cancel: Zrušiť destroy: Zničiť edit: Upraviť @@ -54,7 +54,7 @@ sk: title: 'Aplikácia: %{name}' authorizations: buttons: - authorize: Autorizovať + authorize: Overiť deny: Zamietnuť error: title: Nastala chyba diff --git a/config/locales/doorkeeper.zh-TW.yml b/config/locales/doorkeeper.zh-TW.yml index 01e62df73..2aa271785 100644 --- a/config/locales/doorkeeper.zh-TW.yml +++ b/config/locales/doorkeeper.zh-TW.yml @@ -5,12 +5,14 @@ zh-TW: doorkeeper/application: name: 名稱 redirect_uri: 重新導向 URI + scopes: 範圍 + website: 應用程式網頁 errors: models: doorkeeper/application: attributes: redirect_uri: - fragment_present: URI 不可包含 "#fragment" 部份 + fragment_present: 不能包含 fragment。 invalid_uri: 必需有正確的 URI. relative_uri: 必需為絕對 URI. secured_uri: 必需使用有 HTTPS/SSL 加密的 URI. @@ -31,11 +33,15 @@ zh-TW: help: native_redirect_uri: 使用 %{native_redirect_uri} 作局部測試 redirect_uri: 每行輸入一個 URI - scopes: 請用半形空格分開權限範圍 (scope)。留空表示使用預設的權限範圍 + scopes: 請用半形空格分開權限範圍 (scope)。留空表示使用預設的權限範圍。 index: + application: 應用程式 callback_url: 回傳網址 + delete: 刪除 name: 名稱 new: 新增應用程式 + scopes: 範圍 + show: 顯示 title: 您的應用程式 new: title: 新增應用程式 @@ -57,7 +63,7 @@ zh-TW: prompt: 應用程式 %{client_name} 要求取得您帳號的部份權限 title: 需要授權 show: - title: Copy this authorization code and paste it to the application. + title: 複製此授權碼並貼上到應用程式中。 authorized_applications: buttons: revoke: 取消授權 @@ -77,7 +83,7 @@ zh-TW: invalid_grant: 授權申請不正確、逾期、已被取消、與授權請求內的重新導向 URI 不符、或屬於別的客戶端程式。 invalid_redirect_uri: 不正確的重新導向網址。 invalid_request: 請求缺少必要的參數、包含不支援的參數、或其他輸入錯誤。 - invalid_resource_owner: 資源擁有者的登入資訊錯誤、或無法找到該資源擁有者。 + invalid_resource_owner: 資源擁有者的登入資訊錯誤、或無法找到該資源擁有者 invalid_scope: 請求的權限範圍不正確、未有定義、或輸入錯誤。 invalid_token: expired: access token 已過期 diff --git a/config/locales/eo.yml b/config/locales/eo.yml index 8bc2aaa41..84d63d831 100644 --- a/config/locales/eo.yml +++ b/config/locales/eo.yml @@ -333,7 +333,7 @@ eo: subscriptions: callback_url: Revena URL confirmed: Konfirmita - expires_in: Eksvalidiĝas en + expires_in: Eksvalidiĝas je last_delivery: Lasta livero title: WebSub topic: Temo @@ -485,7 +485,7 @@ eo: max_uses_prompt: Neniu limo prompt: Krei kaj diskonigi ligilojn al aliaj por doni aliron al ĉi tiu nodo table: - expires_at: Eksvalidiĝas + expires_at: Eksvalidiĝas je uses: Uzoj title: Inviti homojn landing_strip_html: "%{name} estas uzanto en %{link_to_root_path}. Vi povas sekvi tiun aŭ interagi kun tiu, se vi havas konton ie ajn en la fediverse." @@ -636,6 +636,15 @@ eo: two_factor_authentication: Dufaktora aŭtentigo your_apps: Viaj aplikaĵoj statuses: + attached: + description: 'Ligita: %{attached}' + image: + one: "%{count} bildo" + other: "%{count} bildoj" + video: + one: "%{count} video" + other: "%{count} videoj" + content_warning: 'Enhava averto: %{warning}' open_in_web: Malfermi retumile over_character_limit: limo de %{max} signoj transpasita pin_errors: diff --git a/config/locales/ja.yml b/config/locales/ja.yml index 1ff309782..090b080e4 100644 --- a/config/locales/ja.yml +++ b/config/locales/ja.yml @@ -641,8 +641,8 @@ ja: one: "%{count} 枚の画像" other: "%{count} 枚の画像" video: - one: "%{count} 枚の動画" - other: "%{count} 枚の動画" + one: "%{count} 本の動画" + other: "%{count} 本の動画" content_warning: '閲覧注意: %{warning}' open_in_web: Webで開く over_character_limit: 上限は %{max}文字までです diff --git a/config/locales/ko.yml b/config/locales/ko.yml index 8a11b096a..ba55b3549 100644 --- a/config/locales/ko.yml +++ b/config/locales/ko.yml @@ -361,6 +361,7 @@ ko: your_token: 액세스 토큰 auth: agreement_html: 이 등록으로 이용규약약관에 동의하는 것으로 간주됩니다. + change_password: 패스워드 confirm_email: 확인 메일 승인 delete_account: 계정 삭제 delete_account_html: 계정을 삭제하고 싶은 경우, 여기서 삭제할 수 있습니다. 삭제 전 확인 화면이 표시됩니다. @@ -373,7 +374,11 @@ ko: migrate_account_html: 이 계정을 다른 계정으로 리디렉션 하길 원하는 경우 여기에서 설정할 수 있습니다. or: 또는 or_log_in_with: 다른 방법으로 로그인 하려면 + providers: + cas: CAS + saml: SAML register: 등록하기 + register_elsewhere: 다른 인스턴스에서 가입 resend_confirmation: 확인 메일을 다시 보내기 reset_password: 비밀번호 재설정 security: 보안 @@ -545,7 +550,9 @@ ko: trillion: T unit: '' pagination: + newer: 새로운 툿 next: 다음 + older: 오래된 툿 prev: 이전 truncate: "…" preferences: @@ -629,6 +636,15 @@ ko: two_factor_authentication: 2단계 인증 your_apps: 애플리케이션 statuses: + attached: + description: '첨부: %{attached}' + image: + one: "%{count} 이미지" + other: "%{count} 이미지" + video: + one: "%{count} 영상" + other: "%{count} 영상" + content_warning: '열람 주의: %{warning}' open_in_web: Web으로 열기 over_character_limit: 최대 %{max}자까지 입력할 수 있습니다 pin_errors: diff --git a/config/locales/simple_form.ko.yml b/config/locales/simple_form.ko.yml index e49bfd9f9..85eccf091 100644 --- a/config/locales/simple_form.ko.yml +++ b/config/locales/simple_form.ko.yml @@ -45,6 +45,7 @@ ko: setting_default_privacy: 툿 프라이버시 setting_default_sensitive: 미디어를 언제나 민감한 컨텐츠로 설정 setting_delete_modal: 툿 삭제 전 확인 창을 표시 + setting_display_sensitive_media: 열람주의로 설정 된 이미지도 항상 보여주기 setting_noindex: 검색엔진의 인덱싱을 거절 setting_reduce_motion: 애니메이션 줄이기 setting_system_font_ui: 시스템의 초기 설정 폰트를 사용 @@ -53,6 +54,7 @@ ko: severity: 심각도 type: 불러오기 종류 username: 유저 이름 + username_or_email: 유저네임 또는 이메일 interactions: must_be_follower: 나를 팔로우 하지 않는 사람에게서 온 알림을 차단 must_be_following: 내가 팔로우 하지 않는 사람에게서 온 알림을 차단 diff --git a/config/locales/sk.yml b/config/locales/sk.yml index a0e1a597c..2ee25b372 100644 --- a/config/locales/sk.yml +++ b/config/locales/sk.yml @@ -580,7 +580,12 @@ sk: browser: Prehliadač browsers: alipay: Alipay + chrome: Google Chrome + edge: Microsoft Edge + electron: Electron + firefox: Mozilla Firefox generic: Neznámy prehliadač + ie: Internet Explorer current_session: Aktuálna sezóna description: "%{browser} na %{platform}" explanation: Tieto sú prehliadače ktoré sú teraz prihlásené na tvoj Mastodon účet. @@ -607,12 +612,22 @@ sk: two_factor_authentication: Dvoj-faktorové overenie your_apps: Tvoje aplikácie statuses: + attached: + description: 'Priložené: %{attached}' + image: + one: "%{count} obrázok" + other: "%{count} obrázkov" + video: + one: "%{count} video" + other: "%{count} videí" + content_warning: 'Varovanie o obsahu: %{warning}' open_in_web: Otvor v okne prehliadača over_character_limit: limit počtu %{max} znakov bol presiahnutý pin_errors: limit: Už ste si pripli ten najvyšší možný počet príspevkov ownership: Nemožno pripnúť príspevok od niekoho iného private: Neverejné príspevky nemôžu byť pripnuté + reblog: Pozdvihnutie sa nedá pripnúť show_more: Ukáž viac visibilities: private: Iba pre sledovateľov @@ -628,11 +643,20 @@ sk: sensitive_content: Senzitívny obsah terms: title: Podmienky užívania, a pravidlá o súkromí pre %{instance} + themes: + default: Mastodon + time: + formats: + default: "%b %d, %R, %H:%M" two_factor_authentication: + code_hint: Pre potvrdenie teraz zadaj kód vygenerovaný pomocou tvojej overovacej aplikácie + description_html: Ak povolíš dvoj-faktorové overovanie, na prihlásenie potom budeš potrebovať svoj telefón, ktorý vygeneruje prístupové kódy, čo musíš zadať. + disable: Zakáž enable: Povoliť enabled: Dvoj-faktorové overovanie je povolené enabled_success: Dvoj-faktorové overovanie bolo úspešne povolené generate_recovery_codes: Vygeneruj zálohové kódy + instructions_html: "Naskenuj tento QR kód do Google Autentikátora, alebo do podobnej TOTP aplikácie pomocou svojho telefónu. Od tejto chvíle bude táto aplikácia pre teba generovať kódy ktoré musíš zadať aby si sa prihlásil/a." lost_recovery_codes: Zálohové kódy ti umožnia dostať sa k svojmu účtu ak stratíš telefón. Pokiaľ si stratila svoje zálohové kódy, môžeš si ich tu znovu vygenerovať. Tvoje staré zálohové kódy budú zneplatnené. manual_instructions: 'Pokiaľ nemôžeš oskenovať daný QR kód, a potrebuješ ho zadať ručne, tu je tajomstvo v textovom formáte:' recovery_codes: Zálohuj kódy pre obnovu From 4fd71accd419fb79cc75e0ebf30df374d174ebf5 Mon Sep 17 00:00:00 2001 From: Emelia Smith Date: Mon, 2 Apr 2018 13:44:19 +0200 Subject: [PATCH 04/12] Fix issues with sending direct messages from user profile (#6999) * Clear compose textarea when starting a new direct message Previous behaviour resulted in potentially misdirected direct messages. * Hide search when starting to compose a direct message --- app/javascript/mastodon/reducers/compose.js | 2 +- app/javascript/mastodon/reducers/search.js | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/app/javascript/mastodon/reducers/compose.js b/app/javascript/mastodon/reducers/compose.js index a48c46941..1f4177585 100644 --- a/app/javascript/mastodon/reducers/compose.js +++ b/app/javascript/mastodon/reducers/compose.js @@ -265,7 +265,7 @@ export default function compose(state = initialState, action) { .set('idempotencyKey', uuid()); case COMPOSE_DIRECT: return state - .update('text', text => `${text}@${action.account.get('acct')} `) + .update('text', text => `@${action.account.get('acct')} `) .set('privacy', 'direct') .set('focusDate', new Date()) .set('idempotencyKey', uuid()); diff --git a/app/javascript/mastodon/reducers/search.js b/app/javascript/mastodon/reducers/search.js index 08d90e4e8..56fd7226b 100644 --- a/app/javascript/mastodon/reducers/search.js +++ b/app/javascript/mastodon/reducers/search.js @@ -4,7 +4,11 @@ import { SEARCH_FETCH_SUCCESS, SEARCH_SHOW, } from '../actions/search'; -import { COMPOSE_MENTION, COMPOSE_REPLY } from '../actions/compose'; +import { + COMPOSE_MENTION, + COMPOSE_REPLY, + COMPOSE_DIRECT, +} from '../actions/compose'; import { Map as ImmutableMap, List as ImmutableList } from 'immutable'; const initialState = ImmutableMap({ @@ -29,6 +33,7 @@ export default function search(state = initialState, action) { return state.set('hidden', false); case COMPOSE_REPLY: case COMPOSE_MENTION: + case COMPOSE_DIRECT: return state.set('hidden', true); case SEARCH_FETCH_SUCCESS: return state.set('results', ImmutableMap({ From e7a17167015dca6864f31152c47334c3b3a857a2 Mon Sep 17 00:00:00 2001 From: Emelia Smith Date: Mon, 2 Apr 2018 13:45:07 +0200 Subject: [PATCH 05/12] Implement the ability for an Administrator or Moderator to remove an account avatar (#6998) --- app/controllers/admin/accounts_controller.rb | 13 ++++++++++++- app/helpers/admin/action_logs_helper.rb | 2 +- app/policies/account_policy.rb | 4 ++++ app/views/admin/accounts/show.html.haml | 8 ++++++++ config/locales/en.yml | 3 +++ config/routes.rb | 1 + 6 files changed, 29 insertions(+), 2 deletions(-) diff --git a/app/controllers/admin/accounts_controller.rb b/app/controllers/admin/accounts_controller.rb index 7428c3f22..e7ca6b907 100644 --- a/app/controllers/admin/accounts_controller.rb +++ b/app/controllers/admin/accounts_controller.rb @@ -2,7 +2,7 @@ module Admin class AccountsController < BaseController - before_action :set_account, only: [:show, :subscribe, :unsubscribe, :redownload, :enable, :disable, :memorialize] + before_action :set_account, only: [:show, :subscribe, :unsubscribe, :redownload, :remove_avatar, :enable, :disable, :memorialize] before_action :require_remote_account!, only: [:subscribe, :unsubscribe, :redownload] before_action :require_local_account!, only: [:enable, :disable, :memorialize] @@ -60,6 +60,17 @@ module Admin redirect_to admin_account_path(@account.id) end + def remove_avatar + authorize @account, :remove_avatar? + + @account.avatar = nil + @account.save! + + log_action :remove_avatar, @account.user + + redirect_to admin_account_path(@account.id) + end + private def set_account diff --git a/app/helpers/admin/action_logs_helper.rb b/app/helpers/admin/action_logs_helper.rb index 4475034a5..78278c700 100644 --- a/app/helpers/admin/action_logs_helper.rb +++ b/app/helpers/admin/action_logs_helper.rb @@ -86,7 +86,7 @@ module Admin::ActionLogsHelper opposite_verbs?(log) ? 'negative' : 'positive' when :update, :reset_password, :disable_2fa, :memorialize 'neutral' - when :demote, :silence, :disable, :suspend + when :demote, :silence, :disable, :suspend, :remove_avatar 'negative' when :destroy opposite_verbs?(log) ? 'positive' : 'negative' diff --git a/app/policies/account_policy.rb b/app/policies/account_policy.rb index 85e2c8419..efabe80d0 100644 --- a/app/policies/account_policy.rb +++ b/app/policies/account_policy.rb @@ -29,6 +29,10 @@ class AccountPolicy < ApplicationPolicy admin? end + def remove_avatar? + staff? + end + def subscribe? admin? end diff --git a/app/views/admin/accounts/show.html.haml b/app/views/admin/accounts/show.html.haml index dbbf5fc09..fecfd6cc8 100644 --- a/app/views/admin/accounts/show.html.haml +++ b/app/views/admin/accounts/show.html.haml @@ -14,6 +14,14 @@ %th= t('admin.accounts.display_name') %td= @account.display_name + %tr + %th= t('admin.accounts.avatar') + %th + = link_to @account.avatar.url(:original) do + = image_tag @account.avatar.url(:original), alt: '', width: 40, height: 40, class: 'avatar' + - if @account.local? && @account.avatar? + = table_link_to 'trash', t('admin.accounts.remove_avatar'), remove_avatar_admin_account_path(@account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') } if can?(:remove_avatar, @account) + - if @account.local? %tr %th= t('admin.accounts.role') diff --git a/config/locales/en.yml b/config/locales/en.yml index e3d76971b..fb2bbf4fe 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -60,6 +60,7 @@ en: destroyed_msg: Moderation note successfully destroyed! accounts: are_you_sure: Are you sure? + avatar: Avatar by_domain: Domain confirm: Confirm confirmed: Confirmed @@ -108,6 +109,7 @@ en: public: Public push_subscription_expires: PuSH subscription expires redownload: Refresh avatar + remove_avatar: Remove avatar reset: Reset reset_password: Reset password resubscribe: Resubscribe @@ -150,6 +152,7 @@ en: enable_user: "%{name} enabled login for user %{target}" memorialize_account: "%{name} turned %{target}'s account into a memoriam page" promote_user: "%{name} promoted user %{target}" + remove_avatar_user: "%{name} removed %{target}'s avatar" reset_password_user: "%{name} reset password of user %{target}" resolve_report: "%{name} dismissed report %{target}" silence_account: "%{name} silenced %{target}'s account" diff --git a/config/routes.rb b/config/routes.rb index 0542cb680..9a4460562 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -144,6 +144,7 @@ Rails.application.routes.draw do post :enable post :disable post :redownload + post :remove_avatar post :memorialize end From 2c51bc0ca5a4c3a4bb140b4b40dabdda859ebb94 Mon Sep 17 00:00:00 2001 From: unarist Date: Mon, 2 Apr 2018 21:51:02 +0900 Subject: [PATCH 06/12] Add missing rejection handling for Promises (#7008) * Add eslint-plugin-promise to detect uncaught rejections * Move alert generation for errors to actions/alert * Add missing rejection handling for Promises * Use catch() instead of onReject on then() Then it will catches rejection from onFulfilled. This detection can be disabled by `allowThen` option, though. --- .eslintrc.yml | 3 ++ app/javascript/mastodon/actions/accounts.js | 2 +- app/javascript/mastodon/actions/alerts.js | 25 ++++++++++++++++ app/javascript/mastodon/actions/compose.js | 7 ++++- app/javascript/mastodon/actions/lists.js | 3 +- .../actions/push_notifications/registerer.js | 15 ++++------ app/javascript/mastodon/actions/settings.js | 5 +++- .../mastodon/containers/status_container.js | 6 +++- .../features/ui/components/embed_modal.js | 3 ++ app/javascript/mastodon/middleware/errors.js | 24 ++------------- app/javascript/mastodon/storage/modifier.js | 30 ++++++++++++++----- package.json | 1 + yarn.lock | 4 +++ 13 files changed, 84 insertions(+), 44 deletions(-) diff --git a/.eslintrc.yml b/.eslintrc.yml index cf276a16f..576e5b70a 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -13,6 +13,7 @@ plugins: - react - jsx-a11y - import +- promise parserOptions: sourceType: module @@ -152,3 +153,5 @@ rules: - "app/javascript/**/__tests__/**" import/no-unresolved: error import/no-webpack-loader-syntax: error + + promise/catch-or-return: error diff --git a/app/javascript/mastodon/actions/accounts.js b/app/javascript/mastodon/actions/accounts.js index 7cacff909..28ae56763 100644 --- a/app/javascript/mastodon/actions/accounts.js +++ b/app/javascript/mastodon/actions/accounts.js @@ -103,7 +103,7 @@ export function fetchAccount(id) { dispatch(importFetchedAccount(response.data)); })).then(() => { dispatch(fetchAccountSuccess()); - }, error => { + }).catch(error => { dispatch(fetchAccountFail(id, error)); }); }; diff --git a/app/javascript/mastodon/actions/alerts.js b/app/javascript/mastodon/actions/alerts.js index f37fdeeb6..3f5d7ef46 100644 --- a/app/javascript/mastodon/actions/alerts.js +++ b/app/javascript/mastodon/actions/alerts.js @@ -1,3 +1,10 @@ +import { defineMessages } from 'react-intl'; + +const messages = defineMessages({ + unexpectedTitle: { id: 'alert.unexpected.title', defaultMessage: 'Oops!' }, + unexpectedMessage: { id: 'alert.unexpected.message', defaultMessage: 'An unexpected error occurred.' }, +}); + export const ALERT_SHOW = 'ALERT_SHOW'; export const ALERT_DISMISS = 'ALERT_DISMISS'; export const ALERT_CLEAR = 'ALERT_CLEAR'; @@ -22,3 +29,21 @@ export function showAlert(title, message) { message, }; }; + +export function showAlertForError(error) { + if (error.response) { + const { data, status, statusText } = error.response; + + let message = statusText; + let title = `${status}`; + + if (data.error) { + message = data.error; + } + + return showAlert(title, message); + } else { + console.error(error); + return showAlert(messages.unexpectedTitle, messages.unexpectedMessage); + } +} diff --git a/app/javascript/mastodon/actions/compose.js b/app/javascript/mastodon/actions/compose.js index 2138f9426..59aa6f98d 100644 --- a/app/javascript/mastodon/actions/compose.js +++ b/app/javascript/mastodon/actions/compose.js @@ -1,11 +1,12 @@ import api from '../api'; -import { CancelToken } from 'axios'; +import { CancelToken, isCancel } from 'axios'; import { throttle } from 'lodash'; import { search as emojiSearch } from '../features/emoji/emoji_mart_search_light'; import { tagHistory } from '../settings'; import { useEmoji } from './emojis'; import { importFetchedAccounts } from './importer'; import { updateTimeline } from './timelines'; +import { showAlertForError } from './alerts'; let cancelFetchComposeSuggestionsAccounts; @@ -291,6 +292,10 @@ const fetchComposeSuggestionsAccounts = throttle((dispatch, getState, token) => }).then(response => { dispatch(importFetchedAccounts(response.data)); dispatch(readyComposeSuggestionsAccounts(token, response.data)); + }).catch(error => { + if (!isCancel(error)) { + dispatch(showAlertForError(error)); + } }); }, 200, { leading: true, trailing: true }); diff --git a/app/javascript/mastodon/actions/lists.js b/app/javascript/mastodon/actions/lists.js index 12d60e3a3..12cb17159 100644 --- a/app/javascript/mastodon/actions/lists.js +++ b/app/javascript/mastodon/actions/lists.js @@ -1,5 +1,6 @@ import api from '../api'; import { importFetchedAccounts } from './importer'; +import { showAlertForError } from './alerts'; export const LIST_FETCH_REQUEST = 'LIST_FETCH_REQUEST'; export const LIST_FETCH_SUCCESS = 'LIST_FETCH_SUCCESS'; @@ -236,7 +237,7 @@ export const fetchListSuggestions = q => (dispatch, getState) => { api(getState).get('/api/v1/accounts/search', { params }).then(({ data }) => { dispatch(importFetchedAccounts(data)); dispatch(fetchListSuggestionsReady(q, data)); - }); + }).catch(error => dispatch(showAlertForError(error))); }; export const fetchListSuggestionsReady = (query, accounts) => ({ diff --git a/app/javascript/mastodon/actions/push_notifications/registerer.js b/app/javascript/mastodon/actions/push_notifications/registerer.js index 51e68cad1..f17d929a6 100644 --- a/app/javascript/mastodon/actions/push_notifications/registerer.js +++ b/app/javascript/mastodon/actions/push_notifications/registerer.js @@ -116,14 +116,11 @@ export function register () { pushNotificationsSetting.remove(me); } - try { - getRegistration() - .then(getPushSubscription) - .then(unsubscribe); - } catch (e) { - - } - }); + return getRegistration() + .then(getPushSubscription) + .then(unsubscribe); + }) + .catch(console.warn); } else { console.warn('Your browser does not support Web Push Notifications.'); } @@ -143,6 +140,6 @@ export function saveSettings() { if (me) { pushNotificationsSetting.set(me, data); } - }); + }).catch(console.warn); }; } diff --git a/app/javascript/mastodon/actions/settings.js b/app/javascript/mastodon/actions/settings.js index b96383daa..5634a11ef 100644 --- a/app/javascript/mastodon/actions/settings.js +++ b/app/javascript/mastodon/actions/settings.js @@ -1,5 +1,6 @@ import api from '../api'; import { debounce } from 'lodash'; +import { showAlertForError } from './alerts'; export const SETTING_CHANGE = 'SETTING_CHANGE'; export const SETTING_SAVE = 'SETTING_SAVE'; @@ -23,7 +24,9 @@ const debouncedSave = debounce((dispatch, getState) => { const data = getState().get('settings').filter((_, path) => path !== 'saved').toJS(); - api(getState).put('/api/web/settings', { data }).then(() => dispatch({ type: SETTING_SAVE })); + api(getState).put('/api/web/settings', { data }) + .then(() => dispatch({ type: SETTING_SAVE })) + .catch(error => dispatch(showAlertForError(error))); }, 5000, { trailing: true }); export function saveSettings() { diff --git a/app/javascript/mastodon/containers/status_container.js b/app/javascript/mastodon/containers/status_container.js index 8ba1015b5..4579bd132 100644 --- a/app/javascript/mastodon/containers/status_container.js +++ b/app/javascript/mastodon/containers/status_container.js @@ -27,6 +27,7 @@ import { initReport } from '../actions/reports'; import { openModal } from '../actions/modal'; import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import { boostModal, deleteModal } from '../initial_state'; +import { showAlertForError } from '../actions/alerts'; const messages = defineMessages({ deleteConfirm: { id: 'confirmations.delete.confirm', defaultMessage: 'Delete' }, @@ -83,7 +84,10 @@ const mapDispatchToProps = (dispatch, { intl }) => ({ }, onEmbed (status) { - dispatch(openModal('EMBED', { url: status.get('url') })); + dispatch(openModal('EMBED', { + url: status.get('url'), + onError: error => dispatch(showAlertForError(error)), + })); }, onDelete (status) { diff --git a/app/javascript/mastodon/features/ui/components/embed_modal.js b/app/javascript/mastodon/features/ui/components/embed_modal.js index d440a8826..52aab00d0 100644 --- a/app/javascript/mastodon/features/ui/components/embed_modal.js +++ b/app/javascript/mastodon/features/ui/components/embed_modal.js @@ -10,6 +10,7 @@ export default class EmbedModal extends ImmutablePureComponent { static propTypes = { url: PropTypes.string.isRequired, onClose: PropTypes.func.isRequired, + onError: PropTypes.func.isRequired, intl: PropTypes.object.isRequired, } @@ -35,6 +36,8 @@ export default class EmbedModal extends ImmutablePureComponent { iframeDocument.body.style.margin = 0; this.iframe.width = iframeDocument.body.scrollWidth; this.iframe.height = iframeDocument.body.scrollHeight; + }).catch(error => { + this.props.onError(error); }); } diff --git a/app/javascript/mastodon/middleware/errors.js b/app/javascript/mastodon/middleware/errors.js index 72e5631e6..3cebb42e0 100644 --- a/app/javascript/mastodon/middleware/errors.js +++ b/app/javascript/mastodon/middleware/errors.js @@ -1,34 +1,14 @@ -import { defineMessages } from 'react-intl'; -import { showAlert } from '../actions/alerts'; +import { showAlertForError } from '../actions/alerts'; const defaultFailSuffix = 'FAIL'; -const messages = defineMessages({ - unexpectedTitle: { id: 'alert.unexpected.title', defaultMessage: 'Oops!' }, - unexpectedMessage: { id: 'alert.unexpected.message', defaultMessage: 'An unexpected error occurred.' }, -}); - export default function errorsMiddleware() { return ({ dispatch }) => next => action => { if (action.type && !action.skipAlert) { const isFail = new RegExp(`${defaultFailSuffix}$`, 'g'); if (action.type.match(isFail)) { - if (action.error.response) { - const { data, status, statusText } = action.error.response; - - let message = statusText; - let title = `${status}`; - - if (data.error) { - message = data.error; - } - - dispatch(showAlert(title, message)); - } else { - console.error(action.error); - dispatch(showAlert(messages.unexpectedTitle, messages.unexpectedMessage)); - } + dispatch(showAlertForError(action.error)); } } diff --git a/app/javascript/mastodon/storage/modifier.js b/app/javascript/mastodon/storage/modifier.js index 1bec04d0f..4773d07a9 100644 --- a/app/javascript/mastodon/storage/modifier.js +++ b/app/javascript/mastodon/storage/modifier.js @@ -9,6 +9,12 @@ const limit = 1024; // https://webkit.org/status/#specification-service-workers const asyncCache = window.caches ? caches.open('mastodon-system') : Promise.reject(); +function printErrorIfAvailable(error) { + if (error) { + console.warn(error); + } +} + function put(name, objects, onupdate, oncreate) { return asyncDB.then(db => new Promise((resolve, reject) => { const putTransaction = db.transaction(name, 'readwrite'); @@ -77,7 +83,9 @@ function evictAccountsByRecords(records) { function evict(toEvict) { toEvict.forEach(record => { - asyncCache.then(cache => accountAssetKeys.forEach(key => cache.delete(records[key]))); + asyncCache + .then(cache => accountAssetKeys.forEach(key => cache.delete(records[key]))) + .catch(printErrorIfAvailable); accountsMovedIndex.getAll(record.id).onsuccess = ({ target }) => evict(target.result); @@ -90,11 +98,11 @@ function evictAccountsByRecords(records) { } evict(records); - }); + }).catch(printErrorIfAvailable); } export function evictStatus(id) { - return evictStatuses([id]); + evictStatuses([id]); } export function evictStatuses(ids) { @@ -110,7 +118,7 @@ export function evictStatuses(ids) { idIndex.getKey(id).onsuccess = ({ target }) => target.result && store.delete(target.result); }); - }); + }).catch(printErrorIfAvailable); } function evictStatusesByRecords(records) { @@ -127,7 +135,9 @@ export function putAccounts(records) { const oldURL = target.result[key]; if (newURL !== oldURL) { - asyncCache.then(cache => cache.delete(oldURL)); + asyncCache + .then(cache => cache.delete(oldURL)) + .catch(printErrorIfAvailable); } }); @@ -145,10 +155,14 @@ export function putAccounts(records) { oncomplete(); }).then(records => { evictAccountsByRecords(records); - asyncCache.then(cache => cache.addAll(newURLs)); - }); + asyncCache + .then(cache => cache.addAll(newURLs)) + .catch(printErrorIfAvailable); + }).catch(printErrorIfAvailable); } export function putStatuses(records) { - put('statuses', records).then(evictStatusesByRecords); + put('statuses', records) + .then(evictStatusesByRecords) + .catch(printErrorIfAvailable); } diff --git a/package.json b/package.json index dfba49afc..d4de3a157 100644 --- a/package.json +++ b/package.json @@ -129,6 +129,7 @@ "eslint": "^4.15.0", "eslint-plugin-import": "^2.8.0", "eslint-plugin-jsx-a11y": "^5.1.1", + "eslint-plugin-promise": "^3.7.0", "eslint-plugin-react": "^7.5.1", "jest": "^21.2.1", "raf": "^3.4.0", diff --git a/yarn.lock b/yarn.lock index a306ebf55..866b24c7a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2433,6 +2433,10 @@ eslint-plugin-jsx-a11y@^5.1.1: emoji-regex "^6.1.0" jsx-ast-utils "^1.4.0" +eslint-plugin-promise@^3.7.0: + version "3.7.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-3.7.0.tgz#f4bde5c2c77cdd69557a8f69a24d1ad3cfc9e67e" + eslint-plugin-react@^7.5.1: version "7.5.1" resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.5.1.tgz#52e56e8d80c810de158859ef07b880d2f56ee30b" From 36eac8ba9011f225f7f949bbf1ca173832561f10 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 2 Apr 2018 19:19:51 +0200 Subject: [PATCH 07/12] Do not default SMTP verify mode to "peer", default to "none" (#6996) --- lib/tasks/mastodon.rake | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/lib/tasks/mastodon.rake b/lib/tasks/mastodon.rake index cfd6a1d25..505c7e0fa 100644 --- a/lib/tasks/mastodon.rake +++ b/lib/tasks/mastodon.rake @@ -256,11 +256,7 @@ namespace :mastodon do q.modify :strip end - env['SMTP_OPENSSL_VERIFY_MODE'] = prompt.ask('SMTP OpenSSL verify mode:') do |q| - q.required - q.default 'peer' - q.modify :strip - end + env['SMTP_OPENSSL_VERIFY_MODE'] = prompt.select('SMTP OpenSSL verify mode:', %w(none peer client_once fail_if_no_peer_cert)) end env['SMTP_FROM_ADDRESS'] = prompt.ask('E-mail address to send e-mails "from":') do |q| From e85cffb2362f914c0f2f7ced4112430b30bc7997 Mon Sep 17 00:00:00 2001 From: Emelia Smith Date: Mon, 2 Apr 2018 22:04:14 +0200 Subject: [PATCH 08/12] Feature: Report improvements (#6967) (#7000) * Implement Assignment of Reports (#6967) * Change translation of admin.report.comment.label to "Report Comment" for clarity As we'll soon add the ability for reports to have comments on them, this clarification makes sense. * Implement notes for Reports This enables moderators to leave comments about a report whilst they work on it * Fix display of report moderation notes * Allow reports to be reopened / marked as unresolved * Redirect to reports listing upon resolution of report * Implement "resolve with note" functionality * Add inverse relationship for report notes * Remove additional database querying when loading report notes * Fix tests for reports * Fix localisations for report notes / reports --- .../admin/report_notes_controller.rb | 49 +++++++++++ app/controllers/admin/reports_controller.rb | 20 ++++- app/helpers/admin/action_logs_helper.rb | 2 +- app/models/account.rb | 2 + app/models/report.rb | 4 + app/models/report_note.rb | 21 +++++ app/policies/report_note_policy.rb | 17 ++++ .../admin/report_notes/_report_note.html.haml | 11 +++ app/views/admin/reports/_report.html.haml | 5 ++ app/views/admin/reports/index.html.haml | 1 + app/views/admin/reports/show.html.haml | 84 +++++++++++++++---- config/locales/en.yml | 22 ++++- config/routes.rb | 2 + ...1200_add_assigned_account_id_to_reports.rb | 5 ++ .../20180402040909_create_report_notes.rb | 14 ++++ db/schema.rb | 16 +++- .../admin/reports_controller_spec.rb | 40 ++++++++- 17 files changed, 290 insertions(+), 25 deletions(-) create mode 100644 app/controllers/admin/report_notes_controller.rb create mode 100644 app/models/report_note.rb create mode 100644 app/policies/report_note_policy.rb create mode 100644 app/views/admin/report_notes/_report_note.html.haml create mode 100644 db/migrate/20180402031200_add_assigned_account_id_to_reports.rb create mode 100644 db/migrate/20180402040909_create_report_notes.rb diff --git a/app/controllers/admin/report_notes_controller.rb b/app/controllers/admin/report_notes_controller.rb new file mode 100644 index 000000000..ef8c0f469 --- /dev/null +++ b/app/controllers/admin/report_notes_controller.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true + +module Admin + class ReportNotesController < BaseController + before_action :set_report_note, only: [:destroy] + + def create + authorize ReportNote, :create? + + @report_note = current_account.report_notes.new(resource_params) + + if @report_note.save + if params[:create_and_resolve] + @report_note.report.update!(action_taken: true, action_taken_by_account_id: current_account.id) + log_action :resolve, @report_note.report + + redirect_to admin_reports_path, notice: I18n.t('admin.reports.resolved_msg') + else + redirect_to admin_report_path(@report_note.report_id), notice: I18n.t('admin.report_notes.created_msg') + end + else + @report = @report_note.report + @report_notes = @report.notes.latest + @form = Form::StatusBatch.new + + render template: 'admin/reports/show' + end + end + + def destroy + authorize @report_note, :destroy? + @report_note.destroy! + redirect_to admin_report_path(@report_note.report_id), notice: I18n.t('admin.report_notes.destroyed_msg') + end + + private + + def resource_params + params.require(:report_note).permit( + :content, + :report_id + ) + end + + def set_report_note + @report_note = ReportNote.find(params[:id]) + end + end +end diff --git a/app/controllers/admin/reports_controller.rb b/app/controllers/admin/reports_controller.rb index 75db6b78a..fc3785e3b 100644 --- a/app/controllers/admin/reports_controller.rb +++ b/app/controllers/admin/reports_controller.rb @@ -11,19 +11,35 @@ module Admin def show authorize @report, :show? + @report_note = @report.notes.new + @report_notes = @report.notes.latest @form = Form::StatusBatch.new end def update authorize @report, :update? process_report - redirect_to admin_report_path(@report) + + if @report.action_taken? + redirect_to admin_reports_path, notice: I18n.t('admin.reports.resolved_msg') + else + redirect_to admin_report_path(@report) + end end private def process_report case params[:outcome].to_s + when 'assign_to_self' + @report.update!(assigned_account_id: current_account.id) + log_action :assigned_to_self, @report + when 'unassign' + @report.update!(assigned_account_id: nil) + log_action :unassigned, @report + when 'reopen' + @report.update!(action_taken: false, action_taken_by_account_id: nil) + log_action :reopen, @report when 'resolve' @report.update!(action_taken_by_current_attributes) log_action :resolve, @report @@ -32,11 +48,13 @@ module Admin log_action :resolve, @report log_action :suspend, @report.target_account resolve_all_target_account_reports + @report.reload when 'silence' @report.target_account.update!(silenced: true) log_action :resolve, @report log_action :silence, @report.target_account resolve_all_target_account_reports + @report.reload else raise ActiveRecord::RecordNotFound end diff --git a/app/helpers/admin/action_logs_helper.rb b/app/helpers/admin/action_logs_helper.rb index 78278c700..7c26c0b05 100644 --- a/app/helpers/admin/action_logs_helper.rb +++ b/app/helpers/admin/action_logs_helper.rb @@ -86,7 +86,7 @@ module Admin::ActionLogsHelper opposite_verbs?(log) ? 'negative' : 'positive' when :update, :reset_password, :disable_2fa, :memorialize 'neutral' - when :demote, :silence, :disable, :suspend, :remove_avatar + when :demote, :silence, :disable, :suspend, :remove_avatar, :reopen 'negative' when :destroy opposite_verbs?(log) ? 'positive' : 'negative' diff --git a/app/models/account.rb b/app/models/account.rb index a34b6a2d3..446144a3e 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -95,6 +95,8 @@ class Account < ApplicationRecord has_many :reports has_many :targeted_reports, class_name: 'Report', foreign_key: :target_account_id + has_many :report_notes, dependent: :destroy + # Moderation notes has_many :account_moderation_notes, dependent: :destroy has_many :targeted_moderation_notes, class_name: 'AccountModerationNote', foreign_key: :target_account_id, dependent: :destroy diff --git a/app/models/report.rb b/app/models/report.rb index dd123fc15..f5b37cb6d 100644 --- a/app/models/report.rb +++ b/app/models/report.rb @@ -12,12 +12,16 @@ # account_id :integer not null # action_taken_by_account_id :integer # target_account_id :integer not null +# assigned_account_id :integer # class Report < ApplicationRecord belongs_to :account belongs_to :target_account, class_name: 'Account' belongs_to :action_taken_by_account, class_name: 'Account', optional: true + belongs_to :assigned_account, class_name: 'Account', optional: true + + has_many :notes, class_name: 'ReportNote', foreign_key: :report_id, inverse_of: :report, dependent: :destroy scope :unresolved, -> { where(action_taken: false) } scope :resolved, -> { where(action_taken: true) } diff --git a/app/models/report_note.rb b/app/models/report_note.rb new file mode 100644 index 000000000..3d12cf7b6 --- /dev/null +++ b/app/models/report_note.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# == Schema Information +# +# Table name: report_notes +# +# id :integer not null, primary key +# content :text not null +# report_id :integer not null +# account_id :integer not null +# created_at :datetime not null +# updated_at :datetime not null +# + +class ReportNote < ApplicationRecord + belongs_to :account + belongs_to :report, inverse_of: :notes + + scope :latest, -> { reorder('created_at ASC') } + + validates :content, presence: true, length: { maximum: 500 } +end diff --git a/app/policies/report_note_policy.rb b/app/policies/report_note_policy.rb new file mode 100644 index 000000000..694bc096b --- /dev/null +++ b/app/policies/report_note_policy.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class ReportNotePolicy < ApplicationPolicy + def create? + staff? + end + + def destroy? + admin? || owner? + end + + private + + def owner? + record.account_id == current_account&.id + end +end diff --git a/app/views/admin/report_notes/_report_note.html.haml b/app/views/admin/report_notes/_report_note.html.haml new file mode 100644 index 000000000..60ac5d0d5 --- /dev/null +++ b/app/views/admin/report_notes/_report_note.html.haml @@ -0,0 +1,11 @@ +%tr + %td + %p + %strong= report_note.account.acct + on + %time.formatted{ datetime: report_note.created_at.iso8601, title: l(report_note.created_at) } + = l report_note.created_at + = table_link_to 'trash', t('admin.reports.notes.delete'), admin_report_note_path(report_note), method: :delete if can?(:destroy, report_note) + %br/ + %br/ + = simple_format(h(report_note.content)) diff --git a/app/views/admin/reports/_report.html.haml b/app/views/admin/reports/_report.html.haml index d5eb161b9..d266f4840 100644 --- a/app/views/admin/reports/_report.html.haml +++ b/app/views/admin/reports/_report.html.haml @@ -17,5 +17,10 @@ %span{ title: t('admin.accounts.media_attachments') } = fa_icon('camera') = report.media_attachments.count + %td + - if report.assigned_account.nil? + \- + - else + = link_to report.assigned_account.acct, admin_account_path(report.assigned_account.id) %td = table_link_to 'circle', t('admin.reports.view'), admin_report_path(report) diff --git a/app/views/admin/reports/index.html.haml b/app/views/admin/reports/index.html.haml index 577c68a86..3b127c4fc 100644 --- a/app/views/admin/reports/index.html.haml +++ b/app/views/admin/reports/index.html.haml @@ -20,6 +20,7 @@ %th= t('admin.reports.reported_by') %th= t('admin.reports.comment.label') %th= t('admin.reports.report_contents') + %th= t('admin.reports.assigned') %th %tbody = render @reports diff --git a/app/views/admin/reports/show.html.haml b/app/views/admin/reports/show.html.haml index 5747cc274..e7634a034 100644 --- a/app/views/admin/reports/show.html.haml +++ b/app/views/admin/reports/show.html.haml @@ -4,24 +4,68 @@ - content_for :page_title do = t('admin.reports.report', id: @report.id) +%div{ style: 'overflow: hidden; margin-bottom: 20px' } + - if !@report.action_taken? + %div{ style: 'float: right' } + = link_to t('admin.reports.silence_account'), admin_report_path(@report, outcome: 'silence'), method: :put, class: 'button' + = link_to t('admin.reports.suspend_account'), admin_report_path(@report, outcome: 'suspend'), method: :put, class: 'button' + %div{ style: 'float: left' } + = link_to t('admin.reports.mark_as_resolved'), admin_report_path(@report, outcome: 'resolve'), method: :put, class: 'button' + - else + = link_to t('admin.reports.mark_as_unresolved'), admin_report_path(@report, outcome: 'reopen'), method: :put, class: 'button' + +.table-wrapper + %table.table.inline-table + %tbody + %tr + %th= t('admin.reports.updated_at') + %td{colspan: 2} + %time.formatted{ datetime: @report.updated_at.iso8601 } + %tr + %th= t('admin.reports.status') + %td{colspan: 2} + - if @report.action_taken? + = t('admin.reports.resolved') + = table_link_to 'envelope-open', t('admin.reports.reopen'), admin_report_path(@report, outcome: 'reopen'), method: :put + - else + = t('admin.reports.unresolved') + - if !@report.action_taken_by_account.nil? + %tr + %th= t('admin.reports.action_taken_by') + %td= @report.action_taken_by_account.acct + - else + %tr + %th= t('admin.reports.assigned') + %td + - if @report.assigned_account.nil? + \- + - else + = link_to @report.assigned_account.acct, admin_account_path(@report.assigned_account.id) + %td{style: "text-align: right"} + - if @report.assigned_account != current_user.account + = table_link_to 'user', t('admin.reports.assign_to_self'), admin_report_path(@report, outcome: 'assign_to_self'), method: :put + - if !@report.assigned_account.nil? + = table_link_to 'trash', t('admin.reports.unassign'), admin_report_path(@report, outcome: 'unassign'), method: :put + .report-accounts .report-accounts__item - %strong= t('admin.reports.reported_account') + %h3= t('admin.reports.reported_account') = render 'authorize_follows/card', account: @report.target_account, admin: true = render 'admin/accounts/card', account: @report.target_account .report-accounts__item - %strong= t('admin.reports.reported_by') + %h3= t('admin.reports.reported_by') = render 'authorize_follows/card', account: @report.account, admin: true = render 'admin/accounts/card', account: @report.account -%p - %strong= t('admin.reports.comment.label') - \: - = simple_format(@report.comment.presence || t('admin.reports.comment.none')) +%h3= t('admin.reports.comment.label') + += simple_format(@report.comment.presence || t('admin.reports.comment.none')) - unless @report.statuses.empty? %hr/ + %h3= t('admin.reports.statuses') + = form_for(@form, url: admin_report_reported_statuses_path(@report.id)) do |f| .batch-form-box .batch-checkbox-all @@ -46,14 +90,20 @@ %hr/ -- if !@report.action_taken? - %div{ style: 'overflow: hidden' } - %div{ style: 'float: right' } - = link_to t('admin.reports.silence_account'), admin_report_path(@report, outcome: 'silence'), method: :put, class: 'button' - = link_to t('admin.reports.suspend_account'), admin_report_path(@report, outcome: 'suspend'), method: :put, class: 'button' - %div{ style: 'float: left' } - = link_to t('admin.reports.mark_as_resolved'), admin_report_path(@report, outcome: 'resolve'), method: :put, class: 'button' -- elsif !@report.action_taken_by_account.nil? - %p - %strong #{t('admin.reports.action_taken_by')}: - = @report.action_taken_by_account.acct +%h3= t('admin.reports.notes.label') + +- if @report_notes.length > 0 + .table-wrapper + %table.table + %thead + %tr + %th + %tbody + = render @report_notes + += simple_form_for @report_note, url: admin_report_notes_path do |f| + = render 'shared/error_messages', object: @report_note + = f.input :content + = f.hidden_field :report_id + = f.button :button, t('admin.reports.notes.create'), type: :submit + = f.button :button, t('admin.reports.notes.create_and_resolve'), type: :submit, name: :create_and_resolve diff --git a/config/locales/en.yml b/config/locales/en.yml index fb2bbf4fe..51d9c906d 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -137,6 +137,7 @@ en: web: Web action_logs: actions: + assigned_to_self_report: "%{name} assigned report %{target} to themselves" confirm_user: "%{name} confirmed e-mail address of user %{target}" create_custom_emoji: "%{name} uploaded new emoji %{target}" create_domain_block: "%{name} blocked domain %{target}" @@ -153,10 +154,12 @@ en: memorialize_account: "%{name} turned %{target}'s account into a memoriam page" promote_user: "%{name} promoted user %{target}" remove_avatar_user: "%{name} removed %{target}'s avatar" + reopen_report: "%{name} reopened report %{target}" reset_password_user: "%{name} reset password of user %{target}" - resolve_report: "%{name} dismissed report %{target}" + resolve_report: "%{name} resolved report %{target}" silence_account: "%{name} silenced %{target}'s account" suspend_account: "%{name} suspended %{target}'s account" + unassigned_report: "%{name} unassigned report %{target}" unsilence_account: "%{name} unsilenced %{target}'s account" unsuspend_account: "%{name} unsuspended %{target}'s account" update_custom_emoji: "%{name} updated emoji %{target}" @@ -242,15 +245,26 @@ en: expired: Expired title: Filter title: Invites + report_notes: + created_msg: Moderation note successfully created! + destroyed_msg: Moderation note successfully destroyed! reports: action_taken_by: Action taken by are_you_sure: Are you sure? + assign_to_self: Assign to me + assigned: Assigned Moderator comment: - label: Comment + label: Report Comment none: None delete: Delete id: ID mark_as_resolved: Mark as resolved + mark_as_unresolved: Mark as unresolved + notes: + create: Add Note + create_and_resolve: Resolve with Note + delete: Delete + label: Notes nsfw: 'false': Unhide media attachments 'true': Hide media attachments @@ -259,12 +273,16 @@ en: reported_account: Reported account reported_by: Reported by resolved: Resolved + resolved_msg: Report successfully resolved! silence_account: Silence account status: Status + statuses: Reported Toots suspend_account: Suspend account target: Target title: Reports + unassign: Unassign unresolved: Unresolved + updated_at: Updated view: View settings: activity_api_enabled: diff --git a/config/routes.rb b/config/routes.rb index 9a4460562..4b5ba5c96 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -137,6 +137,8 @@ Rails.application.routes.draw do resources :reported_statuses, only: [:create, :update, :destroy] end + resources :report_notes, only: [:create, :destroy] + resources :accounts, only: [:index, :show] do member do post :subscribe diff --git a/db/migrate/20180402031200_add_assigned_account_id_to_reports.rb b/db/migrate/20180402031200_add_assigned_account_id_to_reports.rb new file mode 100644 index 000000000..0456839c4 --- /dev/null +++ b/db/migrate/20180402031200_add_assigned_account_id_to_reports.rb @@ -0,0 +1,5 @@ +class AddAssignedAccountIdToReports < ActiveRecord::Migration[5.1] + def change + add_reference :reports, :assigned_account, null: true, default: nil, foreign_key: { on_delete: :nullify, to_table: :accounts }, index: false + end +end diff --git a/db/migrate/20180402040909_create_report_notes.rb b/db/migrate/20180402040909_create_report_notes.rb new file mode 100644 index 000000000..732ddf825 --- /dev/null +++ b/db/migrate/20180402040909_create_report_notes.rb @@ -0,0 +1,14 @@ +class CreateReportNotes < ActiveRecord::Migration[5.1] + def change + create_table :report_notes do |t| + t.text :content, null: false + t.references :report, null: false + t.references :account, null: false + + t.timestamps + end + + add_foreign_key :report_notes, :reports, column: :report_id, on_delete: :cascade + add_foreign_key :report_notes, :accounts, column: :account_id, on_delete: :cascade + end +end diff --git a/db/schema.rb b/db/schema.rb index 18c61dbe0..a9733a2ae 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: 20180310000000) do +ActiveRecord::Schema.define(version: 20180402040909) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -355,6 +355,16 @@ ActiveRecord::Schema.define(version: 20180310000000) do t.index ["status_id", "preview_card_id"], name: "index_preview_cards_statuses_on_status_id_and_preview_card_id" end + create_table "report_notes", force: :cascade do |t| + t.text "content", null: false + t.bigint "report_id", null: false + t.bigint "account_id", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["account_id"], name: "index_report_notes_on_account_id" + t.index ["report_id"], name: "index_report_notes_on_report_id" + end + create_table "reports", force: :cascade do |t| t.bigint "status_ids", default: [], null: false, array: true t.text "comment", default: "", null: false @@ -364,6 +374,7 @@ ActiveRecord::Schema.define(version: 20180310000000) do t.bigint "account_id", null: false t.bigint "action_taken_by_account_id" t.bigint "target_account_id", null: false + t.bigint "assigned_account_id" t.index ["account_id"], name: "index_reports_on_account_id" t.index ["target_account_id"], name: "index_reports_on_target_account_id" end @@ -569,7 +580,10 @@ ActiveRecord::Schema.define(version: 20180310000000) do add_foreign_key "oauth_access_tokens", "oauth_applications", column: "application_id", name: "fk_f5fc4c1ee3", on_delete: :cascade add_foreign_key "oauth_access_tokens", "users", column: "resource_owner_id", name: "fk_e84df68546", on_delete: :cascade add_foreign_key "oauth_applications", "users", column: "owner_id", name: "fk_b0988c7c0a", on_delete: :cascade + add_foreign_key "report_notes", "accounts", on_delete: :cascade + add_foreign_key "report_notes", "reports", on_delete: :cascade add_foreign_key "reports", "accounts", column: "action_taken_by_account_id", name: "fk_bca45b75fd", on_delete: :nullify + add_foreign_key "reports", "accounts", column: "assigned_account_id", on_delete: :nullify add_foreign_key "reports", "accounts", column: "target_account_id", name: "fk_eb37af34f0", on_delete: :cascade add_foreign_key "reports", "accounts", name: "fk_4b81f7522c", on_delete: :cascade add_foreign_key "session_activations", "oauth_access_tokens", column: "access_token_id", name: "fk_957e5bda89", on_delete: :cascade diff --git a/spec/controllers/admin/reports_controller_spec.rb b/spec/controllers/admin/reports_controller_spec.rb index 71a185147..9be298df6 100644 --- a/spec/controllers/admin/reports_controller_spec.rb +++ b/spec/controllers/admin/reports_controller_spec.rb @@ -61,7 +61,7 @@ describe Admin::ReportsController do report = Fabricate(:report) put :update, params: { id: report, outcome: 'resolve' } - expect(response).to redirect_to(admin_report_path(report)) + expect(response).to redirect_to(admin_reports_path) report.reload expect(report.action_taken_by_account).to eq user.account expect(report.action_taken).to eq true @@ -74,7 +74,7 @@ describe Admin::ReportsController do allow(Admin::SuspensionWorker).to receive(:perform_async) put :update, params: { id: report, outcome: 'suspend' } - expect(response).to redirect_to(admin_report_path(report)) + expect(response).to redirect_to(admin_reports_path) report.reload expect(report.action_taken_by_account).to eq user.account expect(report.action_taken).to eq true @@ -88,12 +88,46 @@ describe Admin::ReportsController do report = Fabricate(:report) put :update, params: { id: report, outcome: 'silence' } - expect(response).to redirect_to(admin_report_path(report)) + expect(response).to redirect_to(admin_reports_path) report.reload expect(report.action_taken_by_account).to eq user.account expect(report.action_taken).to eq true expect(report.target_account).to be_silenced end end + + describe 'with an outsome of `reopen`' do + it 'reopens the report' do + report = Fabricate(:report) + + put :update, params: { id: report, outcome: 'reopen' } + expect(response).to redirect_to(admin_report_path(report)) + report.reload + expect(report.action_taken_by_account).to eq nil + expect(report.action_taken).to eq false + end + end + + describe 'with an outsome of `assign_to_self`' do + it 'reopens the report' do + report = Fabricate(:report) + + put :update, params: { id: report, outcome: 'assign_to_self' } + expect(response).to redirect_to(admin_report_path(report)) + report.reload + expect(report.assigned_account).to eq user.account + end + end + + describe 'with an outsome of `unassign`' do + it 'reopens the report' do + report = Fabricate(:report) + + put :update, params: { id: report, outcome: 'unassign' } + expect(response).to redirect_to(admin_report_path(report)) + report.reload + expect(report.assigned_account).to eq nil + end + end end end From 1c293086a16fce465d5bdc123809f2d28b3e2ab6 Mon Sep 17 00:00:00 2001 From: mayaeh Date: Tue, 3 Apr 2018 18:21:33 +0900 Subject: [PATCH 09/12] i18n: Add Japanese translations for #7000 (#7022) * run yarn manage:translations. * run i18n-tasks add-missing ja. * Update Japanese translations. --- .../mastodon/locales/defaultMessages.json | 13 +++++++++++ config/locales/ja.yml | 23 +++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/app/javascript/mastodon/locales/defaultMessages.json b/app/javascript/mastodon/locales/defaultMessages.json index 4c9401deb..5059fc67b 100644 --- a/app/javascript/mastodon/locales/defaultMessages.json +++ b/app/javascript/mastodon/locales/defaultMessages.json @@ -1,4 +1,17 @@ [ + { + "descriptors": [ + { + "defaultMessage": "Oops!", + "id": "alert.unexpected.title" + }, + { + "defaultMessage": "An unexpected error occurred.", + "id": "alert.unexpected.message" + } + ], + "path": "app/javascript/mastodon/actions/alerts.json" + }, { "descriptors": [ { diff --git a/config/locales/ja.yml b/config/locales/ja.yml index 090b080e4..629d688c9 100644 --- a/config/locales/ja.yml +++ b/config/locales/ja.yml @@ -60,6 +60,7 @@ ja: destroyed_msg: モデレーションメモを削除しました! accounts: are_you_sure: 本当に実行しますか? + avatar: アイコン by_domain: ドメイン confirm: 確認 confirmed: 確認済み @@ -108,6 +109,7 @@ ja: public: パブリック push_subscription_expires: PuSH購読期限 redownload: アバターの更新 + remove_avatar: アイコンを削除 reset: リセット reset_password: パスワード再設定 resubscribe: 再講読 @@ -135,6 +137,7 @@ ja: web: Web action_logs: actions: + assigned_to_self_report: "%{name} さんがレポート %{target} を自身の担当に割り当てました" confirm_user: "%{name} さんが %{target} さんのメールアドレスを確認済みにしました" create_custom_emoji: "%{name} さんがカスタム絵文字 %{target} を追加しました" create_domain_block: "%{name} さんがドメイン %{target} をブロックしました" @@ -150,10 +153,13 @@ ja: enable_user: "%{name} さんが %{target} さんのログインを有効化しました" memorialize_account: "%{name} さんが %{target} さんを追悼アカウントページに登録しました" promote_user: "%{name} さんが %{target} さんを昇格しました" + remove_avatar_user: "%{name} さんが %{target} さんのアイコンを削除しました" + reopen_report: "%{name} さんがレポート %{target} を再び開きました" reset_password_user: "%{name} さんが %{target} さんのパスワードをリセットしました" resolve_report: "%{name} さんがレポート %{target} を解決済みにしました" silence_account: "%{name} さんが %{target} さんをサイレンスにしました" suspend_account: "%{name} さんが %{target} さんを停止しました" + unassigned_report: "%{name} さんがレポート %{target} の担当を外しました" unsilence_account: "%{name} さんが %{target} さんのサイレンスを解除しました" unsuspend_account: "%{name} さんが %{target} さんの停止を解除しました" update_custom_emoji: "%{name} さんがカスタム絵文字 %{target} を更新しました" @@ -239,29 +245,45 @@ ja: expired: 期限切れ title: フィルター title: 招待 + report_notes: + created_msg: モデレーションメモを書き込みました! + destroyed_msg: モデレーションメモを削除しました! reports: action_taken_by: レポート処理者 are_you_sure: 本当に実行しますか? + assign_to_self: 担当になる + assigned: 担当者 comment: label: コメント none: なし delete: 削除 id: ID mark_as_resolved: 解決済みとしてマーク + mark_as_unresolved: 未解決として再び開く + notes: + create: 書き込む + create_and_resolve: 書き込み、解決済みにする + delete: 削除 + label: メモ nsfw: 'false': NSFW オフ 'true': NSFW オン + reopen: 再び開く report: レポート#%{id} report_contents: 内容 reported_account: 報告対象アカウント reported_by: 報告者 resolved: 解決済み + resolved_msg: レポートを解決済みにしました! silence_account: アカウントをサイレンス status: ステータス + statuses: 通報されたトゥート suspend_account: アカウントを停止 target: ターゲット title: レポート + unassign: 担当を外す unresolved: 未解決 + updated_at: 更新日時 view: 表示 settings: activity_api_enabled: @@ -475,6 +497,7 @@ ja: '21600': 6 時間 '3600': 1 時間 '43200': 12 時間 + '604800': 1 週間 '86400': 1 日 expires_in_prompt: 無期限 generate: 作成 From 2e59751823585a8ef8729d4287239b326ab02193 Mon Sep 17 00:00:00 2001 From: Emelia Smith Date: Tue, 3 Apr 2018 13:07:32 +0200 Subject: [PATCH 10/12] Improve require_admin! and require_staff! filters (#7018) Previously these returns 302 redirects instead of 403s, which meant posting links to admin pages in slack caused them to unfurl, rather than stay as a link. Additionally, require_admin! doesn't appear to be actively used, on require_staff! --- app/controllers/application_controller.rb | 4 +- .../controllers/admin/base_controller_spec.rb | 25 +++++++---- .../application_controller_spec.rb | 42 ++++++++++++++++++- 3 files changed, 58 insertions(+), 13 deletions(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 6e5042617..588526447 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -39,11 +39,11 @@ class ApplicationController < ActionController::Base end def require_admin! - redirect_to root_path unless current_user&.admin? + forbidden unless current_user&.admin? end def require_staff! - redirect_to root_path unless current_user&.staff? + forbidden unless current_user&.staff? end def check_suspension diff --git a/spec/controllers/admin/base_controller_spec.rb b/spec/controllers/admin/base_controller_spec.rb index 2b60e7e92..9ac833623 100644 --- a/spec/controllers/admin/base_controller_spec.rb +++ b/spec/controllers/admin/base_controller_spec.rb @@ -9,18 +9,25 @@ describe Admin::BaseController, type: :controller do end end - it 'renders admin layout' do + it 'requires administrator or moderator' do + routes.draw { get 'success' => 'admin/base#success' } + sign_in(Fabricate(:user, admin: false, moderator: false)) + get :success + + expect(response).to have_http_status(:forbidden) + end + + it 'renders admin layout as a moderator' do + routes.draw { get 'success' => 'admin/base#success' } + sign_in(Fabricate(:user, moderator: true)) + get :success + expect(response).to render_template layout: 'admin' + end + + it 'renders admin layout as an admin' do routes.draw { get 'success' => 'admin/base#success' } sign_in(Fabricate(:user, admin: true)) get :success expect(response).to render_template layout: 'admin' end - - it 'requires administrator' do - routes.draw { get 'success' => 'admin/base#success' } - sign_in(Fabricate(:user, admin: false)) - get :success - - expect(response).to redirect_to('/') - end end diff --git a/spec/controllers/application_controller_spec.rb b/spec/controllers/application_controller_spec.rb index 51c0e3c70..3e4d27e05 100644 --- a/spec/controllers/application_controller_spec.rb +++ b/spec/controllers/application_controller_spec.rb @@ -181,10 +181,48 @@ describe ApplicationController, type: :controller do routes.draw { get 'sucesss' => 'anonymous#sucesss' } end - it 'redirects to root path if current user is not admin' do + it 'returns a 403 if current user is not admin' do sign_in(Fabricate(:user, admin: false)) get 'sucesss' - expect(response).to redirect_to('/') + expect(response).to have_http_status(403) + end + + it 'returns a 403 if current user is only a moderator' do + sign_in(Fabricate(:user, moderator: true)) + get 'sucesss' + expect(response).to have_http_status(403) + end + + it 'does nothing if current user is admin' do + sign_in(Fabricate(:user, admin: true)) + get 'sucesss' + expect(response).to have_http_status(200) + end + end + + describe 'require_staff!' do + controller do + before_action :require_staff! + + def sucesss + head 200 + end + end + + before do + routes.draw { get 'sucesss' => 'anonymous#sucesss' } + end + + it 'returns a 403 if current user is not admin or moderator' do + sign_in(Fabricate(:user, admin: false, moderator: false)) + get 'sucesss' + expect(response).to have_http_status(403) + end + + it 'does nothing if current user is moderator' do + sign_in(Fabricate(:user, moderator: true)) + get 'sucesss' + expect(response).to have_http_status(200) end it 'does nothing if current user is admin' do From 6ff3b3e4db09c8ddf2faad6710e4a25f988e762d Mon Sep 17 00:00:00 2001 From: Nolan Lawson Date: Tue, 3 Apr 2018 04:08:11 -0700 Subject: [PATCH 11/12] Fix nil account issue in ProcessAccountService (#7019) --- app/services/activitypub/process_account_service.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/services/activitypub/process_account_service.rb b/app/services/activitypub/process_account_service.rb index cf8462821..21c2fc57a 100644 --- a/app/services/activitypub/process_account_service.rb +++ b/app/services/activitypub/process_account_service.rb @@ -28,7 +28,7 @@ class ActivityPub::ProcessAccountService < BaseService after_protocol_change! if protocol_changed? after_key_change! if key_changed? - check_featured_collection! if @account.featured_collection_url.present? + check_featured_collection! if @account&.featured_collection_url&.present? @account rescue Oj::ParseError From d8d42179590db772cc5b1873385cba7e5afe20df Mon Sep 17 00:00:00 2001 From: ThibG Date: Tue, 3 Apr 2018 21:09:14 +0200 Subject: [PATCH 12/12] Fix french wording of reblogged toots in public views, matching the wording of reblogged_by (#7029) --- config/locales/fr.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 6137e1bd4..d7371dc94 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -661,7 +661,7 @@ fr: stream_entries: click_to_show: Cliquer pour afficher pinned: Pouet épinglé - reblogged: partagé + reblogged: a partagé sensitive_content: Contenu sensible terms: body_html: |