From 3442bc0ea3c06e64d891fc2e2af0326f1194e3a3 Mon Sep 17 00:00:00 2001 From: Eric Blade Date: Tue, 11 Apr 2017 19:14:56 -0400 Subject: [PATCH 01/32] update Docker section of README (#1231) Re-ordered the steps so it doesn't read "Do this, but first, do this other step" Added note about keeping the REDIS and DB settings as they are for Docker use Add which variables you will NEED to set to make the Mastodon work Add how to generate the secrets Add how to connect to your Mastodon Add a note to read the Production-guide --- README.md | 42 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 37065f9d..ee6538d1 100644 --- a/README.md +++ b/README.md @@ -67,23 +67,53 @@ Consult the example configuration file, `.env.production.sample` for the full li [![](https://images.microbadger.com/badges/version/gargron/mastodon.svg)](https://microbadger.com/images/gargron/mastodon "Get your own version badge on microbadger.com") [![](https://images.microbadger.com/badges/image/gargron/mastodon.svg)](https://microbadger.com/images/gargron/mastodon "Get your own image badge on microbadger.com") -The project now includes a `Dockerfile` and a `docker-compose.yml` file (which requires at least docker-compose version `1.10.0`). You need to turn `.env.production.sample` into `.env.production` with all the variables set before you can: +The project now includes a `Dockerfile` and a `docker-compose.yml` file (which requires at least docker-compose version `1.10.0`). +Review the settings in docker-compose.yml. Note that it is not default to store the postgresql database and redis databases in a persistent storage location, +so you may need or want to adjust the settings there. + +Before running the first time, you need to build the images: docker-compose build -And finally +Then, you need to fill in the .env.production file: + cp .env.production.sample .env.production + vi .env.production - docker-compose up -d +Do NOT change the REDIS_* or DB_* settings when running with the default docker configurations. -As usual, the first thing you would need to do would be to run migrations: +You will need to fill in, at least: + LOCAL_DOMAIN, LOCAL_HTTPS, PAPERCLIP_SECRET, SECRET_KEY_BASE, OTP_SECRET, and the SMTP_* + settings. To generate the PAPERCLIP_SECRET, SECRET_KEY_BASE, and OTP_SECRET, you may use: + + docker-compose run --rm web rake secret + + Do this once for each of those keys, and copy the result into the .env.production file in + the appropriate field. + +Then you should run the db:migrate command to create the database, or migrate it from an older release: docker-compose run --rm web rails db:migrate -And since the instance running in the container will be running in production mode, you need to pre-compile assets: +Then, you will also need to precompile the assets: docker-compose run --rm web rails assets:precompile -The container has two volumes, for the assets and for user uploads. The default docker-compose.yml maps them to the repository's `public/assets` and `public/system` directories, you may wish to put them somewhere else. Likewise, the PostgreSQL and Redis images have data containers that you may wish to map somewhere where you know how to find them and back them up. + before you can launch the docker image with: + + docker-compose up + +If you wish to run this as a daemon process instead of monitoring it on console, use instead: + + docker-compose up -d + +Then you may login to your new Mastodon instance by browsing to http(s)://(yourhost):3000/ + +Following that, make sure that you read the [production guide](docs/Running-Mastodon/Production-guide.md). You are probably going to want to understand how +to configure NGINX to make your Mastodon instance available to the rest of the world. + +The container has two volumes, for the assets and for user uploads, and optionally two more, for the postgresql and redis databases. + +The default docker-compose.yml maps them to the repository's `public/assets` and `public/system` directories, you may wish to put them somewhere else. Likewise, the PostgreSQL and Redis images have data containers that you may wish to map somewhere where you know how to find them and back them up. **Note**: The `--rm` option for docker-compose will remove the container that is created to run a one-off command after it completes. As data is stored in volumes it is not affected by that container clean-up. From 24eb45425efc82b55c7412f4b43eae1f49d771ca Mon Sep 17 00:00:00 2001 From: Koala Yeung Date: Wed, 12 Apr 2017 14:50:50 +0800 Subject: [PATCH 02/32] Add Traditional Chinese, Hong Kong translation (zh-HK) (#1544) * Added Chinese Traditional Hong Kong (zh-HK) for Ruby * Added translations for Ruby. * Added Chinese Traditional Hong Kong (zh-HK) for JS * Added translations for javascript code. * Rearrange language references in mastodon.jsx * Break `addLocaleData` into multiple lines. Make future commit more readable. * Roughly re-sort the languages in alphabetical orders (only manually put English on top because it is default). * Sort application.rb locale with alphabetical order With exception that English (default language) goes first. Improve code readability. * Resort language selection box alphabetically Sort HUMAN_LOCALES in the alphabetical order of display name (except English, the default language, come first). Improve usability. --- .../components/containers/mastodon.jsx | 32 +++- .../javascripts/components/locales/index.jsx | 5 +- .../javascripts/components/locales/zh-hk.jsx | 113 ++++++++++++ app/helpers/settings_helper.rb | 8 +- config/application.rb | 16 +- config/locales/devise.zh-HK.yml | 61 +++++++ config/locales/doorkeeper.zh-HK.yml | 113 ++++++++++++ config/locales/simple_form.zh-HK.yml | 46 +++++ config/locales/zh-HK.yml | 172 ++++++++++++++++++ 9 files changed, 551 insertions(+), 15 deletions(-) create mode 100644 app/assets/javascripts/components/locales/zh-hk.jsx create mode 100644 config/locales/devise.zh-HK.yml create mode 100644 config/locales/doorkeeper.zh-HK.yml create mode 100644 config/locales/simple_form.zh-HK.yml create mode 100644 config/locales/zh-HK.yml diff --git a/app/assets/javascripts/components/containers/mastodon.jsx b/app/assets/javascripts/components/containers/mastodon.jsx index d48bb2ba..37440da8 100644 --- a/app/assets/javascripts/components/containers/mastodon.jsx +++ b/app/assets/javascripts/components/containers/mastodon.jsx @@ -41,15 +41,17 @@ import Report from '../features/report'; import { IntlProvider, addLocaleData } from 'react-intl'; import en from 'react-intl/locale-data/en'; import de from 'react-intl/locale-data/de'; -import es from 'react-intl/locale-data/es'; -import fr from 'react-intl/locale-data/fr'; -import pt from 'react-intl/locale-data/pt'; -import hu from 'react-intl/locale-data/hu'; -import uk from 'react-intl/locale-data/uk'; -import fi from 'react-intl/locale-data/fi'; import eo from 'react-intl/locale-data/eo'; -import ru from 'react-intl/locale-data/ru'; +import es from 'react-intl/locale-data/es'; +import fi from 'react-intl/locale-data/fi'; +import fr from 'react-intl/locale-data/fr'; +import hu from 'react-intl/locale-data/hu'; import ja from 'react-intl/locale-data/ja'; +import pt from 'react-intl/locale-data/pt'; +import ru from 'react-intl/locale-data/ru'; +import uk from 'react-intl/locale-data/uk'; +import zh from 'react-intl/locale-data/zh'; +import { localeData as zh_hk } from '../locales/zh-hk'; import getMessagesForLocale from '../locales'; import { hydrateStore } from '../actions/store'; @@ -64,7 +66,21 @@ const browserHistory = useRouterHistory(createBrowserHistory)({ }); -addLocaleData([...en, ...de, ...es, ...fr, ...pt, ...hu, ...uk, ...fi, ...eo, ...ru, ...ja]); +addLocaleData([ + ...en, + ...de, + ...eo, + ...es, + ...fi, + ...fr, + ...hu, + ...ja, + ...pt, + ...ru, + ...uk, + ...zh, + ...zh_hk, +]); const Mastodon = React.createClass({ diff --git a/app/assets/javascripts/components/locales/index.jsx b/app/assets/javascripts/components/locales/index.jsx index da85240b..c3c5784a 100644 --- a/app/assets/javascripts/components/locales/index.jsx +++ b/app/assets/javascripts/components/locales/index.jsx @@ -9,6 +9,7 @@ import fi from './fi'; import eo from './eo'; import ru from './ru'; import ja from './ja'; +import zh_hk from './zh-hk'; const locales = { @@ -22,8 +23,8 @@ const locales = { fi, eo, ru, - ja - + ja, + 'zh-HK': zh_hk, }; export default function getMessagesForLocale (locale) { diff --git a/app/assets/javascripts/components/locales/zh-hk.jsx b/app/assets/javascripts/components/locales/zh-hk.jsx new file mode 100644 index 00000000..b26a8c3d --- /dev/null +++ b/app/assets/javascripts/components/locales/zh-hk.jsx @@ -0,0 +1,113 @@ +import zh from 'react-intl/locale-data/zh'; + +const localeData = zh.reduce(function (acc, localeData) { + if (localeData.locale === "zh-Hant-HK") { + // rename the locale "zh-Hant-HK" as "zh-HK" + // (match the code usually used in Accepted-Language header) + acc.push(Object.assign({}, + localeData, + { + "locale": "zh-HK", + "parentLocale": "zh-Hant-HK", + } + )); + } + return acc; +}, []); + +export { localeData as localeData }; + +const zh_hk = { + "account.block": "封鎖 @{name}", + "account.edit_profile": "修改個人資料", + "account.follow": "關注", + "account.followers": "關注的人", + "account.follows_you": "關注你", + "account.follows": "正在關注", + "account.mention": "提及 @{name}", + "account.posts": "文章", + "account.requested": "等候審批", + "account.unblock": "解除對 @{name} 的封鎖", + "account.unfollow": "取消關注", + "column_back_button.label": "先前顯示", + "column.community": "本站時間軸", + "column.home": "家", + "column.notifications": "通知", + "column.public": "跨站公共時間軸", + "compose_form.placeholder": "你在想甚麼?", + "compose_form.privacy_disclaimer": "你的私人文章,將被遞送至你所提及的 {domains} 用戶。你是否信任 {domainsCount, plural, one {這個網站} other {這些網站}}?請留意,文章私隱設定只適用於各 Mastodon 服務站,如果 {domains} {domainsCount, plural, one {不是 Mastodon 服務站} other {之中有些不是 Mastodon 服務站}},對方將無法收到這篇文章的私隱設定,然後可能被轉推給不能預知的用戶閱讀。", + "compose_form.private": "標示為「只有關注你的人能看」", + "compose_form.publish": "發文", + "compose_form.sensitive": "將媒體檔案標示為「敏感內容」", + "compose_form.spoiler": "將部份文字藏於警告訊息之後", + "compose_form.unlisted": "請勿在公共時間軸顯示", + "empty_column.community": "本站時間軸暫時未有內容,快貼文來搶頭香啊!", + "empty_column.hashtag": "這個標籤暫時未有內容。", + "empty_column.home": "你還沒有關注任何用戶。快看看{public},向其他用戶搭訕吧。", + "empty_column.home.public_timeline": "公共時間軸", + "empty_column.notifications": "You don't have any notifications yet. Interact with others to start the conversation.", + "empty_column.public": "There is nothing here! Write something publicly, or manually follow users from other instances to fill it up.", + "getting_started.about_addressing": "只要你知道一位用戶的用戶名稱和域名,你可以用「@用戶名稱@域名」的格式在搜尋欄尋找該用戶。", + "getting_started.about_shortcuts": "只要該用戶是在你現在的服務站開立,你可以直接輸入用戶𠱷搜尋。同樣的規則適用於在文章提及別的用戶。", + "getting_started.apps": "手機或桌面應用程式", + "getting_started.heading": "開始使用", + "getting_started.open_source_notice": "Mastodon 是一個開放源碼的軟件。你可以在官方 GitHub ({github}) 貢獻或者回報問題。你亦可透過{apps}閱讀 Mastodon 上的消息。", + "home.column_settings.basic": "基本", + "home.column_settings.show_reblogs": "顯示被轉推的文章", + "home.column_settings.show_replies": "顯示回應文章", + "home.column_settings.advanced": "進階", + "lightbox.close": "關閉", + "loading_indicator.label": "載入中...", + "missing_indicator.label": "找不到內容", + "navigation_bar.community_timeline": "本站時間軸", + "navigation_bar.edit_profile": "修改個人資料", + "navigation_bar.logout": "登出", + "navigation_bar.preferences": "個人設定", + "navigation_bar.public_timeline": "跨站公共時間軸", + "notification.favourite": "{name} 喜歡你的文章", + "notification.follow": "{name} 開始開始你", + "notification.mention": "{name} 提及你", + "notification.reblog": "{name} 轉推你的文章", + "notifications.column_settings.alert": "顯示桌面通知", + "notifications.column_settings.favourite": "喜歡你的文章:", + "notifications.column_settings.follow": "關注你:", + "notifications.column_settings.mention": "提及你:", + "notifications.column_settings.reblog": "轉推你的文章:", + "notifications.column_settings.show": "在通知欄顯示", + "notifications.column_settings.sound": "播放音效", + "reply_indicator.cancel": "取消", + "report.target": "Reporting", + "search.account": "用戶", + "search.hashtag": "標籤", + "search.placeholder": "搜尋", + "search_results.total": "{count} 項結果", + "search.status_by": "按用戶名稱搜尋文章", + "status.delete": "刪除", + "status.favourite": "喜歡", + "status.load_more": "載入更多", + "status.media_hidden": "隱藏媒體內容", + "status.mention": "提及 @{name}", + "status.open": "展開文章", + "status.reblog": "轉推", + "status.reblogged_by": "{name} 轉推", + "status.reply": "回應", + "status.report": "舉報 @{name}", + "status.sensitive_toggle": "點擊顯示", + "status.sensitive_warning": "敏感內容", + "status.show_less": "減少顯示", + "status.show_more": "顯示更多", + "tabs_bar.compose": "撰寫", + "tabs_bar.home": "家", + "tabs_bar.local_timeline": "本站", + "tabs_bar.mentions": "提及", + "tabs_bar.notifications": "通知", + "tabs_bar.public": "跨站公共時間軸", + "tabs_bar.federated_timeline": "跨站", + "upload_area.title": "將檔案拖放至此上載", + "upload_button.label": "上載媒體檔案", + "upload_progress.label": "上載中……", + "upload_form.undo": "還原", + "video_player.toggle_sound": "開關音效", +}; + +export default zh_hk; diff --git a/app/helpers/settings_helper.rb b/app/helpers/settings_helper.rb index 8a94df5f..0905138b 100644 --- a/app/helpers/settings_helper.rb +++ b/app/helpers/settings_helper.rb @@ -6,15 +6,15 @@ module SettingsHelper de: 'Deutsch', es: 'Español', eo: 'Esperanto', - pt: 'Português', fr: 'Français', hu: 'Magyar', - uk: 'Українська', - 'zh-CN': '简体中文', + pt: 'Português', fi: 'Suomi', ru: 'Русский', + uk: 'Українська', ja: '日本語', - + 'zh-CN': '简体中文', + 'zh-HK': '繁體中文(香港)', }.freeze def human_locale(locale) diff --git a/config/application.rb b/config/application.rb index a3991639..19523c88 100644 --- a/config/application.rb +++ b/config/application.rb @@ -25,7 +25,21 @@ module Mastodon # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] - config.i18n.available_locales = [:en, :de, :es, :pt, :fr, :hu, :uk, 'zh-CN', :fi, :eo, :ru, :ja] + config.i18n.available_locales = [ + :en, + :de, + :eo, + :es, + :fi, + :fr, + :hu, + :ja, + :pt, + :ru, + :uk, + 'zh-CN', + :'zh-HK', + ] config.i18n.default_locale = :en diff --git a/config/locales/devise.zh-HK.yml b/config/locales/devise.zh-HK.yml new file mode 100644 index 00000000..cecd4007 --- /dev/null +++ b/config/locales/devise.zh-HK.yml @@ -0,0 +1,61 @@ +--- +zh-HK: + devise: + confirmations: + confirmed: 你的電郵地址確認成功 + send_instructions: 你將會在幾分鐘內收到確認指示電郵,上面有確認你電郵地址的指示。 + send_paranoid_instructions: 如果你的電郵地址已經存在於我們的資料庫,你將會在幾分鐘內收到電郵,確認你電郵地址的指示。 + failure: + already_authenticated: 你之前已經登入了。 + inactive: 你的用戶並未啟用。 + invalid: 不正確的 %{authentication_keys} 或密碼。 + last_attempt: 若你再一次嘗試失敗,我們將鎖定你的用戶,以察安全。 + locked: 你的用戶已被鎖定 + not_found_in_database: 不正確的 %{authentication_keys} 或密碼。 + timeout: 你的登入階段已經過期,請重新登入以繼續使用。 + unauthenticated: 你必須先登入或登記,以繼續使用。 + unconfirmed: 你必須先確認電郵地址,繼續使用。 + mailer: + confirmation_instructions: + subject: 'Mastodon: 確認電郵地址' + password_change: + subject: 'Mastodon: 更改密碼' + reset_password_instructions: + subject: 'Mastodon: 重設密碼' + unlock_instructions: + subject: 'Mastodon: 解除用戶鎖定' + omniauth_callbacks: + failure: 無法以 %{kind} 登入你的用戶,原因是︰「%{reason}」。 + success: 成功以 %{kind} 登入你的用戶。 + passwords: + no_token: 你必須使用重設密碼電郵內的網址進入本頁。如果你確是使用電郵內的網址,請確認你用了完整的網址。 + send_instructions: 你將在幾分鐘內收到重設密碼的電郵指示。 + send_paranoid_instructions: 如果你的電郵地址已經存在於我們的資料庫,你將會在幾分鐘內收到重設密碼的電郵指示。 + updated: 你的密碼已經更新,你現在正登入本站。 + updated_not_active: 你的密碼已經更新。 + registrations: + destroyed: 再見了!你的用戶已被取消,希望我們相有相見的機會吧。 + signed_up: 歡迎你!你的登記已經成功。 + signed_up_but_inactive: 你的登記已經成功,可是由於你的用戶還被被啟用,暫時還不能讓你登入。 + signed_up_but_locked: 你的登記已經成功,可是由於你的用戶已被鎖定,我們無法讓你登入。 + signed_up_but_unconfirmed: 一條確認連結已經電郵到你的郵址。請使用讓連結啟用你的用戶。 + update_needs_confirmation: 你的用戶已經更新,但我們需要確認你的電郵地址。請打開你的郵箱,使用確認電郵的連結來確認的地郵址。 + updated: 你的用戶已經成功更新。 + sessions: + already_signed_out: 成功登出。 + signed_in: 成功登入。 + signed_out: 成功登出。 + unlocks: + send_instructions: 你將在幾分鐘內收到解除用戶鎖定的電郵指示。 + send_paranoid_instructions: 如果你的電郵地址已經存在於我們的資料庫,你將在幾分鐘內收到解除用戶鎖定的電郵指示。 + unlocked: 你的用戶已經解鎖,請登入以繼續。 + errors: + messages: + already_confirmed: 先前已經確認,請嘗試登入 + confirmation_period_expired: 需要在 %{period} 之內確認。請重新申請 + expired: 已經過期,請重新申請 + not_found: 找不到 + not_locked: 並未被鎖定 + not_saved: + one: '1 個錯誤令 %{resource} 被法被儲存︰' + other: "%{count} 個錯誤令 %{resource} 被法被儲存︰" diff --git a/config/locales/doorkeeper.zh-HK.yml b/config/locales/doorkeeper.zh-HK.yml new file mode 100644 index 00000000..90224c73 --- /dev/null +++ b/config/locales/doorkeeper.zh-HK.yml @@ -0,0 +1,113 @@ +--- +zh-HK: + activerecord: + attributes: + doorkeeper/application: + name: 名稱 + redirect_uri: 轉接 URI + errors: + models: + doorkeeper/application: + attributes: + redirect_uri: + fragment_present: 'URI 不可包含 "#fragment" 部份' + invalid_uri: 必需有正確的 URI. + relative_uri: 必需為絕對 URI. + secured_uri: 必需使用有 HTTPS/SSL 加密的 URI. + doorkeeper: + applications: + buttons: + authorize: 認證 + cancel: 取消 + destroy: 移除 + edit: 編輯 + submit: 提交 + confirmations: + destroy: 是否確定? + edit: + title: 編輯應用程式 + form: + error: 噢!請檢查你表格的錯誤訊息 + help: + native_redirect_uri: 使用 %{native_redirect_uri} 作局部測試 + redirect_uri: 每行輸入一個 URI + scopes: 請用半形空格分開權限範圍 (scope)。留空表示使用預設的權限範圍 + index: + callback_url: 回傳網址 + name: 名稱 + new: 新增應用程式 + title: 你的應用程式 + new: + title: 新增應用程式 + show: + actions: 操作 + application_id: 應用程式 ID + callback_urls: 回傳網址 + scopes: 權限範圍 + secret: 密碼 + title: '應用程式︰ %{name}' + authorizations: + buttons: + authorize: 批准 + deny: 拒絕 + error: + title: 發生錯誤 + new: + able_to: 要求獲取權限 + prompt: 應用程式 %{client_name} 要求得到你用戶的部份權限 + title: 需要用戶授權 + show: + title: 授權代碼 + authorized_applications: + buttons: + revoke: 取消授權 + confirmations: + revoke: 是否確定要取消授權? + index: + application: 應用程式 + created_at: 授權於 + date_format: "%Y-%m-%d %H:%M:%S" + scopes: 權限範圍 + title: 已獲你授權的程用程式 + errors: + messages: + access_denied: 資源擁有者或授權伺服器不接受請求。 + credential_flow_not_configured: 資源擁有者密碼認證程序 (Resource Owner Password Credentials flow) 失敗,原因是 Doorkeeper.configure.resource_owner_from_credentials 沒有設定。 + invalid_client: 用戶程式認證 (Client authentication) 失敗,原因是用戶程式未有登記、沒有指定用戶程式 (client)、或者使用了不支援的認證方法 (method)。 + invalid_grant: 授權申請 (authorization grant) 不正確、過期、已被取消,或者無法對應授權請求 (authorization request) 內的轉接 URI,或者屬於別的用戶程式。 + invalid_redirect_uri: 不正確的轉接網址。 + invalid_request: 請求缺少了必要的參數、包含了不支援的參數、或者其他輸入錯誤。 + invalid_resource_owner: 資源擁有者的登入資訊錯誤、或者無法找到該資源擁有者。 + invalid_scope: 請求的權限範圍 (scope) 不正確、未有定義、或者輸入錯誤。 + invalid_token: + expired: access token 已經過期 + revoked: access token 已被取消 + unknown: access token 不正確 + resource_owner_authenticator_not_configured: 無法找到資源擁有者,原因是 Doorkeeper.configure.resource_owner_authenticator 沒有設定。 + server_error: 認證伺服器遇上未知狀況,令請求無法通過。 + temporarily_unavailable: 認證伺服器由於臨時負荷過重或者維護,目前未能處理請求。 + unauthorized_client: 用戶程式無權用此方法 (method) 請行這個請求。 + unsupported_grant_type: 授權伺服器不支援這個授權類型 (grant type)。 + unsupported_response_type: 授權伺服器不支援這個回應類型 (response type). + flash: + applications: + create: + notice: 已新增應用程式。 + destroy: + notice: 已刪除應用程式。 + update: + notice: 已更新應用程式。 + authorized_applications: + destroy: + notice: 已取消應用程式授權。 + layouts: + admin: + nav: + applications: 應用程式 + oauth2_provider: OAuth2 供應者 + application: + title: 需要 OAuth 授權 + scopes: + follow: 關注、封鎖、解除封鎖及取消關注用戶 + read: 閱讀你的用戶資料 + write: 以你的名義發佈文章 diff --git a/config/locales/simple_form.zh-HK.yml b/config/locales/simple_form.zh-HK.yml new file mode 100644 index 00000000..07d14522 --- /dev/null +++ b/config/locales/simple_form.zh-HK.yml @@ -0,0 +1,46 @@ +--- +zh-HK: + simple_form: + hints: + defaults: + avatar: 支援 PNG, GIF 或 JPG 圖片,檔案大小上限為 2MB,會被縮裁成 120x120px + display_name: 最多 30 個字元 + header: 支援 PNG, GIF 或 JPG 圖片,檔案大小上限為 2MB,會被縮裁成 700x335px + locked: 你必須人手核准每個用戶對你的關注請求,而你的文章私隱會被預設為「只有關注你的人能看」 + note: 最多 160 個字元 + imports: + data: 自其他服務站匯出的 CSV 檔案 + labels: + defaults: + avatar: 個人頭像 + confirm_new_password: 確認新密碼 + confirm_password: 確認密碼 + current_password: 目前密碼 + data: 資料 + display_name: 顯示名稱 + email: 電郵地址 + header: 個人頁面頂部 + locale: 語言 + locked: 將用戶轉為「私人」 + new_password: 新密碼 + note: 簡介 + otp_attempt: 雙重認證碼 + password: 密碼 + setting_default_privacy: 文章預設私隱度 + type: 匯入資料類型 + username: 用戶名稱 + interactions: + must_be_follower: 隱藏沒有關注你的用戶的通知 + must_be_following: 隱藏你不關注的用戶的通知 + notification_emails: + digest: 定期電郵摘要 + favourite: 當有用戶喜歡你的文章時,發電郵通知 + follow: 當有用戶關注你時,發電郵通知 + follow_request: 當有用戶要求關注你時,發電郵通知 + mention: 當有用戶在文章提及你時,發電郵通知 + reblog: 當有用戶轉推你的文章時,發電郵通知 + 'no': '否' + required: + mark: "*" + text: 必須填寫 + 'yes': '是' diff --git a/config/locales/zh-HK.yml b/config/locales/zh-HK.yml new file mode 100644 index 00000000..a1c87a7e --- /dev/null +++ b/config/locales/zh-HK.yml @@ -0,0 +1,172 @@ +--- +zh-HK: + about: + about_mastodon: Mastodon (長毛象)是一個自由、開放源碼的社交網站。它是一個分散式的服務,避免你的通訊被單一商業機構壟斷操控。請你選擇一家你信任的 Mastodon 服務站,在上面建立帳號,然後你就可以和任一 Mastodon 服務站上的用戶互通,享受無縫的社交網絡交流。 + about_this: 關於本服務站 + apps: 應用程式 + business_email: 商業電郵︰ + closed_registrations: 本服務站暫時停止接受登記。 + contact: 聯絡 + description_headline: 關於 %{domain} + domain_count_after: 個其他服務站 + domain_count_before: 已連接至 + features: + api: 開放 API,供各式應用程式及服務連入 + blocks: 完善的封鎖用戶、靜音功能 + characters: 每篇文章最多 500 字 + chronology: 時間軸忠實按時序顯示文章,不作多餘處理 + ethics: 良心設計︰沒有廣告,不追蹤你的使用行為 + gifv: 支援顯示 GIFV 短片圖組 + privacy: 可逐篇文章設定私隱度 + public: 公共時間軸 + features_headline: 甚麼讓 Mastodon 與眾不同 + get_started: 立即登記 + links: 連結 + other_instances: 其他服務站 + source_code: 源代碼 + status_count_after: 篇文章 + status_count_before: 他們共發佈了 + terms: 使用條款 + user_count_after: 位使用者 + user_count_before: 這裏共註冊有 + accounts: + follow: 關注 + followers: 關注者 + following: 正在關注 + nothing_here: 暫時未有內容可以顯示 + people_followed_by: '%{name} 關注的人' + people_who_follow: 關注 %{name} 的人 + posts: 文章 + remote_follow: 跨站關注 + unfollow: 取消關注 + application_mailer: + settings: '修改電郵設定︰ %{link}' + signature: 來自 %{instance} 的 Mastodon 通知 + view: '進入瀏覽︰' + applications: + invalid_url: 所提供的網址不正確 + auth: + change_password: 登入資訊 + didnt_get_confirmation: 沒有收到確認指示電郵? + forgot_password: 忘記了密碼? + login: 登入 + logout: 登出 + register: 登記 + resend_confirmation: 重發確認指示電郵 + reset_password: 重設密碼 + set_new_password: 設定新密碼 + authorize_follow: + error: 對不起,尋找這個跨站用戶的過程發生錯誤 + follow: 關注 + prompt_html: '你 (%{self}) 正準備關注︰' + title: 關注 %{acct} + datetime: + distance_in_words: + about_x_hours: "%{count}小時前" + about_x_months: "%{count}個月前" + about_x_years: "%{count}年前" + almost_x_years: "接近%{count}年前" + half_a_minute: 剛剛 + less_than_x_minutes: "少於%{count}分鐘前" + less_than_x_seconds: 剛剛 + over_x_years: "%{count}y" + x_days: "%{count}日" + x_minutes: "%{count}分鐘" + x_months: "%{count}個月" + x_seconds: "%{count}秒" + exports: + blocks: 被你封鎖的用戶 + csv: CSV + follows: 你所關注的用戶 + storage: 媒體容量大小 + generic: + changes_saved_msg: 已成功儲存修改 + powered_by: 網站由 %{link} 開發 + save_changes: 儲存修改 + validation_errors: + one: 提交的資料有問題 + other: 提交的資料有 %{count} 項問題 + imports: + preface: 你可以在此匯入你在其他服務站所匯出的資料檔,包括︰你所關注的用戶,被你封鎖的用戶。 + success: 你已成功上載資料檔,我們正將資料匯入,請稍候 + types: + blocking: 被你封鎖的用戶名單 + following: 你所關注的用戶名單 + upload: 上載 + landing_strip_html: %{name} 是一個在 %{domain} 的用戶。只要你有任何 Mastodon 服務站、或者聯盟網站的用戶,便可以跨站關注此站用戶,或者與他們互動。如果你沒有這類用戶,歡迎在此處登記。 + media_attachments: + validations: + images_and_video: 不能在已有圖片的文章上加入影片 + too_many: 不可以加入超過 4 個檔案 + notification_mailer: + digest: + body: '這是自從你在%{since}使用%{instance}以後,你錯失了的訊息︰' + mention: "%{name} 在此提及了你︰" + new_followers_summary: + one: 你新獲得了 1 位關注者了!恭喜! + other: 你新獲得了 %{count} 位關注者了!好厲害! + subject: + one: "自從上次登入以來,你收到 1 則新的通知 \U0001F418" + other: "自從上次登入以來,你收到 %{count} 則新的通知 \U0001F418" + favourite: + body: '你的文章獲得 %{name} 的喜愛' + subject: "%{name} 喜歡你的文章" + follow: + body: "%{name} 開始關注你!" + subject: "%{name} 現正關注你" + follow_request: + body: "%{name} 要求關注你" + subject: '等候關注你的用戶︰ %{name}' + mention: + body: '%{name} 在文章中提及你︰' + subject: '%{name} 在文章中提及你' + reblog: + body: '你的文章得到 %{name} 的轉推' + subject: "%{name} 轉推了你的文章" + pagination: + next: 下一頁 + prev: 上一頁 + truncate: "……" + remote_follow: + acct: 請輸入你的︰用戶名稱@服務點域名 + missing_resource: 無法找到你用戶的轉接網址 + proceed: 下一步 + prompt: '你希望關注︰' + settings: + authorized_apps: 授權應用程式 + back: 回到 Mastodon + edit_profile: 修改個人資料 + export: 匯出 + import: 匯入 + preferences: 偏好設定 + settings: 設定 + two_factor_auth: 雙重認證 + statuses: + open_in_web: 開啟網頁 + over_character_limit: 超過了 %{max} 字的限制 + show_more: 顯示更多 + visibilities: + private: 只有關注你的人能看 + public: 公開 + unlisted: 公開,但不在公共時間軸顯示 + stream_entries: + click_to_show: 點擊顯示 + reblogged: 轉推 + sensitive_content: 敏感內容 + time: + formats: + default: "%Y年%-m月%d日 %H:%M" + two_factor_auth: + code_hint: 請輸入你認證器產生的代碼,以確認設定 + description_html: 當你啟用雙重認證後,你登入時將需要使你手機、或其他種類認證器產生的代碼。 + disable: 停用 + enable: 啟用 + enabled_success: 已成功啟用雙重認證 + instructions_html: 請用你手機的認證器應用程式(如 Google Authenticator、Authy),掃描這裏的 QR 圖形碼。在雙重認證啟用後,你登入時將須要使用此應用程式產生的認證碼。 + manual_instructions: 如果你無法掃描 QR 圖形碼,請手動輸入這個文字密碼︰ + setup: 設定 + warning: 如果你現在無法正確設定你的應用程式,請即「停用」雙重認證,否則日後可能無法登入本站。 + wrong_code: 你輸入的認證碼並不正確!可能伺服器時間和你手機不一致,請檢查你手機的時鐘,或與本站管理員聯絡。 + users: + invalid_email: 電郵地址格式不正確 + invalid_otp_token: 雙重認證確認碼不正確 From f16b9a49289b801c309ba3602772cd8f03c0dffa Mon Sep 17 00:00:00 2001 From: Christopher Su Date: Wed, 12 Apr 2017 03:40:37 -0700 Subject: [PATCH 03/32] Fix redirect link on Tuning.md (#1595) --- docs/Running-Mastodon/Tuning.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Running-Mastodon/Tuning.md b/docs/Running-Mastodon/Tuning.md index 41fa93ef..5e547419 100644 --- a/docs/Running-Mastodon/Tuning.md +++ b/docs/Running-Mastodon/Tuning.md @@ -1 +1 @@ -[The documentation has moved to its own repository](https://github.com/tootsuite/documentation/blob/master/Running-Mastodon/Tuning-guide.md) +[The documentation has moved to its own repository](https://github.com/tootsuite/documentation/blob/master/Running-Mastodon/Tuning.md) From b155e6ccf55bbd0e2b07d6e06349849dd1f06f0a Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Wed, 12 Apr 2017 09:53:55 -0400 Subject: [PATCH 04/32] Fix issue with intermittent api/v1/notifications failure (#1606) The spec was checking the activity_id of the activities held in notifications within the controller. Because the activities are different models, it is possible that they are created with the same database IDs, and when they are this spec fails because an activity which should not count as a match is counted as one. --- .../api/v1/notifications_controller_spec.rb | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/spec/controllers/api/v1/notifications_controller_spec.rb b/spec/controllers/api/v1/notifications_controller_spec.rb index c390d4f0..e3c95309 100644 --- a/spec/controllers/api/v1/notifications_controller_spec.rb +++ b/spec/controllers/api/v1/notifications_controller_spec.rb @@ -13,11 +13,12 @@ RSpec.describe Api::V1::NotificationsController, type: :controller do describe 'GET #index' do before do - status = PostStatusService.new.call(user.account, 'Test') - @reblog = ReblogService.new.call(other.account, status) - @mention = PostStatusService.new.call(other.account, 'Hello @alice') - @favourite = FavouriteService.new.call(other.account, status) - @follow = FollowService.new.call(other.account, 'alice') + first_status = PostStatusService.new.call(user.account, 'Test') + @reblog_of_first_status = ReblogService.new.call(other.account, first_status) + mentioning_status = PostStatusService.new.call(other.account, 'Hello @alice') + @mention_from_status = mentioning_status.mentions.first + @favourite = FavouriteService.new.call(other.account, first_status) + @follow = FollowService.new.call(other.account, 'alice') end describe 'with no options' do @@ -30,19 +31,19 @@ RSpec.describe Api::V1::NotificationsController, type: :controller do end it 'includes reblog' do - expect(assigns(:notifications).map(&:activity_id)).to include(@reblog.id) + expect(assigns(:notifications).map(&:activity)).to include(@reblog_of_first_status) end it 'includes mention' do - expect(assigns(:notifications).map(&:activity_id)).to include(@mention.mentions.first.id) + expect(assigns(:notifications).map(&:activity)).to include(@mention_from_status) end it 'includes favourite' do - expect(assigns(:notifications).map(&:activity_id)).to include(@favourite.id) + expect(assigns(:notifications).map(&:activity)).to include(@favourite) end it 'includes follow' do - expect(assigns(:notifications).map(&:activity_id)).to include(@follow.id) + expect(assigns(:notifications).map(&:activity)).to include(@follow) end end @@ -56,19 +57,19 @@ RSpec.describe Api::V1::NotificationsController, type: :controller do end it 'includes reblog' do - expect(assigns(:notifications).map(&:activity_id)).to include(@reblog.id) + expect(assigns(:notifications).map(&:activity)).to include(@reblog_of_first_status) end it 'excludes mention' do - expect(assigns(:notifications).map(&:activity_id)).to_not include(@mention.mentions.first.id) + expect(assigns(:notifications).map(&:activity)).to_not include(@mention_from_status) end it 'includes favourite' do - expect(assigns(:notifications).map(&:activity_id)).to include(@favourite.id) + expect(assigns(:notifications).map(&:activity)).to include(@favourite) end it 'includes follow' do - expect(assigns(:notifications).map(&:activity_id)).to include(@follow.id) + expect(assigns(:notifications).map(&:activity)).to include(@follow) end end end From 323671a653e22704f0d50be13d67bf6fe6ee3a2a Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Wed, 12 Apr 2017 09:58:08 -0400 Subject: [PATCH 05/32] Silence more scope order warnings (#1604) --- app/services/after_block_service.rb | 2 +- app/services/fan_out_on_write_service.rb | 2 +- app/services/mute_service.rb | 2 +- app/services/suspend_account_service.rb | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/services/after_block_service.rb b/app/services/after_block_service.rb index 0f478bcb..d1a846f2 100644 --- a/app/services/after_block_service.rb +++ b/app/services/after_block_service.rb @@ -12,7 +12,7 @@ class AfterBlockService < BaseService home_key = FeedManager.instance.key(:home, account.id) redis.pipelined do - target_account.statuses.select('id').find_each do |status| + target_account.statuses.select('id').reorder(nil).find_each do |status| redis.zrem(home_key, status.id) end end diff --git a/app/services/fan_out_on_write_service.rb b/app/services/fan_out_on_write_service.rb index 19eedc0a..055fda8a 100644 --- a/app/services/fan_out_on_write_service.rb +++ b/app/services/fan_out_on_write_service.rb @@ -34,7 +34,7 @@ class FanOutOnWriteService < BaseService def deliver_to_followers(status) Rails.logger.debug "Delivering status #{status.id} to followers" - status.account.followers.where(domain: nil).joins(:user).where('users.current_sign_in_at > ?', 14.days.ago).select(:id).find_each do |follower| + status.account.followers.where(domain: nil).joins(:user).where('users.current_sign_in_at > ?', 14.days.ago).select(:id).reorder(nil).find_each do |follower| FeedInsertWorker.perform_async(status.id, follower.id) end end diff --git a/app/services/mute_service.rb b/app/services/mute_service.rb index 0050cfc8..1a650ed2 100644 --- a/app/services/mute_service.rb +++ b/app/services/mute_service.rb @@ -12,7 +12,7 @@ class MuteService < BaseService def clear_home_timeline(account, target_account) home_key = FeedManager.instance.key(:home, account.id) - target_account.statuses.select('id').find_each do |status| + target_account.statuses.select('id').reorder(nil).find_each do |status| redis.zrem(home_key, status.id) end end diff --git a/app/services/suspend_account_service.rb b/app/services/suspend_account_service.rb index 8528ef62..42ff4dcb 100644 --- a/app/services/suspend_account_service.rb +++ b/app/services/suspend_account_service.rb @@ -12,7 +12,7 @@ class SuspendAccountService < BaseService private def purge_content - @account.statuses.find_each do |status| + @account.statuses.reorder(nil).find_each do |status| RemoveStatusService.new.call(status) end From fd102059aa63a3953ccfedfe9efa0e6f7993f72a Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Wed, 12 Apr 2017 10:01:59 -0400 Subject: [PATCH 06/32] Clean up stylesheet organization (#1591) --- app/assets/stylesheets/application.scss | 306 +-------------------- app/assets/stylesheets/basics.scss | 58 ++++ app/assets/stylesheets/compact_header.scss | 28 ++ app/assets/stylesheets/containers.scss | 61 ++++ app/assets/stylesheets/footer.scss | 29 ++ app/assets/stylesheets/landing_strip.scss | 17 ++ app/assets/stylesheets/lists.scss | 8 + app/assets/stylesheets/reset.scss | 91 ++++++ 8 files changed, 299 insertions(+), 299 deletions(-) create mode 100644 app/assets/stylesheets/basics.scss create mode 100644 app/assets/stylesheets/compact_header.scss create mode 100644 app/assets/stylesheets/containers.scss create mode 100644 app/assets/stylesheets/footer.scss create mode 100644 app/assets/stylesheets/landing_strip.scss create mode 100644 app/assets/stylesheets/lists.scss create mode 100644 app/assets/stylesheets/reset.scss diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index ba16d4a2..35bdd3b6 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -4,305 +4,13 @@ @import 'fonts/montserrat'; @import 'font-awesome'; -/* http://meyerweb.com/eric/tools/css/reset/ - v2.0 | 20110126 - License: none (public domain) -*/ - -html, body, div, span, applet, object, iframe, -h1, h2, h3, h4, h5, h6, p, blockquote, pre, -a, abbr, acronym, address, big, cite, code, -del, dfn, em, img, ins, kbd, q, s, samp, -small, strike, strong, sub, sup, tt, var, -b, u, i, center, -dl, dt, dd, ol, ul, li, -fieldset, form, label, legend, -table, caption, tbody, tfoot, thead, tr, th, td, -article, aside, canvas, details, embed, -figure, figcaption, footer, header, hgroup, -menu, nav, output, ruby, section, summary, -time, mark, audio, video { - margin: 0; - padding: 0; - border: 0; - font-size: 100%; - font: inherit; - vertical-align: baseline; -} - -/* HTML5 display-role reset for older browsers */ -article, aside, details, figcaption, figure, -footer, header, hgroup, menu, nav, section { - display: block; -} - -body { - line-height: 1; -} - -ol, ul { - list-style: none; -} - -blockquote, q { - quotes: none; -} - -blockquote:before, blockquote:after, -q:before, q:after { - content: ''; - content: none; -} - -table { - border-collapse: collapse; - border-spacing: 0; -} - -::-webkit-scrollbar { - width: 8px; - height: 8px; -} - -::-webkit-scrollbar-thumb { - background: lighten($color1, 4%); - border: 0px none $color5; - border-radius: 50px; -} - -::-webkit-scrollbar-thumb:hover { - background: lighten($color1, 6%); -} - -::-webkit-scrollbar-thumb:active { - background: lighten($color1, 4%); -} - -::-webkit-scrollbar-track { - border: 0px none $color5; - border-radius: 0; - background: rgba($color8, 0.1); -} - -::-webkit-scrollbar-track:hover { - background: $color1; -} - -::-webkit-scrollbar-track:active { - background: $color1; -} - -::-webkit-scrollbar-corner { - background: transparent; -} - -body { - font-family: 'Roboto', sans-serif; - background: $color1 image-url('background-photo.jpeg'); - background-size: cover; - background-attachment: fixed; - font-size: 13px; - line-height: 18px; - font-weight: 400; - color: $color5; - padding-bottom: 140px; - text-rendering: optimizelegibility; - font-feature-settings: "kern"; - text-size-adjust: none; - - &.app-body { - position: fixed; - width: 100%; - height: 100%; - padding: 0; - background: $color1; - } - - &.embed { - background: transparent; - margin: 0; - - .container { - position: absolute; - width: 100%; - height: 100%; - overflow: hidden; - } - } - - &.admin { - background: darken($color1, 4%); - position: fixed; - width: 100%; - height: 100%; - padding: 0; - } - - @media screen and (max-width: 360px) { - padding-bottom: 0; - } -} - -button:focus { - outline: none; -} - -.app-holder { - display: flex; - width: 100%; - height: 100%; - align-items: center; - justify-content: center; -} - -.container { - width: 700px; - margin: 0 auto; - margin-top: 40px; - - @media screen and (max-width: 700px) { - width: 100%; - margin: 0; - } -} - -.logo-container { - max-width: 400px; - margin: 100px auto; - margin-bottom: 0; - cursor: default; - - @media screen and (max-width: 360px) { - margin: 30px auto; - } - - h1 { - display: block; - text-align: center; - color: $color5; - font-size: 48px; - font-weight: 500; - - img { - display: block; - margin: 20px auto; - width: 180px; - height: 180px; - } - - a { - color: inherit; - text-decoration: none; - outline: 0; - - img { - opacity: 0.8; - transition: all 0.8s ease; - } - - &:hover { - img { - opacity: 1; - transition-duration: 0.2s; - } - } - } - - small { - display: block; - font-size: 12px; - font-weight: 400; - font-family: 'Roboto Mono', monospace; - } - } -} - -.no-list { - list-style: none; - - li { - display: inline-block; - margin: 0 5px; - } -} - -.footer { - text-align: center; - margin-top: 30px; - font-size: 12px; - color: darken($color2, 25%); - - .domain { - font-weight: 500; - - a { - color: inherit; - text-decoration: none; - } - } - - .powered-by { - font-weight: 400; - - a { - color: inherit; - text-decoration: underline; - font-weight: 500; - - &:hover { - text-decoration: none; - } - } - } -} - -.compact-header { - h1 { - font-size: 24px; - line-height: 28px; - color: $color3; - overflow: hidden; - font-weight: 500; - margin-bottom: 20px; - - a { - color: inherit; - text-decoration: none; - } - - small { - font-weight: 400; - color: $color2; - } - - img { - display: inline-block; - margin-bottom: -5px; - margin-right: 15px; - width: 36px; - height: 36px; - } - } -} - -.landing-strip { - background: rgba(darken($color1, 7%), 0.8); - color: $color3; - font-weight: 400; - padding: 14px; - border-radius: 4px; - margin-bottom: 20px; - - strong, a { - font-weight: 500; - } - - a { - color: inherit; - text-decoration: underline; - } -} - +@import 'reset'; +@import 'basics'; +@import 'containers'; +@import 'lists'; +@import 'footer'; +@import 'compact_header'; +@import 'landing_strip'; @import 'forms'; @import 'accounts'; @import 'stream_entries'; diff --git a/app/assets/stylesheets/basics.scss b/app/assets/stylesheets/basics.scss new file mode 100644 index 00000000..c8ff7f5d --- /dev/null +++ b/app/assets/stylesheets/basics.scss @@ -0,0 +1,58 @@ +body { + font-family: 'Roboto', sans-serif; + background: $color1 image-url('background-photo.jpeg'); + background-size: cover; + background-attachment: fixed; + font-size: 13px; + line-height: 18px; + font-weight: 400; + color: $color5; + padding-bottom: 140px; + text-rendering: optimizelegibility; + font-feature-settings: "kern"; + text-size-adjust: none; + + &.app-body { + position: fixed; + width: 100%; + height: 100%; + padding: 0; + background: $color1; + } + + &.embed { + background: transparent; + margin: 0; + + .container { + position: absolute; + width: 100%; + height: 100%; + overflow: hidden; + } + } + + &.admin { + background: darken($color1, 4%); + position: fixed; + width: 100%; + height: 100%; + padding: 0; + } + + @media screen and (max-width: 360px) { + padding-bottom: 0; + } +} + +button:focus { + outline: none; +} + +.app-holder { + display: flex; + width: 100%; + height: 100%; + align-items: center; + justify-content: center; +} diff --git a/app/assets/stylesheets/compact_header.scss b/app/assets/stylesheets/compact_header.scss new file mode 100644 index 00000000..8fef05f0 --- /dev/null +++ b/app/assets/stylesheets/compact_header.scss @@ -0,0 +1,28 @@ +.compact-header { + h1 { + font-size: 24px; + line-height: 28px; + color: $color3; + overflow: hidden; + font-weight: 500; + margin-bottom: 20px; + + a { + color: inherit; + text-decoration: none; + } + + small { + font-weight: 400; + color: $color2; + } + + img { + display: inline-block; + margin-bottom: -5px; + margin-right: 15px; + width: 36px; + height: 36px; + } + } +} diff --git a/app/assets/stylesheets/containers.scss b/app/assets/stylesheets/containers.scss new file mode 100644 index 00000000..43705b19 --- /dev/null +++ b/app/assets/stylesheets/containers.scss @@ -0,0 +1,61 @@ +.container { + width: 700px; + margin: 0 auto; + margin-top: 40px; + + @media screen and (max-width: 700px) { + width: 100%; + margin: 0; + } +} + +.logo-container { + max-width: 400px; + margin: 100px auto; + margin-bottom: 0; + cursor: default; + + @media screen and (max-width: 360px) { + margin: 30px auto; + } + + h1 { + display: block; + text-align: center; + color: $color5; + font-size: 48px; + font-weight: 500; + + img { + display: block; + margin: 20px auto; + width: 180px; + height: 180px; + } + + a { + color: inherit; + text-decoration: none; + outline: 0; + + img { + opacity: 0.8; + transition: all 0.8s ease; + } + + &:hover { + img { + opacity: 1; + transition-duration: 0.2s; + } + } + } + + small { + display: block; + font-size: 12px; + font-weight: 400; + font-family: 'Roboto Mono', monospace; + } + } +} diff --git a/app/assets/stylesheets/footer.scss b/app/assets/stylesheets/footer.scss new file mode 100644 index 00000000..719bfcf4 --- /dev/null +++ b/app/assets/stylesheets/footer.scss @@ -0,0 +1,29 @@ +.footer { + text-align: center; + margin-top: 30px; + font-size: 12px; + color: darken($color2, 25%); + + .domain { + font-weight: 500; + + a { + color: inherit; + text-decoration: none; + } + } + + .powered-by { + font-weight: 400; + + a { + color: inherit; + text-decoration: underline; + font-weight: 500; + + &:hover { + text-decoration: none; + } + } + } +} diff --git a/app/assets/stylesheets/landing_strip.scss b/app/assets/stylesheets/landing_strip.scss new file mode 100644 index 00000000..4c240316 --- /dev/null +++ b/app/assets/stylesheets/landing_strip.scss @@ -0,0 +1,17 @@ +.landing-strip { + background: rgba(darken($color1, 7%), 0.8); + color: $color3; + font-weight: 400; + padding: 14px; + border-radius: 4px; + margin-bottom: 20px; + + strong, a { + font-weight: 500; + } + + a { + color: inherit; + text-decoration: underline; + } +} diff --git a/app/assets/stylesheets/lists.scss b/app/assets/stylesheets/lists.scss new file mode 100644 index 00000000..eac9f5a2 --- /dev/null +++ b/app/assets/stylesheets/lists.scss @@ -0,0 +1,8 @@ +.no-list { + list-style: none; + + li { + display: inline-block; + margin: 0 5px; + } +} diff --git a/app/assets/stylesheets/reset.scss b/app/assets/stylesheets/reset.scss new file mode 100644 index 00000000..71064cc3 --- /dev/null +++ b/app/assets/stylesheets/reset.scss @@ -0,0 +1,91 @@ +/* http://meyerweb.com/eric/tools/css/reset/ + v2.0 | 20110126 + License: none (public domain) +*/ + +html, body, div, span, applet, object, iframe, +h1, h2, h3, h4, h5, h6, p, blockquote, pre, +a, abbr, acronym, address, big, cite, code, +del, dfn, em, img, ins, kbd, q, s, samp, +small, strike, strong, sub, sup, tt, var, +b, u, i, center, +dl, dt, dd, ol, ul, li, +fieldset, form, label, legend, +table, caption, tbody, tfoot, thead, tr, th, td, +article, aside, canvas, details, embed, +figure, figcaption, footer, header, hgroup, +menu, nav, output, ruby, section, summary, +time, mark, audio, video { + margin: 0; + padding: 0; + border: 0; + font-size: 100%; + font: inherit; + vertical-align: baseline; +} + +/* HTML5 display-role reset for older browsers */ +article, aside, details, figcaption, figure, +footer, header, hgroup, menu, nav, section { + display: block; +} + +body { + line-height: 1; +} + +ol, ul { + list-style: none; +} + +blockquote, q { + quotes: none; +} + +blockquote:before, blockquote:after, +q:before, q:after { + content: ''; + content: none; +} + +table { + border-collapse: collapse; + border-spacing: 0; +} + +::-webkit-scrollbar { + width: 8px; + height: 8px; +} + +::-webkit-scrollbar-thumb { + background: lighten($color1, 4%); + border: 0px none $color5; + border-radius: 50px; +} + +::-webkit-scrollbar-thumb:hover { + background: lighten($color1, 6%); +} + +::-webkit-scrollbar-thumb:active { + background: lighten($color1, 4%); +} + +::-webkit-scrollbar-track { + border: 0px none $color5; + border-radius: 0; + background: rgba($color8, 0.1); +} + +::-webkit-scrollbar-track:hover { + background: $color1; +} + +::-webkit-scrollbar-track:active { + background: $color1; +} + +::-webkit-scrollbar-corner { + background: transparent; +} From b352a8e5d4f3dba4b923a2a21dc9ae5343e7e8e4 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Wed, 12 Apr 2017 10:03:37 -0400 Subject: [PATCH 07/32] Default to json type for webfinger requests (#1583) --- app/controllers/xrd_controller.rb | 5 ---- config/routes.rb | 2 +- spec/controllers/xrd_controller_spec.rb | 4 +-- spec/requests/webfinger_request_spec.rb | 33 +++++++++++++++++++++++++ 4 files changed, 36 insertions(+), 8 deletions(-) create mode 100644 spec/requests/webfinger_request_spec.rb diff --git a/app/controllers/xrd_controller.rb b/app/controllers/xrd_controller.rb index 5964172e..ba5032ab 100644 --- a/app/controllers/xrd_controller.rb +++ b/app/controllers/xrd_controller.rb @@ -1,7 +1,6 @@ # frozen_string_literal: true class XrdController < ApplicationController - before_action :set_default_format_json, only: :webfinger before_action :set_default_format_xml, only: :host_meta def host_meta @@ -31,10 +30,6 @@ class XrdController < ApplicationController request.format = 'xml' if request.headers['HTTP_ACCEPT'].nil? && params[:format].nil? end - def set_default_format_json - request.format = 'json' if request.headers['HTTP_ACCEPT'].nil? && params[:format].nil? - end - def username_from_resource if resource_param =~ /\Ahttps?:\/\// path_params = Rails.application.routes.recognize_path(resource_param) diff --git a/config/routes.rb b/config/routes.rb index 69f8887b..99ce1754 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -15,7 +15,7 @@ Rails.application.routes.draw do end get '.well-known/host-meta', to: 'xrd#host_meta', as: :host_meta - get '.well-known/webfinger', to: 'xrd#webfinger', as: :webfinger + get '.well-known/webfinger', to: 'xrd#webfinger', as: :webfinger, defaults: { format: 'json' } devise_for :users, path: 'auth', controllers: { sessions: 'auth/sessions', diff --git a/spec/controllers/xrd_controller_spec.rb b/spec/controllers/xrd_controller_spec.rb index b56c68f5..33b17f15 100644 --- a/spec/controllers/xrd_controller_spec.rb +++ b/spec/controllers/xrd_controller_spec.rb @@ -14,12 +14,12 @@ RSpec.describe XrdController, type: :controller do let(:alice) { Fabricate(:account, username: 'alice') } it 'returns http success when account can be found' do - get :webfinger, params: { resource: alice.to_webfinger_s } + get :webfinger, params: { resource: alice.to_webfinger_s }, format: :json expect(response).to have_http_status(:success) end it 'returns http not found when account cannot be found' do - get :webfinger, params: { resource: 'acct:not@existing.com' } + get :webfinger, params: { resource: 'acct:not@existing.com' }, format: :json expect(response).to have_http_status(:not_found) end end diff --git a/spec/requests/webfinger_request_spec.rb b/spec/requests/webfinger_request_spec.rb new file mode 100644 index 00000000..b5690d22 --- /dev/null +++ b/spec/requests/webfinger_request_spec.rb @@ -0,0 +1,33 @@ +require "rails_helper" + +describe "The webfinger route" do + let(:alice) { Fabricate(:account, username: 'alice') } + + describe "requested without accepts headers" do + it "returns a json response" do + get webfinger_url, params: { resource: alice.to_webfinger_s } + + expect(response).to have_http_status(:success) + expect(response.content_type).to eq "application/jrd+json" + end + end + + describe "requested with html in accepts headers" do + it "returns a json response" do + headers = { 'HTTP_ACCEPT' => 'text/html' } + get webfinger_url, params: { resource: alice.to_webfinger_s }, headers: headers + + expect(response).to have_http_status(:success) + expect(response.content_type).to eq "application/jrd+json" + end + end + + describe "requested with xml format" do + it "returns an xml response" do + get webfinger_url(resource: alice.to_webfinger_s, format: :xml) + + expect(response).to have_http_status(:success) + expect(response.content_type).to eq "application/xrd+xml" + end + end +end From dd1ae3b10924ca239daa17ce2fe739f790e6f96d Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Wed, 12 Apr 2017 10:12:42 -0400 Subject: [PATCH 08/32] Simplify the way the embed view is created (#1590) * Add coverage for embedded status view * Refactor embed view to eliminate @external_links variable --- app/controllers/stream_entries_controller.rb | 2 -- app/helpers/stream_entries_helper.rb | 12 +++++++++++- app/views/stream_entries/_detailed_status.html.haml | 4 ++-- app/views/stream_entries/_simple_status.html.haml | 4 ++-- spec/controllers/stream_entries_controller_spec.rb | 10 ++++++++++ 5 files changed, 25 insertions(+), 7 deletions(-) diff --git a/app/controllers/stream_entries_controller.rb b/app/controllers/stream_entries_controller.rb index 469a8c33..a9ee7350 100644 --- a/app/controllers/stream_entries_controller.rb +++ b/app/controllers/stream_entries_controller.rb @@ -27,8 +27,6 @@ class StreamEntriesController < ApplicationController def embed response.headers['X-Frame-Options'] = 'ALLOWALL' - @external_links = true - return gone if @stream_entry.activity.nil? render layout: 'embedded' diff --git a/app/helpers/stream_entries_helper.rb b/app/helpers/stream_entries_helper.rb index d5cc004b..59aac784 100644 --- a/app/helpers/stream_entries_helper.rb +++ b/app/helpers/stream_entries_helper.rb @@ -5,8 +5,12 @@ module StreamEntriesHelper account.display_name.blank? ? account.username : account.display_name end + def stream_link_target + embedded_view? ? '_blank' : nil + end + def acct(account) - "@#{account.acct}#{@external_links && account.local? ? "@#{Rails.configuration.x.local_domain}" : ''}" + "@#{account.acct}#{embedded_view? && account.local? ? "@#{Rails.configuration.x.local_domain}" : ''}" end def entry_classes(status, is_predecessor, is_successor, include_threads) @@ -30,4 +34,10 @@ module StreamEntriesHelper rtl_size / ltr_size > 0.3 end + + private + + def embedded_view? + params[:controller] == 'stream_entries' && params[:action] == 'embed' + end end diff --git a/app/views/stream_entries/_detailed_status.html.haml b/app/views/stream_entries/_detailed_status.html.haml index 8495f28b..5fc6ab42 100644 --- a/app/views/stream_entries/_detailed_status.html.haml +++ b/app/views/stream_entries/_detailed_status.html.haml @@ -1,5 +1,5 @@ .detailed-status.light - = link_to TagManager.instance.url_for(status.account), class: 'detailed-status__display-name p-author h-card', target: @external_links ? '_blank' : nil, rel: 'noopener' do + = link_to TagManager.instance.url_for(status.account), class: 'detailed-status__display-name p-author h-card', target: stream_link_target, rel: 'noopener' do %div %div.avatar = image_tag status.account.avatar.url(:original), width: 48, height: 48, alt: '', class: 'u-photo' @@ -30,7 +30,7 @@ %div.detailed-status__meta %data.dt-published{ value: status.created_at.to_time.iso8601 } - = link_to TagManager.instance.url_for(status), class: 'detailed-status__datetime u-url u-uid', target: @external_links ? '_blank' : nil, rel: 'noopener' do + = link_to TagManager.instance.url_for(status), class: 'detailed-status__datetime u-url u-uid', target: stream_link_target, rel: 'noopener' do %span= l(status.created_at) · - if status.application diff --git a/app/views/stream_entries/_simple_status.html.haml b/app/views/stream_entries/_simple_status.html.haml index 2eb9bf16..5b6069e3 100644 --- a/app/views/stream_entries/_simple_status.html.haml +++ b/app/views/stream_entries/_simple_status.html.haml @@ -1,10 +1,10 @@ .status.light .status__header .status__meta - = link_to time_ago_in_words(status.created_at), TagManager.instance.url_for(status), class: 'status__relative-time u-url u-uid', title: l(status.created_at), target: @external_links ? '_blank' : nil, rel: 'noopener' + = link_to time_ago_in_words(status.created_at), TagManager.instance.url_for(status), class: 'status__relative-time u-url u-uid', title: l(status.created_at), target: stream_link_target, rel: 'noopener' %data.dt-published{ value: status.created_at.to_time.iso8601 } - = link_to TagManager.instance.url_for(status.account), class: 'status__display-name p-author h-card', target: @external_links ? '_blank' : nil, rel: 'noopener' do + = link_to TagManager.instance.url_for(status.account), class: 'status__display-name p-author h-card', target: stream_link_target, rel: 'noopener' do .status__avatar %div = image_tag status.account.avatar(:original), width: 48, height: 48, alt: '', class: 'u-photo' diff --git a/spec/controllers/stream_entries_controller_spec.rb b/spec/controllers/stream_entries_controller_spec.rb index 6f270af9..71de6060 100644 --- a/spec/controllers/stream_entries_controller_spec.rb +++ b/spec/controllers/stream_entries_controller_spec.rb @@ -17,4 +17,14 @@ RSpec.describe StreamEntriesController, type: :controller do expect(response).to have_http_status(:success) end end + + describe 'GET #embed' do + it 'returns embedded view of status' do + get :embed, params: { account_username: alice.username, id: status.stream_entry.id } + + expect(response).to have_http_status(:success) + expect(response.headers['X-Frame-Options']).to eq 'ALLOWALL' + expect(response).to render_template(layout: 'embedded') + end + end end From 13528f50c32a5035fcf8b9f24b9f0eb113fc776f Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Wed, 12 Apr 2017 10:12:56 -0400 Subject: [PATCH 09/32] Params compact deprecation warning (#1580) * Move filter_link_to class formation to separate method in admin/accounts helper * Remove deprecated #compact method usage on strong parameters --- app/helpers/admin/accounts_helper.rb | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/app/helpers/admin/accounts_helper.rb b/app/helpers/admin/accounts_helper.rb index c539229b..6cda7781 100644 --- a/app/helpers/admin/accounts_helper.rb +++ b/app/helpers/admin/accounts_helper.rb @@ -6,10 +6,21 @@ module Admin::AccountsHelper end def filter_link_to(text, more_params) - link_to text, filter_params(more_params), class: params.merge(more_params).compact == params.compact ? 'selected' : '' + new_url = filtered_url_for(more_params) + link_to text, new_url, class: filter_link_class(new_url) end def table_link_to(icon, text, path, options = {}) link_to safe_join([fa_icon(icon), text]), path, options.merge(class: 'table-action-link') end + + private + + def filter_link_class(new_url) + filtered_url_for(params) == new_url ? 'selected' : '' + end + + def filtered_url_for(params) + url_for filter_params(params) + end end From 1f5ff46fd92f679cdb548c93c47920786f2dcc33 Mon Sep 17 00:00:00 2001 From: Thor Harald Johansen Date: Wed, 12 Apr 2017 17:07:51 +0200 Subject: [PATCH 10/32] Working translation for Norwegian. (#1611) --- .../components/containers/mastodon.jsx | 2 + .../javascripts/components/locales/index.jsx | 2 + .../javascripts/components/locales/no.jsx | 72 +++++++++++++++++++ app/helpers/settings_helper.rb | 1 + config/application.rb | 1 + config/locales/no.yml | 4 +- config/locales/simple_form.no.yml | 2 +- 7 files changed, 81 insertions(+), 3 deletions(-) create mode 100644 app/assets/javascripts/components/locales/no.jsx diff --git a/app/assets/javascripts/components/containers/mastodon.jsx b/app/assets/javascripts/components/containers/mastodon.jsx index 37440da8..d8810dc6 100644 --- a/app/assets/javascripts/components/containers/mastodon.jsx +++ b/app/assets/javascripts/components/containers/mastodon.jsx @@ -48,6 +48,7 @@ import fr from 'react-intl/locale-data/fr'; import hu from 'react-intl/locale-data/hu'; import ja from 'react-intl/locale-data/ja'; import pt from 'react-intl/locale-data/pt'; +import no from 'react-intl/locale-data/no'; import ru from 'react-intl/locale-data/ru'; import uk from 'react-intl/locale-data/uk'; import zh from 'react-intl/locale-data/zh'; @@ -76,6 +77,7 @@ addLocaleData([ ...hu, ...ja, ...pt, + ...no, ...ru, ...uk, ...zh, diff --git a/app/assets/javascripts/components/locales/index.jsx b/app/assets/javascripts/components/locales/index.jsx index c3c5784a..e772c107 100644 --- a/app/assets/javascripts/components/locales/index.jsx +++ b/app/assets/javascripts/components/locales/index.jsx @@ -3,6 +3,7 @@ import de from './de'; import es from './es'; import hu from './hu'; import fr from './fr'; +import no from './no'; import pt from './pt'; import uk from './uk'; import fi from './fi'; @@ -18,6 +19,7 @@ const locales = { es, hu, fr, + no, pt, uk, fi, diff --git a/app/assets/javascripts/components/locales/no.jsx b/app/assets/javascripts/components/locales/no.jsx new file mode 100644 index 00000000..3b937246 --- /dev/null +++ b/app/assets/javascripts/components/locales/no.jsx @@ -0,0 +1,72 @@ +const no = { + "column_back_button.label": "Tilbake", + "lightbox.close": "Lukk", + "loading_indicator.label": "Laster...", + "status.mention": "Nevn @{name}", + "status.delete": "Slett", + "status.reply": "Svar", + "status.reblog": "Reblogg", + "status.favourite": "Favoritt", + "status.reblogged_by": "{name} reblogget", + "status.sensitive_warning": "Sensitivt innhold", + "status.sensitive_toggle": "Klikk for å vise", + "status.show_more": "Vis mer", + "status.show_less": "Vis mindre", + "status.open": "Utvid denne statusen", + "status.report": "Rapporter @{name}", + "video_player.toggle_sound": "Veksle lyd", + "account.mention": "Nevn @{name}", + "account.edit_profile": "Rediger profil", + "account.unblock": "Avblokker @{name}", + "account.unfollow": "Avfølg", + "account.block": "Blokker @{name}", + "account.follow": "Følg", + "account.posts": "Poster", + "account.follows": "Følginger", + "account.followers": "Følgere", + "account.follows_you": "Folger deg", + "account.requested": "Venter på godkjennelse", + "getting_started.heading": "Kom i gang", + "getting_started.about_addressing": "Du kan følge noen hvis du vet brukernavnet deres og domenet de er på ved å skrive en e-postadresse inn i søkeskjemaet.", + "getting_started.about_shortcuts": "Hvis målbrukeren er på samme domene som deg, vil kun brukernavnet også fungere. Den samme regelen gjelder når man nevner noen i statuser.", + "getting_started.open_source_notice": "Mastodon er programvare med fri kildekode. Du kan bidra eller rapportere problemer på GitHub på {github}. {apps}.", + "column.home": "Hjem", + "column.community": "Lokal tidslinje", + "column.public": "Føderert tidslinje", + "column.notifications": "Varslinger", + "tabs_bar.compose": "Komponer", + "tabs_bar.home": "Hjem", + "tabs_bar.mentions": "Nevninger", + "tabs_bar.public": "Føderert tidslinje", + "tabs_bar.notifications": "Varslinger", + "compose_form.placeholder": "Hva har du på hjertet?", + "compose_form.publish": "Tut", + "compose_form.sensitive": "Merk media som følsomt", + "compose_form.spoiler": "Skjul tekst bak advarsel", + "compose_form.private": "Merk som privat", + "compose_form.privacy_disclaimer": "Din private status vil leveres til nevnte brukere på {domains}. Stoler du på {domainsCount, plural, one {den serveren} other {de serverne}}? Synlighet fungerer kun på Mastodon-instanser. Hvis {domains} {domainsCount, plural, one {ike er en Mastodon-instans} other {ikke er Mastodon-instanser}}, vil det ikke indikeres at posten din er privat, og den kan kanskje bli reblogget eller på annen måte bli synlig for uventede mottakere.", + "compose_form.unlisted": "Ikke vis på offentlige tidslinjer", + "navigation_bar.edit_profile": "Rediger profil", + "navigation_bar.preferences": "Preferanser", + "navigation_bar.community_timeline": "Lokal tidslinje", + "navigation_bar.public_timeline": "Føderert tidslinje", + "navigation_bar.logout": "Logg ut", + "reply_indicator.cancel": "Avbryt", + "search.placeholder": "Søk", + "search.account": "Konto", + "search.hashtag": "Hashtag", + "upload_button.label": "Legg til media", + "upload_form.undo": "Angre", + "notification.follow": "{name} fulgte deg", + "notification.favourite": "{name} likte din status", + "notification.reblog": "{name} reblogget din status", + "notification.mention": "{name} nevnte deg", + "notifications.column_settings.alert": "Skrivebordsvarslinger", + "notifications.column_settings.show": "Vis i kolonne", + "notifications.column_settings.follow": "Nye følgere:", + "notifications.column_settings.favourite": "Favouritter:", + "notifications.column_settings.mention": "Nevninger:", + "notifications.column_settings.reblog": "Reblogginger:", +}; + +export default no; diff --git a/app/helpers/settings_helper.rb b/app/helpers/settings_helper.rb index 0905138b..211b5704 100644 --- a/app/helpers/settings_helper.rb +++ b/app/helpers/settings_helper.rb @@ -8,6 +8,7 @@ module SettingsHelper eo: 'Esperanto', fr: 'Français', hu: 'Magyar', + no: 'Norsk', pt: 'Português', fi: 'Suomi', ru: 'Русский', diff --git a/config/application.rb b/config/application.rb index 19523c88..2c720474 100644 --- a/config/application.rb +++ b/config/application.rb @@ -34,6 +34,7 @@ module Mastodon :fr, :hu, :ja, + :no, :pt, :ru, :uk, diff --git a/config/locales/no.yml b/config/locales/no.yml index 9aa966d2..28bc066d 100644 --- a/config/locales/no.yml +++ b/config/locales/no.yml @@ -104,8 +104,8 @@ one: "1 ny hendelse siden ditt siste besøk \U0001F418" other: "%{count} nye hendelser siden ditt siste besøk \U0001F418" favourite: - body: 'Din status ble satt som favoritt av %{name}' - subject: "%{name} satte din status som favoritt." + body: 'Din status ble likt av %{name}' + subject: "%{name} likte din status." follow: body: "%{name} følger deg!" subject: "%{name} følger deg" diff --git a/config/locales/simple_form.no.yml b/config/locales/simple_form.no.yml index 7e705b19..c6ccf67b 100644 --- a/config/locales/simple_form.no.yml +++ b/config/locales/simple_form.no.yml @@ -34,7 +34,7 @@ must_be_following: Blokker meldinger fra folk du ikke følger notification_emails: digest: Send oppsummerings eposter - favourite: Send e-post når noen setter din status som favoritt + favourite: Send e-post når noen liker din status follow: Send e-post når noen følger deg follow_request: Send e-post når noen spør om å få følge deg mention: Send e-post når noen nevner deg From d90d23699ca611f05d8def40109505251507fa46 Mon Sep 17 00:00:00 2001 From: Thomas Citharel Date: Wed, 12 Apr 2017 17:11:49 +0200 Subject: [PATCH 11/32] Make Reporting admin section translatable (#1549) * Make Reporting admin section translatable And translate it into english and french Signed-off-by: Thomas Citharel * Make subject of emails translatable and improve french translation Signed-off-by: Thomas Citharel * Make error pages translatable and translate them in english and french Signed-off-by: Thomas Citharel * Translate site setting section * Insert instance in registration emails and improve them a bit Signed-off-by: Thomas Citharel --- app/mailers/user_mailer.rb | 7 +-- app/views/admin/reports/index.html.haml | 18 +++---- app/views/admin/reports/show.html.haml | 19 +++---- app/views/admin/settings/index.html.haml | 42 ++++++--------- app/views/errors/404.html.haml | 4 +- app/views/errors/410.html.haml | 4 +- app/views/errors/422.html.haml | 4 +- .../confirmation_instructions.en.html.erb | 13 +++-- .../confirmation_instructions.en.text.erb | 11 +++- .../confirmation_instructions.fr.html.erb | 15 ++++-- .../confirmation_instructions.fr.text.erb | 13 ++++- config/locales/devise.en.yml | 2 +- config/locales/devise.fr.yml | 6 +-- config/locales/en.yml | 51 +++++++++++++++++++ config/locales/fr.yml | 51 +++++++++++++++++++ 15 files changed, 192 insertions(+), 68 deletions(-) diff --git a/app/mailers/user_mailer.rb b/app/mailers/user_mailer.rb index 3b4d4d07..64ca92a3 100644 --- a/app/mailers/user_mailer.rb +++ b/app/mailers/user_mailer.rb @@ -7,9 +7,10 @@ class UserMailer < Devise::Mailer def confirmation_instructions(user, token, _opts = {}) @resource = user @token = token + @instance = Rails.configuration.x.local_domain I18n.with_locale(@resource.locale || I18n.default_locale) do - mail to: @resource.unconfirmed_email.blank? ? @resource.email : @resource.unconfirmed_email + mail to: @resource.unconfirmed_email.blank? ? @resource.email : @resource.unconfirmed_email, subject: I18n.t('devise.mailer.confirmation_instructions.subject', instance: @instance) end end @@ -18,7 +19,7 @@ class UserMailer < Devise::Mailer @token = token I18n.with_locale(@resource.locale || I18n.default_locale) do - mail to: @resource.email + mail to: @resource.email, subject: I18n.t('devise.mailer.reset_password_instructions.subject') end end @@ -26,7 +27,7 @@ class UserMailer < Devise::Mailer @resource = user I18n.with_locale(@resource.locale || I18n.default_locale) do - mail to: @resource.email + mail to: @resource.email, subject: I18n.t('devise.mailer.password_change.subject') end end end diff --git a/app/views/admin/reports/index.html.haml b/app/views/admin/reports/index.html.haml index 9c5c7893..68dc0701 100644 --- a/app/views/admin/reports/index.html.haml +++ b/app/views/admin/reports/index.html.haml @@ -1,12 +1,12 @@ - content_for :page_title do - Reports + = t('reports.reports') .filters .filter-subset - %strong Status + %strong= t('reports.status') %ul - %li= filter_link_to 'Unresolved', action_taken: nil - %li= filter_link_to 'Resolved', action_taken: '1' + %li= filter_link_to t('reports.unresolved'), action_taken: nil + %li= filter_link_to t('reports.resolved'), action_taken: '1' = form_tag do @@ -14,10 +14,10 @@ %thead %tr %th - %th ID - %th Target - %th Reported by - %th Comment + %th= t('reports.id') + %th= t('reports.target') + %th= t('reports.reported_by') + %th= t('reports.comment.label') %th %tbody - @reports.each do |report| @@ -27,6 +27,6 @@ %td= link_to report.target_account.acct, admin_account_path(report.target_account.id) %td= link_to report.account.acct, admin_account_path(report.account.id) %td= truncate(report.comment, length: 30, separator: ' ') - %td= table_link_to 'circle', 'View', admin_report_path(report) + %td= table_link_to 'circle', t('reports.view'), admin_report_path(report) = paginate @reports diff --git a/app/views/admin/reports/show.html.haml b/app/views/admin/reports/show.html.haml index caa8415d..1143c2c2 100644 --- a/app/views/admin/reports/show.html.haml +++ b/app/views/admin/reports/show.html.haml @@ -1,18 +1,19 @@ - content_for :page_title do - = "Report ##{@report.id}" + = t('reports.report', id: @report.id) .report-accounts .report-accounts__item - %strong Reported account: + %strong= t('reports.reported_account') = render partial: 'authorize_follow/card', locals: { account: @report.target_account } .report-accounts__item - %strong Reported by: + %strong= t('reports.reported_by') = render partial: 'authorize_follow/card', locals: { account: @report.account } %p - %strong Comment: + %strong= t('reports.comment.label') + \: - if @report.comment.blank? - None + = t('reports.comment.none') - else = @report.comment @@ -24,7 +25,7 @@ .activity-stream.activity-stream-headless .entry= render partial: 'stream_entries/simple_status', locals: { status: status } .report-status__actions - = link_to remove_admin_report_path(@report, status_id: status.id), method: :post, class: 'icon-button', style: 'font-size: 24px; width: 24px; height: 24px', title: 'Delete' do + = link_to remove_admin_report_path(@report, status_id: status.id), method: :post, class: 'icon-button', style: 'font-size: 24px; width: 24px; height: 24px', title: t('reports.delete') do = fa_icon 'trash' - if !@report.action_taken? @@ -32,10 +33,10 @@ %div{ style: 'overflow: hidden' } %div{ style: 'float: right' } - = link_to 'Silence account', silence_admin_report_path(@report), method: :post, class: 'button' - = link_to 'Suspend account', suspend_admin_report_path(@report), method: :post, class: 'button' + = link_to t('reports.silence_account'), silence_admin_report_path(@report), method: :post, class: 'button' + = link_to t('reports.suspend_account'), suspend_admin_report_path(@report), method: :post, class: 'button' %div{ style: 'float: left' } - = link_to 'Mark as resolved', resolve_admin_report_path(@report), method: :post, class: 'button' + = link_to t('reports.mark_as_resolved'), resolve_admin_report_path(@report), method: :post, class: 'button' - elsif !@report.action_taken_by_account.nil? %hr/ diff --git a/app/views/admin/settings/index.html.haml b/app/views/admin/settings/index.html.haml index 02faac8c..b00e75a1 100644 --- a/app/views/admin/settings/index.html.haml +++ b/app/views/admin/settings/index.html.haml @@ -1,52 +1,40 @@ - content_for :page_title do - Site Settings + = t('admin.settings.title') %table.table %colgroup %col{ width: '35%' }/ %thead %tr - %th Setting - %th Click to edit + %th= t('admin.settings.setting') + %th= t('admin.settings.click_to_edit') %tbody %tr %td{ rowspan: 2 } - %strong Contact information - %td= best_in_place @settings['site_contact_username'], :value, url: admin_setting_path(@settings['site_contact_username']), place_holder: 'Enter a username' + %strong= t('admin.settings.contact_information.label') + %td= best_in_place @settings['site_contact_username'], :value, url: admin_setting_path(@settings['site_contact_username']), place_holder: t('admin.settings.contact_information.username') %tr - %td= best_in_place @settings['site_contact_email'], :value, url: admin_setting_path(@settings['site_contact_email']), place_holder: 'Enter a public e-mail address' + %td= best_in_place @settings['site_contact_email'], :value, url: admin_setting_path(@settings['site_contact_email']), place_holder: t('admin.settings.contact_information.email') %tr %td - %strong Site title + %strong= t('admin.settings.site_title') %td= best_in_place @settings['site_title'], :value, url: admin_setting_path(@settings['site_title']) %tr %td - %strong Site description - %br/ - Displayed as a paragraph on the frontpage and used as a meta tag. - %br/ - You can use HTML tags, in particular - %code= '' - and - %code= '' + %strong= t('admin.settings.site_description.title') + %p= t('admin.settings.site_description.desc_html') %td= best_in_place @settings['site_description'], :value, as: :textarea, url: admin_setting_path(@settings['site_description']) %tr %td - %strong Extended site description - %br/ - Displayed on extended information page - %br/ - You can use HTML tags + %strong= t('admin.settings.site_description_extended.title') + %p= t('admin.settings.site_description_extended.desc_html') %td= best_in_place @settings['site_extended_description'], :value, as: :textarea, url: admin_setting_path(@settings['site_extended_description']) %tr %td - %strong Open registration - %td= best_in_place @settings['open_registrations'], :value, as: :checkbox, collection: { false: 'Disabled', true: 'Enabled'}, url: admin_setting_path(@settings['open_registrations']) + %strong= t('admin.settings.registrations.open.title') + %td= best_in_place @settings['open_registrations'], :value, as: :checkbox, collection: { false: t('admin.settings.registrations.open.disabled'), true: t('admin.settings.registrations.open.enabled')}, url: admin_setting_path(@settings['open_registrations']) %tr %td - %strong Closed registration message - %br/ - Displayed on frontpage when registrations are closed - %br/ - You can use HTML tags + %strong= t('admin.settings.registrations.closed_message.title') + %p= t('admin.settings.registrations.closed_message.desc_html') %td= best_in_place @settings['closed_registrations_message'], :value, as: :textarea, url: admin_setting_path(@settings['closed_registrations_message']) diff --git a/app/views/errors/404.html.haml b/app/views/errors/404.html.haml index ba1d5f72..5ffba3ca 100644 --- a/app/views/errors/404.html.haml +++ b/app/views/errors/404.html.haml @@ -1,5 +1,5 @@ - content_for :page_title do - The page you were looking for doesn't exist + = t('errors.404') - content_for :content do - The page you were looking for doesn't exist + = t('errors.404') \ No newline at end of file diff --git a/app/views/errors/410.html.haml b/app/views/errors/410.html.haml index 07cf3742..627c6558 100644 --- a/app/views/errors/410.html.haml +++ b/app/views/errors/410.html.haml @@ -1,5 +1,5 @@ - content_for :page_title do - The page you were looking for doesn't exist anymore + = t('errors.410') - content_for :content do - The page you were looking for doesn't exist anymore + = t('errors.410') diff --git a/app/views/errors/422.html.haml b/app/views/errors/422.html.haml index e369cded..e710fecb 100644 --- a/app/views/errors/422.html.haml +++ b/app/views/errors/422.html.haml @@ -1,5 +1,5 @@ - content_for :page_title do - Security verification failed + = t('errors.422.title') - content_for :content do - Security verification failed. Are you blocking cookies? + = t('errors.422.content') diff --git a/app/views/user_mailer/confirmation_instructions.en.html.erb b/app/views/user_mailer/confirmation_instructions.en.html.erb index 69e9ff80..f28a38be 100644 --- a/app/views/user_mailer/confirmation_instructions.en.html.erb +++ b/app/views/user_mailer/confirmation_instructions.en.html.erb @@ -1,5 +1,12 @@ -

Welcome <%= @resource.email %>!

+

Welcome <%= @resource.email %> !

-

You can confirm your Mastodon account email through the link below:

+

You just created an account on <%= @instance %>.

-

<%= link_to 'Confirm my account', confirmation_url(@resource, confirmation_token: @token) %>

+

To confirm your inscription, please click on the following link :
+<%= link_to 'Confirm my account', confirmation_url(@resource, confirmation_token: @token) %> + +

Please also check out our <%= link_to 'terms and conditions', terms_url %>.

+ +

Sincerely,

+ +

The <%= @instance %> team

\ No newline at end of file diff --git a/app/views/user_mailer/confirmation_instructions.en.text.erb b/app/views/user_mailer/confirmation_instructions.en.text.erb index bb21cf8e..0419adef 100644 --- a/app/views/user_mailer/confirmation_instructions.en.text.erb +++ b/app/views/user_mailer/confirmation_instructions.en.text.erb @@ -1,5 +1,12 @@ -Welcome <%= @resource.email %>! +Welcome <%= @resource.email %> ! -You can confirm your Mastodon account email through the link below: +You just created an account on <%= @instance %>. +To confirm your inscription, please click on the following link : <%= confirmation_url(@resource, confirmation_token: @token) %> + +Please also check out our terms and conditions <%= terms_url %> + +Sincerely, + +The <%= @instance %> team \ No newline at end of file diff --git a/app/views/user_mailer/confirmation_instructions.fr.html.erb b/app/views/user_mailer/confirmation_instructions.fr.html.erb index 6c45f1a2..b0b3d0f5 100644 --- a/app/views/user_mailer/confirmation_instructions.fr.html.erb +++ b/app/views/user_mailer/confirmation_instructions.fr.html.erb @@ -1,5 +1,14 @@ -

Bienvenue <%= @resource.email %> !

+

Bonjour <%= @resource.email %> !

-

Vous pouvez confirmer le courriel de votre compte Mastodon en cliquant sur le lien ci-dessous :

+

Vous venez de vous créer un compte sur <%= @instance %> et nous vous en remercions :)

-

<%= link_to 'Confirmer mon compte', confirmation_url(@resource, confirmation_token: @token) %>

+

Pour confirmer votre inscription, merci de cliquer sur le lien suivant :
+<%= link_to 'Confirmer mon compte', confirmation_url(@resource, confirmation_token: @token) %>

+ +

Après votre première connexion, vous pourrez accéder à la documentation de l'outil.

+ +

Pensez également à jeter un œil à nos <%= link_to 'conditions d\'utilisation', terms_url %>.

+ +

Amicalement,

+ +

L'équipe <%= @instance %>

\ No newline at end of file diff --git a/app/views/user_mailer/confirmation_instructions.fr.text.erb b/app/views/user_mailer/confirmation_instructions.fr.text.erb index dfa3f9f7..cf8e3968 100644 --- a/app/views/user_mailer/confirmation_instructions.fr.text.erb +++ b/app/views/user_mailer/confirmation_instructions.fr.text.erb @@ -1,5 +1,14 @@ -Bienvenue <%= @resource.email %> ! +Bonjour <%= @resource.email %> ! -Vous pouvez confirmer le courriel de votre compte Mastodon en cliquant sur le lien ci-dessous : +Vous venez de vous créer un compte sur <%= @instance %> et nous vous en remercions. +Pour confirmer votre inscription, merci de cliquer sur le lien suivant : <%= confirmation_url(@resource, confirmation_token: @token) %> + +Après votre première connexion, vous pourrez accéder à la documentation de l'outil. + +Pour rappel, nos conditions d'utilisation sont indiquées ici <%= terms_url %> + +Amicalement, + +L'équipe <%= @instance %> \ No newline at end of file diff --git a/config/locales/devise.en.yml b/config/locales/devise.en.yml index 442e70d5..b9204b59 100644 --- a/config/locales/devise.en.yml +++ b/config/locales/devise.en.yml @@ -17,7 +17,7 @@ en: unconfirmed: You have to confirm your email address before continuing. mailer: confirmation_instructions: - subject: 'Mastodon: Confirmation instructions' + subject: 'Mastodon: Confirmation instructions for %{instance}' password_change: subject: 'Mastodon: Password changed' reset_password_instructions: diff --git a/config/locales/devise.fr.yml b/config/locales/devise.fr.yml index a986113e..d1dae7c3 100644 --- a/config/locales/devise.fr.yml +++ b/config/locales/devise.fr.yml @@ -17,13 +17,13 @@ fr: unconfirmed: Vous devez valider votre compte pour continuer. mailer: confirmation_instructions: - subject: Instructions de confirmation + subject: "Merci de confirmer votre inscription sur %{instance}" password_change: subject: Votre mot de passe a été modifié avec succés. reset_password_instructions: - subject: Instructions pour modifier le mot de passe + subject: Instructions pour changer votre mot de passe unlock_instructions: - subject: Instructions pour déverrouiller le compte + subject: Instructions pour déverrouiller votre compte omniauth_callbacks: failure: 'Nous n''avons pas pu vous authentifier via %{kind} : ''%{reason}''.' success: Authentifié avec succès via %{kind}. diff --git a/config/locales/en.yml b/config/locales/en.yml index 6c473899..802db148 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -170,3 +170,54 @@ en: users: invalid_email: The e-mail address is invalid invalid_otp_token: Invalid two-factor code + will_paginate: + page_gap: "…" + errors: + 404: The page you were looking for doesn't exist. + 410: The page you were looking for doesn't exist anymore. + 422: + title: Security verification failed + content: Security verification failed. Are you blocking cookies? + reports: + reports: Reports + status: Status + unresolved: Unresolved + resolved: Resolved + id: ID + target: Target + reported_by: Reported by + comment: + label: Comment + none: None + view: View + report: "Report #%{id}" + delete: Delete + reported_account: Reported account + reported_by: Signalé par + silence_account: Silence account + suspend_account: Suspend account + mark_as_resolved: Mark as resolved + admin: + settings: + title: Site Settings + setting: Setting + click_to_edit: Click to edit + contact_information: + label: Contact information + username: Enter a username + email: Enter a public e-mail address + site_title: Site title + site_description: + title: Site description + desc_html: "Displayed as a paragraph on the frontpage and used as a meta tag.
You can use HTML tags, in particular <a> and <em>." + site_description_extended: + title: Extended site description + desc_html: "Displayed on extended information page
You can use HTML tags" + registrations: + open: + title: Open registration + enabled: Enabled + disabled: Disabled + closed_message: + title: Closed registration message + desc_html: "Displayed on frontpage when registrations are closed
You can use HTML tags" diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 92cf4394..86dc13d5 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -167,3 +167,54 @@ fr: users: invalid_email: L'adresse courriel est invalide invalid_otp_token: Le code d'authentification à deux facteurs est invalide + will_paginate: + page_gap: "…" + errors: + 404: La page que vous recherchez n'existe pas. + 410: La page que vous recherchez n'existe plus. + 422: + title: Vérification de sécurité échouée + content: Vérification de sécurité échouée. Bloquez-vous les cookies ? + reports: + reports: Signalements + status: Statut + unresolved: Non résolus + resolved: Résolus + id: ID + target: Cible + reported_by: Signalé par + comment: + label: Commentaire + none: Aucun + view: Voir + report: "Signalement #%{id}" + delete: Supprimer + reported_account: Compte signalé + reported_by: Signalé par + silence_account: Rendre le compte muet + suspend_account: Suspendre le compte + mark_as_resolved: Marqué comme résolu + admin: + settings: + title: Paramètres du site + setting: Paramètre + click_to_edit: Cliquez pour éditer + contact_information: + label: Informations de contact + username: Entrez un nom d'utilisateur + email: Entrez une adresse courriel publique + site_title: Titre du site + site_description: + title: Description du site + desc_html: "Affichée sous la forme d'un paragraphe sur la page d'accueil et utilisée comme balise meta.
Vous pouvez utiliser des balises HTML, en particulier <a> et <em>." + site_description_extended: + title: Description étendue du site + desc_html: "Affichée sur la page d'informations complémentaires du site
Vous pouvez utiliser des balises HTML" + registrations: + open: + title: Inscriptions + enabled: Activées + disabled: Désactivées + closed_message: + title: Message de fermeture des inscriptions + desc_html: "Affiché sur la page d'accueil lorsque les inscriptions sont fermées
Vous pouvez utiliser des balises HTML" From ee69ece7b5e366db03de4eae2393ed7050289f4d Mon Sep 17 00:00:00 2001 From: lindwurm Date: Thu, 13 Apr 2017 00:13:19 +0900 Subject: [PATCH 12/32] [web] Moving docs link to tootsuite/documentation (#1581) related: https://github.com/tootsuite/mastodon/commit/1236529e39a7e2534fdd34686a749b5a386c109b and https://github.com/tootsuite/mastodon/commit/fc47c1d00e507f0bee2575c91822d68b72a22bac Signed-off-by: lindwurm --- .../javascripts/components/features/getting_started/index.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/components/features/getting_started/index.jsx b/app/assets/javascripts/components/features/getting_started/index.jsx index d7a78d9c..0656bf69 100644 --- a/app/assets/javascripts/components/features/getting_started/index.jsx +++ b/app/assets/javascripts/components/features/getting_started/index.jsx @@ -43,7 +43,7 @@ const GettingStarted = ({ intl, me }) => {
-

tootsuite/mastodon, apps: }} />

+

tootsuite/mastodon, apps: }} />

From 3064ef96a12c418281789ee43408fb608d3e9bd2 Mon Sep 17 00:00:00 2001 From: "Carlos A. Escobar" Date: Wed, 12 Apr 2017 10:16:40 -0500 Subject: [PATCH 13/32] Added missing Spanish translations strings (#1292) * Added missing Spanish translations strings * fix bad translation * resolve conflict with tootsuite/master * agreements from spanish community * Add some missing strings --- .../javascripts/components/locales/es.jsx | 63 ++++++-- config/locales/es.yml | 148 ++++++++++++++++-- config/locales/simple_form.es.yml | 20 ++- 3 files changed, 196 insertions(+), 35 deletions(-) diff --git a/app/assets/javascripts/components/locales/es.jsx b/app/assets/javascripts/components/locales/es.jsx index b75fb57d..7e9c0dc2 100644 --- a/app/assets/javascripts/components/locales/es.jsx +++ b/app/assets/javascripts/components/locales/es.jsx @@ -5,28 +5,35 @@ const es = { "status.mention": "Mencionar", "status.delete": "Borrar", "status.reply": "Responder", - "status.reblog": "Republicar", + "status.reblog": "Retoot", "status.favourite": "Favorito", - "status.reblogged_by": "{name} republicado", + "status.reblogged_by": "Retooteado por {name}", + "status.sensitive_warning": "Contenido sensible", + "status.sensitive_toggle": "Click para ver", + "status.show_more": "Mostrar más", + "status.show_less": "Mostrar menos", + "status.open": "Expandir estado", + "status.report": "Reportar", "video_player.toggle_sound": "Act/Desac. sonido", - "account.mention": "Mención", + "account.mention": "Mencionar", "account.edit_profile": "Editar perfil", "account.unblock": "Desbloquear", "account.unfollow": "Dejar de seguir", + "account.mute": "Silenciar", "account.block": "Bloquear", "account.follow": "Seguir", - "account.block": "Bloquear", "account.posts": "Publicaciones", "account.follows": "Seguir", "account.followers": "Seguidores", "account.follows_you": "Te sigue", + "account.requested": "Esperando aprobación", "getting_started.heading": "Primeros pasos", "getting_started.about_addressing": "Puedes seguir a gente si conoces su nombre de usuario y el dominio en el que están registrados, introduciendo algo similar a una dirección de correo electrónico en el formulario en la parte superior de la barra lateral.", "getting_started.about_shortcuts": "Si el usuario que buscas está en el mismo dominio que tú, simplemente funcionará introduciendo el nombre de usuario. La misma regla se aplica para mencionar a usuarios.", - "getting_started.about_developer": "Puedes seguir al desarrollador de este proyecto en Gargron@mastodon.social", + "getting_started.open_source_notice": "Mastodon es software libre. Puedes contribuir o reportar errores en {github}. {apps}.", "column.home": "Inicio", - "column.mentions": "Menciones", - "column.public": "Historia pública", + "column.community": "Historia local", + "column.public": "Historia federada", "column.notifications": "Notificaciones", "tabs_bar.compose": "Redactar", "tabs_bar.home": "Inicio", @@ -34,23 +41,47 @@ const es = { "tabs_bar.public": "Público", "tabs_bar.notifications": "Notificaciones", "compose_form.placeholder": "¿En qué estás pensando?", - "compose_form.publish": "Publicar", - "compose_form.sensitive": "Marcar el contenido como sensible", - "compose_form.unlisted": "Privado", + "compose_form.publish": "Tootear", + "compose_form.sensitive": "Marcar contenido como sensible", + "compose_form.spoiler": "Ocultar texto tras advertencia", + "compose_form.spoiler_placeholder": "Advertencia de contenido", + "composer_form.private": "Marcar como privado", + "composer_form.privacy_disclaimer": "Tu estado se mostrará a los usuarios mencionados en {domains}. Tu estado podrá ser visto en otras instancias, quizás no quieras que tu estado sea visto por otros usuarios.", + "compose_form.unlisted": "No mostrar en la historia federada", "navigation_bar.edit_profile": "Editar perfil", "navigation_bar.preferences": "Preferencias", - "navigation_bar.public_timeline": "Público", + "navigation_bar.community_timeline": "Historia local", + "navigation_bar.public_timeline": "Historia federada", + "navigation_bar.favourites": "Favoritos", + "navigation_bar.blocks": "Usuarios bloqueados", + "navigation_bar.info": "Información adicional", "navigation_bar.logout": "Cerrar sesión", "reply_indicator.cancel": "Cancelar", "search.placeholder": "Buscar", "search.account": "Cuenta", "search.hashtag": "Etiqueta", - "upload_button.label": "Añadir medio", + "upload_button.label": "Subir multimedia", "upload_form.undo": "Deshacer", - "notification.follow": "{name} le esta ahora siguiendo", - "notification.favourite": "{name} marcó como favorito su estado", - "notification.reblog": "{name} volvió a publicar su estado", - "notification.mention": "Fue mencionado por {name}" + "notification.follow": "{name} te empezó a seguir", + "notification.favourite": "{name} marcó tu estado como favorito", + "notification.reblog": "{name} ha retooteado tu estado", + "notification.mention": "{name} te ha mencionado", + "notifications.column_settings.alert": "Notificaciones de escritorio", + "notifications.column_settings.show": "Mostrar en columna", + "notifications.column_settings.follow": "Nuevos seguidores:", + "notifications.column_settings.favourite": "Favoritos:", + "notifications.column_settings.mention": "Menciones:", + "notifications.column_settings.reblog": "Retoots:", + "emoji_button.label": "Insertar emoji", + "privacy.public.short": "Público", + "privacy.public.long": "Mostrar en la historia federada", + "privacy.unlisted.short": "Sin federar", + "privacy.unlisted.long": "No mostrar en la historia federada", + "privacy.private.short": "Privado", + "privacy.private.long": "Sólo mostrar a seguidores", + "privacy.direct.short": "Directo", + "privacy.direct.long": "Sólo mostrar a los usuarios mencionados", + "privacy.change": "Ajustar privacidad" }; export default es; diff --git a/config/locales/es.yml b/config/locales/es.yml index 42245d67..da4270e9 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -2,52 +2,166 @@ es: about: about_mastodon: Mastodon es un servidor de red social libre y de código abierto. Una alternativa descentralizada a plataformas comerciales, que evita el riesgo de que una única compañía monopolice tu comunicación. Cualquiera puede ejecutar Mastodon y participar sin problemas en la red social. + about_this: Acerca de esta instancia + apps: Apps + business_email: 'Correo de negocios:' + closed_registrations: Los registros están actualmente cerrados en esta instancia. + contact: Contacto + description_headline: ¿Qué es %{domain}? + domain_count_after: otras instancias + domain_count_before: Conectado a + features: + api: API pública para aplicaciones y servicios + blocks: Moderación de contenido + characters: 500 caracteres por publicación + chronology: Las historias son cronológicas + ethics: 'Diseño etico: sin anuncios, sin rastreos' + gifv: Videos cortos y GIFV + privacy: Configuraciones de privacidad ajustables + public: Historia federada + features_headline: Lo que distingue a Mastodon get_started: Comenzar + links: Enlaces + other_instances: Otras instancias source_code: Código fuente - terms: Términos de uso + status_count_after: estados + status_count_before: Que han escrito + terms: Términos + user_count_after: usuarios registrados + user_count_before: Tenemos accounts: follow: Seguir followers: Seguidores following: Siguiendo - nothing_here: "¡No hay nada aquí!" + nothing_here: ¡No hay nada aquí! people_followed_by: Usuarios a quien %{name} sigue people_who_follow: Usuarios que siguen a %{name} - posts: Publicaciones + posts: Toots + remote_follow: Seguir unfollow: Dejar de seguir application_mailer: + settings: 'Cambiar preferencias de correo: %{link}' signature: Notificaciones de Mastodon desde %{instance} + view: 'Vista:' + applications: + invalid_url: La URL proporcionada es incorrecta auth: change_password: Cambiar contraseña - didnt_get_confirmation: "¿No recibió instrucciones de confirmación?" - forgot_password: "¿Olvidó su contraseña?" + didnt_get_confirmation: ¿No recibió el correo de confirmación? + forgot_password: ¿Olvidaste tu contraseña? login: Iniciar sesión + logout: Cerrar sesión register: Registrarse - resend_confirmation: Volver a enviar las instrucciones de confirmación + resend_confirmation: Volver a enviar el correo de confirmación reset_password: Restablecer contraseña set_new_password: Establecer nueva contraseña + authorize_follow: + error: Desafortunadamente, ha ocurrido un error buscando la cuenta remota + follow: Seguir + prompt_html: 'Tú (%{self}) has solicitado seguir:' + title: Seguir %{acct} + datetime: + distance_in_words: + about_x_hours: "%{count}h" + about_x_months: "%{count}m" + about_x_years: "%{count}y" + almost_x_years: "%{count}y" + half_a_minute: Justo ahora + less_than_x_minutes: "%{count}m" + less_than_x_seconds: Justo ahora + over_x_years: "%{count}y" + x_days: "%{count}d" + x_minutes: "%{count}m" + x_months: "%{count}m" + x_seconds: "%{count}s" + exports: + blocks: Personas que has bloqueado + csv: CSV + follows: Personas que sigues + storage: Almacenamiento generic: - changes_saved_msg: "¡Cambios guardados con éxito!" + changes_saved_msg: ¡Cambios guardados con éxito! powered_by: powered by %{link} save_changes: Guardar cambios validation_errors: - one: "¡Algo no está todavía bien! Por favor, revise el error más abajo" - other: "¡Algo no está todavía bien! Por favor, revise %{count} errores más abajo" + one: ¡Algo no está bien! Por favor, revisa el error + other: ¡Algo no está bien! Por favor, revise %{count} errores más abajo + imports: + preface: Puedes importar ciertos datos, como todas las personas que estás siguiendo o bloqueando en tu cuenta en esta instancia, desde archivos exportados de otra instancia. + success: Sus datos se han cargado correctamente y serán procesados en brevedad + types: + blocking: Lista de bloqueados + following: Lista de seguidos + upload: Cargar + landing_strip_html: %{name} es un usuario en %{domain}. Puedes seguirlo(a) o interactuar con el o ella si tienes una cuenta en cualquier parte del fediverse. Si no tienes una, puedes registrar aquí. notification_mailer: + digest: + body: 'Un resumen de lo que te perdiste en %{instance} desde tu última visita el %{since}:' + mention: "%{name} te ha mencionado en:" + new_followers_summary: + one: ¡Hurra!. Alguien más te ha comenzado a seguir + other: ¡Genial!. Te han seguido %{count} nuevas personas + subject: + one: "1 nueva notificación desde tu última visita \U0001F418" + other: "%{count} nuevas notificaciones desde tu última visita \U0001F418" favourite: - body: 'Su estado fue marcado como favorito por %{name}:' - subject: "%{name} marcó como favorito su estado" + body: 'Tu estado fue marcado como favorito por %{name}:' + subject: "%{name} marcó como favorito tu estado" follow: - body: "¡%{name} le está ahora siguiendo!" - subject: "%{name} le esta ahora siguiendo" + body: "¡%{name} te está siguiendo!" + subject: "%{name} te está siguiendo" + follow_request: + body: "%{name} ha solicitado seguirte" + subject: 'Seguidor pendiente: %{name}' mention: - body: 'Fue mencionado por %{name} en:' - subject: Fue mencionado por %{name} + body: 'Fuiste mencionado por %{name} en:' + subject: Fuiste mencionado por %{name} reblog: - body: 'Su estado fue vuelto a publicar por %{name}:' - subject: "%{name} volvió a publicar su estado" + body: '%{name} ha retooteado tu estado' + subject: "%{name} ha retooteado tu estado" pagination: next: Próximo prev: Anterior + remote_follow: + acct: Ingesa el usuario@dominio de la persona que quieres seguir + missing_resource: No se pudo encontrar la URL de redirección necesaria para su cuenta. + proceed: Proceder a seguir + prompt: 'Vas a seguir a:' settings: + authorized_apps: Aplicaciones autorizadas + back: Volver al inicio edit_profile: Editar perfil + export: Exportar información + import: Importar preferences: Preferencias + settings: Ajustes + two_factor_auth: Aute/ción. de dos factores + statuses: + open_in_web: Abrir en web + over_character_limit: Límite de caracteres de %{max} superado + show_more: Mostrar más + visibilities: + private: Sólo mostrar a seguidores + public: Público + unlisted: Público, pero no mostrar en la historia federada + stream_entries: + click_to_show: Click para mostrar + reblogged: retooteado + sensitive_content: Contenido sensible + time: + formats: + default: "%b %d, %Y, %H:%M" + two_factor_auth: + description_html: Sí habilitas la autenticación de dos factores, se requerirá estar en posesión de su teléfono, lo que generará tokens para que usted pueda iniciar sesión. + disable: Deshabilitar + enable: Habilitar + instructions_html: "Escanea este código QR desde Google Authenticator o una aplicación similar en su teléfono. Desde ahora, esta aplicación va a generar tokens que tienes que ingresar cuando quieras iniciar sesión." + plaintext_secret_html: 'Código en texto plano: %{secret}' + warning: Sí no puedes configurar una aplicación de autenticación ahora, deberás deshabilitar la autenticación de dos factores o no podrás iniciar sesión. + users: + invalid_email: La dirección de correo es incorrecta + invalid_otp_token: Código de dos factores incorrecto + media_attachments: + validations: + too_many: No se pueden adjuntar más de 4 archivos + images_and_video: No se puede adjuntar un video a un estado que ya contenga imágenes diff --git a/config/locales/simple_form.es.yml b/config/locales/simple_form.es.yml index f1db48df..1c1afcdd 100644 --- a/config/locales/simple_form.es.yml +++ b/config/locales/simple_form.es.yml @@ -1,24 +1,40 @@ --- es: simple_form: + hints: + defaults: + avatar: PNG, GIF o JPG. Máximo 2MB. Será escalado a 120x120px + display_name: Máximo 30 caracteres + header: PNG, GIF o JPG. Máximo 2MB. Será escalado a 700x335px + locked: Requiere que manualmente apruebes seguidores y las publicaciones serán mostradas solamente a tus seguidores + note: Máximo 160 caracteres + imports: + data: Archivo CSV exportado desde otra instancia de Mastodon labels: defaults: avatar: Avatar confirm_new_password: Confirmar nueva contraseña confirm_password: Confirmar contraseña current_password: Contraseña actual + data: Información display_name: Mostrar nombre email: Dirección de correo electrónico header: Img. cabecera locale: Idioma new_password: Nueva contraseña note: Biografía + otp_attempt: Código de dos factores password: Contraseña + setting_default_privacy: Privacidad de publicaciones + type: Importar tipo username: Nombre de usuario + interactions: + must_be_follower: Bloquear notificaciones de personas que no te siguen + must_be_following: Bloquear notificaciones de personas que no sigues notification_emails: favourite: Enviar correo electrónico cuando alguien de a favorito en su publicación - follow: Enviar correo electrónico cuando alguien le siga - mention: Enviar correo electrónico cuando alguien le mencione + follow: Enviar correo electrónico cuando alguien te siga + mention: Enviar correo electrónico cuando alguien te mencione reblog: Enviar correo electrónico cuando alguien comparta su publicación 'no': 'No' required: From 08fce0821706a3c84b70fd513eb75c0ad7014c04 Mon Sep 17 00:00:00 2001 From: Henry Smith Date: Wed, 12 Apr 2017 17:16:59 +0200 Subject: [PATCH 14/32] Add unit tests for https://github.com/tootsuite/mastodon/pull/1574 (#1584) --- .../features/ui/components/column.test.jsx | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 spec/javascript/components/features/ui/components/column.test.jsx diff --git a/spec/javascript/components/features/ui/components/column.test.jsx b/spec/javascript/components/features/ui/components/column.test.jsx new file mode 100644 index 00000000..b7e25775 --- /dev/null +++ b/spec/javascript/components/features/ui/components/column.test.jsx @@ -0,0 +1,30 @@ +import { expect } from 'chai'; +import { mount } from 'enzyme'; +import sinon from 'sinon'; + +import Column from '../../../../../../app/assets/javascripts/components/features/ui/components/column'; +import ColumnHeader from '../../../../../../app/assets/javascripts/components/features/ui/components/column_header'; + +describe('', () => { + describe(' click handler', () => { + beforeEach(() => { + global.requestAnimationFrame = sinon.spy(); + }); + + it('runs the scroll animation if the column contains scrollable content', () => { + const wrapper = mount( + +
+ + ); + wrapper.find(ColumnHeader).simulate('click'); + expect(global.requestAnimationFrame.called).to.equal(true); + }); + + it('does not try to scroll if there is no scrollable content', () => { + const wrapper = mount(); + wrapper.find(ColumnHeader).simulate('click'); + expect(global.requestAnimationFrame.called).to.equal(false); + }); + }); +}); From 7f0a865b05628fa82ac692ec9a21c418e30dac14 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Wed, 12 Apr 2017 12:20:44 -0400 Subject: [PATCH 15/32] Allow import/export of mutes list (#1541) * Allow export of mutes list * Allow importing of mutes list * Refactor to use Settings::Exports::BaseController and DRY up exports code --- .../settings/exports/base_controller.rb | 23 +++++++++++++++++++ .../exports/blocked_accounts_controller.rb | 12 ++++------ .../exports/following_accounts_controller.rb | 12 ++++------ .../exports/muted_accounts_controller.rb | 13 +++++++++++ .../settings/exports_controller.rb | 1 + app/models/import.rb | 2 +- app/views/settings/exports/show.html.haml | 4 ++++ app/workers/import_worker.rb | 14 +++++++++++ config/locales/en.yml | 2 ++ config/routes.rb | 1 + .../blocked_accounts_controller_spec.rb | 2 +- .../following_accounts_controller_spec.rb | 2 +- .../exports/muted_accounts_controller_spec.rb | 17 ++++++++++++++ 13 files changed, 86 insertions(+), 19 deletions(-) create mode 100644 app/controllers/settings/exports/base_controller.rb create mode 100644 app/controllers/settings/exports/muted_accounts_controller.rb create mode 100644 spec/controllers/settings/exports/muted_accounts_controller_spec.rb diff --git a/app/controllers/settings/exports/base_controller.rb b/app/controllers/settings/exports/base_controller.rb new file mode 100644 index 00000000..0b790959 --- /dev/null +++ b/app/controllers/settings/exports/base_controller.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +module Settings + module Exports + class BaseController < ApplicationController + before_action :authenticate_user! + + def index + export_data = Export.new(export_accounts).to_csv + + respond_to do |format| + format.csv { send_data export_data, filename: export_filename } + end + end + + private + + def export_filename + "#{controller_name}.csv" + end + end + end +end diff --git a/app/controllers/settings/exports/blocked_accounts_controller.rb b/app/controllers/settings/exports/blocked_accounts_controller.rb index 0bf8848b..9c4bcaa5 100644 --- a/app/controllers/settings/exports/blocked_accounts_controller.rb +++ b/app/controllers/settings/exports/blocked_accounts_controller.rb @@ -2,15 +2,11 @@ module Settings module Exports - class BlockedAccountsController < ApplicationController - before_action :authenticate_user! + class BlockedAccountsController < BaseController + private - def index - export_data = Export.new(current_account.blocking).to_csv - - respond_to do |format| - format.csv { send_data export_data, filename: 'blocking.csv' } - end + def export_accounts + current_account.blocking end end end diff --git a/app/controllers/settings/exports/following_accounts_controller.rb b/app/controllers/settings/exports/following_accounts_controller.rb index a7f4344c..8d06bcc9 100644 --- a/app/controllers/settings/exports/following_accounts_controller.rb +++ b/app/controllers/settings/exports/following_accounts_controller.rb @@ -2,15 +2,11 @@ module Settings module Exports - class FollowingAccountsController < ApplicationController - before_action :authenticate_user! + class FollowingAccountsController < BaseController + private - def index - export_data = Export.new(current_account.following).to_csv - - respond_to do |format| - format.csv { send_data export_data, filename: 'following.csv' } - end + def export_accounts + current_account.following end end end diff --git a/app/controllers/settings/exports/muted_accounts_controller.rb b/app/controllers/settings/exports/muted_accounts_controller.rb new file mode 100644 index 00000000..a77a9af6 --- /dev/null +++ b/app/controllers/settings/exports/muted_accounts_controller.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module Settings + module Exports + class MutedAccountsController < BaseController + private + + def export_accounts + current_account.muting + end + end + end +end diff --git a/app/controllers/settings/exports_controller.rb b/app/controllers/settings/exports_controller.rb index e060f03d..77dea323 100644 --- a/app/controllers/settings/exports_controller.rb +++ b/app/controllers/settings/exports_controller.rb @@ -9,5 +9,6 @@ class Settings::ExportsController < ApplicationController @total_storage = current_account.media_attachments.sum(:file_file_size) @total_follows = current_account.following.count @total_blocks = current_account.blocking.count + @total_mutes = current_account.muting.count end end diff --git a/app/models/import.rb b/app/models/import.rb index 5384986d..3013bc50 100644 --- a/app/models/import.rb +++ b/app/models/import.rb @@ -3,7 +3,7 @@ class Import < ApplicationRecord self.inheritance_column = false - enum type: [:following, :blocking] + enum type: [:following, :blocking, :muting] belongs_to :account diff --git a/app/views/settings/exports/show.html.haml b/app/views/settings/exports/show.html.haml index 432a61b4..51be40fb 100644 --- a/app/views/settings/exports/show.html.haml +++ b/app/views/settings/exports/show.html.haml @@ -15,3 +15,7 @@ %th= t('exports.blocks') %td= @total_blocks %td= table_link_to 'download', t('exports.csv'), settings_exports_blocks_path(format: :csv) + %tr + %th= t('exports.mutes') + %td= @total_mutes + %td= table_link_to 'download', t('exports.csv'), settings_exports_mutes_path(format: :csv) diff --git a/app/workers/import_worker.rb b/app/workers/import_worker.rb index 60529c0e..bb21468e 100644 --- a/app/workers/import_worker.rb +++ b/app/workers/import_worker.rb @@ -16,6 +16,8 @@ class ImportWorker process_blocks when 'following' process_follows + when 'muting' + process_mutes end @import.destroy @@ -35,6 +37,18 @@ class ImportWorker CSV.new(import_contents).reject(&:blank?) end + def process_mutes + import_rows.each do |row| + begin + target_account = FollowRemoteAccountService.new.call(row.first) + next if target_account.nil? + MuteService.new.call(from_account, target_account) + rescue Goldfinger::Error, HTTP::Error, OpenSSL::SSL::SSLError + next + end + end + end + def process_blocks import_rows.each do |row| begin diff --git a/config/locales/en.yml b/config/locales/en.yml index 802db148..6e32d2c3 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -76,6 +76,7 @@ en: x_seconds: "%{count}s" exports: blocks: You block + mutes: You mute csv: CSV follows: You follow storage: Media storage @@ -92,6 +93,7 @@ en: types: blocking: Blocking list following: Following list + muting: Muting list upload: Upload landing_strip_html: %{name} is a user on %{domain}. You can follow them or interact with them if you have an account anywhere in the fediverse. If you don't, you can sign up here. media_attachments: diff --git a/config/routes.rb b/config/routes.rb index 99ce1754..78bf7870 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -57,6 +57,7 @@ Rails.application.routes.draw do namespace :exports, constraints: { format: :csv } do resources :follows, only: :index, controller: :following_accounts resources :blocks, only: :index, controller: :blocked_accounts + resources :mutes, only: :index, controller: :muted_accounts end resource :two_factor_auth, only: [:show, :new, :create] do diff --git a/spec/controllers/settings/exports/blocked_accounts_controller_spec.rb b/spec/controllers/settings/exports/blocked_accounts_controller_spec.rb index 574d4d87..c815bdfe 100644 --- a/spec/controllers/settings/exports/blocked_accounts_controller_spec.rb +++ b/spec/controllers/settings/exports/blocked_accounts_controller_spec.rb @@ -11,7 +11,7 @@ describe Settings::Exports::BlockedAccountsController do expect(response).to have_http_status(:success) expect(response.content_type).to eq 'text/csv' - expect(response.headers['Content-Disposition']).to eq 'attachment; filename="blocking.csv"' + expect(response.headers['Content-Disposition']).to eq 'attachment; filename="blocked_accounts.csv"' end end end diff --git a/spec/controllers/settings/exports/following_accounts_controller_spec.rb b/spec/controllers/settings/exports/following_accounts_controller_spec.rb index bf768052..a7029709 100644 --- a/spec/controllers/settings/exports/following_accounts_controller_spec.rb +++ b/spec/controllers/settings/exports/following_accounts_controller_spec.rb @@ -11,7 +11,7 @@ describe Settings::Exports::FollowingAccountsController do expect(response).to have_http_status(:success) expect(response.content_type).to eq 'text/csv' - expect(response.headers['Content-Disposition']).to eq 'attachment; filename="following.csv"' + expect(response.headers['Content-Disposition']).to eq 'attachment; filename="following_accounts.csv"' end end end diff --git a/spec/controllers/settings/exports/muted_accounts_controller_spec.rb b/spec/controllers/settings/exports/muted_accounts_controller_spec.rb new file mode 100644 index 00000000..bb52b6fc --- /dev/null +++ b/spec/controllers/settings/exports/muted_accounts_controller_spec.rb @@ -0,0 +1,17 @@ +require 'rails_helper' + +describe Settings::Exports::MutedAccountsController do + before do + sign_in Fabricate(:user), scope: :user + end + + describe 'GET #index' do + it 'returns a csv of the muting accounts' do + get :index, format: :csv + + expect(response).to have_http_status(:success) + expect(response.content_type).to eq 'text/csv' + expect(response.headers['Content-Disposition']).to eq 'attachment; filename="muted_accounts.csv"' + end + end +end From 0930ce5560749f5ede3aa70aef4130ad1a9dc6ba Mon Sep 17 00:00:00 2001 From: Rachel H Date: Wed, 12 Apr 2017 09:21:07 -0700 Subject: [PATCH 16/32] Focus textarea when text is inserted (#1320) Place space after uploaded filenames --- .gitignore | 4 ++++ app/assets/javascripts/components/reducers/compose.jsx | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 6d540c41..b671bcb9 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,7 @@ neo4j/ # Ignore Capistrano customizations config/deploy/* + + +# Ignore IDE files +.vscode/ diff --git a/app/assets/javascripts/components/reducers/compose.jsx b/app/assets/javascripts/components/reducers/compose.jsx index 4470ad64..00cc758a 100644 --- a/app/assets/javascripts/components/reducers/compose.jsx +++ b/app/assets/javascripts/components/reducers/compose.jsx @@ -76,7 +76,8 @@ function appendMedia(state, media) { map.update('media_attachments', list => list.push(media)); map.set('is_uploading', false); map.set('resetFileKey', Math.floor((Math.random() * 0x10000))); - map.update('text', oldText => `${oldText} ${media.get('text_url')}`.trim()); + map.set('focusDate', new Date()); + map.update('text', oldText => `${oldText.trim()} ${media.get('text_url')}`.trim() + ' '); }); }; From aa9079838648e9656a1bf8d10151713686e1c0dd Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Wed, 12 Apr 2017 12:22:38 -0400 Subject: [PATCH 17/32] Webfinger resource to extract username from resource string (#1607) * Add WebfingerResource class to extract usernames * Use WebfingerResource in xrd#webfinger --- app/controllers/xrd_controller.rb | 10 +--- app/lib/webfinger_resource.rb | 66 ++++++++++++++++++++++ spec/lib/webfinger_resource_spec.rb | 88 +++++++++++++++++++++++++++++ 3 files changed, 155 insertions(+), 9 deletions(-) create mode 100644 app/lib/webfinger_resource.rb create mode 100644 spec/lib/webfinger_resource_spec.rb diff --git a/app/controllers/xrd_controller.rb b/app/controllers/xrd_controller.rb index ba5032ab..2886315a 100644 --- a/app/controllers/xrd_controller.rb +++ b/app/controllers/xrd_controller.rb @@ -31,15 +31,7 @@ class XrdController < ApplicationController end def username_from_resource - if resource_param =~ /\Ahttps?:\/\// - path_params = Rails.application.routes.recognize_path(resource_param) - raise ActiveRecord::RecordNotFound unless path_params[:controller] == 'users' && path_params[:action] == 'show' - path_params[:username] - else - username, domain = resource_param.gsub(/\Aacct:/, '').split('@') - raise ActiveRecord::RecordNotFound unless TagManager.instance.local_domain?(domain) - username - end + WebfingerResource.new(resource_param).username end def pem_to_magic_key(public_key) diff --git a/app/lib/webfinger_resource.rb b/app/lib/webfinger_resource.rb new file mode 100644 index 00000000..8c5db795 --- /dev/null +++ b/app/lib/webfinger_resource.rb @@ -0,0 +1,66 @@ +# frozen_string_literal: true + +class WebfingerResource + attr_reader :resource + + def initialize(resource) + @resource = resource + end + + def username + case resource + when /\Ahttps?/i + username_from_url + when /\@/ + username_from_acct + else + raise(ActiveRecord::RecordNotFound) + end + end + + private + + def username_from_url + if account_show_page? + path_params[:username] + else + raise ActiveRecord::RecordNotFound + end + end + + def account_show_page? + path_params[:controller] == 'accounts' && path_params[:action] == 'show' + end + + def path_params + Rails.application.routes.recognize_path(resource) + end + + def username_from_acct + if domain_matches_local? + local_username + else + raise ActiveRecord::RecordNotFound + end + end + + def split_acct + resource_without_acct_string.split('@') + end + + def resource_without_acct_string + resource.gsub(/\Aacct:/, '') + end + + def local_username + split_acct.first + end + + def local_domain + split_acct.last + end + + def domain_matches_local? + TagManager.instance.local_domain?(local_domain) + end +end diff --git a/spec/lib/webfinger_resource_spec.rb b/spec/lib/webfinger_resource_spec.rb new file mode 100644 index 00000000..6c9a5ff2 --- /dev/null +++ b/spec/lib/webfinger_resource_spec.rb @@ -0,0 +1,88 @@ +require 'rails_helper' + +describe WebfingerResource do + describe '#username' do + describe 'with a URL value' do + it 'raises with an unrecognized route' do + resource = 'https://example.com/users/alice/other' + + expect { + WebfingerResource.new(resource).username + }.to raise_error(ActiveRecord::RecordNotFound) + end + + it 'raises with a string that doesnt start with URL' do + resource = 'website for http://example.com/users/alice/other' + + expect { + WebfingerResource.new(resource).username + }.to raise_error(ActiveRecord::RecordNotFound) + end + + it 'finds the username in a valid https route' do + resource = 'https://example.com/users/alice' + + result = WebfingerResource.new(resource).username + expect(result).to eq 'alice' + end + + it 'finds the username in a mixed case http route' do + resource = 'HTTp://exAMPLEe.com/users/alice' + + result = WebfingerResource.new(resource).username + expect(result).to eq 'alice' + end + + it 'finds the username in a valid http route' do + resource = 'http://example.com/users/alice' + + result = WebfingerResource.new(resource).username + expect(result).to eq 'alice' + end + end + + describe 'with a username and hostname value' do + it 'raises on a non-local domain' do + resource = 'user@remote-host.com' + + expect { + WebfingerResource.new(resource).username + }.to raise_error(ActiveRecord::RecordNotFound) + end + + it 'finds username for a local domain' do + Rails.configuration.x.local_domain = 'example.com' + resource = 'alice@example.com' + + result = WebfingerResource.new(resource).username + expect(result).to eq 'alice' + end + end + + describe 'with an acct value' do + it 'raises on a non-local domain' do + resource = 'acct:user@remote-host.com' + + expect { + WebfingerResource.new(resource).username + }.to raise_error(ActiveRecord::RecordNotFound) + end + + it 'raises on a nonsense domain' do + resource = 'acct:user@remote-host@remote-hostess.remote.local@remote' + + expect { + WebfingerResource.new(resource).username + }.to raise_error(ActiveRecord::RecordNotFound) + end + + it 'finds the username for a local account' do + Rails.configuration.x.local_domain = 'example.com' + resource = 'acct:alice@example.com' + + result = WebfingerResource.new(resource).username + expect(result).to eq 'alice' + end + end + end +end From c44a7002525d6f87dde923971ac7a95a48e9bc4f Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Wed, 12 Apr 2017 12:24:18 -0400 Subject: [PATCH 18/32] Quick best practice cleanup of views/helpers (#1546) * Remove trailing whitespace * Use query methods instead of explicit .blank? checks --- app/controllers/concerns/localized.rb | 2 +- app/helpers/stream_entries_helper.rb | 2 +- app/lib/atom_serializer.rb | 6 +++--- app/views/admin/pubsubhubbub/index.html.haml | 6 +++--- app/views/admin/reports/show.html.haml | 5 +---- app/views/authorize_follow/_card.html.haml | 2 +- app/views/stream_entries/_detailed_status.html.haml | 4 ++-- app/views/stream_entries/_simple_status.html.haml | 4 ++-- app/workers/pubsubhubbub/delivery_worker.rb | 2 +- config/initializers/blacklists.rb | 2 +- 10 files changed, 16 insertions(+), 19 deletions(-) diff --git a/app/controllers/concerns/localized.rb b/app/controllers/concerns/localized.rb index bcf3fd0a..22bb5b21 100644 --- a/app/controllers/concerns/localized.rb +++ b/app/controllers/concerns/localized.rb @@ -26,7 +26,7 @@ module Localized end def default_locale - ENV.fetch('DEFAULT_LOCALE') { + ENV.fetch('DEFAULT_LOCALE') { http_accept_language.compatible_language_from(I18n.available_locales) || I18n.default_locale } end diff --git a/app/helpers/stream_entries_helper.rb b/app/helpers/stream_entries_helper.rb index 59aac784..18ef8b90 100644 --- a/app/helpers/stream_entries_helper.rb +++ b/app/helpers/stream_entries_helper.rb @@ -2,7 +2,7 @@ module StreamEntriesHelper def display_name(account) - account.display_name.blank? ? account.username : account.display_name + account.display_name.presence || account.username end def stream_link_target diff --git a/app/lib/atom_serializer.rb b/app/lib/atom_serializer.rb index 68d2fce6..69e1f153 100644 --- a/app/lib/atom_serializer.rb +++ b/app/lib/atom_serializer.rb @@ -26,8 +26,8 @@ class AtomSerializer append_element(author, 'link', nil, rel: :avatar, type: account.avatar_content_type, 'media:width': 120, 'media:height': 120, href: full_asset_url(account.avatar.url(:original))) append_element(author, 'link', nil, rel: :header, type: account.header_content_type, 'media:width': 700, 'media:height': 335, href: full_asset_url(account.header.url(:original))) append_element(author, 'poco:preferredUsername', account.username) - append_element(author, 'poco:displayName', account.display_name) unless account.display_name.blank? - append_element(author, 'poco:note', Formatter.instance.simplified_format(account).to_str) unless account.note.blank? + append_element(author, 'poco:displayName', account.display_name) if account.display_name? + append_element(author, 'poco:note', Formatter.instance.simplified_format(account).to_str) if account.note? append_element(author, 'mastodon:scope', account.locked? ? :private : :public) author @@ -327,7 +327,7 @@ class AtomSerializer end def serialize_status_attributes(entry, status) - append_element(entry, 'summary', status.spoiler_text) unless status.spoiler_text.blank? + append_element(entry, 'summary', status.spoiler_text) if status.spoiler_text? append_element(entry, 'content', Formatter.instance.format(status.proper).to_str, type: 'html') status.mentions.each do |mentioned| diff --git a/app/views/admin/pubsubhubbub/index.html.haml b/app/views/admin/pubsubhubbub/index.html.haml index 2b8e36e6..dcbb11c1 100644 --- a/app/views/admin/pubsubhubbub/index.html.haml +++ b/app/views/admin/pubsubhubbub/index.html.haml @@ -21,9 +21,9 @@ %i.fa.fa-check %td= distance_of_time_in_words(Time.now, subscription.expires_at) %td - - if subscription.last_successful_delivery_at.nil? - %i.fa.fa-times - - else + - if subscription.last_successful_delivery_at? = l subscription.last_successful_delivery_at + - else + %i.fa.fa-times = paginate @subscriptions diff --git a/app/views/admin/reports/show.html.haml b/app/views/admin/reports/show.html.haml index 1143c2c2..ecbb9848 100644 --- a/app/views/admin/reports/show.html.haml +++ b/app/views/admin/reports/show.html.haml @@ -12,10 +12,7 @@ %p %strong= t('reports.comment.label') \: - - if @report.comment.blank? - = t('reports.comment.none') - - else - = @report.comment + = @report.comment.presence || t('reports.comment.none') - unless @statuses.empty? %hr/ diff --git a/app/views/authorize_follow/_card.html.haml b/app/views/authorize_follow/_card.html.haml index eef0bec0..16af9220 100644 --- a/app/views/authorize_follow/_card.html.haml +++ b/app/views/authorize_follow/_card.html.haml @@ -7,5 +7,5 @@ %strong.emojify= display_name(account) %span= "@#{account.acct}" - - unless account.note.blank? + - if account.note? .account__header__content.emojify= Formatter.instance.simplified_format(account) diff --git a/app/views/stream_entries/_detailed_status.html.haml b/app/views/stream_entries/_detailed_status.html.haml index 5fc6ab42..c42e6614 100644 --- a/app/views/stream_entries/_detailed_status.html.haml +++ b/app/views/stream_entries/_detailed_status.html.haml @@ -8,11 +8,11 @@ %span.p-nickname= acct(status.account) .status__content.e-content.p-name.emojify< - - unless status.spoiler_text.blank? + - if status.spoiler_text? %p{ style: 'margin-bottom: 0' }< %span>= "#{status.spoiler_text} " %a.status__content__spoiler-link{ href: '#' }= t('statuses.show_more') - %div{ style: "display: #{status.spoiler_text.blank? ? 'block' : 'none'}; direction: #{rtl?(status.content) ? 'rtl' : 'ltr'}" }= Formatter.instance.format(status) + %div{ style: "display: #{status.spoiler_text? ? 'none' : 'block'}; direction: #{rtl?(status.content) ? 'rtl' : 'ltr'}" }= Formatter.instance.format(status) - unless status.media_attachments.empty? - if status.media_attachments.first.video? diff --git a/app/views/stream_entries/_simple_status.html.haml b/app/views/stream_entries/_simple_status.html.haml index 5b6069e3..a758d5cc 100644 --- a/app/views/stream_entries/_simple_status.html.haml +++ b/app/views/stream_entries/_simple_status.html.haml @@ -13,11 +13,11 @@ %span.p-nickname= acct(status.account) .status__content.e-content.p-name.emojify< - - unless status.spoiler_text.blank? + - if status.spoiler_text? %p{ style: 'margin-bottom: 0' }< %span>= "#{status.spoiler_text} " %a.status__content__spoiler-link{ href: '#' }= t('statuses.show_more') - %div{ style: "display: #{status.spoiler_text.blank? ? 'block' : 'none'}; direction: #{rtl?(status.content) ? 'rtl' : 'ltr'}" }= Formatter.instance.format(status) + %div{ style: "display: #{status.spoiler_text? ? 'none' : 'block'}; direction: #{rtl?(status.content) ? 'rtl' : 'ltr'}" }= Formatter.instance.format(status) - unless status.media_attachments.empty? .status__attachments diff --git a/app/workers/pubsubhubbub/delivery_worker.rb b/app/workers/pubsubhubbub/delivery_worker.rb index 8412be4b..b440f798 100644 --- a/app/workers/pubsubhubbub/delivery_worker.rb +++ b/app/workers/pubsubhubbub/delivery_worker.rb @@ -19,7 +19,7 @@ class Pubsubhubbub::DeliveryWorker headers['User-Agent'] = 'Mastodon/PubSubHubbub' headers['Link'] = LinkHeader.new([[api_push_url, [%w(rel hub)]], [account_url(subscription.account, format: :atom), [%w(rel self)]]]).to_s - headers['X-Hub-Signature'] = signature(subscription.secret, payload) unless subscription.secret.blank? + headers['X-Hub-Signature'] = signature(subscription.secret, payload) if subscription.secret? response = HTTP.timeout(:per_operation, write: 50, connect: 20, read: 50) .headers(headers) diff --git a/config/initializers/blacklists.rb b/config/initializers/blacklists.rb index 6db7be7d..020d84f5 100644 --- a/config/initializers/blacklists.rb +++ b/config/initializers/blacklists.rb @@ -2,5 +2,5 @@ Rails.application.configure do config.x.email_domains_blacklist = ENV.fetch('EMAIL_DOMAIN_BLACKLIST') { 'mvrht.com' } - config.x.email_domains_whitelist = ENV.fetch('EMAIL_DOMAIN_WHITELIST') { '' } + config.x.email_domains_whitelist = ENV.fetch('EMAIL_DOMAIN_WHITELIST') { '' } end From 9e63bf446e04fea9e3985eeb36068ca9f32b9539 Mon Sep 17 00:00:00 2001 From: Shel R Date: Wed, 12 Apr 2017 12:27:33 -0400 Subject: [PATCH 19/32] Request documentation (#1616) This addition to the submission guidelines requests that contributors remember to document their code. It's not a hard fast rule just a reminder. --- CONTRIBUTING.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index bfc771ab..9ca01a56 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -7,7 +7,7 @@ There are three ways in which you can contribute to this repository: 2. By working on the back-end application 3. By working on the front-end application -Choosing what to work on in a large open source project is not easy. The list of GitHub issues may provide some ideas, but not every feature request has been greenlit. Likewise, not every change or feature that resolves a personal itch will be merged into the main repository. Some communication ahead of time may be wise. +Choosing what to work on in a large open source project is not easy. The list of GitHub issues may provide some ideas, but not every feature request has been greenlit. Likewise, not every change or feature that resolves a personal itch will be merged into the main repository. Some communication ahead of time may be wise. If your addition creates a new feature or setting, or otherwise changes how things work in some substantial way, please remember to submit a correlating pull request to document your changes in the [documentation](http://github.com/tootsuite/documentation). Below are the guidelines for working on pull requests: @@ -41,3 +41,4 @@ It is expected that you have a working development environment set up (see back- * If you are introducing new strings, they must be using localization methods If the JavaScript or CSS assets won't compile due to a syntax error, it's a good sign that the pull request isn't ready for submission yet. + From c2a31b8032326e55a0832723bf2a590720d59892 Mon Sep 17 00:00:00 2001 From: David Libeau Date: Wed, 12 Apr 2017 19:09:58 +0200 Subject: [PATCH 20/32] Fix target blank on "open_in_web" link (#1612) When you render the "embed" view in an iframe, this link bugs when clicked, due to missing target blank. --- app/views/stream_entries/_detailed_status.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/stream_entries/_detailed_status.html.haml b/app/views/stream_entries/_detailed_status.html.haml index c42e6614..466e0dd5 100644 --- a/app/views/stream_entries/_detailed_status.html.haml +++ b/app/views/stream_entries/_detailed_status.html.haml @@ -49,4 +49,4 @@ - if user_signed_in? · - = link_to t('statuses.open_in_web'), web_url("statuses/#{status.id}"), class: 'open-in-web-link' + = link_to t('statuses.open_in_web'), web_url("statuses/#{status.id}"), class: 'open-in-web-link', target: '_blank' From c4baa9fb6babc5c47332f31a12081e22fd210e51 Mon Sep 17 00:00:00 2001 From: Julien Deswaef Date: Wed, 12 Apr 2017 13:10:52 -0400 Subject: [PATCH 21/32] vector (svg) logo with correct inner shape and colors (#1362) * vector (svg) logo with correct inner shape and colors * minimized svg logo --- app/assets/images/logo.svg | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/app/assets/images/logo.svg b/app/assets/images/logo.svg index 5379a024..52bf86b0 100644 --- a/app/assets/images/logo.svg +++ b/app/assets/images/logo.svg @@ -1,4 +1 @@ - - - - + \ No newline at end of file From e17b5b228d4b18452c25bdedd6c375de9b89cb53 Mon Sep 17 00:00:00 2001 From: Eugen Date: Wed, 12 Apr 2017 19:34:40 +0200 Subject: [PATCH 22/32] Improve docker update instructions (#1619) --- README.md | 43 ++++++++++++++++++------------------------- 1 file changed, 18 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index ee6538d1..6a253b28 100644 --- a/README.md +++ b/README.md @@ -69,28 +69,27 @@ Consult the example configuration file, `.env.production.sample` for the full li The project now includes a `Dockerfile` and a `docker-compose.yml` file (which requires at least docker-compose version `1.10.0`). -Review the settings in docker-compose.yml. Note that it is not default to store the postgresql database and redis databases in a persistent storage location, +Review the settings in `docker-compose.yml`. Note that it is not default to store the postgresql database and redis databases in a persistent storage location, so you may need or want to adjust the settings there. Before running the first time, you need to build the images: + docker-compose build -Then, you need to fill in the .env.production file: +Then, you need to fill in the `.env.production` file: + cp .env.production.sample .env.production - vi .env.production + nano .env.production -Do NOT change the REDIS_* or DB_* settings when running with the default docker configurations. +Do NOT change the `REDIS_*` or `DB_*` settings when running with the default docker configurations. -You will need to fill in, at least: - LOCAL_DOMAIN, LOCAL_HTTPS, PAPERCLIP_SECRET, SECRET_KEY_BASE, OTP_SECRET, and the SMTP_* - settings. To generate the PAPERCLIP_SECRET, SECRET_KEY_BASE, and OTP_SECRET, you may use: +You will need to fill in, at least: `LOCAL_DOMAIN`, `LOCAL_HTTPS`, `PAPERCLIP_SECRET`, `SECRET_KEY_BASE`, `OTP_SECRET`, and the `SMTP_*` settings. To generate the `PAPERCLIP_SECRET`, `SECRET_KEY_BASE`, and `OTP_SECRET`, you may use: docker-compose run --rm web rake secret - Do this once for each of those keys, and copy the result into the .env.production file in - the appropriate field. +Do this once for each of those keys, and copy the result into the `.env.production` file in the appropriate field. -Then you should run the db:migrate command to create the database, or migrate it from an older release: +Then you should run the `db:migrate` command to create the database, or migrate it from an older release: docker-compose run --rm web rails db:migrate @@ -98,7 +97,7 @@ Then, you will also need to precompile the assets: docker-compose run --rm web rails assets:precompile - before you can launch the docker image with: +before you can launch the docker image with: docker-compose up @@ -106,10 +105,10 @@ If you wish to run this as a daemon process instead of monitoring it on console, docker-compose up -d -Then you may login to your new Mastodon instance by browsing to http(s)://(yourhost):3000/ +Then you may login to your new Mastodon instance by browsing to http://localhost:3000/ Following that, make sure that you read the [production guide](docs/Running-Mastodon/Production-guide.md). You are probably going to want to understand how -to configure NGINX to make your Mastodon instance available to the rest of the world. +to configure Nginx to make your Mastodon instance available to the rest of the world. The container has two volumes, for the assets and for user uploads, and optionally two more, for the postgresql and redis databases. @@ -133,17 +132,11 @@ Running any of these tasks via docker-compose would look like this: This approach makes updating to the latest version a real breeze. - git pull - -To pull down the updates, re-run - - docker-compose build - -And finally, - - docker-compose up -d - -Which will re-create the updated containers, leaving databases and data as is. Depending on what files have been updated, you might need to re-run migrations and asset compilation. +1. `git pull` to download updates from the repository +2. `docker-compose build` to compile the Docker image out of the changed source files +3. (optional) `docker-compose run --rm web rails db:migrate` to perform database migrations. Does nothing if your database is up to date +4. (optional) `docker-compose run --rm web rails assets:precompile` to compile new JS and CSS assets +5. `docker-compose up -d` to re-create (restart) containers and pick up the changes ## Deployment without Docker @@ -159,7 +152,7 @@ Docker is great for quickly trying out software, but it has its drawbacks too. I [![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy) -Mastodon can theoretically run indefinitely on a free [Heroku](https://heroku.com) app. [You can view a guide for deployment on Heroku here.](https://github.com/tootsuite/documentation/blob/master/Running-Mastodon/Heroku-guide.md) +Mastodon can run on [Heroku](https://heroku.com), but it gets expensive and impractical due to how Heroku prices resource usage. [You can view a guide for deployment on Heroku here](https://github.com/tootsuite/documentation/blob/master/Running-Mastodon/Heroku-guide.md), but you have been warned. ## Development with Vagrant From dab9b5bd3a3afe829ade39684b996d9ded9ef33b Mon Sep 17 00:00:00 2001 From: karlyeurl Date: Wed, 12 Apr 2017 19:54:16 +0200 Subject: [PATCH 23/32] locale-fr: fix typo (#1603) In this case, the adjective applies to a feminine noun. --- app/assets/javascripts/components/locales/fr.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/components/locales/fr.jsx b/app/assets/javascripts/components/locales/fr.jsx index 9dff8f2b..23d4c358 100644 --- a/app/assets/javascripts/components/locales/fr.jsx +++ b/app/assets/javascripts/components/locales/fr.jsx @@ -107,7 +107,7 @@ const fr = { "privacy.private.short": "Privé", "privacy.private.long": "N’afficher que pour vos abonné⋅e⋅s", "privacy.direct.short": "Direct", - "privacy.direct.long": "N’afficher que pour les personnes mentionné⋅e⋅s", + "privacy.direct.long": "N’afficher que pour les personnes mentionnées", "privacy.change": "Ajuster la confidentialité du message", "media_gallery.toggle_visible": "Modifier la visibilité", "missing_indicator.label": "Non trouvé", From e32edd247f04916270d5b2477c1ff1777e75cf51 Mon Sep 17 00:00:00 2001 From: CgX Date: Wed, 12 Apr 2017 19:56:09 +0200 Subject: [PATCH 24/32] Update fr.yml (#1600) Mistake on %{link} variable --- 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 86dc13d5..0ab75637 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -40,7 +40,7 @@ fr: remote_follow: Suivre à distance unfollow: Ne plus suivre application_mailer: - settings: 'Changer les préférences courriel : ${link}' + settings: 'Changer les préférences courriel : %{link}' signature: Notifications de Mastodon depuis %{instance} view: 'Voir :' applications: From 0254ee9795822ec75ff64ace6ec2b91573bc9a52 Mon Sep 17 00:00:00 2001 From: Ben Roberts Date: Wed, 12 Apr 2017 14:04:33 -0400 Subject: [PATCH 25/32] significant improvement in microformats markup (#1063) * significant improvement in microformats markup This is a huge improvement and I believe will close #965. Had these microformats reviewed by others in the community to help ensure they are at least correct, if not complete. I did not want to change the structure of the page, and so there it does not fully mark up the entire ancestry chain, or reply chain, only the direct decendants and direct ancestors are correctly associated, but this is likely fine as the most important bit is to have access to the urls for those toots which are now correctly fetchable. * improve code climate * trying to pass code climate tests * code climate * fix p-summary for content warning posts * fix error introduced when merging via github --- app/helpers/stream_entries_helper.rb | 24 +++++++++++++++---- app/lib/formatter.rb | 2 +- app/views/accounts/_header.html.haml | 2 +- .../stream_entries/_detailed_status.html.haml | 9 +++---- .../stream_entries/_simple_status.html.haml | 8 +++---- app/views/stream_entries/_status.html.haml | 16 ++++++++++--- app/views/stream_entries/show.html.haml | 2 +- 7 files changed, 44 insertions(+), 19 deletions(-) diff --git a/app/helpers/stream_entries_helper.rb b/app/helpers/stream_entries_helper.rb index 18ef8b90..00a01df4 100644 --- a/app/helpers/stream_entries_helper.rb +++ b/app/helpers/stream_entries_helper.rb @@ -13,15 +13,29 @@ module StreamEntriesHelper "@#{account.acct}#{embedded_view? && account.local? ? "@#{Rails.configuration.x.local_domain}" : ''}" end - def entry_classes(status, is_predecessor, is_successor, include_threads) + def style_classes(status, is_predecessor, is_successor, include_threads) classes = ['entry'] - classes << 'entry-reblog u-repost-of h-cite' if status.reblog? - classes << 'entry-predecessor u-in-reply-to h-cite' if is_predecessor - classes << 'entry-successor u-comment h-cite' if is_successor - classes << 'entry-center h-entry' if include_threads + classes << 'entry-predecessor' if is_predecessor + classes << 'entry-reblog' if status.reblog? + classes << 'entry-successor' if is_successor + classes << 'entry-center' if include_threads classes.join(' ') end + def microformats_classes(status, is_direct_parent, is_direct_child) + classes = [] + classes << 'p-in-reply-to' if is_direct_parent + classes << 'p-repost-of' if status.reblog? && is_direct_parent + classes << 'p-comment' if is_direct_child + classes.join(' ') + end + + def microformats_h_class(status, is_predecessor, is_successor, include_threads) + return 'h-cite' if is_predecessor || status.reblog || is_successor + return 'h-entry' unless include_threads + '' + end + def rtl?(text) return false if text.empty? diff --git a/app/lib/formatter.rb b/app/lib/formatter.rb index c3f331ff..b6d371ed 100644 --- a/app/lib/formatter.rb +++ b/app/lib/formatter.rb @@ -95,6 +95,6 @@ class Formatter end def mention_html(match, account) - "#{match.split('@').first}@#{account.username}" + "#{match.split('@').first}@#{account.username}" end end diff --git a/app/views/accounts/_header.html.haml b/app/views/accounts/_header.html.haml index 0d43fba3..beee96cd 100644 --- a/app/views/accounts/_header.html.haml +++ b/app/views/accounts/_header.html.haml @@ -13,7 +13,7 @@ %h1.name %span.p-name.emojify= display_name(@account) %small - %span.p-nickname= "@#{@account.username}" + %span= "@#{@account.username}" = fa_icon('lock') if @account.locked? .details .bio diff --git a/app/views/stream_entries/_detailed_status.html.haml b/app/views/stream_entries/_detailed_status.html.haml index 466e0dd5..e3cc522b 100644 --- a/app/views/stream_entries/_detailed_status.html.haml +++ b/app/views/stream_entries/_detailed_status.html.haml @@ -5,14 +5,15 @@ = image_tag status.account.avatar.url(:original), width: 48, height: 48, alt: '', class: 'u-photo' %span.display-name %strong.p-name.emojify= display_name(status.account) - %span.p-nickname= acct(status.account) + %span= acct(status.account) - .status__content.e-content.p-name.emojify< + .status__content.p-name.emojify< - if status.spoiler_text? %p{ style: 'margin-bottom: 0' }< - %span>= "#{status.spoiler_text} " + %span.p-summary>= "#{status.spoiler_text} " %a.status__content__spoiler-link{ href: '#' }= t('statuses.show_more') - %div{ style: "display: #{status.spoiler_text? ? 'none' : 'block'}; direction: #{rtl?(status.content) ? 'rtl' : 'ltr'}" }= Formatter.instance.format(status) + %div.e-content{ style: "display: #{status.spoiler_text? ? 'none' : 'block'}; direction: #{rtl?(status.content) ? 'rtl' : 'ltr'}" }= Formatter.instance.format(status) + - unless status.media_attachments.empty? - if status.media_attachments.first.video? diff --git a/app/views/stream_entries/_simple_status.html.haml b/app/views/stream_entries/_simple_status.html.haml index a758d5cc..52905ff5 100644 --- a/app/views/stream_entries/_simple_status.html.haml +++ b/app/views/stream_entries/_simple_status.html.haml @@ -10,14 +10,14 @@ = image_tag status.account.avatar(:original), width: 48, height: 48, alt: '', class: 'u-photo' %span.display-name %strong.p-name.emojify= display_name(status.account) - %span.p-nickname= acct(status.account) + %span= acct(status.account) - .status__content.e-content.p-name.emojify< + .status__content.p-name.emojify< - if status.spoiler_text? %p{ style: 'margin-bottom: 0' }< - %span>= "#{status.spoiler_text} " + %span.p-summary>= "#{status.spoiler_text} " %a.status__content__spoiler-link{ href: '#' }= t('statuses.show_more') - %div{ style: "display: #{status.spoiler_text? ? 'none' : 'block'}; direction: #{rtl?(status.content) ? 'rtl' : 'ltr'}" }= Formatter.instance.format(status) + %div.e-content{ style: "display: #{status.spoiler_text? ? 'none' : 'block'}; direction: #{rtl?(status.content) ? 'rtl' : 'ltr'}" }= Formatter.instance.format(status) - unless status.media_attachments.empty? .status__attachments diff --git a/app/views/stream_entries/_status.html.haml b/app/views/stream_entries/_status.html.haml index 1333d4d8..f389a8df 100644 --- a/app/views/stream_entries/_status.html.haml +++ b/app/views/stream_entries/_status.html.haml @@ -1,12 +1,22 @@ - include_threads ||= false - is_predecessor ||= false - is_successor ||= false +- direct_reply_id ||= false +- parent_id ||= false +- is_direct_parent = direct_reply_id == status.id +- is_direct_child = parent_id == status.in_reply_to_id +- parent_id ||= false - centered ||= include_threads && !is_predecessor && !is_successor +- h_class = microformats_h_class(status, is_predecessor, is_successor, include_threads) +- style_classes = style_classes(status, is_predecessor, is_successor, include_threads) +- mf_classes = microformats_classes(status, is_direct_parent, is_direct_child) +- entry_classes = h_class + ' ' + mf_classes + ' ' + style_classes - if status.reply? && include_threads - = render partial: 'stream_entries/status', collection: @ancestors, as: :status, locals: { is_predecessor: true } + = render partial: 'stream_entries/status', collection: @ancestors, as: :status, locals: { is_predecessor: true, direct_reply_id: status.in_reply_to_id} + +.entry{ class: entry_classes } -.entry{ class: entry_classes(status, is_predecessor, is_successor, include_threads) } - if status.reblog? .pre-header %div.pre-header__icon @@ -19,4 +29,4 @@ = render partial: centered ? 'stream_entries/detailed_status' : 'stream_entries/simple_status', locals: { status: status.proper } - if include_threads - = render partial: 'stream_entries/status', collection: @descendants, as: :status, locals: { is_successor: true } + = render partial: 'stream_entries/status', collection: @descendants, as: :status, locals: { is_successor: true, parent_id: status.id} diff --git a/app/views/stream_entries/show.html.haml b/app/views/stream_entries/show.html.haml index 088881b1..f37fb791 100644 --- a/app/views/stream_entries/show.html.haml +++ b/app/views/stream_entries/show.html.haml @@ -23,5 +23,5 @@ - if !user_signed_in? && !Rails.configuration.x.single_user_mode = render partial: 'shared/landing_strip', locals: { account: @stream_entry.account } -.activity-stream.activity-stream-headless +.activity-stream.activity-stream-headless.h-entry = render partial: "stream_entries/#{@type}", locals: { @type.to_sym => @stream_entry.activity, include_threads: true } From 9b698bf448a030bd091f222fffc17076af9423f5 Mon Sep 17 00:00:00 2001 From: goofy-bz Date: Wed, 12 Apr 2017 20:11:09 +0200 Subject: [PATCH 26/32] Update fr.jsx (#1551) fixing to minor typos --- app/assets/javascripts/components/locales/fr.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/components/locales/fr.jsx b/app/assets/javascripts/components/locales/fr.jsx index 23d4c358..8838c264 100644 --- a/app/assets/javascripts/components/locales/fr.jsx +++ b/app/assets/javascripts/components/locales/fr.jsx @@ -34,7 +34,7 @@ const fr = { "account.report": "Signaler", "account.disclaimer": "Ce compte est situé sur une autre instance. Les nombres peuvent être plus grands.", "getting_started.heading": "Pour commencer", - "getting_started.about_addressing": "Vous pouvez suivre les statuts de quelqu’un en entrant dans le champs de recherche leur identifiant et le domaine de leur instance, séparés par un @ à la manière d’une adresse courriel.", + "getting_started.about_addressing": "Vous pouvez suivre les statuts de quelqu’un en entrant dans le champ de recherche leur identifiant et le domaine de leur instance, séparés par un @ à la manière d’une adresse courriel.", "getting_started.about_shortcuts": "Si cette personne utilise la même instance que vous, l’identifiant suffit. C’est le même principe pour mentionner quelqu’un dans vos statuts.", "getting_started.about_developer": "Pour suivre le développeur de ce projet, c’est Gargron@mastodon.social", "getting_started.open_source_notice": "Mastodon est un logiciel libre. Vous pouvez contribuer et envoyer vos commentaires et rapports de bogues via {github} sur GitHub.", From bf3e56b8ad924156442047ca9e690f851a952476 Mon Sep 17 00:00:00 2001 From: Manato Kameya Date: Thu, 13 Apr 2017 03:19:27 +0900 Subject: [PATCH 27/32] Fix incorrect notation in simple_form.ja.yml (#1620) --- config/locales/simple_form.ja.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/locales/simple_form.ja.yml b/config/locales/simple_form.ja.yml index 565ec74e..acea022c 100644 --- a/config/locales/simple_form.ja.yml +++ b/config/locales/simple_form.ja.yml @@ -7,7 +7,7 @@ ja: display_name: 名前は30文字まで設定することができます。 header: PNGやGIF、JPGは2MBまでです。 700x335pxまで縮小されます。 locked: フォロワーを手動で承認する必要があります。デフォルトでは投稿範囲はフォロワーまでです。 - note: プロフィールは30文字まで設定することができます。 + note: プロフィールは160文字まで設定することができます。 imports: data: CSVファイルからデータをインポートしました。 labels: From 38e24a699b65ba5e397709a3a7d1681da02b173f Mon Sep 17 00:00:00 2001 From: pinfort Date: Thu, 13 Apr 2017 03:19:38 +0900 Subject: [PATCH 28/32] fix Japanese translation (#1623) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add device.ja.yml * update device.ja.yml * add file simple_form.ja.yml * 👍Added doorkeeper.ja.yml * add ja.yml * Update doorkeeper.ja.yml fixed url to uri * update ja.yml * fix some translations * fix japanese grammar of a translate * fix some translates * fix ja.yml * add ja.jsx * add Japanese user mail views * Added japanese translate locales * Added :ja to available_locales こっちも * Added "日本語" to HUMAN_LOCALES * Imported/Added ja to addLocaleData * update ja.jsx * fix translations 翻訳の誤りの修正と改善 * freeの訳修正 * いいねをお気に入りに統一 * Revert "いいねをお気に入りに統一" This reverts commit 568d5cccfa0b6620ccb6c9db8346c52c0396d99f. 間違ってtranslateブランチにコミットしたため取り消し * Revert "freeの訳修正" This reverts commit 565658a60583ff7e1e7a63ef597bf3ac6118e1bf. * revertでミスったので戻す * Revert "ミスったので戻す" This reverts commit 00be7a748a6a2ae85a62be847172424278c52ec7, reversing changes made to b4e1e06503c77e079cb2569a53ab4d6fcfcfd116. * freeの訳修正 * いいねをお気に入りに統一 * 一回戻す * 戻しきれてなかった * 再度変更 * 戻す * 再度変更 * 再度変更 * Update doorkeeper.ja.yml Fixed a lot of unnatural translations * Update ja.yml 資格情報 isn't easy to understanding. so fixed to ログイン情報. * Update ja.yml fixed some unnatural translations * Update simple_form.ja.yml Fixed wrong translate 「アカウント」 to 「アイコン画像」 * Update simple_form.ja.yml * Update doorkeeper.ja.yml * Revert "多くの不自然な翻訳を解消しました。" * Update ja.jsx fixed typo * 文字化け修正 --- app/assets/javascripts/components/locales/ja.jsx | 16 ++++++++-------- config/locales/ja.yml | 6 +++--- config/locales/simple_form.ja.yml | 4 ++-- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/app/assets/javascripts/components/locales/ja.jsx b/app/assets/javascripts/components/locales/ja.jsx index ac451203..7737f148 100644 --- a/app/assets/javascripts/components/locales/ja.jsx +++ b/app/assets/javascripts/components/locales/ja.jsx @@ -16,7 +16,7 @@ const ja = { "status.report": "@{name}さんを報告", "video_player.toggle_sound": "音切り替え", "account.mention": "@{name}さんに返信", - "account.edit_profile": "プロフィール返信", + "account.edit_profile": "プロフィール編集", "account.unblock": "@{name}さんのブロックを解除", "account.unfollow": "フォロー解除", "account.block": "@{name}さんをブロック", @@ -24,7 +24,7 @@ const ja = { "account.posts": "投稿", "account.follows": "フォロー", "account.followers": "フォロワー", - "account.follows_you": "フォロー中", + "account.follows_you": "フォローされています", "account.requested": "承認待ち", "getting_started.heading": "スタート", "getting_started.about_addressing": "ドメインとユーザー名を知っているなら検索フォームに入力すればフォローできます。", @@ -58,15 +58,15 @@ const ja = { "upload_button.label": "メディアを追加", "upload_form.undo": "やり直す", "notification.follow": "{name}さんにフォローされました", - "notification.favourite": "{name}さんがあなたのトゥートをいいねしました", + "notification.favourite": "{name}さんがあなたのトゥートをお気に入りしました", "notification.reblog": "{name}さんがあなたのトゥートをブーストしました", "notification.mention": "{name}さんがあなたに返信しました", "notifications.column_settings.alert": "デスクトップ通知", - "notifications.column_settings.show": "表示項目", - "notifications.column_settings.follow": "新しいフォロワー:", - "notifications.column_settings.favourite": "いいね:", - "notifications.column_settings.mention": "返信:", - "notifications.column_settings.reblog": "ブースト:", + "notifications.column_settings.show": "カラムに表示", + "notifications.column_settings.follow": "新しいフォロワー", + "notifications.column_settings.favourite": "お気に入り", + "notifications.column_settings.mention": "返信", + "notifications.column_settings.reblog": "ブースト", }; export default ja; diff --git a/config/locales/ja.yml b/config/locales/ja.yml index d30fd348..4a1675fd 100644 --- a/config/locales/ja.yml +++ b/config/locales/ja.yml @@ -1,7 +1,7 @@ --- ja: about: - about_mastodon: Mastodon は無料でオープンソースのソーシャルネットワークです。 従来のプラットフォームとは違う分散型で、これはあなたの会話が一つの会社によって独占されるのを防ぎます。自分の信頼できるサーバーを選びます— どのサーバーを選んでも、誰とでも会話することができます。 だれでも自分の Mastodon サーバーを作ることができ、シームレスにソーシャルネットワークに参加できます。 + about_mastodon: Mastodon は自由なオープンソースのソーシャルネットワークです。 従来のプラットフォームとは違う分散型で、これはあなたの会話が一つの会社によって独占されるのを防ぎます。自分の信頼できるサーバーを選びます— どのサーバーを選んでも、誰とでも会話することができます。 だれでも自分の Mastodon サーバーを作ることができ、シームレスにソーシャルネットワークに参加できます。 about_this: このサーバーについて apps: アプリ business_email: 'ビジネスメールアドレス:' @@ -109,8 +109,8 @@ ja: one: "新しい1つの通知 \U0001F418" other: "新しい%{count}つの通知 \U0001F418" favourite: - body: 'あなたのステータスが%{name}さんにいいねされました:' - subject: "%{name}さんがあなたのステータスをいいねしました" + body: 'あなたのステータスが%{name}さんにお気に入りされました:' + subject: "%{name}さんがあなたのステータスをお気に入りしました" follow: body: "%{name}さんにフォローされています" subject: "%{name}さんにフォローされています" diff --git a/config/locales/simple_form.ja.yml b/config/locales/simple_form.ja.yml index acea022c..9cdf650a 100644 --- a/config/locales/simple_form.ja.yml +++ b/config/locales/simple_form.ja.yml @@ -34,11 +34,11 @@ ja: must_be_following: フォローしていないユーザーからの通知をブロック notification_emails: digest: タイムラインからピックアップしてメールで通知する - favourite: いいねされた時メールで通知する + favourite: お気に入りされた時メールで通知する follow: フォローされた時メールで通知する follow_request: フォローリクエストを受けた時メールで通知する mention: 返信された時メールで通知する - reblog: あなたのトゥートがブーストされた時メールで通知する + reblog: ブーストされた時メールで通知する 'no': 'いいえ' required: mark: "*" From e1264bbd92718cd6d78bed8c2d1ad9cb96384fea Mon Sep 17 00:00:00 2001 From: Knut Erik Date: Wed, 12 Apr 2017 20:28:56 +0200 Subject: [PATCH 29/32] Added norwegian version of terms of service and privacy policy (#1625) --- app/views/about/terms.no.html.haml | 76 ++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 app/views/about/terms.no.html.haml diff --git a/app/views/about/terms.no.html.haml b/app/views/about/terms.no.html.haml new file mode 100644 index 00000000..5506cd86 --- /dev/null +++ b/app/views/about/terms.no.html.haml @@ -0,0 +1,76 @@ +- content_for :page_title do + #{Rails.configuration.x.local_domain} Personvern og villkår for bruk av nettstedet + +.wrapper + %h2 Personvernserklæring + + %h3#collect Hvilke opplysninger samler vi? + + %p Vi samler opplysninger fra deg når du registrerer deg på nettstedet vårt, og vi samler data når du deltar på forumet ved å lese, skrive og evaluere innholdet som deles her. + + %p Når du registrerer deg på nettstedet vårt, kan du bli bedt om å oppgi navnet og e-postadressen din. Imidlertid kan du besøke nettstedet vårt uten å registrere deg. E-postadressen din vil bli bekreftet med en e-post som inneholder en unik lenke. Hvis siden den lenker til, blir besøkt, vet vi at du har kontroll over e-postadressen. + + %p Når du registrerer deg og skriver innlegg, registrerer vi IP-adressen som innlegget stammer fra. Vi kan også oppbevare logger som inkluderer IP-adressen til alle forespørslene sendt til tjeneren vår. + + %h3#use Hva bruker vi opplysningene dine til? + + %p Alle opplysningene vi samler fra deg, kan bli brukt på en av følgende måter: + + %ul + %li For å gjøre opplevelsen din mer personlig. Opplysningene dine hjelper oss å svare bedre på dine individuelle behov. + %li For å forbedre nettstedet vårt. Vi jobber konstant for å forbedre nettstedets tilbud basert på opplysningene og tilbakemeldingene vi mottar fra deg. + %li For å forbedre vår kundeservice. Dine opplysninger hjelper oss å svare mer effektivt på dine forespørsler sendt til kundeservice eller behov om støtte. + %li For å sende periodiske e-poster. E-postadressen du oppgir, kan bli brukt til å sende deg informasjon, påminnelser som du ber om ved endringer av emner eller ved svar til brukernavnet ditt, til henvendelser, og/eller andre forspørsler eller andre spørsmål. + + %h3#protect Hvordan sikrer vi opplysningene? + + %p Vi gjennomfører flere sikkerhetstiltak for å holde personopplysningene dine sikre når du skriver inn, lagrer eller henter dem. + + %h3#data-retention Hva er retningslinjene deres for lagring av data? + + %p Vi vil forsøke i god tro å: + + %ul + %li Ikke oppbevare tjener-logger som inneholder IP-adressen til alle forespørslene til denne tjeneren i lenger enn i 90 dager. + %li Ikke oppbevare IP-adressene forbundet med registrerte brukere og deres innlegg lenger enn i 5 år. + + %h3#cookies Bruker vi informasjonskapsler? + + %p Ja. Informasjonskapsler er små filer som et nettsted eller dets tjenesteleverandør overfører til harddisken på datamaskinen din gjennom nettleseren din (dersom du tillater det). Disse informasjonskapslene gjør det mulig for nettstedet å gjenkjenne nettleseren din og, dersom du har en konto, knytte nettleseren til den. + + %p Vi bruker informasjonskapsler for å forstå og lagre preferansene dine for fremtidige besøk og for å samle aggregatdata om trafikk på og samhandling med nettstedet slik at vi kan tilby bedre opplevelser og verktøy på nettstedet i fremtiden. Vi kan inngå avtaler med tredjeparts tjenesteleverandører for å bistå oss i å forstå besøkerne våres bedre. Disse tjenesteleverandørene har ikke lov til å bruke opplysningene samlet på våres vegne unntatt til å hjelpe oss å gjennomføre og forbedre anliggendet vårt. + + %h3#disclose Gir vi noen opplysninger videre til andre parter? + + %p Vi verken selger, handler med eller overfører på noen annen måte til andre parter dine identifiserbare personopplysninger. Dette inkluderer ikke tredjeparter som har vår tillit og bistår oss i å drive nettstedet, utføre våre anliggender eller yter tjenester til deg, så lenge disse partene samtykker til å behandle disse opplysningene fortrolig. Vi kan også frigi opplysningene dine dersom vi tror at å frigi dem er hensiktsmessig for å overholde loven, håndheve nettstedet retningslinjer eller beskytte våre og andres rettigheter. Imidlertid kan opplysninger som ikke er personlig identifiserbare, bli delt med andre parter for markedsføring, reklame eller annet bruk. + + %h3#third-party Tredjeparts lenker + + %p Av og til, etter skjønn, kan vil inkludere eller tilby tredjeparts produkter eller tjenester på nettstedet vårt. Disse tredjeparts nettstedene har separate og selvstendige personvernerklæringer. Vi bærer derfor intet ansvar eller forpliktelser for innholdet eller aktivitetene til disse nettstedene det lenkes til. Ikke mindre prøver vi å bevare vår eget nettsteds integritet og ønsker enhver tilbakemelding om disse nettstedene velkomne. + + %h3#coppa Overensstemmelse med Children's Online Privacy Protection Act + + %p + Nettstedet er rettet mot folk som er minst 13 år gamle. Dersom denne tjeneren er i USA, og du er under 13 år i henhold til kravene i COPPA + = surround '(', '),' do + = link_to 'Children\'s Online Privacy Protection Act', 'https://en.wikipedia.org/wiki/Children%27s_Online_Privacy_Protection_Act' + ikke bruk dette nettstedet. + + %h3#online Personvernerklæring bare for nettet + + %p Denne nett-personvernerklæringen gjelder bare for informasjon samlet gjennom nettstedet vårt og ikke for opplysninger samlet når en er frakoblet. + + %h3#consent Ditt samtykke + + %p Ved å bruke dette nettstedet samtykker du til nettstedets personvernerklæring. + + %h3#changes Endringer i vår personvernerklæring + + %p Dersom vi beslutter å endre personvernerklæringen vår, vil vi publisere disse endringene på denne siden. + + %p Dette dokumentet er lisensiert under CC-BY-SA. De ble sist oppdatert 12. april 2017. + + %p + Dokumentet er en adoptert og endret versjon fra + = succeed '.' do + = link_to 'Discourse privacy policy', 'https://github.com/discourse/discourse' From b0ab632531c82c2c84c557c7c12afb8a91074e2e Mon Sep 17 00:00:00 2001 From: Isabelle Knott Date: Wed, 12 Apr 2017 14:40:03 -0400 Subject: [PATCH 30/32] Fix missing compose box when viewport width is exactly 1024px (#1632) --- app/assets/stylesheets/components.scss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/assets/stylesheets/components.scss b/app/assets/stylesheets/components.scss index 8e4a667e..1c7f375b 100644 --- a/app/assets/stylesheets/components.scss +++ b/app/assets/stylesheets/components.scss @@ -59,7 +59,7 @@ z-index: 2; } -@media screen and (min-width: 1024px) { +@media screen and (min-width: 1025px) { .column-icon-clear { top: 10px; } @@ -857,7 +857,7 @@ a.status__content__spoiler-link { } } -@media screen and (min-width: 1024px) { +@media screen and (min-width: 1025px) { .columns-area { padding: 0; } From 9966bd27c2f568b34dc6d6d428301120b2153182 Mon Sep 17 00:00:00 2001 From: lindwurm Date: Thu, 13 Apr 2017 03:41:50 +0900 Subject: [PATCH 31/32] [l10n] ja: Improve Japanese Translations (#1631) * ja: about: Fix highlighting * ja: Update Translations * ja: Translate admin settings Signed-off-by: lindwurm --- .../javascripts/components/locales/ja.jsx | 49 +++++--- config/locales/doorkeeper.ja.yml | 10 +- config/locales/ja.yml | 118 +++++++++++------- config/locales/simple_form.ja.yml | 27 ++-- 4 files changed, 122 insertions(+), 82 deletions(-) diff --git a/app/assets/javascripts/components/locales/ja.jsx b/app/assets/javascripts/components/locales/ja.jsx index 7737f148..25a6f7f6 100644 --- a/app/assets/javascripts/components/locales/ja.jsx +++ b/app/assets/javascripts/components/locales/ja.jsx @@ -2,24 +2,26 @@ const ja = { "column_back_button.label": "戻る", "lightbox.close": "閉じる", "loading_indicator.label": "読み込み中...", - "status.mention": "@{name}さんへの返信", + "status.mention": "@{name} さんへの返信", "status.delete": "削除", "status.reply": "返信", "status.reblog": "ブースト", "status.favourite": "お気に入り", - "status.reblogged_by": "{name}さんにブーストされました", + "status.reblogged_by": "{name} さんにブーストされました", "status.sensitive_warning": "不適切なコンテンツ", - "status.sensitive_toggle": "見るにはクリック", + "status.sensitive_toggle": "クリックして表示", "status.show_more": "もっと見る", "status.show_less": "隠す", "status.open": "Expand this status", - "status.report": "@{name}さんを報告", - "video_player.toggle_sound": "音切り替え", - "account.mention": "@{name}さんに返信", - "account.edit_profile": "プロフィール編集", - "account.unblock": "@{name}さんのブロックを解除", + "status.report": "@{name} さんを報告", + "video_player.toggle_sound": "音の切り替え", + "account.mention": "@{name} さんに返信", + "account.edit_profile": "プロフィールを編集", + "account.unblock": "@{name} さんのブロックを解除", "account.unfollow": "フォロー解除", - "account.block": "@{name}さんをブロック", + "account.block": "@{name} さんをブロック", + "account.mute": "ミュート", + "account.unmute": "ミュート解除", "account.follow": "フォロー", "account.posts": "投稿", "account.follows": "フォロー", @@ -29,15 +31,16 @@ const ja = { "getting_started.heading": "スタート", "getting_started.about_addressing": "ドメインとユーザー名を知っているなら検索フォームに入力すればフォローできます。", "getting_started.about_shortcuts": "対象のアカウントがあなたと同じドメインのユーザーならばユーザー名のみで検索できます。これは返信のときも一緒です。", - "getting_started.open_source_notice": "Mastodon はオープンソースのソフトウェアです。誰でもGitHub({github})から開発に参加したり、問題を報告したりできます。 {apps}", + "getting_started.open_source_notice": "Mastodon はオープンソースソフトウェアです。誰でも GitHub({github})から開発に参加したり、問題を報告したりできます。 {apps}", "column.home": "ホーム", "column.community": "ローカルタイムライン", - "column.public": "連邦タイムライン", + "column.public": "連合タイムライン", "column.notifications": "通知", - "tabs_bar.compose": "Compose", + "tabs_bar.compose": "投稿", "tabs_bar.home": "ホーム", "tabs_bar.mentions": "返信", - "tabs_bar.public": "連邦タイムライン", + "tabs_bar.local_timeline": "ローカルTL", + "tabs_bar.federated_timeline": "連合TL", "tabs_bar.notifications": "通知", "compose_form.placeholder": "今なにしてる?", "compose_form.publish": "トゥート", @@ -46,27 +49,35 @@ const ja = { "compose_form.private": "非公開にする", "compose_form.privacy_disclaimer": "あなたの非公開トゥートは返信先のユーザー(at {domains})に公開されます。{domainsCount, plural, one {that server} other {those servers}}を信頼しますか?投稿のプライバシー保護はMastodonサーバー内でのみ有効です。 もし{domains} {domainsCount, plural, one {is not a Mastodon instance} other {are not Mastodon instances}}ならばあなたの投稿のプライバシーは保護されず、ブーストされたり予期しないユーザーに見られる可能性があります。", "compose_form.unlisted": "公開タイムラインに表示しない", - "navigation_bar.edit_profile": "プロフィール編集", + "navigation_bar.edit_profile": "プロフィールを編集", "navigation_bar.preferences": "ユーザー設定", "navigation_bar.community_timeline": "ローカルタイムライン", - "navigation_bar.public_timeline": "連邦タイムライン", + "navigation_bar.public_timeline": "連合タイムライン", "navigation_bar.logout": "ログアウト", + "navigation_bar.favourites": "お気に入り", + "navigation_bar.blocks": "ブロックしたユーザー", + "navigation_bar.info": "サーバー情報", "reply_indicator.cancel": "キャンセル", "search.placeholder": "検索", "search.account": "アカウント", "search.hashtag": "ハッシュタグ", "upload_button.label": "メディアを追加", "upload_form.undo": "やり直す", - "notification.follow": "{name}さんにフォローされました", - "notification.favourite": "{name}さんがあなたのトゥートをお気に入りしました", - "notification.reblog": "{name}さんがあなたのトゥートをブーストしました", - "notification.mention": "{name}さんがあなたに返信しました", + "notification.follow": "{name} さんにフォローされました", + "notification.favourite": "{name} さんがあなたのトゥートをお気に入りに登録しました", + "notification.reblog": "{name} さんがあなたのトゥートをブーストしました", + "notification.mention": "{name} さんがあなたに返信しました", "notifications.column_settings.alert": "デスクトップ通知", "notifications.column_settings.show": "カラムに表示", "notifications.column_settings.follow": "新しいフォロワー", "notifications.column_settings.favourite": "お気に入り", "notifications.column_settings.mention": "返信", "notifications.column_settings.reblog": "ブースト", + "notifications.column_settings.sound": "通知音を再生", + "empty_column.home": "まだ誰もフォローしていません。{public}を見に行くか、検索を使って他のユーザーを見つけましょう。", + "empty_column.home.public_timeline": "連合タイムライン", + "empty_column.notifications": "まだ通知がありません。他の人とふれ合って会話を始めましょう。", + "empty_column.public": "ここにはまだ何もありません!公開で何かを投稿したり、他のインスタンスのユーザーをフォローしたりしていっぱいにしましょう!", }; export default ja; diff --git a/config/locales/doorkeeper.ja.yml b/config/locales/doorkeeper.ja.yml index 7c6a1405..35592bc4 100644 --- a/config/locales/doorkeeper.ja.yml +++ b/config/locales/doorkeeper.ja.yml @@ -60,15 +60,15 @@ ja: title: 認証コード authorized_applications: buttons: - revoke: 取り消す + revoke: 取消 confirmations: revoke: 本当に取り消しますか? index: - application: アプリケーション - created_at: 認証済み + application: アプリ名 + created_at: 許可した日時 date_format: "%Y年%m月%d日 %H時%M分%S秒" scopes: アクセス権 - title: あなたの認証済みアプリケーション + title: 認証済みアプリケーション errors: messages: access_denied: リソースの所有者または認証サーバーが要求を拒否しました。 @@ -83,7 +83,7 @@ ja: expired: アクセストークンの有効期限が切れています revoked: アクセストークンは取り消されています。 unknown: アクセストークンが無効です。 - resource_owner_authenticator_not_configured: Doorkeeper.configure.resource_owner_authenticatorが設定されていないため、リソース所有者の検索に失敗しました。 + resource_owner_authenticator_not_configured: Doorkeeper.configure.resource_owner_authenticator が設定されていないため、リソース所有者の検索に失敗しました。 server_error: 認証サーバーに予期せぬ例外が発生したため、リクエストを実行できなくなりました。 temporarily_unavailable: 現在、認証サーバーに一時的な過負荷が掛かっているか、またはメンテナンス中のため、リクエストを処理できません。 unauthorized_client: クライアントはこのメゾットで要求を実行する権限がありません。 diff --git a/config/locales/ja.yml b/config/locales/ja.yml index 4a1675fd..9407c766 100644 --- a/config/locales/ja.yml +++ b/config/locales/ja.yml @@ -1,32 +1,32 @@ --- ja: about: - about_mastodon: Mastodon は自由なオープンソースのソーシャルネットワークです。 従来のプラットフォームとは違う分散型で、これはあなたの会話が一つの会社によって独占されるのを防ぎます。自分の信頼できるサーバーを選びます— どのサーバーを選んでも、誰とでも会話することができます。 だれでも自分の Mastodon サーバーを作ることができ、シームレスにソーシャルネットワークに参加できます。 - about_this: このサーバーについて + about_mastodon: Mastodon は自由でオープンソースなソーシャルネットワークです。商用プラットフォームの代替となる分散型を採用し、あなたのやりとりが一つの会社によって独占されるのを防ぎます。信頼できるインスタンスを選択してください — どのインスタンスを選んでも、誰とでもやりとりすることができます。 だれでも自分の Mastodon インスタンスを作ることができ、シームレスにソーシャルネットワークに参加できます。 + about_this: このインスタンスについて apps: アプリ business_email: 'ビジネスメールアドレス:' - closed_registrations: 現在このサーバーでの新規登録は受け付けていません。 + closed_registrations: 現在このインスタンスでの新規登録は受け付けていません。 contact: 連絡先 - description_headline: '%{domain}とは?' - domain_count_after: 個のサーバー + description_headline: '%{domain} とは?' + domain_count_after: 個のインスタンス domain_count_before: 接続中 features: api: アプリやその他サービスにAPIを公開 - blocks: ブロックやミュートの種類は豊富 - characters: 1投稿は500文字まで可能 - chronology: 時系列に沿ったタイムライン - ethics: 広告も行動追跡もなく、プライバシーにも配慮 + blocks: 豊富なブロックやミュート機能 + characters: 1つの投稿は500文字まで利用可能 + chronology: 時系列順のタイムライン + ethics: 広告もトラッキングもありません gifv: GIFVや短い動画にも対応 - privacy: 細かく投稿ごとに公開範囲が設定可能 + privacy: 投稿ごとに公開範囲を細かく設定可能 public: 公開タイムライン - features_headline: Mastodonの特徴 - get_started: 始める + features_headline: Mastodon の特徴 + get_started: 参加する links: リンク - other_instances: 他のサーバー + other_instances: 他のインスタンス source_code: ソースコード status_count_after: トゥート status_count_before: トゥート数 - terms: 規約 + terms: プライバシーポリシー user_count_after: 人 user_count_before: ユーザー数 accounts: @@ -34,14 +34,14 @@ ja: followers: フォロワー following: フォロー中 nothing_here: 何もありません - people_followed_by: '%{name}さんをフォロー中のアカウント' - people_who_follow: '%{name}さんがフォロー中のアカウント' + people_followed_by: '%{name} さんをフォロー中のアカウント' + people_who_follow: '%{name} さんがフォロー中のアカウント' posts: 投稿 remote_follow: リモートフォロー unfollow: フォロー解除 application_mailer: settings: 'メール設定の変更: %{link}' - signature: 'Mastodon %{instance}サーバーからの通知' + signature: 'Mastodon %{instance} インスタンスからの通知' view: 'View:' applications: invalid_url: URLが無効です @@ -51,15 +51,15 @@ ja: forgot_password: パスワードをお忘れですか? login: ログイン logout: ログアウト - register: サインアップ + register: 登録する resend_confirmation: 確認メールを再送する - reset_password: パスワード再発行 + reset_password: パスワードを再発行 set_new_password: 新しいパスワード authorize_follow: error: 残念ながら、リモートアカウントにエラーが発生しました。 follow: フォロー - prompt_html: 'あなた (%{self}) は以下のアカウントのフォローをリクエストしました:' - title: '%{acct}をフォロー' + prompt_html: 'あなた(%{self})は以下のアカウントのフォローをリクエストしました:' + title: '%{acct} をフォロー' datetime: distance_in_words: about_x_hours: "%{count}時間" @@ -87,42 +87,42 @@ ja: one: エラーが発生しました。以下のエラーを確認してください other: エラーが発生しました。以下の%{count}個のエラーを確認してください imports: - preface: このサーバーのあなたのアカウントにフォロー、ブロック、などの他のサーバーからエクスポートされたファイルの情報をインポートできます。 + preface: 他のインスタンスでエクスポートされたファイルから、フォロー/ブロックした情報をこのインスタンス上のアカウントにインポートできます。 success: ファイルは正常にアップロードされ、現在処理中です。しばらくしてから確認してください types: blocking: ブロック中のアカウントリスト following: フォロー中のアカウントリスト upload: アップロード - landing_strip_html: %{name}さんはサーバー%{domain}のユーザーです。アカウントさえ持っていればフォローしたり会話したりできます。もしお持ちでないならこちらからサインアップできます。 + landing_strip_html: %{name} さんはインスタンス %{domain} のユーザーです。アカウントさえ持っていればフォローしたり会話したりできます。もしお持ちでないなら こちら からサインアップできます。 media_attachments: validations: - images_and_video: 既に画像が追加されている場合動画を追加することはできません。 + images_and_video: 既に画像が追加されているため、動画を追加することはできません。 too_many: 追加できるファイルは4つまでです。 notification_mailer: digest: - body: '%{instance}での最後のログインからの出来事:' - mention: "%{name}さんがあなたに返信しました:" + body: '%{instance} での最後のログインからの出来事:' + mention: "%{name} さんがあなたに返信しました:" new_followers_summary: one: 新たなフォロワーを獲得しました! - other: '%{count}人の新たなフォロワーを獲得しました!' + other: '%{count} 人の新たなフォロワーを獲得しました!' subject: - one: "新しい1つの通知 \U0001F418" - other: "新しい%{count}つの通知 \U0001F418" + one: "新しい1件の通知 \U0001F418" + other: "新しい%{count}件の通知 \U0001F418" favourite: - body: 'あなたのステータスが%{name}さんにお気に入りされました:' - subject: "%{name}さんがあなたのステータスをお気に入りしました" + body: 'あなたのトゥートが %{name} さんにお気に入り登録されました:' + subject: "%{name} さんがあなたのトゥートをお気に入りに登録しました" follow: - body: "%{name}さんにフォローされています" - subject: "%{name}さんにフォローされています" + body: "%{name} さんにフォローされています" + subject: "%{name} さんにフォローされています" follow_request: - body: "%{name}さんがあなたにフォローをリクエストしました。" - subject: '%{name}さんからのフォローリクエスト' + body: "%{name} さんがあなたにフォローをリクエストしました。" + subject: '%{name} さんからのフォローリクエスト' mention: - body: '%{name}さんから返信がありました:' - subject: '%{name}さんに返信されました' + body: '%{name} さんから返信がありました:' + subject: '%{name} さんに返信されました' reblog: - body: 'あなたのステータスが%{name}さんにブーストされました:' - subject: "あなたのステータスが%{name}さんにブーストされました" + body: 'あなたのトゥートが %{name} さんにブーストされました:' + subject: "あなたのトゥートが %{name} さんにブーストされました" pagination: next: 次 prev: 前 @@ -134,7 +134,7 @@ ja: settings: authorized_apps: 認証済みアプリ back: 戻る - edit_profile: プロフィール編集 + edit_profile: プロフィールを編集 export: データのエクスポート import: データのインポート preferences: ユーザー設定 @@ -142,14 +142,14 @@ ja: two_factor_auth: 二段階認証 statuses: open_in_web: Webで開く - over_character_limit: '%{max}文字までしか入力できません' + over_character_limit: '上限は %{max}文字までです' show_more: もっと見る visibilities: - private: フォロワーだけに見せる - public: 公開 - unlisted: 公開されますが、公開タイムラインには載りません + private: Private - フォロワーだけに見せる + public: Public - 全体に公開する + unlisted: Unlisted - トゥートは公開するが、公開タイムラインには表示しない stream_entries: - click_to_show: 見るにはクリック + click_to_show: クリックして表示 reblogged: ブーストされました sensitive_content: 不適切なコンテンツの可能性があります time: @@ -171,3 +171,31 @@ ja: invalid_otp_token: 二段階認証コードが間違っています will_paginate: page_gap: "…" + + errors: + 404: お探しのページは見つかりませんでした。 + 410: お探しのページはもう存在しません。 + 422: + title: セキュリティ認証に失敗 + content: セキュリティ認証に失敗しました。Cookieをブロックしていませんか? + admin: + settings: + title: サイト設定 + setting: 設定 + click_to_edit: クリックして編集 + contact_information: + label: 連絡先情報 + username: ユーザー名を入力 + email: 公開するメールアドレスを入力 + site_title: サイトのタイトル + site_description: + title: サイトの説明文 + desc_html: "トップページへの表示と meta タグに使用されます。
HTMLタグ、特に<a> and <em>が利用可能です。" + site_description_extended: + title: サイトの詳細な説明 + desc_html: "インスタンスについてのページに表示されます。
HTMLタグが利用可能です。" + registrations: + open: + title: 新規登録を受け付ける + enabled: 有効 + disabled: 無効 diff --git a/config/locales/simple_form.ja.yml b/config/locales/simple_form.ja.yml index 9cdf650a..bdf8e0f5 100644 --- a/config/locales/simple_form.ja.yml +++ b/config/locales/simple_form.ja.yml @@ -3,17 +3,17 @@ ja: simple_form: hints: defaults: - avatar: PNGやGIF、JPGは2MBまでです。120x120pxまで縮小されます。 + avatar: 2MBまでのPNGやGIF、JPGが利用可能です。120x120pxまで縮小されます。 display_name: 名前は30文字まで設定することができます。 - header: PNGやGIF、JPGは2MBまでです。 700x335pxまで縮小されます。 - locked: フォロワーを手動で承認する必要があります。デフォルトでは投稿範囲はフォロワーまでです。 + header: 2MBまでのPNGやGIF、JPGが利用可能です。 700x335pxまで縮小されます。 + locked: フォロワーを手動で承認する必要があります。デフォルトではトゥートの公開範囲はフォロワーのみです。 note: プロフィールは160文字まで設定することができます。 imports: - data: CSVファイルからデータをインポートしました。 + data: 他の Mastodon サーバーからエクスポートしたCSVファイルを選択して下さい labels: defaults: - avatar: アカウント - confirm_new_password: 新しいパスワード(確認用) + avatar: アイコン + confirm_new_password: 新しいパスワード(確認用) confirm_password: 新しいパスワード current_password: 現在のパスワード data: データ @@ -26,19 +26,20 @@ ja: note: プロフィール otp_attempt: 二段階認証コード password: パスワード - setting_default_privacy: 投稿範囲 - type: インポートするファイルの種類 + setting_default_privacy: 投稿の公開範囲 + type: インポートする項目 username: ユーザー名 + setting_boost_modal: ブーストする前に確認ダイアログを表示する interactions: must_be_follower: フォロワー以外からの通知をブロック must_be_following: フォローしていないユーザーからの通知をブロック notification_emails: digest: タイムラインからピックアップしてメールで通知する - favourite: お気に入りされた時メールで通知する - follow: フォローされた時メールで通知する - follow_request: フォローリクエストを受けた時メールで通知する - mention: 返信された時メールで通知する - reblog: ブーストされた時メールで通知する + favourite: お気に入りに登録された時にメールで通知する + follow: フォローされた時にメールで通知する + follow_request: フォローリクエストを受けた時にメールで通知する + mention: 返信が来た時にメールで通知する + reblog: トゥートがブーストされた時にメールで通知する 'no': 'いいえ' required: mark: "*" From bd834add567fc0a0f3960385a7f9abe4324ff212 Mon Sep 17 00:00:00 2001 From: Eugen Date: Wed, 12 Apr 2017 20:54:49 +0200 Subject: [PATCH 32/32] Fix visuals introduced in #1463 (#1634) --- app/assets/stylesheets/accounts.scss | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/assets/stylesheets/accounts.scss b/app/assets/stylesheets/accounts.scss index 407e917b..f9a69882 100644 --- a/app/assets/stylesheets/accounts.scss +++ b/app/assets/stylesheets/accounts.scss @@ -14,7 +14,7 @@ } &:after { - background: rgba($color8, 0.5); + background: linear-gradient(rgba($color8, 0.5), rgba($color8, 0.8)); display: block; content: ""; position: absolute; @@ -72,7 +72,6 @@ position: relative; z-index: 2; flex-direction: row; - background: rgba(0,0,0,0.5); } .details-counters { @@ -388,6 +387,5 @@ .account__header__content { font-size: 14px; color: $color1; - text-shadow: 0 0 2px $color8; } }