From 1ea662963f447bd7a1682afb939f8ff3886aa062 Mon Sep 17 00:00:00 2001 From: Isabelle Knott Date: Wed, 12 Apr 2017 20:15:45 -0400 Subject: [PATCH 01/43] Use shift+click instead of alt+click to bypass boost dialog (#1638) --- .../javascripts/components/containers/status_container.jsx | 2 +- app/assets/javascripts/components/features/status/index.jsx | 2 +- .../components/features/ui/components/boost_modal.jsx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/assets/javascripts/components/containers/status_container.jsx b/app/assets/javascripts/components/containers/status_container.jsx index f92c1cdf..fedf80fb 100644 --- a/app/assets/javascripts/components/containers/status_container.jsx +++ b/app/assets/javascripts/components/containers/status_container.jsx @@ -47,7 +47,7 @@ const mapDispatchToProps = (dispatch) => ({ if (status.get('reblogged')) { dispatch(unreblog(status)); } else { - if (e.altKey || !this.boostModal) { + if (e.shiftKey || !this.boostModal) { this.onModalReblog(status); } else { dispatch(openModal('BOOST', { status, onReblog: this.onModalReblog })); diff --git a/app/assets/javascripts/components/features/status/index.jsx b/app/assets/javascripts/components/features/status/index.jsx index 91302bc3..48fea658 100644 --- a/app/assets/javascripts/components/features/status/index.jsx +++ b/app/assets/javascripts/components/features/status/index.jsx @@ -92,7 +92,7 @@ const Status = React.createClass({ if (status.get('reblogged')) { this.props.dispatch(unreblog(status)); } else { - if (e.altKey || !this.props.boostModal) { + if (e.shiftKey || !this.props.boostModal) { this.handleModalReblog(status); } else { this.props.dispatch(openModal('BOOST', { status, onReblog: this.handleModalReblog })); diff --git a/app/assets/javascripts/components/features/ui/components/boost_modal.jsx b/app/assets/javascripts/components/features/ui/components/boost_modal.jsx index 023abc6a..b5476863 100644 --- a/app/assets/javascripts/components/features/ui/components/boost_modal.jsx +++ b/app/assets/javascripts/components/features/ui/components/boost_modal.jsx @@ -65,7 +65,7 @@ const BoostModal = React.createClass({
-
Alt + }} />
+
Shift + }} />
From ccaf3dbc5ad2df867fe05fa5291d62cf2bc377d2 Mon Sep 17 00:00:00 2001 From: Thor Harald Johansen Date: Thu, 13 Apr 2017 02:17:26 +0200 Subject: [PATCH 02/43] Adjustments to the Norwegian translation (#1648) * Working translation for Norwegian. * Fixes to Norwegian translation. * Further adjustments to Norwegian translation. * Further adjustments to Norwegian translation. --- .../javascripts/components/locales/no.jsx | 15 +++++++---- config/locales/no.yml | 26 +++++++++---------- config/locales/simple_form.no.yml | 9 ++++--- 3 files changed, 28 insertions(+), 22 deletions(-) diff --git a/app/assets/javascripts/components/locales/no.jsx b/app/assets/javascripts/components/locales/no.jsx index 3b937246..64b53fb1 100644 --- a/app/assets/javascripts/components/locales/no.jsx +++ b/app/assets/javascripts/components/locales/no.jsx @@ -6,7 +6,7 @@ const no = { "status.delete": "Slett", "status.reply": "Svar", "status.reblog": "Reblogg", - "status.favourite": "Favoritt", + "status.favourite": "Lik", "status.reblogged_by": "{name} reblogget", "status.sensitive_warning": "Sensitivt innhold", "status.sensitive_toggle": "Klikk for å vise", @@ -32,12 +32,14 @@ const no = { "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.public": "Forent tidslinje", "column.notifications": "Varslinger", + "column.blocks": "Blokkerte brukere", + "column.favourites": "Likt", "tabs_bar.compose": "Komponer", "tabs_bar.home": "Hjem", "tabs_bar.mentions": "Nevninger", - "tabs_bar.public": "Føderert tidslinje", + "tabs_bar.public": "Forent tidslinje", "tabs_bar.notifications": "Varslinger", "compose_form.placeholder": "Hva har du på hjertet?", "compose_form.publish": "Tut", @@ -49,8 +51,11 @@ const no = { "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.public_timeline": "Forent tidslinje", "navigation_bar.logout": "Logg ut", + "navigation_bar.blocks": "Blokkerte brukere", + "navigation_bar.info": "Utvidet informasjon", + "navigation_bar.favourites": "Likt", "reply_indicator.cancel": "Avbryt", "search.placeholder": "Søk", "search.account": "Konto", @@ -64,7 +69,7 @@ const no = { "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.favourite": "Likt:", "notifications.column_settings.mention": "Nevninger:", "notifications.column_settings.reblog": "Reblogginger:", }; diff --git a/config/locales/no.yml b/config/locales/no.yml index 28bc066d..d13d90c2 100644 --- a/config/locales/no.yml +++ b/config/locales/no.yml @@ -1,7 +1,7 @@ --- 'no': about: - about_mastodon: Mastodon er et gratis, åpen kildekode sosialt nettverk. Et desentralisert alternativ til kommersielle plattformer. Slik kan det unngå risikoene ved å ha et enkelt selskap med monopol på din kommunikasjon. Velg en tjener du stoler på — uansett hvilken du velger så kan du interagere med alle andre. Alle kan kjøre sin egen Mastodon og delta sømløst i det sosiale nettverket. + about_mastodon: Mastodon er et sosialt nettverk laget med fri programvare. Et desentralisert alternativ til kommersielle plattformer. Slik kan det unngå risikoene ved å ha et enkelt selskap som monopoliserer din kommunikasjon. Velg en tjener du stoler på — uansett hvilken du velger så kan du kommunisere med alle andre. Alle kan kjøre sin egen Mastodon og delta sømløst i det sosiale nettverket. about_this: Om denne instansen apps: Applikasjoner business_email: 'Bedriftsepost:' @@ -10,24 +10,24 @@ domain_count_after: andre instanser domain_count_before: Koblet til features: - api: Åpent api for applikasjoner og tjenester - blocks: Rikholdige blokkerings verktøy - characters: 500 tegn per post + api: Åpent API for applikasjoner og tjenester + blocks: Rikholdige blokkeringsverktøy + characters: 500 tegn per status chronology: Tidslinjer er kronologiske ethics: 'Etisk design: Ingen reklame, ingen sporing' - gifv: GIFV sett og korte videoer - privacy: Finmaskete personvernsinnstillinger - public: Offentlige tidslinjer + gifv: Støtte for GIFV og korte videoer + privacy: Finmaskede personvernsinnstillinger + public: Forente tidslinjer features_headline: Hva skiller Mastodon fra andre sosiale nettverk get_started: Kom i gang links: Lenker other_instances: Andre instanser source_code: Kildekode status_count_after: statuser - status_count_before: Hvem skrev + status_count_before: Som skrev terms: Betingelser user_count_after: brukere - user_count_before: Hjem til + user_count_before: Her bor accounts: follow: Følg followers: Følgere @@ -116,8 +116,8 @@ body: 'Du ble nevnt av %{name} i:' subject: Du ble nevnt av %{name} reblog: - body: 'Din status fikk en boost av %{name}:' - subject: "%{name} ga din status en boost" + body: 'Din status ble reblogget av %{name}:' + subject: "%{name} reblogget din status" pagination: next: Neste prev: Forrige @@ -142,10 +142,10 @@ visibilities: private: Vis kun til følgere public: Offentlig - unlisted: Offentlig, men vis ikke på offentlig tidslinje + unlisted: Offentlig, men vis ikke på forent tidslinje stream_entries: click_to_show: Klikk for å vise - reblogged: boostet + reblogged: reblogget sensitive_content: Sensitivt innhold time: formats: diff --git a/config/locales/simple_form.no.yml b/config/locales/simple_form.no.yml index c6ccf67b..a4e43b1a 100644 --- a/config/locales/simple_form.no.yml +++ b/config/locales/simple_form.no.yml @@ -29,14 +29,15 @@ setting_default_privacy: Leserettigheter for poster type: Importeringstype username: Brukernavn + setting_boost_modal: Vis bekreftelsesdialog før reblogging interactions: - must_be_follower: Blokker meldinger fra ikke-følgere - must_be_following: Blokker meldinger fra folk du ikke følger + must_be_follower: Blokker varslinger fra ikke-følgere + must_be_following: Blokker varslinger fra folk du ikke følger notification_emails: - digest: Send oppsummerings eposter + digest: Send oppsummeringseposter 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 + follow_request: Send e-post når noen ber om å få følge deg mention: Send e-post når noen nevner deg reblog: Send e-post når noen reblogger din status 'no': 'Nei' From 5dc73339ae0a139d06296ae935e23b6f8d0efb5b Mon Sep 17 00:00:00 2001 From: Eugen Date: Thu, 13 Apr 2017 02:17:40 +0200 Subject: [PATCH 03/43] Fix tests issue introduced in #1607 (#1639) --- spec/lib/webfinger_resource_spec.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/spec/lib/webfinger_resource_spec.rb b/spec/lib/webfinger_resource_spec.rb index 6c9a5ff2..dfd23062 100644 --- a/spec/lib/webfinger_resource_spec.rb +++ b/spec/lib/webfinger_resource_spec.rb @@ -1,6 +1,12 @@ require 'rails_helper' describe WebfingerResource do + around do |example| + before = Rails.configuration.x.local_domain + example.run + Rails.configuration.x.local_domain = before + end + describe '#username' do describe 'with a URL value' do it 'raises with an unrecognized route' do From af96e71883755a0509aa23d550cd55bd17bfb323 Mon Sep 17 00:00:00 2001 From: tom Date: Wed, 12 Apr 2017 20:50:56 -0400 Subject: [PATCH 04/43] Smoother scrolling on older iOS devices (#1654) This may address the scrolling issues mentioned here: https://github.com/tootsuite/mastodon/issues/1622 --- app/assets/stylesheets/components.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/app/assets/stylesheets/components.scss b/app/assets/stylesheets/components.scss index 1c7f375b..b135d27c 100644 --- a/app/assets/stylesheets/components.scss +++ b/app/assets/stylesheets/components.scss @@ -1,6 +1,7 @@ @import 'variables'; .app-body{ + -webkit-overflow-scrolling: touch; -ms-overflow-style: -ms-autohiding-scrollbar; } From f24daa399ba78fee689241cd27911f6769da7bb7 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Wed, 12 Apr 2017 20:51:13 -0400 Subject: [PATCH 05/43] Remove pending specs for methods that dont exist (#1658) * Remote spec for non-existent entry_classes helper method This method no longer exists, and is handled by a local variable in a partial instead. * Remove spec for non-existent Account#ping! method --- spec/helpers/stream_entries_helper_spec.rb | 4 ---- spec/models/account_spec.rb | 4 ---- 2 files changed, 8 deletions(-) diff --git a/spec/helpers/stream_entries_helper_spec.rb b/spec/helpers/stream_entries_helper_spec.rb index a8313391..e2544e31 100644 --- a/spec/helpers/stream_entries_helper_spec.rb +++ b/spec/helpers/stream_entries_helper_spec.rb @@ -14,8 +14,4 @@ RSpec.describe StreamEntriesHelper, type: :helper do expect(helper.display_name(account)).to eq "Username" end end - - describe '#entry_classes' do - pending - end end diff --git a/spec/models/account_spec.rb b/spec/models/account_spec.rb index fb367ab7..46c1ff63 100644 --- a/spec/models/account_spec.rb +++ b/spec/models/account_spec.rb @@ -118,10 +118,6 @@ RSpec.describe Account, type: :model do end end - describe '#ping!' do - pending - end - describe '#favourited?' do let(:original_status) do author = Fabricate(:account, username: 'original') From 96715d9af5a95d75b244efc67c6870325c2b322d Mon Sep 17 00:00:00 2001 From: Isabelle Knott Date: Wed, 12 Apr 2017 21:17:34 -0400 Subject: [PATCH 06/43] Clear spoiler when replying to toot that doesn't also have a spoiler (#1662) --- app/assets/javascripts/components/reducers/compose.jsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/assets/javascripts/components/reducers/compose.jsx b/app/assets/javascripts/components/reducers/compose.jsx index 00cc758a..86974239 100644 --- a/app/assets/javascripts/components/reducers/compose.jsx +++ b/app/assets/javascripts/components/reducers/compose.jsx @@ -157,6 +157,9 @@ export default function compose(state = initialState, action) { if (action.status.get('spoiler_text').length > 0) { map.set('spoiler', true); map.set('spoiler_text', action.status.get('spoiler_text')); + } else { + map.set('spoiler', false); + map.set('spoiler_text', ''); } }); case COMPOSE_REPLY_CANCEL: From faefd8ec8f164e174fd887f06d01c7fe8ed05531 Mon Sep 17 00:00:00 2001 From: Koala Yeung Date: Thu, 13 Apr 2017 18:57:41 +0800 Subject: [PATCH 07/43] Update javascript English translation files and some defaultValue (#1676) * Reorder javascript English locale file * Reorder translation string in order of the locale key. * Add javascript English locale missing language keys * Search all javascript language keys by command: `grep -REho '' ./app/assets/javascripts/.` * Add all the missing language keys and their values to `en.jsx`. * Add javascript English locale missing language keys (2) * Find all `defineMessages` calls with this command: `grep -Rl 'defineMessages({.*' ./app/assets/javascripts/.` * Open all these files. Find the language key (`id`) in these statements. * Add all the missing language keys and their values to `en.jsx`. * Remove javascript English locale obsoleted language keys * Find all language keys that no longer exists in the source code and remove them. The removed keys include: * "compose_form.private" * "compose_form.unlisted" * "getting_started.about_addressing" * "getting_started.about_shortcuts" * "notification.mention" * "search.account" * "search.hashtag" * "tabs_bar.mentions" * "tabs_bar.public" * Javascript English locale file add note * Add notes to contributors about the English translation files. Hope that will make translation process smoother. * Update javascript locale defaultValue in code * Update the defaultValue in code according to the relevant translation in English locale file. --- .../features/community_timeline/index.jsx | 2 +- .../compose/components/compose_form.jsx | 2 +- .../components/features/compose/index.jsx | 2 +- .../features/getting_started/index.jsx | 4 +- .../features/public_timeline/index.jsx | 2 +- .../javascripts/components/locales/en.jsx | 155 ++++++++++++------ 6 files changed, 112 insertions(+), 55 deletions(-) diff --git a/app/assets/javascripts/components/features/community_timeline/index.jsx b/app/assets/javascripts/components/features/community_timeline/index.jsx index 0957338c..acfc30b6 100644 --- a/app/assets/javascripts/components/features/community_timeline/index.jsx +++ b/app/assets/javascripts/components/features/community_timeline/index.jsx @@ -14,7 +14,7 @@ import ColumnBackButtonSlim from '../../components/column_back_button_slim'; import createStream from '../../stream'; const messages = defineMessages({ - title: { id: 'column.community', defaultMessage: 'Local' } + title: { id: 'column.community', defaultMessage: 'Local timeline' } }); const mapStateToProps = state => ({ diff --git a/app/assets/javascripts/components/features/compose/components/compose_form.jsx b/app/assets/javascripts/components/features/compose/components/compose_form.jsx index cb4b62f6..d2e65359 100644 --- a/app/assets/javascripts/components/features/compose/components/compose_form.jsx +++ b/app/assets/javascripts/components/features/compose/components/compose_form.jsx @@ -19,7 +19,7 @@ import TextIconButton from './text_icon_button'; const messages = defineMessages({ placeholder: { id: 'compose_form.placeholder', defaultMessage: 'What is on your mind?' }, spoiler_placeholder: { id: 'compose_form.spoiler_placeholder', defaultMessage: 'Content warning' }, - publish: { id: 'compose_form.publish', defaultMessage: 'Publish' } + publish: { id: 'compose_form.publish', defaultMessage: 'Toot' } }); const ComposeForm = React.createClass({ diff --git a/app/assets/javascripts/components/features/compose/index.jsx b/app/assets/javascripts/components/features/compose/index.jsx index 9421de3f..33e16472 100644 --- a/app/assets/javascripts/components/features/compose/index.jsx +++ b/app/assets/javascripts/components/features/compose/index.jsx @@ -12,7 +12,7 @@ import SearchResultsContainer from './containers/search_results_container'; const messages = defineMessages({ start: { id: 'getting_started.heading', defaultMessage: 'Getting started' }, - public: { id: 'navigation_bar.public_timeline', defaultMessage: 'Whole Known Network' }, + public: { id: 'navigation_bar.public_timeline', defaultMessage: 'Federated timeline' }, community: { id: 'navigation_bar.community_timeline', defaultMessage: 'Local timeline' }, preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' }, logout: { id: 'navigation_bar.logout', defaultMessage: 'Logout' } diff --git a/app/assets/javascripts/components/features/getting_started/index.jsx b/app/assets/javascripts/components/features/getting_started/index.jsx index 0656bf69..05bfcc22 100644 --- a/app/assets/javascripts/components/features/getting_started/index.jsx +++ b/app/assets/javascripts/components/features/getting_started/index.jsx @@ -7,11 +7,11 @@ import ImmutablePropTypes from 'react-immutable-proptypes'; const messages = defineMessages({ heading: { id: 'getting_started.heading', defaultMessage: 'Getting started' }, - public_timeline: { id: 'navigation_bar.public_timeline', defaultMessage: 'Whole Known Network' }, + public_timeline: { id: 'navigation_bar.public_timeline', defaultMessage: 'Federated timeline' }, community_timeline: { id: 'navigation_bar.community_timeline', defaultMessage: 'Local timeline' }, preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' }, follow_requests: { id: 'navigation_bar.follow_requests', defaultMessage: 'Follow requests' }, - sign_out: { id: 'navigation_bar.logout', defaultMessage: 'Sign out' }, + sign_out: { id: 'navigation_bar.logout', defaultMessage: 'Logout' }, favourites: { id: 'navigation_bar.favourites', defaultMessage: 'Favourites' }, blocks: { id: 'navigation_bar.blocks', defaultMessage: 'Blocked users' }, info: { id: 'navigation_bar.info', defaultMessage: 'Extended information' } diff --git a/app/assets/javascripts/components/features/public_timeline/index.jsx b/app/assets/javascripts/components/features/public_timeline/index.jsx index 6d766a83..a7ac95ab 100644 --- a/app/assets/javascripts/components/features/public_timeline/index.jsx +++ b/app/assets/javascripts/components/features/public_timeline/index.jsx @@ -14,7 +14,7 @@ import ColumnBackButtonSlim from '../../components/column_back_button_slim'; import createStream from '../../stream'; const messages = defineMessages({ - title: { id: 'column.public', defaultMessage: 'Whole Known Network' } + title: { id: 'column.public', defaultMessage: 'Federated timeline' } }); const mapStateToProps = state => ({ diff --git a/app/assets/javascripts/components/locales/en.jsx b/app/assets/javascripts/components/locales/en.jsx index f249b196..1834567f 100644 --- a/app/assets/javascripts/components/locales/en.jsx +++ b/app/assets/javascripts/components/locales/en.jsx @@ -1,72 +1,129 @@ +/** + * Note for Contributors: + * This file (en.jsx) serve as a template for other languages. + * To make other contributors' life easier, please REMEMBER: + * 1. to add your new string here; and + * 2. to remove old strings that are no longer needed; and + * 3. to sort the strings by the key. + * Thanks! + */ const en = { - "column_back_button.label": "Back", - "lightbox.close": "Close", - "loading_indicator.label": "Loading...", - "status.mention": "Mention @{name}", - "status.delete": "Delete", - "status.reply": "Reply", - "status.reblog": "Boost", - "status.favourite": "Favourite", - "status.reblogged_by": "{name} boosted", - "status.sensitive_warning": "Sensitive content", - "status.sensitive_toggle": "Click to view", - "status.show_more": "Show more", - "status.show_less": "Show less", - "status.open": "Expand this status", - "status.report": "Report @{name}", - "video_player.toggle_sound": "Toggle sound", - "account.mention": "Mention @{name}", - "account.edit_profile": "Edit profile", - "account.unblock": "Unblock @{name}", - "account.unfollow": "Unfollow", "account.block": "Block @{name}", + "account.disclaimer": "This user is from another instance. This number may be larger.", + "account.edit_profile": "Edit profile", "account.follow": "Follow", - "account.posts": "Posts", - "account.follows": "Follows", "account.followers": "Followers", "account.follows_you": "Follows you", + "account.follows": "Follows", + "account.mention": "Mention @{name}", + "account.mute": "Mute @{name}", + "account.posts": "Posts", + "account.report": "Report @{name}", "account.requested": "Awaiting approval", - "getting_started.heading": "Getting started", - "getting_started.about_addressing": "You can follow people if you know their username and the domain they are on by entering an e-mail-esque address into the search form.", - "getting_started.about_shortcuts": "If the target user is on the same domain as you, just the username will work. The same rule applies to mentioning people in statuses.", - "getting_started.open_source_notice": "Mastodon is open source software. You can contribute or report issues on GitHub at {github}. {apps}.", - "column.home": "Home", + "account.unblock": "Unblock @{name}", + "account.unfollow": "Unfollow", + "account.unmute": "Unmute @{name}", + "boost_modal.combo": "You can press {combo} to skip this next time", + "column_back_button.label": "Back", + "column.blocks": "Blocked users", "column.community": "Local timeline", - "column.public": "Federated timeline", + "column.favourites": "Favourites", + "column.follow_requests": "Follow requests", + "column.home": "Home", "column.notifications": "Notifications", - "tabs_bar.compose": "Compose", - "tabs_bar.home": "Home", - "tabs_bar.mentions": "Mentions", - "tabs_bar.public": "Federated timeline", - "tabs_bar.notifications": "Notifications", + "column.public": "Federated timeline", "compose_form.placeholder": "What is on your mind?", + "compose_form.privacy_disclaimer": "Your private status will be delivered to mentioned users on {domains}. Do you trust {domainsCount, plural, one {that server} other {those servers}}? Post privacy only works on Mastodon instances. If {domains} {domainsCount, plural, one {is not a Mastodon instance} other {are not Mastodon instances}}, there will be no indication that your post is private, and it may be boosted or otherwise made visible to unintended recipients.", "compose_form.publish": "Toot", "compose_form.sensitive": "Mark media as sensitive", + "compose_form.spoiler_placeholder": "Content warning", "compose_form.spoiler": "Hide text behind warning", - "compose_form.private": "Mark as private", - "compose_form.privacy_disclaimer": "Your private status will be delivered to mentioned users on {domains}. Do you trust {domainsCount, plural, one {that server} other {those servers}}? Post privacy only works on Mastodon instances. If {domains} {domainsCount, plural, one {is not a Mastodon instance} other {are not Mastodon instances}}, there will be no indication that your post is private, and it may be boosted or otherwise made visible to unintended recipients.", - "compose_form.unlisted": "Do not display on public timelines", - "navigation_bar.edit_profile": "Edit profile", - "navigation_bar.preferences": "Preferences", + "emoji_button.label": "Insert emoji", + "empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!", + "empty_column.hashtag": "There is nothing in this hashtag yet.", + "empty_column.home.public_timeline": "the public timeline", + "empty_column.home": "You aren't following anyone yet. Visit {public} or use search to get started and meet other users.", + "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", + "follow_request.authorize": "Authorize", + "follow_request.reject": "Rejec", + "getting_started.apps": "Various apps are available", + "getting_started.heading": "Getting started", + "getting_started.open_source_notice": "Mastodon is open source software. You can contribute or report issues on GitHub at {github}. {apps}.", + "home.column_settings.advanced": "Advanced", + "home.column_settings.basic": "Basic", + "home.column_settings.filter_regex": "Filter out by regular expressions", + "home.column_settings.show_reblogs": "Show boosts", + "home.column_settings.show_replies": "Show replies", + "home.settings": "Column settings", + "lightbox.close": "Close", + "loading_indicator.label": "Loading...", + "media_gallery.toggle_visible": "Toggle visibility", + "missing_indicator.label": "Not found", + "navigation_bar.blocks": "Blocked users", "navigation_bar.community_timeline": "Local timeline", - "navigation_bar.public_timeline": "Federated timeline", + "navigation_bar.edit_profile": "Edit profile", + "navigation_bar.favourites": "Favourites", + "navigation_bar.follow_requests": "Follow requests", + "navigation_bar.info": "Extended information", "navigation_bar.logout": "Logout", - "reply_indicator.cancel": "Cancel", - "search.placeholder": "Search", - "search.account": "Account", - "search.hashtag": "Hashtag", - "upload_button.label": "Add media", - "upload_form.undo": "Undo", - "notification.follow": "{name} followed you", + "navigation_bar.preferences": "Preferences", + "navigation_bar.public_timeline": "Federated timeline", "notification.favourite": "{name} favourited your status", + "notification.follow": "{name} followed you", "notification.reblog": "{name} boosted your status", - "notification.mention": "{name} mentioned you", + "notifications.clear_confirmation": "Are you sure you want to clear all your notifications?", + "notifications.clear": "Clear notifications", "notifications.column_settings.alert": "Desktop notifications", - "notifications.column_settings.show": "Show in column", - "notifications.column_settings.follow": "New followers:", "notifications.column_settings.favourite": "Favourites:", + "notifications.column_settings.follow": "New followers:", "notifications.column_settings.mention": "Mentions:", "notifications.column_settings.reblog": "Boosts:", + "notifications.column_settings.show": "Show in column", + "notifications.column_settings.sound": "Play sound", + "notifications.settings": "Column settings", + "privacy.change": "Adjust status privacy", + "privacy.direct.long": "Post to mentioned users only", + "privacy.direct.short": "Direct", + "privacy.private.long": "Post to followers only", + "privacy.private.short": "Private", + "privacy.public.long": "Post to public timelines", + "privacy.public.short": "Public", + "privacy.unlisted.long": "Do not show in public timelines", + "privacy.unlisted.short": "Unlisted", + "reply_indicator.cancel": "Cancel", + "report.heading": "New report", + "report.placeholder": "Additional comments", + "report.submit": "Submit", + "report.target": "Reporting", + "search_results.total": "{count} {count, plural, one {result} other {results}}", + "search.placeholder": "Search", + "search.status_by": "Status by {name}", + "status.delete": "Delete", + "status.favourite": "Favourite", + "status.load_more": "Load more", + "status.media_hidden": "Media hidden", + "status.mention": "Mention @{name}", + "status.open": "Expand this status", + "status.reblog": "Boost", + "status.reblogged_by": "{name} boosted", + "status.reply": "Reply", + "status.report": "Report @{name}", + "status.sensitive_toggle": "Click to view", + "status.sensitive_warning": "Sensitive content", + "status.show_less": "Show less", + "status.show_more": "Show more", + "tabs_bar.compose": "Compose", + "tabs_bar.federated_timeline": "Federated", + "tabs_bar.home": "Home", + "tabs_bar.local_timeline": "Local", + "tabs_bar.notifications": "Notifications", + "upload_area.title": "Drag & drop to upload", + "upload_button.label": "Add media", + "upload_form.undo": "Undo", + "upload_progress.label": "Uploading...", + "video_player.toggle_sound": "Toggle sound", + "video_player.toggle_visible": "Toggle visibility", }; export default en; From 0e39cc6a35661416a1f1ccb8841863f7bf307020 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 13 Apr 2017 07:02:02 -0400 Subject: [PATCH 08/43] Settings export refactor (#1646) * Refactor Export to take an account and know about the export types * Use Export instance in settings/exports#show --- .../settings/exports/base_controller.rb | 2 +- .../exports/blocked_accounts_controller.rb | 4 +- .../exports/following_accounts_controller.rb | 4 +- .../exports/muted_accounts_controller.rb | 4 +- .../settings/exports_controller.rb | 5 +-- app/models/export.rb | 38 +++++++++++++++++-- app/views/settings/exports/show.html.haml | 8 ++-- .../settings/exports_controller_spec.rb | 3 ++ 8 files changed, 49 insertions(+), 19 deletions(-) diff --git a/app/controllers/settings/exports/base_controller.rb b/app/controllers/settings/exports/base_controller.rb index 0b790959..c082ed80 100644 --- a/app/controllers/settings/exports/base_controller.rb +++ b/app/controllers/settings/exports/base_controller.rb @@ -6,7 +6,7 @@ module Settings before_action :authenticate_user! def index - export_data = Export.new(export_accounts).to_csv + @export = Export.new(current_account) respond_to do |format| format.csv { send_data export_data, filename: export_filename } diff --git a/app/controllers/settings/exports/blocked_accounts_controller.rb b/app/controllers/settings/exports/blocked_accounts_controller.rb index 9c4bcaa5..f1115b21 100644 --- a/app/controllers/settings/exports/blocked_accounts_controller.rb +++ b/app/controllers/settings/exports/blocked_accounts_controller.rb @@ -5,8 +5,8 @@ module Settings class BlockedAccountsController < BaseController private - def export_accounts - current_account.blocking + def export_data + @export.to_blocked_accounts_csv end end end diff --git a/app/controllers/settings/exports/following_accounts_controller.rb b/app/controllers/settings/exports/following_accounts_controller.rb index 8d06bcc9..0011d246 100644 --- a/app/controllers/settings/exports/following_accounts_controller.rb +++ b/app/controllers/settings/exports/following_accounts_controller.rb @@ -5,8 +5,8 @@ module Settings class FollowingAccountsController < BaseController private - def export_accounts - current_account.following + def export_data + @export.to_following_accounts_csv end end end diff --git a/app/controllers/settings/exports/muted_accounts_controller.rb b/app/controllers/settings/exports/muted_accounts_controller.rb index a77a9af6..dfe72cfc 100644 --- a/app/controllers/settings/exports/muted_accounts_controller.rb +++ b/app/controllers/settings/exports/muted_accounts_controller.rb @@ -5,8 +5,8 @@ module Settings class MutedAccountsController < BaseController private - def export_accounts - current_account.muting + def export_data + @export.to_muted_accounts_csv end end end diff --git a/app/controllers/settings/exports_controller.rb b/app/controllers/settings/exports_controller.rb index 77dea323..ae62f00c 100644 --- a/app/controllers/settings/exports_controller.rb +++ b/app/controllers/settings/exports_controller.rb @@ -6,9 +6,6 @@ class Settings::ExportsController < ApplicationController before_action :authenticate_user! def show - @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 + @export = Export.new(current_account) end end diff --git a/app/models/export.rb b/app/models/export.rb index cd1a58eb..f0d5dd25 100644 --- a/app/models/export.rb +++ b/app/models/export.rb @@ -2,13 +2,43 @@ require 'csv' class Export - attr_reader :accounts + attr_reader :account - def initialize(accounts) - @accounts = accounts + def initialize(account) + @account = account end - def to_csv + def to_blocked_accounts_csv + to_csv account.blocking + end + + def to_muted_accounts_csv + to_csv account.muting + end + + def to_following_accounts_csv + to_csv account.following + end + + def total_storage + account.media_attachments.sum(:file_file_size) + end + + def total_follows + account.following.count + end + + def total_blocks + account.blocking.count + end + + def total_mutes + account.muting.count + end + + private + + def to_csv(accounts) CSV.generate do |csv| accounts.each do |account| csv << [(account.local? ? account.local_username_and_domain : account.acct)] diff --git a/app/views/settings/exports/show.html.haml b/app/views/settings/exports/show.html.haml index 51be40fb..f2f6f955 100644 --- a/app/views/settings/exports/show.html.haml +++ b/app/views/settings/exports/show.html.haml @@ -5,17 +5,17 @@ %tbody %tr %th= t('exports.storage') - %td= number_to_human_size @total_storage + %td= number_to_human_size @export.total_storage %td %tr %th= t('exports.follows') - %td= @total_follows + %td= @export.total_follows %td= table_link_to 'download', t('exports.csv'), settings_exports_follows_path(format: :csv) %tr %th= t('exports.blocks') - %td= @total_blocks + %td= @export.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= @export.total_mutes %td= table_link_to 'download', t('exports.csv'), settings_exports_mutes_path(format: :csv) diff --git a/spec/controllers/settings/exports_controller_spec.rb b/spec/controllers/settings/exports_controller_spec.rb index ff98f3ad..2be6e474 100644 --- a/spec/controllers/settings/exports_controller_spec.rb +++ b/spec/controllers/settings/exports_controller_spec.rb @@ -1,6 +1,8 @@ require 'rails_helper' describe Settings::ExportsController do + render_views + before do sign_in Fabricate(:user), scope: :user end @@ -8,6 +10,7 @@ describe Settings::ExportsController do describe 'GET #show' do it 'returns http success' do get :show + expect(response).to have_http_status(:success) end end From 3a9eb81a8006af0306e8abc54bd8aca8381eee25 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 13 Apr 2017 07:04:23 -0400 Subject: [PATCH 09/43] Admin accounts controller cleanup (#1664) * Remove unused account_params method in admin/accounts controller * Introduce AccountFilter to find accounts * Use AccountFilter in admin/accounts controller * Use more restful routes admin silence and suspension area * Add admin/silences and admin/suspensions controllers --- app/controllers/admin/accounts_controller.rb | 48 ++++++------------- app/controllers/admin/silences_controller.rb | 23 +++++++++ .../admin/suspensions_controller.rb | 23 +++++++++ app/models/account_filter.rb | 36 ++++++++++++++ app/views/admin/accounts/show.html.haml | 8 ++-- config/routes.rb | 9 ++-- .../admin/silences_controller_spec.rb | 24 ++++++++++ .../admin/suspensions_controller_spec.rb | 24 ++++++++++ spec/models/account_filter_spec.rb | 31 ++++++++++++ 9 files changed, 182 insertions(+), 44 deletions(-) create mode 100644 app/controllers/admin/silences_controller.rb create mode 100644 app/controllers/admin/suspensions_controller.rb create mode 100644 app/models/account_filter.rb create mode 100644 spec/controllers/admin/silences_controller_spec.rb create mode 100644 spec/controllers/admin/suspensions_controller_spec.rb create mode 100644 spec/models/account_filter_spec.rb diff --git a/app/controllers/admin/accounts_controller.rb b/app/controllers/admin/accounts_controller.rb index 71cb8edd..0e9e52f4 100644 --- a/app/controllers/admin/accounts_controller.rb +++ b/app/controllers/admin/accounts_controller.rb @@ -2,49 +2,29 @@ module Admin class AccountsController < BaseController - before_action :set_account, except: :index - def index - @accounts = Account.alphabetic.page(params[:page]) - - @accounts = @accounts.local if params[:local].present? - @accounts = @accounts.remote if params[:remote].present? - @accounts = @accounts.where(domain: params[:by_domain]) if params[:by_domain].present? - @accounts = @accounts.silenced if params[:silenced].present? - @accounts = @accounts.recent if params[:recent].present? - @accounts = @accounts.suspended if params[:suspended].present? + @accounts = filtered_accounts.page(params[:page]) end - def show; end - - def suspend - Admin::SuspensionWorker.perform_async(@account.id) - redirect_to admin_accounts_path - end - - def unsuspend - @account.update(suspended: false) - redirect_to admin_accounts_path - end - - def silence - @account.update(silenced: true) - redirect_to admin_accounts_path - end - - def unsilence - @account.update(silenced: false) - redirect_to admin_accounts_path + def show + @account = Account.find(params[:id]) end private - def set_account - @account = Account.find(params[:id]) + def filtered_accounts + AccountFilter.new(filter_params).results end - def account_params - params.require(:account).permit(:silenced, :suspended) + def filter_params + params.permit( + :local, + :remote, + :by_domain, + :silenced, + :recent, + :suspended + ) end end end diff --git a/app/controllers/admin/silences_controller.rb b/app/controllers/admin/silences_controller.rb new file mode 100644 index 00000000..81a3008b --- /dev/null +++ b/app/controllers/admin/silences_controller.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +module Admin + class SilencesController < BaseController + before_action :set_account + + def create + @account.update(silenced: true) + redirect_to admin_accounts_path + end + + def destroy + @account.update(silenced: false) + redirect_to admin_accounts_path + end + + private + + def set_account + @account = Account.find(params[:account_id]) + end + end +end diff --git a/app/controllers/admin/suspensions_controller.rb b/app/controllers/admin/suspensions_controller.rb new file mode 100644 index 00000000..5d9048d9 --- /dev/null +++ b/app/controllers/admin/suspensions_controller.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +module Admin + class SuspensionsController < BaseController + before_action :set_account + + def create + Admin::SuspensionWorker.perform_async(@account.id) + redirect_to admin_accounts_path + end + + def destroy + @account.update(suspended: false) + redirect_to admin_accounts_path + end + + private + + def set_account + @account = Account.find(params[:account_id]) + end + end +end diff --git a/app/models/account_filter.rb b/app/models/account_filter.rb new file mode 100644 index 00000000..a8d8c883 --- /dev/null +++ b/app/models/account_filter.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +class AccountFilter + attr_reader :params + + def initialize(params) + @params = params + end + + def results + scope = Account.alphabetic + params.each do |key, value| + scope = scope.merge scope_for(key, value) + end + scope + end + + def scope_for(key, value) + case key + when /local/ + Account.local + when /remote/ + Account.remote + when /by_domain/ + Account.where(domain: value) + when /silenced/ + Account.silenced + when /recent/ + Account.recent + when /suspended/ + Account.suspended + else + raise "Unknown filter: #{key}" + end + end +end diff --git a/app/views/admin/accounts/show.html.haml b/app/views/admin/accounts/show.html.haml index ba1c3bae..22901aed 100644 --- a/app/views/admin/accounts/show.html.haml +++ b/app/views/admin/accounts/show.html.haml @@ -62,11 +62,11 @@ = number_to_human_size @account.media_attachments.sum('file_file_size') - if @account.silenced? - = link_to 'Undo silence', unsilence_admin_account_path(@account.id), method: :post, class: 'button' + = link_to 'Undo silence', admin_account_silence_path(@account.id), method: :delete, class: 'button' - else - = link_to 'Silence', silence_admin_account_path(@account.id), method: :post, class: 'button' + = link_to 'Silence', admin_account_silence_path(@account.id), method: :post, class: 'button' - if @account.suspended? - = link_to 'Undo suspension', unsuspend_admin_account_path(@account.id), method: :post, class: 'button' + = link_to 'Undo suspension', admin_account_suspension_path(@account.id), method: :delete, class: 'button' - else - = link_to 'Perform full suspension', suspend_admin_account_path(@account.id), method: :post, data: { confirm: 'Are you sure?' }, class: 'button' + = link_to 'Perform full suspension', admin_account_suspension_path(@account.id), method: :post, data: { confirm: 'Are you sure?' }, class: 'button' diff --git a/config/routes.rb b/config/routes.rb index 78bf7870..ca3f3105 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,3 +1,4 @@ + # frozen_string_literal: true require 'sidekiq/web' @@ -89,12 +90,8 @@ Rails.application.routes.draw do end resources :accounts, only: [:index, :show] do - member do - post :silence - post :unsilence - post :suspend - post :unsuspend - end + resource :silence, only: [:create, :destroy] + resource :suspension, only: [:create, :destroy] end end diff --git a/spec/controllers/admin/silences_controller_spec.rb b/spec/controllers/admin/silences_controller_spec.rb new file mode 100644 index 00000000..7c541d79 --- /dev/null +++ b/spec/controllers/admin/silences_controller_spec.rb @@ -0,0 +1,24 @@ +require 'rails_helper' + +describe Admin::SilencesController do + let(:account) { Fabricate(:account) } + before do + sign_in Fabricate(:user, admin: true), scope: :user + end + + describe 'POST #create' do + it 'redirects to admin accounts page' do + post :create, params: { account_id: account.id } + + expect(response).to redirect_to(admin_accounts_path) + end + end + + describe 'DELETE #destroy' do + it 'redirects to admin accounts page' do + delete :destroy, params: { account_id: account.id } + + expect(response).to redirect_to(admin_accounts_path) + end + end +end diff --git a/spec/controllers/admin/suspensions_controller_spec.rb b/spec/controllers/admin/suspensions_controller_spec.rb new file mode 100644 index 00000000..9096f067 --- /dev/null +++ b/spec/controllers/admin/suspensions_controller_spec.rb @@ -0,0 +1,24 @@ +require 'rails_helper' + +describe Admin::SuspensionsController do + let(:account) { Fabricate(:account) } + before do + sign_in Fabricate(:user, admin: true), scope: :user + end + + describe 'POST #create' do + it 'redirects to admin accounts page' do + post :create, params: { account_id: account.id } + + expect(response).to redirect_to(admin_accounts_path) + end + end + + describe 'DELETE #destroy' do + it 'redirects to admin accounts page' do + delete :destroy, params: { account_id: account.id } + + expect(response).to redirect_to(admin_accounts_path) + end + end +end diff --git a/spec/models/account_filter_spec.rb b/spec/models/account_filter_spec.rb new file mode 100644 index 00000000..1599c5ae --- /dev/null +++ b/spec/models/account_filter_spec.rb @@ -0,0 +1,31 @@ +require 'rails_helper' + +describe AccountFilter do + describe 'with empty params' do + it 'defaults to alphabetic account list' do + filter = AccountFilter.new({}) + + expect(filter.results).to eq Account.alphabetic + end + end + + describe 'with invalid params' do + it 'raises with key error' do + filter = AccountFilter.new(wrong: true) + + expect { filter.results }.to raise_error(/wrong/) + end + end + + describe 'with valid params' do + it 'combines filters on Account' do + filter = AccountFilter.new(by_domain: 'test.com', silenced: true) + + allow(Account).to receive(:where).and_return(Account.none) + allow(Account).to receive(:silenced).and_return(Account.none) + filter.results + expect(Account).to have_received(:where).with(domain: 'test.com') + expect(Account).to have_received(:silenced) + end + end +end From 137100dcf38c0da0fe7044a4c92aa06eae02c420 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 13 Apr 2017 07:09:07 -0400 Subject: [PATCH 10/43] Clean up well-known routes/controllers (#1649) * Add request spec for host meta route returning xml * Add routing spec for xrd routes * Update well-known routes * Move webfinger and host-meta actions to their own controllers --- .../well_known/host_meta_controller.rb | 13 +++++ .../well_known/webfinger_controller.rb | 43 +++++++++++++++ app/controllers/xrd_controller.rb | 55 ------------------- .../host_meta/show.xml.ruby} | 0 .../webfinger/show.json.rabl} | 0 .../webfinger/show.xml.ruby} | 0 config/routes.rb | 4 +- .../well_known/host_meta_controller_spec.rb | 13 +++++ .../well_known/webfinger_controller_spec.rb | 21 +++++++ spec/controllers/xrd_controller_spec.rb | 26 --------- spec/requests/host_meta_request_spec.rb | 12 ++++ spec/routing/well_known_routes_spec.rb | 15 +++++ 12 files changed, 119 insertions(+), 83 deletions(-) create mode 100644 app/controllers/well_known/host_meta_controller.rb create mode 100644 app/controllers/well_known/webfinger_controller.rb delete mode 100644 app/controllers/xrd_controller.rb rename app/views/{xrd/host_meta.xml.ruby => well_known/host_meta/show.xml.ruby} (100%) rename app/views/{xrd/webfinger.json.rabl => well_known/webfinger/show.json.rabl} (100%) rename app/views/{xrd/webfinger.xml.ruby => well_known/webfinger/show.xml.ruby} (100%) create mode 100644 spec/controllers/well_known/host_meta_controller_spec.rb create mode 100644 spec/controllers/well_known/webfinger_controller_spec.rb delete mode 100644 spec/controllers/xrd_controller_spec.rb create mode 100644 spec/requests/host_meta_request_spec.rb create mode 100644 spec/routing/well_known_routes_spec.rb diff --git a/app/controllers/well_known/host_meta_controller.rb b/app/controllers/well_known/host_meta_controller.rb new file mode 100644 index 00000000..2f0960ac --- /dev/null +++ b/app/controllers/well_known/host_meta_controller.rb @@ -0,0 +1,13 @@ + # frozen_string_literal: true + +module WellKnown + class HostMetaController < ApplicationController + def show + @webfinger_template = "#{webfinger_url}?resource={uri}" + + respond_to do |format| + format.xml { render content_type: 'application/xrd+xml' } + end + end + end +end diff --git a/app/controllers/well_known/webfinger_controller.rb b/app/controllers/well_known/webfinger_controller.rb new file mode 100644 index 00000000..1a8ef5f9 --- /dev/null +++ b/app/controllers/well_known/webfinger_controller.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +module WellKnown + class WebfingerController < ApplicationController + def show + @account = Account.find_local!(username_from_resource) + @canonical_account_uri = @account.to_webfinger_s + @magic_key = pem_to_magic_key(@account.keypair.public_key) + + respond_to do |format| + format.xml { render content_type: 'application/xrd+xml' } + format.json { render content_type: 'application/jrd+json' } + end + rescue ActiveRecord::RecordNotFound + head 404 + end + + private + + def username_from_resource + WebfingerResource.new(resource_param).username + end + + def pem_to_magic_key(public_key) + modulus, exponent = [public_key.n, public_key.e].map do |component| + result = [] + + until component.zero? + result << [component % 256].pack('C') + component >>= 8 + end + + result.reverse.join + end + + (['RSA'] + [modulus, exponent].map { |n| Base64.urlsafe_encode64(n) }).join('.') + end + + def resource_param + params.require(:resource) + end + end +end diff --git a/app/controllers/xrd_controller.rb b/app/controllers/xrd_controller.rb deleted file mode 100644 index 2886315a..00000000 --- a/app/controllers/xrd_controller.rb +++ /dev/null @@ -1,55 +0,0 @@ -# frozen_string_literal: true - -class XrdController < ApplicationController - before_action :set_default_format_xml, only: :host_meta - - def host_meta - @webfinger_template = "#{webfinger_url}?resource={uri}" - - respond_to do |format| - format.xml { render content_type: 'application/xrd+xml' } - end - end - - def webfinger - @account = Account.find_local!(username_from_resource) - @canonical_account_uri = @account.to_webfinger_s - @magic_key = pem_to_magic_key(@account.keypair.public_key) - - respond_to do |format| - format.xml { render content_type: 'application/xrd+xml' } - format.json { render content_type: 'application/jrd+json' } - end - rescue ActiveRecord::RecordNotFound - head 404 - end - - private - - def set_default_format_xml - request.format = 'xml' if request.headers['HTTP_ACCEPT'].nil? && params[:format].nil? - end - - def username_from_resource - WebfingerResource.new(resource_param).username - end - - def pem_to_magic_key(public_key) - modulus, exponent = [public_key.n, public_key.e].map do |component| - result = [] - - until component.zero? - result << [component % 256].pack('C') - component >>= 8 - end - - result.reverse.join - end - - (['RSA'] + [modulus, exponent].map { |n| Base64.urlsafe_encode64(n) }).join('.') - end - - def resource_param - params.require(:resource) - end -end diff --git a/app/views/xrd/host_meta.xml.ruby b/app/views/well_known/host_meta/show.xml.ruby similarity index 100% rename from app/views/xrd/host_meta.xml.ruby rename to app/views/well_known/host_meta/show.xml.ruby diff --git a/app/views/xrd/webfinger.json.rabl b/app/views/well_known/webfinger/show.json.rabl similarity index 100% rename from app/views/xrd/webfinger.json.rabl rename to app/views/well_known/webfinger/show.json.rabl diff --git a/app/views/xrd/webfinger.xml.ruby b/app/views/well_known/webfinger/show.xml.ruby similarity index 100% rename from app/views/xrd/webfinger.xml.ruby rename to app/views/well_known/webfinger/show.xml.ruby diff --git a/config/routes.rb b/config/routes.rb index ca3f3105..6e48d3b9 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -15,8 +15,8 @@ Rails.application.routes.draw do controllers authorizations: 'oauth/authorizations', authorized_applications: 'oauth/authorized_applications' end - get '.well-known/host-meta', to: 'xrd#host_meta', as: :host_meta - get '.well-known/webfinger', to: 'xrd#webfinger', as: :webfinger, defaults: { format: 'json' } + get '.well-known/host-meta', to: 'well_known/host_meta#show', as: :host_meta, defaults: { format: 'xml' } + get '.well-known/webfinger', to: 'well_known/webfinger#show', as: :webfinger, defaults: { format: 'json' } devise_for :users, path: 'auth', controllers: { sessions: 'auth/sessions', diff --git a/spec/controllers/well_known/host_meta_controller_spec.rb b/spec/controllers/well_known/host_meta_controller_spec.rb new file mode 100644 index 00000000..8a040021 --- /dev/null +++ b/spec/controllers/well_known/host_meta_controller_spec.rb @@ -0,0 +1,13 @@ +require 'rails_helper' + +describe WellKnown::HostMetaController, type: :controller do + render_views + + describe 'GET #show' do + it 'returns http success' do + get :show, format: :xml + + expect(response).to have_http_status(:success) + end + end +end diff --git a/spec/controllers/well_known/webfinger_controller_spec.rb b/spec/controllers/well_known/webfinger_controller_spec.rb new file mode 100644 index 00000000..6e493b03 --- /dev/null +++ b/spec/controllers/well_known/webfinger_controller_spec.rb @@ -0,0 +1,21 @@ +require 'rails_helper' + +describe WellKnown::WebfingerController, type: :controller do + render_views + + describe 'GET #show' do + let(:alice) { Fabricate(:account, username: 'alice') } + + it 'returns http success when account can be found' do + get :show, 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 :show, params: { resource: 'acct:not@existing.com' }, format: :json + + expect(response).to have_http_status(:not_found) + end + end +end diff --git a/spec/controllers/xrd_controller_spec.rb b/spec/controllers/xrd_controller_spec.rb deleted file mode 100644 index 33b17f15..00000000 --- a/spec/controllers/xrd_controller_spec.rb +++ /dev/null @@ -1,26 +0,0 @@ -require 'rails_helper' - -RSpec.describe XrdController, type: :controller do - render_views - - describe 'GET #host_meta' do - it 'returns http success' do - get :host_meta - expect(response).to have_http_status(:success) - end - end - - describe 'GET #webfinger' 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 }, 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' }, format: :json - expect(response).to have_http_status(:not_found) - end - end -end diff --git a/spec/requests/host_meta_request_spec.rb b/spec/requests/host_meta_request_spec.rb new file mode 100644 index 00000000..0c51b5f4 --- /dev/null +++ b/spec/requests/host_meta_request_spec.rb @@ -0,0 +1,12 @@ +require "rails_helper" + +describe "The host_meta route" do + describe "requested without accepts headers" do + it "returns an xml response" do + get host_meta_url + + expect(response).to have_http_status(:success) + expect(response.content_type).to eq "application/xrd+xml" + end + end +end diff --git a/spec/routing/well_known_routes_spec.rb b/spec/routing/well_known_routes_spec.rb new file mode 100644 index 00000000..9540c3de --- /dev/null +++ b/spec/routing/well_known_routes_spec.rb @@ -0,0 +1,15 @@ +require 'rails_helper' + +describe 'the host-meta route' do + it 'routes to correct place with xml format' do + expect(get('/.well-known/host-meta')). + to route_to('well_known/host_meta#show', format: 'xml') + end +end + +describe 'the webfinger route' do + it 'routes to correct place with json format' do + expect(get('/.well-known/webfinger')). + to route_to('well_known/webfinger#show', format: 'json') + end +end From 4f781b17cc0644a1e464dc8fd968d393ccb9b605 Mon Sep 17 00:00:00 2001 From: Daijiro Wachi Date: Thu, 13 Apr 2017 13:13:17 +0200 Subject: [PATCH 11/43] Use input type `number` for Two-factor code (#1683) --- app/assets/stylesheets/forms.scss | 2 +- app/views/auth/sessions/two_factor.html.haml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/assets/stylesheets/forms.scss b/app/assets/stylesheets/forms.scss index 2e3a4f14..e5e8697a 100644 --- a/app/assets/stylesheets/forms.scss +++ b/app/assets/stylesheets/forms.scss @@ -88,7 +88,7 @@ code { } } - input[type=text], input[type=email], input[type=password], textarea { + input[type=text], input[type=number], input[type=email], input[type=password], textarea { background: transparent; box-sizing: border-box; border: 0; diff --git a/app/views/auth/sessions/two_factor.html.haml b/app/views/auth/sessions/two_factor.html.haml index 8bf99855..1deff82b 100644 --- a/app/views/auth/sessions/two_factor.html.haml +++ b/app/views/auth/sessions/two_factor.html.haml @@ -2,7 +2,7 @@ = t('auth.login') = simple_form_for(resource, as: resource_name, url: session_path(resource_name), method: :post) do |f| - = f.input :otp_attempt, placeholder: t('simple_form.labels.defaults.otp_attempt'), input_html: { 'aria-label' => t('simple_form.labels.defaults.otp_attempt') }, required: true, autofocus: true, autocomplete: 'off' + = f.input :otp_attempt, type: :number, placeholder: t('simple_form.labels.defaults.otp_attempt'), input_html: { 'aria-label' => t('simple_form.labels.defaults.otp_attempt') }, required: true, autofocus: true, autocomplete: 'off' .actions = f.button :button, t('auth.login'), type: :submit From aa7bf1515c4d00baa47217336a3a7191b7f15041 Mon Sep 17 00:00:00 2001 From: Svetlozar Todorov Date: Thu, 13 Apr 2017 14:16:28 +0300 Subject: [PATCH 12/43] Fix #624 - Add localization for Bulgarian (#645) * Add translation files and declarations for Bulgarian * Add a bunch of translations to bg.jsx * Add rest of translations to bg.jsx * Add devise translations * Fix devise translations --- .../components/containers/mastodon.jsx | 5 +- .../javascripts/components/locales/bg.jsx | 68 +++++++ .../javascripts/components/locales/index.jsx | 3 +- app/helpers/settings_helper.rb | 1 + config/application.rb | 1 + config/locales/bg.yml | 169 ++++++++++++++++++ config/locales/devise.bg.yml | 61 +++++++ config/locales/doorkeeper.bg.yml | 113 ++++++++++++ config/locales/simple_form.bg.yml | 46 +++++ 9 files changed, 463 insertions(+), 4 deletions(-) create mode 100644 app/assets/javascripts/components/locales/bg.jsx create mode 100644 config/locales/bg.yml create mode 100644 config/locales/devise.bg.yml create mode 100644 config/locales/doorkeeper.bg.yml create mode 100644 config/locales/simple_form.bg.yml diff --git a/app/assets/javascripts/components/containers/mastodon.jsx b/app/assets/javascripts/components/containers/mastodon.jsx index d8810dc6..b9086de4 100644 --- a/app/assets/javascripts/components/containers/mastodon.jsx +++ b/app/assets/javascripts/components/containers/mastodon.jsx @@ -52,8 +52,8 @@ 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'; +import bg from 'react-intl/locale-data/bg'; import { localeData as zh_hk } from '../locales/zh-hk'; - import getMessagesForLocale from '../locales'; import { hydrateStore } from '../actions/store'; import createStream from '../stream'; @@ -66,7 +66,6 @@ const browserHistory = useRouterHistory(createBrowserHistory)({ basename: '/web' }); - addLocaleData([ ...en, ...de, @@ -82,9 +81,9 @@ addLocaleData([ ...uk, ...zh, ...zh_hk, + ...bg, ]); - const Mastodon = React.createClass({ propTypes: { diff --git a/app/assets/javascripts/components/locales/bg.jsx b/app/assets/javascripts/components/locales/bg.jsx new file mode 100644 index 00000000..cac984aa --- /dev/null +++ b/app/assets/javascripts/components/locales/bg.jsx @@ -0,0 +1,68 @@ +const bg = { + "column_back_button.label": "Назад", + "lightbox.close": "Затвори", + "loading_indicator.label": "Зареждане...", + "status.mention": "Споменаване", + "status.delete": "Изтриване", + "status.reply": "Отговор", + "status.reblog": "Споделяне", + "status.favourite": "Предпочитани", + "status.reblogged_by": "{name} сподели", + "status.sensitive_warning": "Деликатно съдържание", + "status.sensitive_toggle": "Покажи", + "video_player.toggle_sound": "Звук", + "account.mention": "Споменаване", + "account.edit_profile": "Редактирай профила си", + "account.unblock": "Не блокирай", + "account.unfollow": "Не следвай", + "account.block": "Блокирай", + "account.follow": "Последвай", + "account.posts": "Публикации", + "account.follows": "Следвам", + "account.followers": "Последователи", + "account.follows_you": "Твой последовател", + "account.requested": "В очакване на одобрение", + "getting_started.heading": "Първи стъпки", + "getting_started.about_addressing": "Можеш да последваш потребител, ако знаеш потребителското му име и домейна, на който се намира, като в полето за търсене ги въведеш по този начин: име@домейн", + "getting_started.about_shortcuts": "Ако с търсения потребител се намирате на един и същ домейн, достатъчно е да въведеш само името. Същото важи и за споменаване на хора в публикации.", + "getting_started.about_developer": "Можеш да потърсиш разработчика на този проект като: Gargron@mastodon.social", + "getting_started.open_source_notice": "Mastodon е софтуер с отворен код. Можеш да помогнеш или да докладваш за проблеми в Github: {github}.", + "column.home": "Начало", + "column.mentions": "Споменавания", + "column.public": "Публичен канал", + "column.notifications": "Известия", + "tabs_bar.compose": "Съставяне", + "tabs_bar.home": "Начало", + "tabs_bar.mentions": "Споменавания", + "tabs_bar.public": "Публичен канал", + "tabs_bar.notifications": "Известия", + "compose_form.placeholder": "Какво си мислиш?", + "compose_form.publish": "Раздумай", + "compose_form.sensitive": "Отбележи съдържанието като деликатно", + "compose_form.spoiler": "Скрий текста зад предупреждение", + "compose_form.private": "Отбележи като поверително", + "compose_form.privacy_disclaimer": "Поверителни публикации ще бъдат изпратени до споменатите потребители на {domains}. Доверяваш ли се на {domainsCount, plural, one {that server} other {those servers}}, че няма да издаде твоята публикация?", + "compose_form.unlisted": "Не показвай в публичния канал", + "navigation_bar.edit_profile": "Редактирай профил", + "navigation_bar.preferences": "Предпочитания", + "navigation_bar.public_timeline": "Публичен канал", + "navigation_bar.logout": "Излизане", + "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} те спомена", + "notifications.column_settings.alert": "Десктоп известия", + "notifications.column_settings.show": "Покажи в колона", + "notifications.column_settings.follow": "Нови последователи:", + "notifications.column_settings.favourite": "Предпочитани:", + "notifications.column_settings.mention": "Споменавания:", + "notifications.column_settings.reblog": "Споделяния:", +}; + +export default en; diff --git a/app/assets/javascripts/components/locales/index.jsx b/app/assets/javascripts/components/locales/index.jsx index e772c107..f14568a3 100644 --- a/app/assets/javascripts/components/locales/index.jsx +++ b/app/assets/javascripts/components/locales/index.jsx @@ -11,7 +11,7 @@ import eo from './eo'; import ru from './ru'; import ja from './ja'; import zh_hk from './zh-hk'; - +import bg from './bg'; const locales = { en, @@ -27,6 +27,7 @@ const locales = { ru, ja, 'zh-HK': zh_hk, + bg, }; export default function getMessagesForLocale (locale) { diff --git a/app/helpers/settings_helper.rb b/app/helpers/settings_helper.rb index 211b5704..212f88c3 100644 --- a/app/helpers/settings_helper.rb +++ b/app/helpers/settings_helper.rb @@ -16,6 +16,7 @@ module SettingsHelper ja: '日本語', 'zh-CN': '简体中文', 'zh-HK': '繁體中文(香港)', + bg: 'Български', }.freeze def human_locale(locale) diff --git a/config/application.rb b/config/application.rb index 2c720474..1383d45a 100644 --- a/config/application.rb +++ b/config/application.rb @@ -27,6 +27,7 @@ module Mastodon config.i18n.available_locales = [ :en, + :bg, :de, :eo, :es, diff --git a/config/locales/bg.yml b/config/locales/bg.yml new file mode 100644 index 00000000..a8687f3c --- /dev/null +++ b/config/locales/bg.yml @@ -0,0 +1,169 @@ +--- +bg: + about: + about_mastodon: Mastodon е безплатен сървър с отворен код за социални мрежи. Като децентрализирана алтернатива на комерсиалните платформи, той позволява избягването на риска от монополизация на твоята комуникация от единични компании. Изберете си сървър, на който се доверявате, и ще можете да контактувате с всички останали. Всеки може да пусне Mastodon и лесно да вземе участие в социалната мрежа. + about_this: За тази инстанция + apps: Приложения + business_email: 'Служебен e-mail:' + 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: 'Промяна на предпочитанията за e-mail: %{link}' + signature: Mastodon известия от %{instance} + view: 'Преглед:' + applications: + invalid_url: Предоставеният 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} г." + 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: Нещо все още не е наред! Моля, прегледай грешките по-долу + imports: + preface: Можеш да импортираш някои данни, като например всички хора, които следваш или блокираш в акаунта си на тази инстанция, от файлове, създадени чрез експорт в друга инстанция. + success: Твоите данни бяха успешно качени и ще бъдат обработени впоследствие. + types: + blocking: Списък на блокираните + following: Списък на последователите + upload: Качване + landing_strip_html: %{name} е потребител от %{domain}. Можеш да ги следваш, или да контактуваш с тях, ако имаш акаунт където и да е из федерираната вселена на Mastodon. Ако нямаш акаунт, можеш да си създадеш ето тук. + notification_mailer: + digest: + body: 'Ето кратко резюме на нещата, които се случиха от последното ти посещение в %{instance} на %{since}:' + mention: "%{name} те спомена в:" + new_followers_summary: + one: Имаш един нов последовател! Ура! + 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: Назад + remote_follow: + acct: Въведи потребителско_име@домейн, от които искаш да следваш + missing_resource: Неуспешно търсене на нужния URL за пренасочване за твоя акаунт + 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: "%d %b, %Y, %H:%M" + two_factor_auth: + description_html: При активация на двустепенно удостоверяване, за да влезеш в приложението, ще трябва да използваш телефона си. През него ще се генерира код, който да въвеждаш при влизане. + disable: Деактивирай + enable: Активирай + instructions_html: "Сканирай този QR код с Google Authenticator или подобно приложение от своя телефон. Oтсега нататък, това приложение ще генерира код, който ще трябва да въвеждаш при всяко влизане." + plaintext_secret_html: "Тайна в обикновен текст: %{secret}" + warning: Ако не можеш да настроиш приложението за удостверяване сега, избери "Деактивирай". В противен случай, няма да можеш да влезеш в акаунта си. + users: + invalid_email: E-mail адресът е невалиден + invalid_otp_token: Невалиден код + will_paginate: + page_gap: "…" + media_attachments: + validations: + too_many: Не мога да прикача повече от 4 файла + images_and_video: Не мога да прикача видеоклип към публикация, която вече съдържа изображения diff --git a/config/locales/devise.bg.yml b/config/locales/devise.bg.yml new file mode 100644 index 00000000..7485b823 --- /dev/null +++ b/config/locales/devise.bg.yml @@ -0,0 +1,61 @@ +--- +bg: + devise: + confirmations: + confirmed: Твоят профил беше успешно потвърден. Влизането в профила е успешно. + send_instructions: Ще получиш писмо с инструкции как да потвърдиш своя профил до няколко минути. + send_paranoid_instructions: Ако твоят имейл адрес съществува в базата ни, ще получиш там инструкции как да потвърдиш своя профил. + failure: + already_authenticated: Вече си вътре в профила си. + inactive: Профилът ти все още не е активиран. + invalid: Невалиден имейл адрес или парола. + 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: 'Инструкции за смяна на паролата' + unlock_instructions: + subject: 'Инструкции за отключване' + omniauth_callbacks: + failure: "Не успяхме да те упълномощим чрез %{kind}, защото \"%{reason}\"." + success: "Успешно упълномощаване чрез %{kind} профил." + passwords: + no_token: Може да достъпваш тази страница само от имейл за промяна на паролата. Ако тази страница е отворена от такъв имейл, увери се, че използваш целия URL-адрес, който сме ти изпратили. + 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: "Една грешка попречи този %{resource} да бъде записан:" + other: "%{count} грешки попречиха този %{resource} да бъде записан:" diff --git a/config/locales/doorkeeper.bg.yml b/config/locales/doorkeeper.bg.yml new file mode 100644 index 00000000..6fafdfc5 --- /dev/null +++ b/config/locales/doorkeeper.bg.yml @@ -0,0 +1,113 @@ +--- +bg: + activerecord: + attributes: + doorkeeper/application: + name: Име + redirect_uri: URI за пренасочване + errors: + models: + doorkeeper/application: + attributes: + redirect_uri: + fragment_present: не може да съдържа фрагмент. + 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: Разделяй диапазоните с интервал. Остави празно, за да използваш диапазона по подразбиране. + index: + callback_url: URL за обратно повикване + name: Име + new: Ново приложение + title: Твоите приложения + new: + title: Ново приложение + show: + actions: Действия + application_id: Идентификатор на приложението + callback_urls: URL-и за обратно повикване + 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 предизвика грешка, заради това, че настройките за Doorkeeper.configure.resource_owner_from_credentials липсват. + invalid_client: Удостоверяването на клиента предизвика грешка, поради непознат клиент, липсващо клиентско удостоверяване, или заради това, че методът на удостоверяване не се поддържа. + invalid_grant: Предоставеното удостоверение за достъп е невалидно, изтекло, отхвърлено, не съвпада с пренасочващото URI, използвано в заявката за удостоверение, или е бил издадено от друг клиент. + invalid_redirect_uri: Наличното пренасочващо URI е невалидно. + invalid_request: Заявката е с липсващ задължителен параметър, включва стойност на параметъра, която не се поддържа, или е изкривена по друг начин. + invalid_resource_owner: Предоставените идентификационни данни на притежателя на ресурса са невалидни, или притежателят не може да бъде намерен. + invalid_scope: Заявеният диапазон е невалиден, неизвестен или изкривен. + invalid_token: + expired: Маркерът за достъп изтече + revoked: Маркерът за достъп беше отхвърлен + unknown: Маркерът за достъп е невалиден + resource_owner_authenticator_not_configured: Намирането на Resource Owner се провали поради липса на конфигурация на Doorkeeper.configure.resource_owner_authenticator. + server_error: Сървърът за удостоверяване попадна на неочаквано условие, което предотврати изпълнението на заявката. + temporarily_unavailable: Сървърът за удостоверяване не може да се справи със заявката в момента поради временно претоварване или профилактика на сървъра. + unauthorized_client: Клиентът не е удостоверен да изпълни заявката по този начин. + unsupported_grant_type: Типът на удостоврението за достъп не се поддържа от сървъра за удостоверяване. + unsupported_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.bg.yml b/config/locales/simple_form.bg.yml new file mode 100644 index 00000000..55b80277 --- /dev/null +++ b/config/locales/simple_form.bg.yml @@ -0,0 +1,46 @@ +--- +bg: + simple_form: + hints: + defaults: + avatar: PNG, GIF или JPG. До 2MB. Ще бъде смалена до 120x120 пиксела + display_name: До 30 символа + header: PNG, GIF или JPG. До 2MB. Ще бъде смалена до 700x335 пиксела + locked: Изисква ръчно одобрение на последователите. По подразбиране, публикациите са достъпни само до последователи. + note: До 160 символа + imports: + data: CSV файл, експортиран от друга инстанция на Mastodon + labels: + defaults: + avatar: Аватар + confirm_new_password: Потвърди новата парола + confirm_password: Потвърди паролата + current_password: Текуща парола + data: Данни + display_name: Показвано име + email: E-mail адрес + 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: Изпращай e-mail, когато някой хареса твоя публикация + follow: Изпращай e-mail, когато някой те последва + follow_request: Изпращай e-mail, когато някой пожелае да те последва + mention: Изпращай e-mail, когато някой те спомене + reblog: Изпращай e-mail, когато някой сподели твоя публикация + 'no': 'Не' + required: + mark: "*" + text: задължително + 'yes': 'Да' From af7e880df568e76af88a19f471b267378b725794 Mon Sep 17 00:00:00 2001 From: Ratmir Karabut Date: Thu, 13 Apr 2017 14:23:23 +0300 Subject: [PATCH 13/43] Update Russian translation (#1570) * Add Russian translation (ru) * Fix a missing comma * Fix the wording for better consistency * Update Russian translation * Arrange Russian setting alphabetically * Fix syntax error --- .../javascripts/components/locales/ru.jsx | 43 ++++++++++++++++--- config/locales/ru.yml | 19 +++++--- config/locales/simple_form.ru.yml | 2 +- 3 files changed, 51 insertions(+), 13 deletions(-) diff --git a/app/assets/javascripts/components/locales/ru.jsx b/app/assets/javascripts/components/locales/ru.jsx index e109005a..30a92df8 100644 --- a/app/assets/javascripts/components/locales/ru.jsx +++ b/app/assets/javascripts/components/locales/ru.jsx @@ -10,22 +10,29 @@ const ru = { "status.reblogged_by": "{name} продвинул(а)", "status.sensitive_warning": "Чувствительный контент", "status.sensitive_toggle": "Нажмите для просмотра", + "status.show_more": "Развернуть", + "status.show_less": "Свернуть", + "status.open": "Развернуть статус", + "status.report": "Пожаловаться", + "status.load_more": "Показать еще", "video_player.toggle_sound": "Вкл./выкл. звук", - "account.mention": "Упомянуть @{name}", + "account.mention": "Упомянуть", "account.edit_profile": "Изменить профиль", - "account.unblock": "Разблокировать @{name}", + "account.unblock": "Разблокировать", "account.unfollow": "Отписаться", - "account.block": "Блокировать @{name}", + "account.block": "Блокировать", + "account.mute": "Заглушить", "account.follow": "Подписаться", "account.posts": "Посты", "account.follows": "Подписки", - "account.followers": "Подписчики", + "account.followers": "Подписаны", "account.follows_you": "Подписан(а) на Вас", "account.requested": "Ожидает подтверждения", "getting_started.heading": "Добро пожаловать", "getting_started.about_addressing": "Вы можете подписаться на человека, зная имя пользователя и домен, на котором он находится, введя e-mail-подобный адрес в форму поиска.", "getting_started.about_shortcuts": "Если пользователь находится на одном с Вами домене, можно использовать только имя. То же правило применимо к упоминанию пользователей в статусах.", "getting_started.open_source_notice": "Mastodon - программа с открытым исходным кодом. Вы можете помочь проекту или сообщить о проблемах на GitHub по адресу {github}. {apps}.", + "getting_started.apps": "Доступны различные приложения.", "column.home": "Главная", "column.community": "Локальная лента", "column.public": "Глобальная лента", @@ -36,7 +43,7 @@ const ru = { "tabs_bar.public": "Глобальная лента", "tabs_bar.notifications": "Уведомления", "compose_form.placeholder": "О чем Вы думаете?", - "compose_form.publish": "Протрубить", + "compose_form.publish": "Трубить", "compose_form.sensitive": "Отметить как чувствительный контент", "compose_form.spoiler": "Скрыть текст за предупреждением", "compose_form.private": "Отметить как приватное", @@ -47,6 +54,9 @@ const ru = { "navigation_bar.community_timeline": "Локальная лента", "navigation_bar.public_timeline": "Глобальная лента", "navigation_bar.logout": "Выйти", + "navigation_bar.info": "Об узле", + "navigation_bar.favourites": "Понравившееся", + "navigation_bar.blocks": "Список блокировки", "reply_indicator.cancel": "Отмена", "search.placeholder": "Поиск", "search.account": "Аккаунт", @@ -57,12 +67,35 @@ const ru = { "notification.favourite": "{name} понравился Ваш статус", "notification.reblog": "{name} продвинул(а) Ваш статус", "notification.mention": "{name} упомянул(а) Вас", + "home.settings": "Настройки колонки", + "home.column_settings.basic": "Основные", + "home.column_settings.advanced": "Дополнительные", + "home.column_settings.filter_regex": "Отфильтровать регулярным выражением", + "home.column_settings.show_replies": "Показывать продвижения", + "home.column_settings.show_replies": "Показывать ответы", + "notifications.clear": "Очистить уведомления", + "notifications.settings": "Настройки колонки", "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.notifications": "У Вас еще нет уведомлений. Заведите знакомство с другими пользователями, чтобы начать разговор.", + "empty_column.hashtag": "Статусов с таким хэштегом еще не существует.", + "empty_column.community": "Локальная лента пуста. Напишите что-нибудь, чтобы разогреть народ!", + "empty_column.public": "Здесь ничего нет! Опубликуйте что-нибудь или подпишитесь на пользователей с других узлов, чтобы заполнить ленту.", + "empty_column.home": "Пока Вы ни на кого не подписаны. Полистайте {public} или используйте поиск, чтобы освоиться и завести новые знакомства.", + "empty_column.home.public_timeline": "публичные ленты", + "privacy.public.short": "Публичный", + "privacy.public.long": "Показать в публичных лентах", + "privacy.unlisted.short": "Скрытый", + "privacy.unlisted.long": "Не показывать в лентах", + "privacy.private.short": "Приватный", + "privacy.private.long": "Показать только подписчикам", + "privacy.direct.short": "Направленный", + "privacy.direct.long": "Показать только упомянутым", }; export default ru; diff --git a/config/locales/ru.yml b/config/locales/ru.yml index fab17862..0c272585 100644 --- a/config/locales/ru.yml +++ b/config/locales/ru.yml @@ -9,7 +9,7 @@ ru: contact: Связаться description_headline: Что такое %{domain}? domain_count_after: другими узлами - domain_count_before: Связывается с + domain_count_before: Связан с features: api: Открытый API для приложений и сервисов blocks: Продвинутые инструменты блокирования и глушения @@ -25,7 +25,7 @@ ru: other_instances: Другие узлы source_code: Исходный код status_count_after: статусов - status_count_before: Автор + status_count_before: Опубликовано terms: Условия user_count_after: пользователей user_count_before: Здесь живет @@ -42,7 +42,7 @@ ru: application_mailer: settings: 'Изменить настройки e-mail: %{link}' signature: Уведомления Mastodon от %{instance} - view: 'View:' + view: 'Просмотр:' applications: invalid_url: Введенный URL неверен auth: @@ -126,7 +126,7 @@ ru: acct: Введите username@domain, откуда Вы хотите подписаться missing_resource: Поиск требуемого перенаправления URL для Вашего аккаунта завершился неудачей proceed: Продолжить подписку - prompt: 'Вы ходите подписаться на:' + prompt: 'Вы хотите подписаться на:' settings: authorized_apps: Авторизованные приложения back: Назад в Mastodon @@ -142,8 +142,8 @@ ru: show_more: Подробнее visibilities: private: Показывать только подписчикам - public: Публичный - unlisted: Публичный, но без отображения в публичных лентах + public: Показывать всем + unlisted: Показывать всем, но не отображать в публичных лентах stream_entries: click_to_show: Показать reblogged: продвинул(а) @@ -156,8 +156,13 @@ ru: disable: Отключить enable: Включить instructions_html: "Отсканируйте этот QR-код с помощью Google Authenticator или другого подобного приложения на Вашем телефоне. С этого момента приложение будет генерировать токены, которые будет необходимо ввести для входа." + manual_instructions: 'Если Вы не можете отсканировать QR-код и хотите ввести его вручную, секрет представлен здесь открытым текстом:' plaintext_secret_html: 'Секрет открытым текстом: %{secret}' - warning: Если сейчас у Вас не получается настроить аутентификатор, нажмите "отключить", иначе Вы не сможете войти! + code_hint: 'Для подтверждения введите код, сгенерированный приложением аутентификатора' + setup: Настроить + warning: 'Если сейчас у Вас не получается настроить аутентификатор, нажмите "отключить", иначе Вы не сможете войти!' users: invalid_email: Введенный e-mail неверен invalid_otp_token: Введен неверный код + will_paginate: + page_gap: "…" diff --git a/config/locales/simple_form.ru.yml b/config/locales/simple_form.ru.yml index 6f4873bf..b7d8e4e0 100644 --- a/config/locales/simple_form.ru.yml +++ b/config/locales/simple_form.ru.yml @@ -26,7 +26,7 @@ ru: note: О Вас otp_attempt: Двухфакторный код password: Пароль - setting_default_privacy: Приватность постов + setting_default_privacy: Видимость постов type: Тип импорта username: Имя пользователя interactions: From 0e4479bb3aec9dc6db3f352fd4933e2643e3e628 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=96=B0=E9=83=BD=E5=BF=83=28Neet=20Shin=29?= Date: Thu, 13 Apr 2017 16:53:45 +0530 Subject: [PATCH 14/43] Update Japanese translation files (#1640) * [l10n] ja: Improve Japanese Translations * ja: about: Fix highlighting * ja: Update Translations * ja: Translate admin settings Signed-off-by: lindwurm * Update ja.jsx * Update doorkeeper.ja.yml * Update ja.yml * Update ja.jsx * Update ja.jsx --- .../javascripts/components/locales/ja.jsx | 4 +-- config/locales/doorkeeper.ja.yml | 32 +++++++++---------- config/locales/ja.yml | 2 +- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/app/assets/javascripts/components/locales/ja.jsx b/app/assets/javascripts/components/locales/ja.jsx index 25a6f7f6..fdfc91c2 100644 --- a/app/assets/javascripts/components/locales/ja.jsx +++ b/app/assets/javascripts/components/locales/ja.jsx @@ -39,8 +39,8 @@ const ja = { "tabs_bar.compose": "投稿", "tabs_bar.home": "ホーム", "tabs_bar.mentions": "返信", - "tabs_bar.local_timeline": "ローカルTL", - "tabs_bar.federated_timeline": "連合TL", + "tabs_bar.local_timeline": "ローカル", + "tabs_bar.federated_timeline": "連合", "tabs_bar.notifications": "通知", "compose_form.placeholder": "今なにしてる?", "compose_form.publish": "トゥート", diff --git a/config/locales/doorkeeper.ja.yml b/config/locales/doorkeeper.ja.yml index 35592bc4..d3ea9378 100644 --- a/config/locales/doorkeeper.ja.yml +++ b/config/locales/doorkeeper.ja.yml @@ -25,7 +25,7 @@ ja: confirmations: destroy: 本当に削除しますか? edit: - title: アプリケーションの編集 + title: アプリの編集 form: error: フォームにエラーが無いか確認してください。 help: @@ -35,17 +35,17 @@ ja: index: callback_url: コールバックURL name: 名前 - new: 新規アプリケーション - title: あなたのアプリケーション + new: 新規アプリ + title: アプリ new: - title: 新規アプリケーション + title: 新規アプリ show: actions: アクション application_id: アクションId callback_urls: コールバックurl scopes: アクセス権 secret: 非公開 - title: 'アプリケーション: %{name}' + title: 'アプリ: %{name}' authorizations: buttons: authorize: 承認 @@ -53,8 +53,8 @@ ja: error: title: エラーが発生しました。 new: - able_to: このアプリケーションは以下のことができます - prompt: アプリケーション %{client_name} があなたのアカウントへのアクセスを要求しています。 + able_to: このアプリは以下のことができます + prompt: アプリ %{client_name} があなたのアカウントへのアクセスを要求しています。 title: 認証が必要です。 show: title: 認証コード @@ -68,7 +68,7 @@ ja: created_at: 許可した日時 date_format: "%Y年%m月%d日 %H時%M分%S秒" scopes: アクセス権 - title: 認証済みアプリケーション + title: 認証済みアプリ errors: messages: access_denied: リソースの所有者または認証サーバーが要求を拒否しました。 @@ -92,22 +92,22 @@ ja: flash: applications: create: - notice: アプリケーションが作成されました。 + notice: アプリが作成されました。 destroy: - notice: アプリケーションが削除されました。 + notice: アプリが削除されました。 update: - notice: アプリケーションが更新されました。 + notice: アプリが更新されました。 authorized_applications: destroy: - notice: アプリケーションが取り消されました。 + notice: アプリが取り消されました。 layouts: admin: nav: - applications: アプリケーション + applications: アプリ oauth2_provider: OAuth2プロバイダー application: - title: OAuth認証が必要です。 + title: OAuth認証 scopes: follow: アカウントのフォロー, ブロック, ブロック解除, フォロー解除 - read: アカウントへのデータの読み取り - write: アカウントからの投稿の書き込み + read: アカウントからのデータの読み取り + write: アカウントへのデータの書き込み diff --git a/config/locales/ja.yml b/config/locales/ja.yml index 9407c766..cd6b6543 100644 --- a/config/locales/ja.yml +++ b/config/locales/ja.yml @@ -46,7 +46,7 @@ ja: applications: invalid_url: URLが無効です auth: - change_password: 資格情報 + change_password: ログイン情報 didnt_get_confirmation: 確認メールを受信できませんか? forgot_password: パスワードをお忘れですか? login: ログイン From 282bb55c3cae07229d4c9a2fe58c1c2a136c57b9 Mon Sep 17 00:00:00 2001 From: Hugo Gameiro Date: Thu, 13 Apr 2017 12:25:34 +0100 Subject: [PATCH 15/43] fix Portuguese translation (#1661) * update portuguese translation added the missing fields and improved the translation * pt translations fix * improve last translation commit * fix damn quotes --- .../javascripts/components/locales/pt.jsx | 62 ++++++++++++++++++- 1 file changed, 59 insertions(+), 3 deletions(-) diff --git a/app/assets/javascripts/components/locales/pt.jsx b/app/assets/javascripts/components/locales/pt.jsx index 8d1b88c7..cd345a58 100644 --- a/app/assets/javascripts/components/locales/pt.jsx +++ b/app/assets/javascripts/components/locales/pt.jsx @@ -14,59 +14,115 @@ const pt = { "status.show_less": "Mostrar menos", "status.open": "Expandir", "status.report": "Reportar @{name}", + "status.load_more": "Carregar mais", + "status.media_hidden": "Media escondida", "video_player.toggle_sound": "Ligar/Desligar som", + "video_player.toggle_visible": "Ligar/Desligar vídeo", "account.mention": "Mencionar @{name}", "account.edit_profile": "Editar perfil", "account.unblock": "Não bloquear @{name}", "account.unfollow": "Não seguir", "account.block": "Bloquear @{name}", + "account.mute": "Mute", + "account.unmute": "Remover Mute", "account.follow": "Seguir", "account.posts": "Posts", "account.follows": "Segue", "account.followers": "Seguidores", "account.follows_you": "É teu seguidor", "account.requested": "A aguardar aprovação", + "account.report": "Denunciar", + "account.disclaimer": "Essa conta está localizado em outra instância. Os nomes podem ser maiores.", "getting_started.heading": "Primeiros passos", "getting_started.about_addressing": "Podes seguir pessoas se sabes o nome de usuário deles e o domínio em que estão colocando um endereço similar a e-mail no campo no topo da barra lateral.", "getting_started.about_shortcuts": "Se o usuário alvo está no mesmo domínio, só o nome funcionará. A mesma regra se aplica a mencionar pessoas nas postagens.", + "getting_started.about_developer": "Pode seguir o developer deste projecto em Gargron@mastodon.social", "getting_started.open_source_notice": "Mastodon é software de fonte aberta. Podes contribuir ou repostar problemas no GitHub do projecto: {github}. {apps}.", "column.home": "Home", "column.community": "Local", - "column.public": "Público", + "column.public": "Global", "column.notifications": "Notificações", + "column.blocks": "Utilizadores Bloqueados", + "column.favourites": "Favoritos", + "column.follow_requests": "Seguidores Pendentes", + "empty_column.notifications": "Não tens notificações. Interage com outros utilizadores para iniciar uma conversa.", + "empty_column.public": "Não há nada aqui! Escreve algo publicamente ou segue outros utilizadores para ver aqui os conteúdos públicos.", + "empty_column.home": "Ainda não segues qualquer utilizador. Visita {public} ou utiliza a pesquisa para procurar outros utilizadores.", + "empty_column.home.public_timeline": "global", + "empty_column.community": "Ainda não existem conteúdo local para mostrar!", + "empty_column.hashtag": "Não existe qualquer conteúdo com essa hashtag", "tabs_bar.compose": "Criar", "tabs_bar.home": "Home", "tabs_bar.mentions": "Menções", "tabs_bar.public": "Público", "tabs_bar.notifications": "Notificações", + "tabs_bar.local_timeline": "Local", + "tabs_bar.federated_timeline": "Global", "compose_form.placeholder": "Em que estás a pensar?", "compose_form.publish": "Publicar", - "compose_form.sensitive": "Media com conteúdo sensível", + "compose_form.sensitive": "Marcar media como conteúdo sensível", "compose_form.spoiler": "Esconder texto com aviso", + "compose_form.spoiler_placeholder": "Aviso", "compose_form.private": "Tornar privado", "compose_form.privacy_disclaimer": "O teu conteúdo privado vai ser partilhado com os utilizadores do {domains}. Confias {domainsCount, plural, one {neste servidor} other {nestes servidores}}? A privacidade só funciona em instâncias do Mastodon. Se {domains} {domainsCount, plural, one {não é uma instância} other {não são instâncias}}, não existem indicadores da privacidade da tua partilha, e podem ser partilhados com outros.", "compose_form.unlisted": "Não mostrar na listagem pública", + "emoji_button.label": "Inserir Emoji", "navigation_bar.edit_profile": "Editar perfil", "navigation_bar.preferences": "Preferências", "navigation_bar.community_timeline": "Local", - "navigation_bar.public_timeline": "Público", + "navigation_bar.public_timeline": "Global", + "navigation_bar.blocks": "Utilizadores bloqueados", + "navigation_bar.favourites": "Favoritos", + "navigation_bar.info": "Mais informações", "navigation_bar.logout": "Sair", + "navigation_bar.follow_requests": "Seguidores pendentes", "reply_indicator.cancel": "Cancelar", "search.placeholder": "Pesquisar", "search.account": "Conta", "search.hashtag": "Hashtag", + "search_results.total": "{count} {count, plural, one {resultado} other {resultados}}", + "search.status_by": "Post de {name}", "upload_button.label": "Adicionar media", "upload_form.undo": "Anular", + "upload_progress.label": "A gravar…", + "upload_area.title": "Arraste e solte para enviar", "notification.follow": "{name} seguiu-te", "notification.favourite": "{name} adicionou o teu post aos favoritos", "notification.reblog": "{name} partilhou o teu post", "notification.mention": "{name} mencionou-te", "notifications.column_settings.alert": "Notificações no computador", "notifications.column_settings.show": "Mostrar nas colunas", + "notifications.column_settings.sound": "Reproduzir som", "notifications.column_settings.follow": "Novos seguidores:", "notifications.column_settings.favourite": "Favoritos:", "notifications.column_settings.mention": "Menções:", "notifications.column_settings.reblog": "Partilhas:", + "notifications.clear": "Limpar notificações", + "notifications.clear_confirmation": "Queres mesmo limpar todas as notificações?", + "notifications.settings": "Parâmetros da lista de Notificações", + "privacy.public.short": "Público", + "privacy.public.long": "Publicar em todos os feeds", + "privacy.unlisted.short": "Não listar", + "privacy.unlisted.long": "Não publicar nos feeds públicos", + "privacy.private.short": "Privado", + "privacy.private.long": "Apenas para os seguidores", + "privacy.direct.short": "Directo", + "privacy.direct.long": "Apenas para utilizadores mencionados", + "privacy.change": "Ajustar a privacidade da mensagem", + "media_gallery.toggle_visible": "Modificar a visibilidade", + "missing_indicator.label": "Não encontrado", + "follow_request.authorize": "Autorizar", + "follow_request.reject": "Rejeitar", + "home.settings": "Parâmetros da coluna Home", + "home.column_settings.basic": "Básico", + "home.column_settings.show_reblogs": "Mostrar as partilhas", + "home.column_settings.show_replies": "Mostrar as respostas", + "home.column_settings.advanced": "Avançadas", + "home.column_settings.filter_regex": "Filtrar com uma expressão regular", + "report.heading": "Nova denuncia", + "report.placeholder": "Comentários adicionais", + "report.submit": "Enviar", + "report.target": "Denunciar" }; export default pt; From 90d0018fd5023a2029e13ea74df22cbc0d938b49 Mon Sep 17 00:00:00 2001 From: May Kittens Devour Your Soul Date: Thu, 13 Apr 2017 13:38:44 +0200 Subject: [PATCH 16/43] Adds Croatian language [Hrvatski] (#1000) * Create simple.form.hr.yml * Create hr.yml * Update hr.yml * Update hr.yml * Create doorkeeper.hr.yml * Create devise.hr.yml --- config/locales/devise.hr.yml | 60 +++++++++++ config/locales/doorkeeper.hr.yml | 113 ++++++++++++++++++++ config/locales/hr.yml | 165 ++++++++++++++++++++++++++++++ config/locales/simple.form.hr.yml | 46 +++++++++ 4 files changed, 384 insertions(+) create mode 100644 config/locales/devise.hr.yml create mode 100644 config/locales/doorkeeper.hr.yml create mode 100644 config/locales/hr.yml create mode 100644 config/locales/simple.form.hr.yml diff --git a/config/locales/devise.hr.yml b/config/locales/devise.hr.yml new file mode 100644 index 00000000..352641ca --- /dev/null +++ b/config/locales/devise.hr.yml @@ -0,0 +1,60 @@ +--- +hr: + devise: + confirmations: + confirmed: Tvoja email adresa je uspješno potvrđena. + send_instructions: Primit ćeš email sa uputama kako potvrditi svoju email adresu za nekoliko minuta. + send_paranoid_instructions: Ako tvoja email adresa postoji u našoj bazi podataka, primit ćeš email sa uputama kako ju potvrditi za nekoliko minuta. + already_authenticated: Već si prijavljen. + inactive: Tvoj račun još nije aktiviran. + invalid: Nevaljan %{authentication_keys} ili lozinka. + last_attempt: Imaš još jedan pokušaj prije no što ti se račun zaključa. + locked: Tvoj račun je zaključan. + not_found_in_database: Nevaljani %{authentication_keys} ili lozinka. + timeout: Tvoja sesija je istekla. Molimo te, prijavi se ponovo kako bi nastavio. + unauthenticated: Moraš se registrirati ili prijaviti prije no što nastaviš. + unconfirmed: Moraš potvrditi svoju email adresu prije no što nastaviš. + mailer: + confirmation_instructions: + subject: 'Mastodon: Upute za potvrđivanje' + password_change: + subject: 'Mastodon: Lozinka je promijenjena' + reset_password_instructions: + subject: 'Mastodon: Upute za resetiranje lozinke' + unlock_instructions: + subject: 'Mastodon: Upute za otključavanje' + omniauth_callbacks: + failure: Ne možemo te autentificirati sa %{kind} zbog "%{reason}". + success: Uspješno autentificiran sa %{kind} računa. + passwords: + no_token: Ne možeš pristupiti ovoj stranici bez dolaženja sa emaila za resetiranje lozinke. Ako dolaziš sa tog emaila, pazi da koristiš potpuni link koji ti je dan. + send_instructions: Primit ćeš email sa uputama kako resetirati svoju lozinku za nekoliko minuta. + send_paranoid_instructions: Ako tvoja email adresa postoji u našoj bazi podataka, primit ćeš link za povrat lozinke na svoju email adresu za nekoliko minuta. + updated: Tvoja lozinka je uspješno izmijenjena. Sada si prijavljen. + updated_not_active: Toja lozinka je uspješno izmijenjena. + registrations: + destroyed: Zbogom! Tvoj račun je uspješno otkazan. Nadamo se da ćemo te vidjeti ponovo. + signed_up: Dobro došao! Uspješno si se prijavio. + signed_up_but_inactive: Uspješno si se registrirao. No, ne možeš se prijaviti, jer ti račun još nije aktiviran. + signed_up_but_locked: Uspješno si se registrirao. No, ne možeš se prijaviti jer je tvoj račun zaključan. + signed_up_but_unconfirmed: Poruka sa linkom za potvrđivanje je poslana na tvoju email adresu. Molimo, slijedi link kako bi tvoj račun bio aktiviran. + update_needs_confirmation: Tvoj račun je uspješno ažuriran, ali trebamo provjeriti tvoju novu email adresu. Molimo, provjeri svoj email i slijedi link za potvrđivanje kako bi tvoja nova email adresa bila potvrđena. + updated: Tvoj račun je uspješno ažuriran. + sessions: + already_signed_out: Uspješno si odjavljen. + signed_in: Uspješno si prijavljen. + signed_out: Uspješno si odjavljen. + unlocks: + send_instructions: Primit ćeš email sa uputama kako otključati svoj račun za nekoliko minuta. + send_paranoid_instructions: Ako tvoj račun postoji, primit ćeš email sa uputama kako ga otključati za nekoliko minuta. + unlocked: Tvoj račun je uspješno otključan. Prijavi se kako bi nastavio. + errors: + messages: + already_confirmed: je već potvrđen, pokušaj se prijaviti + confirmation_period_expired: mora biti potvrđen u roku od %{period}, molimo zatraži novi + expired: je istekao, zatraži novu + not_found: nije nađen + not_locked: nije zaključan + not_saved: + one: '1 greška je zabranila da ovaj %{resource} bude sačuvan:' + other: "%{count} greške su zabranile da ovaj %{resource} bude sačuvan:" diff --git a/config/locales/doorkeeper.hr.yml b/config/locales/doorkeeper.hr.yml new file mode 100644 index 00000000..26d21c10 --- /dev/null +++ b/config/locales/doorkeeper.hr.yml @@ -0,0 +1,113 @@ +--- +hr: + activerecord: + attributes: + doorkeeper/application: + name: Ime + redirect_uri: Redirect URI + errors: + models: + doorkeeper/application: + attributes: + redirect_uri: + fragment_present: ne može sadržavati fragment. + invalid_uri: mora biti valjan URI. + relative_uri: mora biti apsolutan URI. + secured_uri: mora biti HTTPS/SSL URI. + doorkeeper: + applications: + buttons: + authorize: Odobri + cancel: Otkaži + destroy: Uništi + edit: Uredi + submit: Pošalji + confirmations: + destroy: Jesi li siguran? + edit: + title: Uredi aplikaciju + form: + error: Ups! Provjeri svoju formu za moguće greške + help: + native_redirect_uri: Koristi %{native_redirect_uri} za lokalne testove + redirect_uri: Koristi jednu liniju po URI + scopes: Odvoji scopes sa razmacima. Ostavi prazninu kako bi koristio zadane scopes. + index: + callback_url: Callback URL + name: Ime + new: Nova Aplikacija + title: Tvoje aplikacije + new: + title: Nova Aplikacija + show: + actions: Akcije + application_id: Id Aplikacije + callback_urls: Callback urls + scopes: Scopes + secret: Tajna + title: 'Aplikacija: %{name}' + authorizations: + buttons: + authorize: Odobri + deny: Odbij + error: + title: Došlo je do greške + new: + able_to: Moći će + prompt: Aplikacija %{client_name} je zatražila pristup tvom računu + title: Traži se autorizacija + show: + title: Autorizacijski kod + authorized_applications: + buttons: + revoke: Odbij + confirmations: + revoke: Jesi li siguran? + index: + application: Aplikacija + created_at: Ovlašeno + date_format: "%Y-%m-%d %H:%M:%S" + scopes: Scopes + title: Tvoje autorizirane aplikacije + errors: + messages: + access_denied: Vlasnik resursa / autorizacijski server je odbio zahtjev. + credential_flow_not_configured: Resource Owner Password Credentials flow failed due to Doorkeeper.configure.resource_owner_from_credentials being unconfigured. + invalid_client: Autentifikacija klijenta nije uspjela zbog nepoznatog klijenta, neuključene autentifikacije od strane klijenta, ili nepodržane metode autentifikacije. + invalid_grant: The provided authorization grant is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client. + invalid_redirect_uri: The redirect uri included nije valjan. + invalid_request: Zahtjevu nedostaje traženi parametar, uključuje nepodržanu vrijednost parametra, ili je na neki drugi način neispravno formiran. + invalid_resource_owner: The provided resource owner credentials nisu valjani, ili vlasnik resursa ne može biti nađen + invalid_scope: Traženi scope nije valjan, znan, ili je neispravno oblikovan. + invalid_token: + expired: Pristupni token je istekao + revoked: Pristupni token je odbijen + unknown: Pristupni token nije valjan + resource_owner_authenticator_not_configured: Resource Owner find failed due to Doorkeeper.configure.resource_owner_authenticator being unconfiged. + server_error: Autorizacijski server naišao je na neočekivani uvjet, što ga je onemogućilo da ispuni zahtjev. + temporarily_unavailable: Autorizacijski server trenutno nije u mogućnosti izvesti zahtjev zbog privremenog preopterećenja ili održavanja servera. + unauthorized_client: Klijent nije ovlašten izvesti zahtjev koristeći ovu metodu. + unsupported_grant_type: The authorization grant tip nije podržan od autorizacijskog servera. + unsupported_response_type: Autorizacijski server ne podržava ovaj tip odgovora. + flash: + applications: + create: + notice: Aplikacija je stvorena. + destroy: + notice: Aplikacija je obrisana. + update: + notice: Aplikacija je ažurirana. + authorized_applications: + destroy: + notice: Aplikacija je odbijena. + layouts: + admin: + nav: + applications: Aplikacije + oauth2_provider: OAuth2 Provider + application: + title: Traži se OAuth autorizacija + scopes: + follow: slijediti, blokirati, deblokirati i prestati slijediti račune + read: čitati podatke tvog računa + write: slati poruke u tvoje ime diff --git a/config/locales/hr.yml b/config/locales/hr.yml new file mode 100644 index 00000000..64b1ae2c --- /dev/null +++ b/config/locales/hr.yml @@ -0,0 +1,165 @@ +--- +hr: + about: + about_mastodon: Mastodon je besplatna, open-source socijalna mreža. Decentralizirana alternativa komercijalnim platformama, izbjegava rizik toga da jedna tvrtka monopolizira vašu komunikaciju. Izaberite server kojem ćete vjerovati — koji god odabrali, moći ćete komunicirati sa svima ostalima. Bilo tko može imati svoju vlastitu Mastodon instancu i sudjelovati u socijalnoj mreži bez problema. + about_this: O ovoj instanci + apps: Aplikacije + business_email: 'Poslovni e-mail:' + closed_registrations: Registracije na ovoj instanci su trenutno zatvorene. + contact: Kontakt + description_headline: Što je %{domain}? + domain_count_after: druge instance + domain_count_before: Spojen na + features: + api: Otvoren API za aplikacije i servise + blocks: Bogati alati za blokiranje i ušutkivanje + characters: 500 znakova po postu + chronology: Timelines su kronološke + ethics: 'Etički dizajn: bez oglasa, bez praćenja' + gifv: GIFV setovi i kratki videi + privacy: Granularne postavke privatnosti, po postu + public: Javne timelines + features_headline: Po čemu se Mastodon razlikuje + get_started: Započni + links: Linkovi + other_instances: Druge instance + source_code: Izvorni kod + status_count_after: statusi + status_count_before: Tko je autor + terms: Uvjeti + user_count_after: korisnici + user_count_before: Home to + accounts: + follow: Slijedi + followers: Sljedbenici + following: Slijedim + nothing_here: Ovdje nema ničeg! + people_followed_by: Ljudi koje %{name} slijedi + people_who_follow: Ljudi koji slijede %{name} + posts: Postovi + remote_follow: Remote follow + unfollow: Prestani slijediti + application_mailer: + settings: 'Promijeni e-mail postavke: %{link}' + signature: Mastodon notifikacije sa %{instance} + view: 'View:' + applications: + invalid_url: Uneseni link nije valjan + auth: + change_password: Vjerodajnice + didnt_get_confirmation: Niste primili instrukcije za potvrđivanje? + forgot_password: Zaboravljena lozinka? + login: Prijavi se + logout: Odjavi se + register: Registriraj se + resend_confirmation: Ponovo pošalji instrukcije za potvrđivanje + reset_password: Resetiraj lozinku + set_new_password: Postavi novu lozinku + authorize_follow: + error: Nažalost, došlo je do greške looking up the remote račun + follow: Slijedi + prompt_html: 'Ti si (%{self}) poslao zahtjev za sljeđenje:' + title: Slijedi %{acct} + datetime: + distance_in_words: + about_x_hours: "%{count}s" + about_x_months: "%{count}mj" + about_x_years: "%{count}g" + almost_x_years: "%{count}g" + half_a_minute: upravo + less_than_x_minutes: "%{count}m" + less_than_x_seconds: upravo + over_x_years: "%{count}g" + x_days: "%{count}d" + x_minutes: "%{count}m" + x_months: "%{count}mj" + x_seconds: "%{count}sek" + exports: + blocks: Blokirao si + csv: CSV + follows: Slijediš + storage: Pohrana media zapisa + generic: + changes_saved_msg: Izmjene su uspješno sačuvane! + powered_by: omogućuje %{link} + save_changes: Sačuvaj izmjene + validation_errors: + one: Nešto ne štima! Vidi grešku ispod + other: Nešto još uvijek ne štima! Vidi %{count} greške ispod + imports: + preface: Možeš uvesti određene podatke kao što su svi ljudi koje slijediš ili blokiraš u svoj račun na ovoj instanci, sa fajlova kreiranih izvozom sa druge instance. + success: Tvoji podaci su uspješno uploadani i bit će obrađeni u dogledno vrijeme + types: + blocking: Lista blokiranih + following: Lista onih koje slijedim + upload: Upload + landing_strip_html: %{name} je korisnik na %{domain}. Možeš ih slijediti ili komunicirati s njima ako imaš račun igdje u fediversu. Ako nemaš, možeš se registrirati ovdje. + notification_mailer: + digest: + body: 'Ovo je kratak sažetak propuštenog %{instance} od tvog prošlog posjeta %{since}:' + mention: "%{name} te je spomenuo:" + new_followers_summary: + one: Imaš novog sljedbenika! Yay! + other: Imaš %{count} novih sljedbenika! Prekrašno! + subject: + one: "1 nova notifikacija od tvog prošlog posjeta \U0001F418" + other: "%{count} novih notifikacija od tvog prošlog posjeta \U0001F418" + favourite: + body: 'Tvoj status je %{name} označio kao omiljen:' + subject: "%{name} je označio kao omiljen tvoj status" + follow: + body: "%{name} te sada slijedi!" + subject: "%{name} te sada slijedi" + follow_request: + body: "%{name} je zatražio da te slijedi" + subject: 'Sljedbenik na čekanju: %{name}' + mention: + body: 'Spomenuo te je %{name} in:' + subject: Spomenuo te je %{name} + reblog: + body: 'Tvoj status je potaknut od %{name}:' + subject: "%{name} je potakao tvoj status" + pagination: + next: Sljedeći + prev: Prošli + remote_follow: + acct: Unesi svoje username@domain sa koje želiš slijediti + missing_resource: Could not find the required redirect URL za tvoj račun + proceed: Nastavi slijediti + prompt: 'Slijediti ćeš:' + settings: + authorized_apps: Autorizirane aplikacije + back: Natrag na Mastodon + edit_profile: Uredi profil + export: Izvoz podataka + import: Uvezi + preferences: Postavke + settings: Podešenja + two_factor_auth: Dvo-faktorska Autentifikacija + statuses: + open_in_web: Otvori na webu + over_character_limit: prijeđen je limit od %{max} znakova + show_more: Prikaži više + visibilities: + private: Pokaži samo sljedbenicima + public: Javno + unlisted: Javno, no nemoj prikazati na javnom timelineu + stream_entries: + click_to_show: Klikni da bi prikazao + reblogged: potaknut + sensitive_content: Osjetljivi sadržaj + time: + formats: + default: "%b %d, %Y, %H:%M" + two_factor_auth: + description_html: Ako omogućiš two-factor autentifikaciju, prijavljivanje će zahtjevati da kod sebe imaš svoj mobitel, koji će generirati tokene koje ćeš unijeti. + disable: Onemogući + enable: Omogući + instructions_html: "Skeniraj ovaj QR kod into Google Authenticator or a similiar app on your phone. Od sada, ta aplikacija će generirati tokene koje ćeš unijeti pri prijavljivanju." + plaintext_secret_html: 'Plain-text secret: %{secret}' + warning: Ako trenuno ne možeš konfigurirati authenticator app, trebaš kliknuti "onemogući" ili se nećeš moći prijaviti. + users: + invalid_email: E-mail adresa nije valjana + invalid_otp_token: Nevaljani dvo-faktorski kod + will_paginate: + page_gap: "…" diff --git a/config/locales/simple.form.hr.yml b/config/locales/simple.form.hr.yml new file mode 100644 index 00000000..d34b4623 --- /dev/null +++ b/config/locales/simple.form.hr.yml @@ -0,0 +1,46 @@ +--- +hr: + simple_form: + hints: + defaults: + avatar: PNG, GIF ili JPG. Najviše 2MB. Bit će smanjen na 120x120px + display_name: Najviše 30 znakova + header: PNG, GIF ili JPG. Najviše 2MB. Bit će smanjen na 700x335px + locked: traži te da ručno odobriš sljedbenike i postavlja privatnost postova na dostupnu samo sljedbenicima + note: Najviše 160 znakova + imports: + data: CSV fajl izvezen iz druge Mastodon instance + labels: + defaults: + avatar: Avatar + confirm_new_password: Potvrdi novu lozinku + confirm_password: Potvrdi lozinku + current_password: Trenutna lozinka + data: Podaci + display_name: Ime koje ću prikazati + email: E-mail adresa + header: Header + locale: Jezik + locked: Učini račun privatnim + new_password: Nova lozinka + note: Bio + otp_attempt: Dvo-faktorski kod + password: Lozinka + setting_default_privacy: Privatnost posta + type: Tip uvoženja + username: Korisničko ime + interactions: + must_be_follower: Blokiraj notifikacije onih koji me ne slijede + must_be_following: Blokiraj notifikacije ljudi koje ne slijedim + notification_emails: + digest: Šalji mi e-mailove s notifikacijama + favourite: Pošalji mi e-mail kad netko lajka moj status + follow: Pošalji mi e-mail kad me netko počne slijediti + follow_request: Pošalji mi e-mail kad mi netko pošalje zahtjev da me želi slijediti + mention: Pošalji mi e-mail kad me netko spomene + reblog: Pošalji mi e-mail kad netko rebloga moj status + 'no': 'Ne' + required: + mark: "*" + text: traženo + 'yes': 'Da' From 79546799af8b6303e681c48aba76adb6d4274da7 Mon Sep 17 00:00:00 2001 From: Matteo Aquila Date: Thu, 13 Apr 2017 13:39:00 +0200 Subject: [PATCH 17/43] Added Italian language (it) (#1679) --- devise.it.yml | 61 ++++++++++++++++ doorkeeper.it.yml | 113 +++++++++++++++++++++++++++++ it.yml | 172 +++++++++++++++++++++++++++++++++++++++++++++ simple_form.it.yml | 47 +++++++++++++ 4 files changed, 393 insertions(+) create mode 100644 devise.it.yml create mode 100644 doorkeeper.it.yml create mode 100644 it.yml create mode 100644 simple_form.it.yml diff --git a/devise.it.yml b/devise.it.yml new file mode 100644 index 00000000..813ccaba --- /dev/null +++ b/devise.it.yml @@ -0,0 +1,61 @@ +--- +it: + devise: + confirmations: + confirmed: Il tuo indirizzo email è stato confermato con successo. + send_instructions: Riceverai in pochi minuti una email con istruzioni per confermare il tuo account al tuo indirizzo email. + send_paranoid_instructions: Se il tuo indirizzo email è presente nel nostro database, riceverai in pochi minuti una email con istruzioni per confermare il tuo account al tuo indirizzo email. + failure: + already_authenticated: Hai già effettuato l'accesso. + inactive: Non hai ancora attivato il tuo account. + invalid: %{authentication_keys} o password invalida. + last_attempt: Hai un altro tentativo prima che il tuo account venga bloccato. + locked: Il tuo account è stato bloccato. + not_found_in_database: %{authentication_keys} o password invalida. + timeout: La tua sessione è terminata. Per favore, effettua l'accesso o registrati per continuare. + unauthenticated: Devi effettuare l'accesso o registrarti per continuare. + unconfirmed: Devi confermare il tuo indirizzo email per continuare. + mailer: + confirmation_instructions: + subject: 'Mastodon: Istruzioni di conferma per %{instance}' + password_change: + subject: 'Mastodon: Password modificata' + reset_password_instructions: + subject: 'Mastodon: Istruzioni per il reset della password' + unlock_instructions: + subject: 'Mastodon: Istruzioni di sblocco' + omniauth_callbacks: + failure: Impossibile autenticarti da %{kind} perché "%{reason}". + success: Autenticato con successo con account %{kind}. + passwords: + no_token: Non puoi accedere a questa pagina senza essere stato reindirizzato da una mail di reset password. Se arrivi da una mail di reset password, per favore controlla di aver copiato per intero l'URL fornito. + send_instructions: Se la tua mail è presente nel nostro database, riceverai in pochi minuti un link per recuperare la tua password al tuo indirizzo mail. + send_paranoid_instructions: Se la tua mail è presente nel nostro database, riceverai in pochi minuti un link per recuperare la tua password al tuo indirizzo mail. + updated: La tua password è stata modificata con successo. Abbiamo già effettuato l'accesso per te. + updated_not_active: La tua password è stata modificata con successo. + registrations: + destroyed: Addio! Il tuo account è stato cancellato. Speriamo di rivederti presto. + signed_up: Benvenuto! Ti sei registrato con successo. + signed_up_but_inactive: Ti sei registrato con successo. Purtroppo però non possiamo farti accedere perché non hai ancora attivato il tuo account. + signed_up_but_locked: Ti sei registrato con successo. Purtroppo però non possiamo farti accedere perché il tuo account è bloccato. + signed_up_but_unconfirmed: Un messaggio con un link di conferma è stato inviato al tuo indirizzo email. Per favore, visita il link per attivare il tuo account. + update_needs_confirmation: Hai aggiornato correttamente il tuo account, ma abbiamo bisogno di verificare il tuo nuovo indirizzo email. Per favore, controlla la posta in arrivo e visita il link di conferma per verificare il tuo indirizzo email. + updated: Il tuo account è stato aggiornato con successo. + sessions: + already_signed_out: Sei uscito correttamente dal tuo account. + signed_in: Accesso eseguito correttamente. + signed_out: Sei uscito correttamente dal tuo account. + unlocks: + send_instructions: Riceverai in pochi minuti una email con istruzioni su come sbloccare il tuo account. + send_paranoid_instructions: Se il tuo account esiste, riceverai in pochi minuti una email con istruzioni su come sbloccarlo. + unlocked: Il tuo account è stato sbloccato con successo. Per favore, esegui l'accesso per continuare. + errors: + messages: + already_confirmed: era già stata confermata; per favore, prova ad eseguire l'accesso + confirmation_period_expired: deve essere confermata entro %{period}; per favore, richiedine una nuova + expired: è terminata; per favore, richiedine una nuova + not_found: non trovato + not_locked: non era stato bloccato + not_saved: + one: '1 errore ha impedito che %{resource} venisse salvato:' + other: "%{count} errori hanno impedito che %{resource} venisse salvato:" \ No newline at end of file diff --git a/doorkeeper.it.yml b/doorkeeper.it.yml new file mode 100644 index 00000000..2f9b9151 --- /dev/null +++ b/doorkeeper.it.yml @@ -0,0 +1,113 @@ +--- +it: + activerecord: + attributes: + doorkeeper/application: + name: Nome + redirect_uri: URI di reindirizzamento + errors: + models: + doorkeeper/application: + attributes: + redirect_uri: + fragment_present: non può contenere un frammento. + invalid_uri: deve essere un URI valido. + relative_uri: deve essere un URI assoluto. + secured_uri: deve essere un URI HTTPS/SSL. + doorkeeper: + applications: + buttons: + authorize: Autorizza + cancel: Annulla + destroy: Distruggi + edit: Modifica + submit: Invia + confirmations: + destroy: Sei sicuro? + edit: + title: Modifica applicazione + form: + error: Ooops! Controlla nel modulo la presenza di errori + help: + native_redirect_uri: Usa %{native_redirect_uri} per test locali + redirect_uri: Usa una riga per URI + scopes: Dividi gli scopes con spazi. Lascia vuoto per utilizzare gli scopes di default. + index: + callback_url: Callback URL + name: Nome + new: Nuova applicazione + title: Le tue applicazioni + new: + title: Nuova applicazione + show: + actions: Azioni + application_id: Id applicazione + callback_urls: Callback urls + scopes: Scopes + secret: Secret + title: 'Applicazione: %{name}' + authorizations: + buttons: + authorize: Autorizza + deny: Nega + error: + title: Si è verificato un errore + new: + able_to: Non sarà in grado di + prompt: L'applicazione %{client_name} richiede l'accesso al tuo account + title: Autorizzazione richiesta + show: + title: Codice autorizzazione + authorized_applications: + buttons: + revoke: Disabilita + confirmations: + revoke: Sei sicuro? + index: + application: Applicazione + created_at: Autorizzato + date_format: "%d-%m-%Y %H:%M:%S" + scopes: Scopes + title: Applicazioni autorizzate + errors: + messages: + access_denied: Il proprietario del servizio o il server di autorizzazione hanno rifiutato la richiesta. + credential_flow_not_configured: Il processo Resource Owner Password Credentials è fallito perché Doorkeeper.configure.resource_owner_from_credentials non è stato configurato. + invalid_client: Accesso al servizio fallito perché il servizio è sconosciuto, l'accesso al servizio non è stato incluso, o il metodo di accesso non è supportato. + invalid_grant: Il permesso d'autorizzazione è non valido, scaduto, disabilitato, non coincide con l'URI di reindirizzamento fornito nella richiesta di autorizzazione, o è stato rilasciato da un altro client. + invalid_redirect_uri: L'URI di reindirizzamento fornito non è valido. + invalid_request: La richiesta non contiene un parametro necessario, contiene un valore parametrico non supportato, o è altrimenti malformulata. + invalid_resource_owner: Le credenziali di accesso fornite per il proprietario non sono corrette, o il proprietario del servizio non è stato trovato + invalid_scope: Lo scope richiesto è invalido, sconosciuto, o malformulato. + invalid_token: + expired: Il token di accesso è scaduto + revoked: Il token di accesso è stato disabilitato + unknown: Il token di accesso non è valido + resource_owner_authenticator_not_configured: Impossibile trovare il proprietario del servizio perché Doorkeeper.configure.resource_owner_authenticator non è stato configurato. + server_error: Il server di autorizzazione ha riscontrato un errore imprevisto che non ha permesso di completare la tua richiesta. + temporarily_unavailable: Al momento il server di autorizzazione non può completare la tua richiesta a causa di un temporaneo sovraccarico o di manutenzione del server. + unauthorized_client: Il client non è autorizzato a eseguire questa operazione con questo metodo. + unsupported_grant_type: Questa modalità di trasmissione di autenticazione non è supportata da questo server. + unsupported_response_type: Il server autorizzatore non supporta questa modalità di risposta. + flash: + applications: + create: + notice: Applicazione creata. + destroy: + notice: Applicazione cancellata. + update: + notice: Applicazione aggiornata. + authorized_applications: + destroy: + notice: Applicazione disabilitata. + layouts: + admin: + nav: + applications: Applicazioni + oauth2_provider: OAuth2 Provider + application: + title: Autorizzazione OAuth richiesta + scopes: + follow: seguire, bloccare, sbloccare e smettere di seguire account + read: leggere le informazioni del tuo account + write: pubblicare post in tua vece \ No newline at end of file diff --git a/it.yml b/it.yml new file mode 100644 index 00000000..453de87a --- /dev/null +++ b/it.yml @@ -0,0 +1,172 @@ +--- +it: + about: + about_mastodon: Mastodon è un social network gratuito e open-source. Un'alternativa decentralizzata alle piattaforme commerciali che evita che una singola compagnia monopolizzi il tuo modo di comunicare. Scegli un server di cui ti fidi — qualunque sia la tua scelta, potrai interagire con chiunque altro. Chiunque può sviluppare un suo server Mastodon e partecipare alla vita del social network. + about_this: A proposito di questo server + apps: Applicazioni + business_email: 'Email di lavoro:' + closed_registrations: Al momento le iscrizioni a questo server sono chiuse. + contact: Contatti + description_headline: Cos'è %{domain}? + domain_count_after: altri server + domain_count_before: Connesso a + features: + api: API aperto per applicazioni e servizi + blocks: Potenti strumenti di blocco e silenziamento + characters: 500 caratteri per status + chronology: Le timeline sono cronologiche + ethics: 'Design etico: niente pubblicità, niente tracking' + gifv: Set di GIFV e brevi video + privacy: Opzioni di privacy mirate per-post + public: Timeline pubbliche + features_headline: Cosa rende Mastodon migliore + get_started: Inizia + links: Links + other_instances: Altri server + source_code: Codice sorgente + status_count_after: status + status_count_before: Che hanno pubblicato + terms: Termini di Utilizzo + user_count_after: utenti + user_count_before: Casa di + accounts: + follow: Segui + followers: Seguaci + following: Seguiti + nothing_here: Qui non c'è nulla! + people_followed_by: Persone seguite da %{name} + people_who_follow: Persone che seguono %{name} + posts: Posts + remote_follow: Segui da remoto + unfollow: Non seguire più + application_mailer: + settings: 'Cambia le impostazioni per le e-mail: %{link}' + signature: Notifiche Mastodon da %{instance} + view: 'Guarda:' + applications: + invalid_url: L'URL fornito non è valido + auth: + change_password: Credenziali + didnt_get_confirmation: Non hai ricevuto le istruzioni di conferma? + forgot_password: Hai dimenticato la tua password? + login: Entra + logout: Logout + register: Iscriviti + resend_confirmation: Invia di nuovo le istruzioni di conferma + reset_password: Resetta la password + set_new_password: Imposta una nuova password + authorize_follow: + error: Sfortunatamente c'è stato un errore nel consultare l'account remoto + follow: Segui + prompt_html: 'Tu, (%{self}), hai richiesto di seguire:' + title: Segui %{acct} + datetime: + distance_in_words: + about_x_hours: "%{count} ore" + about_x_months: "%{count} mesi" + about_x_years: "%{count} anni" + almost_x_years: "%{count} anni" + half_a_minute: Adesso + less_than_x_minutes: "%{count} minuti" + less_than_x_seconds: Adesso + over_x_years: "%{count} anni" + x_days: "%{count} giorni" + x_minutes: "%{count} minuti" + x_months: "%{count} mesi" + x_seconds: "%{count} secondi" + exports: + blocks: Stai bloccando + csv: CSV + follows: Stai seguendo + storage: Archiviazione media + generic: + changes_saved_msg: Modifiche effettuate con successo! + powered_by: offerto da %{link} + save_changes: Salva modifiche + validation_errors: + one: Qualcosa ancora non va bene! Per favore, controlla l'errore qui sotto + other: Qualcosa ancora non va bene! Per favore, controlla i %{count} errori qui sotto + imports: + preface: Puoi importare alcune informazioni, come le persone che segui o hai bloccato su questo server, da file creati da un esportazione su un altro server. + success: Le tue impostazioni sono state importate correttamente e verranno applicate in breve tempo + types: + blocking: Lista dei bloccati + following: Lista dei seguaci + upload: Carica + landing_strip_html: %{name} è un utente su %{domain}. Puoi seguirlo o interagire con lui se possiedi un account ovunque nel fediverse. Se non possiedi un account, puoi iscriverti qui. + media_attachments: + validations: + images_and_video: Impossibile allegare video a un post che contiene già immagini + too_many: Impossibile allegare più di 4 file + notification_mailer: + digest: + body: 'Ecco un breve riassunto di quello che ti sei perso su %{instance} dalla tua ultima visita del %{since}:' + mention: "%{name} ti ha menzionato:" + new_followers_summary: + one: Hai ricevuto un nuovo seguace! Urrà! + other: Hai ricevuto %{count} nuovi seguaci! Incredibile! + subject: + one: "1 nuova notifica dalla tua ultima visita \U0001F418" + other: "%{count} nuove notifiche dalla tua ultima visita \U0001F418" + favourite: + body: 'Il tuo status è stato apprezzato da %{name}:' + subject: "%{name} ha apprezzato il tuo status" + follow: + body: "%{name} ti sta seguendo!" + subject: "%{name} ti sta seguendo" + follow_request: + body: "%{name} ha chiesto di seguirti" + subject: 'Seguace in sospeso: %{name}' + mention: + body: 'Sei stato menzionato da %{name} su:' + subject: Sei stato menzionato da %{name} + reblog: + body: 'Il tuo status è stato condiviso da %{name}:' + subject: "%{name} ha condiviso il tuo status" + pagination: + next: Avanti + prev: Indietro + truncate: "…" + remote_follow: + acct: Inserisci il tuo username@dominio da cui vuoi seguire questo utente + missing_resource: Impossibile trovare l'URL di reindirizzamento richiesto per il tuo account + proceed: Conferma + prompt: 'Stai per seguire:' + settings: + authorized_apps: Applicazioni autorizzate + back: Torna a Mastodon + edit_profile: Modifica profilo + export: Esporta impostazioni + import: Importa + preferences: Preferenze + settings: Impostazioni + two_factor_auth: Autenticazione a Due Fattori + statuses: + open_in_web: Apri sul Web + over_character_limit: Limite caratteri superato di %{max} + show_more: Mostra di più + visibilities: + private: Mostra solo ai tuoi seguaci + public: Pubblico + unlisted: Pubblico, ma non visibile sulla timeline pubblica + stream_entries: + click_to_show: Clicca per mostrare + reblogged: condiviso + sensitive_content: Materiale sensibile + time: + formats: + default: "%b %d, %Y, %H:%M" + two_factor_auth: + code_hint: Inserisci il codice generato dalla tua app di autenticazione + description_html: Se abiliti l'autorizzazione a due fattori, entrare nel tuo account ti richiederà di avere vicino il tuo telefono, il quale ti genererà un codice per eseguire l'accesso. + disable: Disabilita + enable: Abilita + enabled_success: Autenticazione a due fattori attivata con successo + instructions_html: "Scannerizza questo QR code con Google Authenticator o un'app TOTP simile sul tuo telefono. Da ora in poi, quell'applicazione genererà codici da inserire necessariamente per eseguire l'accesso." + manual_instructions: 'Se non puoi scannerizzare il QR code e hai bisogno di inserirlo manualmente, questo è il codice segreto in chiaro:' + setup: Configura + warning: Se non puoi convalidare immediatamente la tua app di autenticazione, dovresti selezionare "disabilita" o non sarai più in grado di eseguire l'accesso. + wrong_code: Il codice inserito non è corretto! Assicurati che l'orario del server e l'orario del telefono siano corretti. + users: + invalid_email: L'indirizzo e-mail inserito non è valido + invalid_otp_token: Codice d'accesso non valido diff --git a/simple_form.it.yml b/simple_form.it.yml new file mode 100644 index 00000000..1c5026e3 --- /dev/null +++ b/simple_form.it.yml @@ -0,0 +1,47 @@ +--- +it: + simple_form: + hints: + defaults: + avatar: PNG, GIF o JPG. Al massimo 2MB. Sarà ridotto a 120x120px + display_name: Al massimo 30 characters + header: PNG, GIF or JPG. Al massimo 2MB. Sarà ridotto a 700x335px + locked: Richiede la tua approvazione per i nuovi seguaci e rende i nuovi post automaticamente visibili solo ai seguaci + note: Al massimo 160 caratteri + imports: + data: CSV esportato da un altro server Mastodon + labels: + defaults: + avatar: Avatar + confirm_new_password: Conferma la nuova password + confirm_password: Conferma la password + current_password: Password corrente + data: Data + display_name: Nome pubblico + email: Indirizzo e-mail + header: Header + locale: Lingua + locked: Rendi l'account privato + new_password: Nuova password + note: Biografia + otp_attempt: Codice d'accesso + password: Password + setting_default_privacy: Privacy del post + type: Importa + username: Username + setting_boost_modal: Mostra finestra di conferma prima di condividere + interactions: + must_be_follower: Blocca notifiche da chi non ti segue + must_be_following: Blocca notifiche da chi non segui + notification_emails: + digest: Invia riassunto via e-mail + favourite: Invia e-mail quando qualcuno apprezza i tuoi status + follow: Invia e-mail quando qualcuno ti segue + follow_request: Invia e-mail quando qualcuno ti richiede di seguirti + mention: Invia e-mail quando qualcuno ti menziona + reblog: Invia e-mail quando qualcuno condivide i tuoi status + 'no': 'No' + required: + mark: "*" + text: richiesto + 'yes': 'Sì' \ No newline at end of file From 8aadb7b0b2619e6b90231bfbbdced347340b6d18 Mon Sep 17 00:00:00 2001 From: Koala Yeung Date: Thu, 13 Apr 2017 19:40:25 +0800 Subject: [PATCH 18/43] Exclude javascript locale file from dup check (#1677) * Exclude javascript locale files form Code Climate's duplication engine. It is silly to have duplication check with locale files. They are supposed to look similar. * Prevent unnecessary blocking for translation updates (like #1661) --- .codeclimate.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.codeclimate.yml b/.codeclimate.yml index f0c238b1..8558e313 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -1,6 +1,8 @@ engines: duplication: enabled: true + exclude_paths: + - app/assets/javascripts/components/locales/ config: languages: - ruby From 467d32fce32ef234c6c268f18093aefb29b22a1f Mon Sep 17 00:00:00 2001 From: Musee U Date: Thu, 13 Apr 2017 04:40:58 -0700 Subject: [PATCH 19/43] [l10n] ja: update missing Japanese translations (#1684) --- .../javascripts/components/locales/ja.jsx | 38 ++++++++++++++++++- config/locales/ja.yml | 25 +++++++++++- 2 files changed, 60 insertions(+), 3 deletions(-) diff --git a/app/assets/javascripts/components/locales/ja.jsx b/app/assets/javascripts/components/locales/ja.jsx index fdfc91c2..544cc537 100644 --- a/app/assets/javascripts/components/locales/ja.jsx +++ b/app/assets/javascripts/components/locales/ja.jsx @@ -11,9 +11,11 @@ const ja = { "status.sensitive_warning": "不適切なコンテンツ", "status.sensitive_toggle": "クリックして表示", "status.show_more": "もっと見る", + "status.load_more": "もっと見る", "status.show_less": "隠す", "status.open": "Expand this status", - "status.report": "@{name} さんを報告", + "status.report": "@{name} さんを通報", + "status.media_hidden": "非表示のメデイア", "video_player.toggle_sound": "音の切り替え", "account.mention": "@{name} さんに返信", "account.edit_profile": "プロフィールを編集", @@ -23,11 +25,14 @@ const ja = { "account.mute": "ミュート", "account.unmute": "ミュート解除", "account.follow": "フォロー", + "account.report": "@{name}を通報する", "account.posts": "投稿", "account.follows": "フォロー", "account.followers": "フォロワー", "account.follows_you": "フォローされています", "account.requested": "承認待ち", + "follow_request.authorize": "許可", + "follow_request.reject": "拒否", "getting_started.heading": "スタート", "getting_started.about_addressing": "ドメインとユーザー名を知っているなら検索フォームに入力すればフォローできます。", "getting_started.about_shortcuts": "対象のアカウントがあなたと同じドメインのユーザーならばユーザー名のみで検索できます。これは返信のときも一緒です。", @@ -36,6 +41,7 @@ const ja = { "column.community": "ローカルタイムライン", "column.public": "連合タイムライン", "column.notifications": "通知", + "column.favourites": "お気に入り", "tabs_bar.compose": "投稿", "tabs_bar.home": "ホーム", "tabs_bar.mentions": "返信", @@ -46,9 +52,23 @@ const ja = { "compose_form.publish": "トゥート", "compose_form.sensitive": "メディアを不適切なコンテンツとしてマークする", "compose_form.spoiler": "テキストを隠す", + "compose_form.spoiler_placeholder": "内容注意メッセジ", "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": "公開タイムラインに表示しない", + "privacy.public.short": "公開", + "privacy.public.long": "公開TLに投稿する", + "privacy.unlisted.short": "未収載", + "privacy.unlisted.long": "公開TLで表示しない", + "privacy.private.short": "非公開", + "privacy.private.long": "フォロワーだけに公開", + "privacy.direct.short": "ダイレクト", + "privacy.direct.long": "含んだユーザーだけに公開", + "privacy.change": "投稿のプライバシーを変更2", + "report.heading": "新規通報", + "report.placeholder": "コメント", + "report.target": "問題のユーザー", + "report.submit": "通報する", "navigation_bar.edit_profile": "プロフィールを編集", "navigation_bar.preferences": "ユーザー設定", "navigation_bar.community_timeline": "ローカルタイムライン", @@ -61,12 +81,16 @@ const ja = { "search.placeholder": "検索", "search.account": "アカウント", "search.hashtag": "ハッシュタグ", + "search.status_by": "{uuuname}からの投稿", + "upload_area.title": "ファイルをこちらにドラッグしてください", "upload_button.label": "メディアを追加", "upload_form.undo": "やり直す", "notification.follow": "{name} さんにフォローされました", "notification.favourite": "{name} さんがあなたのトゥートをお気に入りに登録しました", "notification.reblog": "{name} さんがあなたのトゥートをブーストしました", "notification.mention": "{name} さんがあなたに返信しました", + "notifications.clear": "通知を片付ける", + "notifications.clear_confirmation": "通知を全部片付けます。大丈夫ですか?", "notifications.column_settings.alert": "デスクトップ通知", "notifications.column_settings.show": "カラムに表示", "notifications.column_settings.follow": "新しいフォロワー", @@ -78,6 +102,18 @@ const ja = { "empty_column.home.public_timeline": "連合タイムライン", "empty_column.notifications": "まだ通知がありません。他の人とふれ合って会話を始めましょう。", "empty_column.public": "ここにはまだ何もありません!公開で何かを投稿したり、他のインスタンスのユーザーをフォローしたりしていっぱいにしましょう!", + "empty_column.hashtag": "このハッシュタグはまだ使っていません。", + "upload_progress.label": "アップロード中…", + "emoji_button.label": "絵文字を追加", + "home.column_settings.basic": "シンプル", + "home.column_settings.advanced": "エキスパート", + "home.column_settings.show_reblogs": "ブースト表示", + "home.column_settings.show_replies": "返信表示", + "home.column_settings.filter_regex": "正規表現でフィルター", + "home.settings": "カラム設定", + "notification.settings": "カラム設定", + "missing_indicator.label": "見つかりません", + "boost_modal.combo": "次は{combo}を押せば、これをスキップできます。" }; export default ja; diff --git a/config/locales/ja.yml b/config/locales/ja.yml index cd6b6543..cf208678 100644 --- a/config/locales/ja.yml +++ b/config/locales/ja.yml @@ -76,6 +76,7 @@ ja: x_seconds: "%{count}秒" exports: blocks: ブロック + mutes: ミュート csv: CSV follows: フォロー storage: メディア @@ -90,8 +91,9 @@ ja: preface: 他のインスタンスでエクスポートされたファイルから、フォロー/ブロックした情報をこのインスタンス上のアカウントにインポートできます。 success: ファイルは正常にアップロードされ、現在処理中です。しばらくしてから確認してください types: - blocking: ブロック中のアカウントリスト + blocking: ブロックしたアカウントリスト following: フォロー中のアカウントリスト + muting: ミュートしたアカウントリスト upload: アップロード landing_strip_html: %{name} さんはインスタンス %{domain} のユーザーです。アカウントさえ持っていればフォローしたり会話したりできます。もしお持ちでないなら こちら からサインアップできます。 media_attachments: @@ -126,6 +128,7 @@ ja: pagination: next: 次 prev: 前 + truncate: "…" remote_follow: acct: フォローしたい人の ユーザー名@ドメイン を入力してください missing_resource: リダイレクト先が見つかりませんでした @@ -171,13 +174,31 @@ ja: invalid_otp_token: 二段階認証コードが間違っています will_paginate: page_gap: "…" - errors: 404: お探しのページは見つかりませんでした。 410: お探しのページはもう存在しません。 422: title: セキュリティ認証に失敗 content: セキュリティ認証に失敗しました。Cookieをブロックしていませんか? + reports: + reports: 通報 + status: 現状 + unresolved: 未決 + resolved: 解決済み + id: ID + target: 通報されているユーザー + reported_by: 通報者 + comment: + label: コメント + none: なし + view: 見る + report: "通報 #%{id}" + delete: 削除 + reported_account: 通報されているユーザー + reported_by: 通報者 + silence_account: ユーザーをサイレンスする + suspend_account: ユーザーを停止する + mark_as_resolved: 解決する admin: settings: title: サイト設定 From a57d30c6800eb3ebe15b0398d5f542527faa47f9 Mon Sep 17 00:00:00 2001 From: YOSHIOKA Eiichiro Date: Thu, 13 Apr 2017 21:39:14 +0900 Subject: [PATCH 20/43] [l10n] ja: update missing Japanese translations (#1687) --- app/assets/javascripts/components/locales/ja.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/components/locales/ja.jsx b/app/assets/javascripts/components/locales/ja.jsx index 544cc537..565e2e6c 100644 --- a/app/assets/javascripts/components/locales/ja.jsx +++ b/app/assets/javascripts/components/locales/ja.jsx @@ -52,7 +52,7 @@ const ja = { "compose_form.publish": "トゥート", "compose_form.sensitive": "メディアを不適切なコンテンツとしてマークする", "compose_form.spoiler": "テキストを隠す", - "compose_form.spoiler_placeholder": "内容注意メッセジ", + "compose_form.spoiler_placeholder": "内容注意メッセージ", "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": "公開タイムラインに表示しない", From 00cc3066a2781f1cc21b23677e797c7bfa9a2f6b Mon Sep 17 00:00:00 2001 From: blackle Date: Thu, 13 Apr 2017 09:04:18 -0400 Subject: [PATCH 21/43] Allow video to be expanded into lightbox --- .../components/extended_video_player.jsx | 6 ++- .../components/components/status.jsx | 3 +- .../components/components/video_player.jsx | 29 +++++++++++- .../containers/status_container.jsx | 4 ++ .../status/components/detailed_status.jsx | 5 +- .../components/features/status/index.jsx | 6 ++- .../features/ui/components/media_modal.jsx | 2 +- .../features/ui/components/modal_root.jsx | 2 + .../features/ui/components/video_modal.jsx | 46 +++++++++++++++++++ .../javascripts/components/locales/en.jsx | 1 + 10 files changed, 95 insertions(+), 9 deletions(-) create mode 100644 app/assets/javascripts/components/features/ui/components/video_modal.jsx diff --git a/app/assets/javascripts/components/components/extended_video_player.jsx b/app/assets/javascripts/components/components/extended_video_player.jsx index 66e5dee1..603f005f 100644 --- a/app/assets/javascripts/components/components/extended_video_player.jsx +++ b/app/assets/javascripts/components/components/extended_video_player.jsx @@ -3,7 +3,9 @@ import PureRenderMixin from 'react-addons-pure-render-mixin'; const ExtendedVideoPlayer = React.createClass({ propTypes: { - src: React.PropTypes.string.isRequired + src: React.PropTypes.string.isRequired, + controls: React.PropTypes.bool.isRequired, + muted: React.PropTypes.bool.isRequired }, mixins: [PureRenderMixin], @@ -11,7 +13,7 @@ const ExtendedVideoPlayer = React.createClass({ render () { return (
-
); }, diff --git a/app/assets/javascripts/components/components/status.jsx b/app/assets/javascripts/components/components/status.jsx index c4d5f829..d2d2aaf2 100644 --- a/app/assets/javascripts/components/components/status.jsx +++ b/app/assets/javascripts/components/components/status.jsx @@ -25,6 +25,7 @@ const Status = React.createClass({ onReblog: React.PropTypes.func, onDelete: React.PropTypes.func, onOpenMedia: React.PropTypes.func, + onOpenVideo: React.PropTypes.func, onBlock: React.PropTypes.func, me: React.PropTypes.number, boostModal: React.PropTypes.bool, @@ -76,7 +77,7 @@ const Status = React.createClass({ if (status.get('media_attachments').size > 0 && !this.props.muted) { if (status.getIn(['media_attachments', 0, 'type']) === 'video') { - media = ; + media = ; } else { media = ; } diff --git a/app/assets/javascripts/components/components/video_player.jsx b/app/assets/javascripts/components/components/video_player.jsx index ab21ca9c..f019664c 100644 --- a/app/assets/javascripts/components/components/video_player.jsx +++ b/app/assets/javascripts/components/components/video_player.jsx @@ -6,7 +6,8 @@ import { isIOS } from '../is_mobile'; const messages = defineMessages({ toggle_sound: { id: 'video_player.toggle_sound', defaultMessage: 'Toggle sound' }, - toggle_visible: { id: 'video_player.toggle_visible', defaultMessage: 'Toggle visibility' } + toggle_visible: { id: 'video_player.toggle_visible', defaultMessage: 'Toggle visibility' }, + expand_video: { id: 'video_player.expand', defaultMessage: 'Expand video' } }); const videoStyle = { @@ -61,6 +62,15 @@ const spoilerButtonStyle = { zIndex: '100' }; +const expandButtonStyle = { + position: 'absolute', + bottom: '6px', + right: '8px', + color: 'white', + textShadow: "0px 1px 1px black, 1px 0px 1px black", + zIndex: '100' +}; + const VideoPlayer = React.createClass({ propTypes: { media: ImmutablePropTypes.map.isRequired, @@ -68,7 +78,8 @@ const VideoPlayer = React.createClass({ height: React.PropTypes.number, sensitive: React.PropTypes.bool, intl: React.PropTypes.object.isRequired, - autoplay: React.PropTypes.bool + autoplay: React.PropTypes.bool, + onOpenVideo: React.PropTypes.func.isRequired }, getDefaultProps () { @@ -116,6 +127,13 @@ const VideoPlayer = React.createClass({ }); }, + handleExpand () { + const node = ReactDOM.findDOMNode(this).querySelector('video'); + node.pause(); + + this.props.onOpenVideo(this.props.media); + }, + setRef (c) { this.video = c; }, @@ -159,6 +177,12 @@ const VideoPlayer = React.createClass({ ); + let expandButton = ( +
+ +
+ ); + let muteButton = ''; if (this.state.hasAudio) { @@ -202,6 +226,7 @@ const VideoPlayer = React.createClass({
{spoilerButton} {muteButton} + {expandButton}
); diff --git a/app/assets/javascripts/components/containers/status_container.jsx b/app/assets/javascripts/components/containers/status_container.jsx index fedf80fb..d68acd96 100644 --- a/app/assets/javascripts/components/containers/status_container.jsx +++ b/app/assets/javascripts/components/containers/status_container.jsx @@ -75,6 +75,10 @@ const mapDispatchToProps = (dispatch) => ({ dispatch(openModal('MEDIA', { media, index })); }, + onOpenVideo (media) { + dispatch(openModal('VIDEO', { media })); + }, + onBlock (account) { dispatch(blockAccount(account.get('id'))); }, diff --git a/app/assets/javascripts/components/features/status/components/detailed_status.jsx b/app/assets/javascripts/components/features/status/components/detailed_status.jsx index 2da57252..ceafc1a3 100644 --- a/app/assets/javascripts/components/features/status/components/detailed_status.jsx +++ b/app/assets/javascripts/components/features/status/components/detailed_status.jsx @@ -17,7 +17,8 @@ const DetailedStatus = React.createClass({ propTypes: { status: ImmutablePropTypes.map.isRequired, - onOpenMedia: React.PropTypes.func.isRequired + onOpenMedia: React.PropTypes.func.isRequired, + onOpenVideo: React.PropTypes.func.isRequired, }, mixins: [PureRenderMixin], @@ -39,7 +40,7 @@ const DetailedStatus = React.createClass({ if (status.get('media_attachments').size > 0) { if (status.getIn(['media_attachments', 0, 'type']) === 'video') { - media = ; + media = ; } else { media = ; } diff --git a/app/assets/javascripts/components/features/status/index.jsx b/app/assets/javascripts/components/features/status/index.jsx index 48fea658..b30d991e 100644 --- a/app/assets/javascripts/components/features/status/index.jsx +++ b/app/assets/javascripts/components/features/status/index.jsx @@ -112,6 +112,10 @@ const Status = React.createClass({ this.props.dispatch(openModal('MEDIA', { media, index })); }, + handleOpenVideo (media) { + this.props.dispatch(openModal('VIDEO', { media })); + }, + handleReport (status) { this.props.dispatch(initReport(status.get('account'), status)); }, @@ -151,7 +155,7 @@ const Status = React.createClass({
{ancestors} - + {descendants} diff --git a/app/assets/javascripts/components/features/ui/components/media_modal.jsx b/app/assets/javascripts/components/features/ui/components/media_modal.jsx index 35eb2cb0..130f48b4 100644 --- a/app/assets/javascripts/components/features/ui/components/media_modal.jsx +++ b/app/assets/javascripts/components/features/ui/components/media_modal.jsx @@ -111,7 +111,7 @@ const MediaModal = React.createClass({ if (attachment.get('type') === 'image') { content = ; } else if (attachment.get('type') === 'gifv') { - content = ; + content = ; } return ( diff --git a/app/assets/javascripts/components/features/ui/components/modal_root.jsx b/app/assets/javascripts/components/features/ui/components/modal_root.jsx index e7ac02dd..74eb5003 100644 --- a/app/assets/javascripts/components/features/ui/components/modal_root.jsx +++ b/app/assets/javascripts/components/features/ui/components/modal_root.jsx @@ -1,10 +1,12 @@ import PureRenderMixin from 'react-addons-pure-render-mixin'; import MediaModal from './media_modal'; +import VideoModal from './video_modal'; import BoostModal from './boost_modal'; import { TransitionMotion, spring } from 'react-motion'; const MODAL_COMPONENTS = { 'MEDIA': MediaModal, + 'VIDEO': VideoModal, 'BOOST': BoostModal }; diff --git a/app/assets/javascripts/components/features/ui/components/video_modal.jsx b/app/assets/javascripts/components/features/ui/components/video_modal.jsx new file mode 100644 index 00000000..fa222d7a --- /dev/null +++ b/app/assets/javascripts/components/features/ui/components/video_modal.jsx @@ -0,0 +1,46 @@ +import LoadingIndicator from '../../../components/loading_indicator'; +import PureRenderMixin from 'react-addons-pure-render-mixin'; +import ImmutablePropTypes from 'react-immutable-proptypes'; +import ExtendedVideoPlayer from '../../../components/extended_video_player'; +import { defineMessages, injectIntl } from 'react-intl'; +import IconButton from '../../../components/icon_button'; + +const messages = defineMessages({ + close: { id: 'lightbox.close', defaultMessage: 'Close' } +}); + +const closeStyle = { + position: 'absolute', + zIndex: '100', + top: '4px', + right: '4px' +}; + +const VideoModal = React.createClass({ + + propTypes: { + media: ImmutablePropTypes.map.isRequired, + onClose: React.PropTypes.func.isRequired, + intl: React.PropTypes.object.isRequired + }, + + mixins: [PureRenderMixin], + + render () { + const { media, intl, onClose } = this.props; + + const url = media.get('url'); + + return ( +
+
+ + +
+
+ ); + } + +}); + +export default injectIntl(VideoModal); diff --git a/app/assets/javascripts/components/locales/en.jsx b/app/assets/javascripts/components/locales/en.jsx index 1834567f..19a981d1 100644 --- a/app/assets/javascripts/components/locales/en.jsx +++ b/app/assets/javascripts/components/locales/en.jsx @@ -124,6 +124,7 @@ const en = { "upload_progress.label": "Uploading...", "video_player.toggle_sound": "Toggle sound", "video_player.toggle_visible": "Toggle visibility", + "video_player.expand": "Expand video", }; export default en; From 4fe5e04ea47b187b5578d0c9da23ecbe6c382544 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 13 Apr 2017 09:29:30 -0400 Subject: [PATCH 22/43] Fix csv export coverage in export spec (#1691) --- spec/models/export_spec.rb | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/spec/models/export_spec.rb b/spec/models/export_spec.rb index 5cc62c26..3ee042fb 100644 --- a/spec/models/export_spec.rb +++ b/spec/models/export_spec.rb @@ -2,12 +2,32 @@ require 'rails_helper' describe Export do describe 'to_csv' do - it 'returns a csv of the accounts' do + before do one = Account.new(username: 'one', domain: 'local.host') two = Account.new(username: 'two', domain: 'local.host') accounts = [one, two] - export = Export.new(accounts).to_csv + @account = double(blocking: accounts, muting: accounts, following: accounts) + end + + it 'returns a csv of the blocked accounts' do + export = Export.new(@account).to_blocked_accounts_csv + results = export.strip.split + + expect(results.size).to eq 2 + expect(results.first).to eq 'one@local.host' + end + + it 'returns a csv of the muted accounts' do + export = Export.new(@account).to_muted_accounts_csv + results = export.strip.split + + expect(results.size).to eq 2 + expect(results.first).to eq 'one@local.host' + end + + it 'returns a csv of the following accounts' do + export = Export.new(@account).to_following_accounts_csv results = export.strip.split expect(results.size).to eq 2 From 093879c1778a525b7aa9b847b58e9ce6604b5acf Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 13 Apr 2017 09:59:12 -0400 Subject: [PATCH 23/43] Fix language export variables (#1689) * Fix naming of JS locale constants * Improve the translation instructions re: const names --- app/assets/javascripts/components/locales/bg.jsx | 2 +- app/assets/javascripts/components/locales/de.jsx | 4 ++-- app/assets/javascripts/components/locales/en.jsx | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/assets/javascripts/components/locales/bg.jsx b/app/assets/javascripts/components/locales/bg.jsx index cac984aa..a194cdbd 100644 --- a/app/assets/javascripts/components/locales/bg.jsx +++ b/app/assets/javascripts/components/locales/bg.jsx @@ -65,4 +65,4 @@ const bg = { "notifications.column_settings.reblog": "Споделяния:", }; -export default en; +export default bg; diff --git a/app/assets/javascripts/components/locales/de.jsx b/app/assets/javascripts/components/locales/de.jsx index 92897f54..bd98b759 100644 --- a/app/assets/javascripts/components/locales/de.jsx +++ b/app/assets/javascripts/components/locales/de.jsx @@ -1,4 +1,4 @@ -const en = { +const de = { "column_back_button.label": "Zurück", "lightbox.close": "Schließen", "loading_indicator.label": "Lade…", @@ -74,4 +74,4 @@ const en = { "missing_indicator.label": "Nicht gefunden" }; -export default en; +export default de; diff --git a/app/assets/javascripts/components/locales/en.jsx b/app/assets/javascripts/components/locales/en.jsx index 1834567f..740caef9 100644 --- a/app/assets/javascripts/components/locales/en.jsx +++ b/app/assets/javascripts/components/locales/en.jsx @@ -5,6 +5,7 @@ * 1. to add your new string here; and * 2. to remove old strings that are no longer needed; and * 3. to sort the strings by the key. + # 4. To rename the `en` const name and export default name to match your locale. * Thanks! */ const en = { From 447b8bc44eb33ae6ffdfbcc7ae52fbe0bba93ece Mon Sep 17 00:00:00 2001 From: Isabelle Knott Date: Thu, 13 Apr 2017 09:59:43 -0400 Subject: [PATCH 24/43] Do not show media attachment as og:image if it was marked as NSFW (#1693) --- app/views/stream_entries/show.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/stream_entries/show.html.haml b/app/views/stream_entries/show.html.haml index f37fb791..86294675 100644 --- a/app/views/stream_entries/show.html.haml +++ b/app/views/stream_entries/show.html.haml @@ -11,7 +11,7 @@ - else %meta{ property: 'og:description', content: @stream_entry.activity.content }/ - - if @stream_entry.activity.is_a?(Status) && @stream_entry.activity.media_attachments.size > 0 + - if @stream_entry.activity.is_a?(Status) && !@stream_entry.activity.sensitive? && @stream_entry.activity.media_attachments.size > 0 %meta{ property: 'og:image', content: full_asset_url(@stream_entry.activity.media_attachments.first.file.url(:small)) }/ - else %meta{ property: 'og:image', content: full_asset_url(@account.avatar.url(:original)) }/ From b330d1f000ef354a856c43aeaa27e079c89fc822 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 13 Apr 2017 10:00:31 -0400 Subject: [PATCH 25/43] Organize coverage dirs (#1695) * Add `Presenters` group to SimpleCov configuration * Move validators to app/validators, add to simplecov config --- app/{lib => validators}/email_validator.rb | 0 app/{lib => validators}/status_length_validator.rb | 0 app/{lib => validators}/url_validator.rb | 0 spec/spec_helper.rb | 4 +++- 4 files changed, 3 insertions(+), 1 deletion(-) rename app/{lib => validators}/email_validator.rb (100%) rename app/{lib => validators}/status_length_validator.rb (100%) rename app/{lib => validators}/url_validator.rb (100%) diff --git a/app/lib/email_validator.rb b/app/validators/email_validator.rb similarity index 100% rename from app/lib/email_validator.rb rename to app/validators/email_validator.rb diff --git a/app/lib/status_length_validator.rb b/app/validators/status_length_validator.rb similarity index 100% rename from app/lib/status_length_validator.rb rename to app/validators/status_length_validator.rb diff --git a/app/lib/url_validator.rb b/app/validators/url_validator.rb similarity index 100% rename from app/lib/url_validator.rb rename to app/validators/url_validator.rb diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index a5dce977..7038efce 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,7 +1,9 @@ require 'simplecov' SimpleCov.start 'rails' do - add_group "Services", "app/services" + add_group 'Services', 'app/services' + add_group 'Presenters', 'app/presenters' + add_group 'Validators', 'app/validators' end RSpec.configure do |config| From edefcfcf4239675afd99539810d18f128266007a Mon Sep 17 00:00:00 2001 From: Isabelle Knott Date: Thu, 13 Apr 2017 10:00:56 -0400 Subject: [PATCH 26/43] Fix issue where 'sensitive content click to show' item takes up whole screen on public view (#1692) --- app/assets/stylesheets/stream_entries.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/app/assets/stylesheets/stream_entries.scss b/app/assets/stylesheets/stream_entries.scss index 4a6dc6aa..7bd180c1 100644 --- a/app/assets/stylesheets/stream_entries.scss +++ b/app/assets/stylesheets/stream_entries.scss @@ -218,6 +218,7 @@ margin-top: 8px; height: 300px; overflow: hidden; + position: relative; video { position: relative; From 1206627c5957c9c2afea7126dbe6d44e2b00a849 Mon Sep 17 00:00:00 2001 From: Koala Yeung Date: Thu, 13 Apr 2017 22:02:23 +0800 Subject: [PATCH 27/43] Add Dutch translation (nl) (#1682) * Dutch language files for Ruby code * Created RoR translation ymls: * config/locales/devise.nl.yml * config/locales/doorkeeper.nl.yml * config/locales/nl.yml * config/locales/simple_form.nl.yml * Modified RoR config and helper * app/helpers/settings_helper.rb * config/application.rb * Dutch language javascript locale * Created javascript locale files: * app/assets/javascripts/components/locales/index.jsx * app/assets/javascripts/components/locales/nl.jsx * Reference the newly created locale files: * app/assets/javascripts/components/containers/mastodon.jsx * Fix syntax error in locale file (nl) * Fix missing translate in js locale (nl) * Convert all ruby Dutch locale (nl) file to utf8 Fix yml conversion issues. * Fix duplicated key in devise.nl.yml * Fix indentation error in doorkeeper.nl.yml --- .../components/containers/mastodon.jsx | 2 + .../javascripts/components/locales/index.jsx | 2 + .../javascripts/components/locales/nl.jsx | 68 ++++++++ app/helpers/settings_helper.rb | 1 + config/application.rb | 2 +- config/locales/devise.nl.yml | 59 +++++++ config/locales/doorkeeper.nl.yml | 129 ++++++++++++++ config/locales/nl.yml | 165 ++++++++++++++++++ config/locales/simple_form.nl.yml | 46 +++++ 9 files changed, 473 insertions(+), 1 deletion(-) create mode 100644 app/assets/javascripts/components/locales/nl.jsx create mode 100644 config/locales/devise.nl.yml create mode 100644 config/locales/doorkeeper.nl.yml create mode 100644 config/locales/nl.yml create mode 100644 config/locales/simple_form.nl.yml diff --git a/app/assets/javascripts/components/containers/mastodon.jsx b/app/assets/javascripts/components/containers/mastodon.jsx index b9086de4..5cd72782 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 nl from 'react-intl/locale-data/nl'; import no from 'react-intl/locale-data/no'; import ru from 'react-intl/locale-data/ru'; import uk from 'react-intl/locale-data/uk'; @@ -76,6 +77,7 @@ addLocaleData([ ...hu, ...ja, ...pt, + ...nl, ...no, ...ru, ...uk, diff --git a/app/assets/javascripts/components/locales/index.jsx b/app/assets/javascripts/components/locales/index.jsx index f14568a3..7525022b 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 nl from './nl'; import no from './no'; import pt from './pt'; import uk from './uk'; @@ -19,6 +20,7 @@ const locales = { es, hu, fr, + nl, no, pt, uk, diff --git a/app/assets/javascripts/components/locales/nl.jsx b/app/assets/javascripts/components/locales/nl.jsx new file mode 100644 index 00000000..cc80854f --- /dev/null +++ b/app/assets/javascripts/components/locales/nl.jsx @@ -0,0 +1,68 @@ +const nl = { + "column_back_button.label": "terug", + "lightbox.close": "Sluiten", + "loading_indicator.label": "Laden...", + "status.mention": "Vermeld @{name}", + "status.delete": "Verwijder", + "status.reply": "Reageer", + "status.reblog": "Boost", + "status.favourite": "Favoriet", + "status.reblogged_by": "{name} boostte", + "status.sensitive_warning": "Gevoelige inhoud", + "status.sensitive_toggle": "Klik om te zien", + "video_player.toggle_sound": "Geluid omschakelen", + "account.mention": "Vermeld @{name}", + "account.edit_profile": "Bewerk profiel", + "account.unblock": "Deblokkeer @{name}", + "account.unfollow": "Ontvolg", + "account.block": "Blokkeer @{name}", + "account.follow": "Volg", + "account.posts": "Berichten", + "account.follows": "Volgt", + "account.followers": "Volgers", + "account.follows_you": "Volgt jou", + "account.requested": "Wacht op goedkeuring", + "getting_started.heading": "Beginnen", + "getting_started.about_addressing": "Je kunt mensen volgen als je hun gebruikersnaam en het domein van hun server kent, door het e-mailachtige adres in het zoekscherm in te voeren.", + "getting_started.about_shortcuts": "Als de gezochte gebruiker op hetzelfde domein zit als jijzelf, is invoeren van de gebruikersnaam genoeg. Dat geldt ook als je mensen in de statussen wilt vermelden.", + "getting_started.open_source_notice": "Mastodon is open source software. Je kunt bijdragen of problemen melden op GitHub via {github}. {apps}.", + "column.home": "Thuis", + "column.community": "Lokale tijdlijn", + "column.public": "Federatietijdlijn", + "column.notifications": "Meldingen", + "tabs_bar.compose": "Schrijven", + "tabs_bar.home": "Thuis", + "tabs_bar.mentions": "Vermeldingen", + "tabs_bar.public": "Federatietijdlijn", + "tabs_bar.notifications": "Meldingen", + "compose_form.placeholder": "Waar ben je mee bezig?", + "compose_form.publish": "Toot", + "compose_form.sensitive": "Markeer media als gevoelig", + "compose_form.spoiler": "Verberg tekst achter waarschuwing", + "compose_form.private": "Mark als priv", + "compose_form.privacy_disclaimer": "Je besloten status wordt afgeleverd aan vermelde gebruikers op {domains}. Vertrouw je {domainsCount, plural, one {that server} andere {those servers}}? Priv plaatsen werkt alleen op Mastodon servers. Als {domains} {domainsCount, plural, een {is not a Mastodon instance} andere {are not Mastodon instances}}, dan wordt er geen indicatie gegeven dat he bericht besloten is, waardoor het kan worden geboost of op andere manier zichtbaar worden voor niet bedoelde lezers.", + "compose_form.unlisted": "Niet tonen op openbare tijdlijnen", + "navigation_bar.edit_profile": "Bewerk profiel", + "navigation_bar.preferences": "Voorkeuren", + "navigation_bar.community_timeline": "Lokale tijdlijn", + "navigation_bar.public_timeline": "Federatietijdlijn", + "navigation_bar.logout": "Uitloggen", + "reply_indicator.cancel": "Annuleren", + "search.placeholder": "Zoeken", + "search.account": "Account", + "search.hashtag": "Hashtag", + "upload_button.label": "Toevoegen media", + "upload_form.undo": "Ongedaan maken", + "notification.follow": "{name} volgde jou", + "notification.favourite": "{name} markeerde je status als favoriet", + "notification.reblog": "{name} boostte je status", + "notification.mention": "{name} vermeldde jou", + "notifications.column_settings.alert": "Desktopmeldingen", + "notifications.column_settings.show": "Tonen in kolom", + "notifications.column_settings.follow": "Nieuwe volgers:", + "notifications.column_settings.favourite": "Favoriten:", + "notifications.column_settings.mention": "Vermeldingen:", + "notifications.column_settings.reblog": "Boosts:", +}; + +export default nl; diff --git a/app/helpers/settings_helper.rb b/app/helpers/settings_helper.rb index 212f88c3..c6ffe184 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', + nl: 'Nederlands', no: 'Norsk', pt: 'Português', fi: 'Suomi', diff --git a/config/application.rb b/config/application.rb index 1383d45a..f3f1f7bf 100644 --- a/config/application.rb +++ b/config/application.rb @@ -24,7 +24,6 @@ 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, :bg, @@ -35,6 +34,7 @@ module Mastodon :fr, :hu, :ja, + :nl, :no, :pt, :ru, diff --git a/config/locales/devise.nl.yml b/config/locales/devise.nl.yml new file mode 100644 index 00000000..1f5c681b --- /dev/null +++ b/config/locales/devise.nl.yml @@ -0,0 +1,59 @@ +--- +nl: + devise: + confirmations: + confirmed: 'Je account is bevestigd.' + send_instructions: 'Je ontvangt via e-mail instructies hoe je je account kan bevestigen.' + send_paranoid_instructions: 'Als je e-mailadres bestaat in de database, ontvang je via e-mail instructies hoe je je account kan bevestigen.' + failure: + already_authenticated: 'Je bent al ingelogd.' + unauthenticated: 'Je dient in te loggen of je in te schrijven.' + unconfirmed: 'Je dient eerst je account te bevestigen.' + locked: 'Je account is gelocked.' + invalid: 'Ongeldig e-mail of wachtwoord.' + invalid_token: 'Invalide authenticiteit token.' + timeout: 'Je sessie is verlopen, log a.u.b. opnieuw in.' + inactive: 'Je account is nog niet geactiveerd.' + last_attempt: 'Je hebt nog een poging over voordat je account wordt geblokkeerd.' + not_found_in_database: "Ongeldig e-mail of wachtwoord." + mailer: + confirmation_instructions: + subject: 'Bevestiging mailadres' + reset_password_instructions: + subject: 'Wachtwoord resetten' + unlock_instructions: + subject: 'Unlock instructies' + omniauth_callbacks: + success: 'Successvol aangemeld met je %{kind} account.' + failure: 'Kon je niet aanmelden met je %{kind} account, omdat "%{reason}".' + passwords: + no_token: 'Je kan deze pagina niet benaderen zonder een "wachtwoord reset e-mail"' + send_instructions: 'Je ontvangt via e-mail instructies hoe je je wachtwoord moet resetten.' + send_paranoid_instructions: 'Als je e-mailadres bestaat in de database, ontvang je via e-mail instructies hoe je je wachtwoord moet resetten.' + updated: 'Je wachtwoord is gewijzigd. Je bent nu ingelogd.' + updated_not_active: 'Je wachtwoord is gewijzigd.' + registrations: + signed_up_but_unconfirmed: 'Je ontvangt via e-mail instructies hoe je je account kunt activeren.' + signed_up_but_inactive: 'Je bent ingeschreven. Je kon alleen niet automatisch ingelogd worden omdat je account nog niet geactiveerd is.' + signed_up_but_locked: 'Je bent ingeschreven. Je kon alleen niet automatisch ingelogd worden omdat je account geblokkeerd is.' + signed_up: 'Je bent ingeschreven.' + update_needs_confirmation: 'Je hebt je e-mailadres succesvol gewijzigd, maar we moeten je nieuwe mailadres nog verifiëren. Controleer je e-mail en klik op de link in de mail om je mailadres te verifiëren.' + updated: 'Je account gegevens zijn opgeslagen.' + destroyed: 'Je account is verwijderd, wellicht tot ziens!' + sessions: + signed_in: 'Je bent succesvol ingelogd.' + signed_out: 'Je bent succesvol uitgelogd.' + unlocks: + send_instructions: 'Je ontvangt via e-mail instructies hoe je je account kan unlocken.' + send_paranoid_instructions: 'Als je e-mailadres bestaat in de database, ontvang je via e-mail instructies hoe je je account kan unlocken.' + unlocked: 'Je account is ge-unlocked. Je kan nu weer inloggen.' + errors: + messages: + already_confirmed: "is reeds bevestigd" + confirmation_period_expired: "moet worden bevestigd binnen %{period}, probeer het a.u.b. nog een keer" + expired: "is verlopen, vraag een nieuwe aan" + not_found: "niet gevonden" + not_locked: "is niet gesloten" + not_saved: + one: '1 fout blokkeerde het opslaan van deze %{resource}:' + other: "%{count} fouten blokkeerden het opslaan van deze %{resource}:" diff --git a/config/locales/doorkeeper.nl.yml b/config/locales/doorkeeper.nl.yml new file mode 100644 index 00000000..98f2172b --- /dev/null +++ b/config/locales/doorkeeper.nl.yml @@ -0,0 +1,129 @@ +nl: + activerecord: + attributes: + doorkeeper/application: + name: 'Naam' + redirect_uri: 'Redirect URI' + scopes: 'Scopes' + errors: + models: + doorkeeper/application: + attributes: + redirect_uri: + fragment_present: 'kan geen fragment bevatten.' + invalid_uri: 'moet een geldige URI zijn.' + relative_uri: 'moet een absolute URI zijn.' + secured_uri: 'moet een HTTPS/SSL URI zijn.' + + doorkeeper: + applications: + confirmations: + destroy: 'Weet je het zeker?' + buttons: + edit: 'Bewerken' + destroy: 'Verwijderen' + submit: 'Opslaan' + cancel: 'Annuleren' + authorize: 'Autoriseren' + form: + error: 'Oops! Controleer het formulier op fouten' + help: + redirect_uri: 'Gebruik één regel per URI. ' + native_redirect_uri: 'Gebruik %{native_redirect_uri} voor lokale tests' + scopes: 'Scheid scopes met spaties. Laat leeg om de standaard scopes te gebruiken.' + edit: + title: 'Bewerk applicatie' + index: + title: 'Jouw applicaties' + new: 'Nieuwe applicatie' + name: 'Naam' + callback_url: 'Callback URL' + new: + title: 'Nieuwe applicatie' + show: + title: 'Applicatie: %{name}' + application_id: 'Applicatie Id' + secret: 'Secret' + scopes: 'Scopes' + callback_urls: 'Callback urls' + actions: 'Acties' + + authorizations: + buttons: + authorize: 'Autoriseren' + deny: 'Weigeren' + error: + title: 'Er is een fout opgetreden' + new: + title: 'Autorisatie vereist' + prompt: '%{client_name} autoriseren om uw account te gebruiken?' + able_to: 'Deze applicatie zal in staat zijn om' + show: + title: 'Autorisatie code' + + authorized_applications: + confirmations: + revoke: 'Weet je het zeker?' + buttons: + revoke: 'Intrekken' + index: + title: 'Jouw geautoriseerde applicaties' + application: 'Applicatie' + created_at: 'Aangemaakt op' + date_format: '%d-%m-%Y %H:%M:%S' + + errors: + messages: + # Common error messages + invalid_request: 'Het verzoek mist een vereiste parameter, bevat een niet-ondersteunde parameter waarde of is anderszins onjuist.' + invalid_redirect_uri: 'De opgegeven redirect uri is niet geldig.' + unauthorized_client: 'De client is niet bevoegd om dit verzoek met deze methode uit te voeren.' + access_denied: 'De resource eigenaar of autorisatie-server weigerde het verzoek.' + invalid_scope: 'De opgevraagde scope is niet geldig, onbekend of onjuist.' + server_error: 'De autorisatieserver is een onverwachte voorwaarde tegengekomen die het verzoek verhinderd.' + temporarily_unavailable: 'De autorisatieserver is momenteel niet in staat het verzoek te behandelen als gevolg van een tijdelijke overbelasting of onderhoud aan de server.' + + #configuration error messages + credential_flow_not_configured: 'Resource Owner Password Credentials flow failed due to Doorkeeper.configure.resource_owner_from_credentials being unconfigured.' + resource_owner_authenticator_not_configured: 'Resource Owner find failed due to Doorkeeper.configure.resource_owner_authenticator being unconfiged.' + + # Access grant errors + unsupported_response_type: 'De autorisatieserver ondersteund dit response type niet' + + # Access token errors + invalid_client: 'Client verificatie is mislukt door onbekende klant, geen client authenticatie opgegeven, of een niet-ondersteunde authenticatie methode.' + invalid_grant: 'De verstrekte autorisatie is ongeldig, verlopen, ingetrokken, komt niet overeen met de redirect uri die is opgegeven, of werd uitgegeven aan een andere klant.' + unsupported_grant_type: 'Het type autorisatie is niet ondersteund door de autorisatieserver' + + # Password Access token errors + invalid_resource_owner: 'De verstrekte resource eigenaar gegevens zijn niet geldig of de resource eigenaar kan niet worden gevonden' + + invalid_token: + revoked: "Het toegangstoken is geweigerd" + expired: "Het toegangstoken is verlopen" + unknown: "Het toegangstoken is ongeldig" + + flash: + applications: + create: + notice: 'Applicatie aangemaakt.' + destroy: + notice: 'Applicatie verwijderd.' + update: + notice: 'Applicatie bewerkt.' + authorized_applications: + destroy: + notice: 'Applicatie ingetrokken.' + + layouts: + admin: + nav: + oauth2_provider: 'OAuth2 Provider' + applications: 'Applicaties' + home: 'Home' + application: + title: 'OAuth autorisatie vereist' + scopes: + follow: volg, blokkeer, deblokkeer en stop volgen accounts + read: lees je accountgegevens + write: plaatsen namens jou diff --git a/config/locales/nl.yml b/config/locales/nl.yml new file mode 100644 index 00000000..22fed228 --- /dev/null +++ b/config/locales/nl.yml @@ -0,0 +1,165 @@ +--- +nl: + about: + about_mastodon: Mastodon is een vrije, gratis, open-source sociaal netwerk. E gedecentraliseerd alternatief voor commerciële platforms, het voorkomt de risico's van een enkel bedrijf dat jouw communicatie monopoliseert. Kies een server die je vertrouwt — welke je ook kiest, je kunt met iedere ander communiceren. Iedereen kan een eigen Mastodon server draaien en naadloos deelnemen in het sociale netwerk. + about_this: Over deze server + apps: Apps + business_email: 'Zakelijke e-mailadres:' + closed_registrations: Registrateren op deze server is momenteel uitgeschakeld. + contact: Contact + description_headline: Wat is %{domain}? + domain_count_after: andere servers + domain_count_before: Verbonden met + features: + api: Open API voor apps en services + blocks: Rijke blokkeer- en dempingshulpmiddelen + characters: 500 tekens per bericht + chronology: Tijdlijnen zijn chronologisch + ethics: 'Ethisch design: geen ads, geen spionage' + gifv: GIFV sets en korte video's + privacy: Granulaire, privacy instellingen per bericht + public: Openbare tijdlijnen + features_headline: Wat maak Mastodon anders + get_started: Beginnen + links: Links + other_instances: Andere servers + source_code: Source code + status_count_after: statussen + status_count_before: Wie schreef + terms: Voorw + user_count_after: gebruikers + user_count_before: Thuis naar + accounts: + follow: Volg + followers: Volgens + following: Volgend + nothing_here: Hier is niets! + people_followed_by: Mensen die %{name} volgt + people_who_follow: Mensen die %{name} volgen + posts: Berichten + remote_follow: Externe volg + unfollow: Ontvolgen + application_mailer: + settings: 'Wijzigen e-mailvoorkeuren: %{link}' + signature: Mastodon meldingen van %{instance} + view: 'Bekijk:' + applications: + invalid_url: De opgegevens URL is ongeldig + auth: + change_password: Inloggegevens + didnt_get_confirmation: Ontving je geen bevestigingsinstructies? + forgot_password: Wachtwoord vergeten? + login: Inloggen + logout: Uitloggen + register: Registreren + resend_confirmation: Herstuur de bevestigingsinstructies + reset_password: Herstel wachtwoord + set_new_password: Instellen nieuw wachtwoord + authorize_follow: + error: Helaas, er was een fout bij het opzoeken van het externe account + follow: Volgen + prompt_html: 'Je (%{self}) hebt volgen aangevraagd:' + title: Volg %{acct} + datetime: + distance_in_words: + about_x_hours: "%{count}u" + about_x_months: "%{count}ma" + about_x_years: "%{count}j" + almost_x_years: "%{count}j" + half_a_minute: Net + less_than_x_minutes: "%{count}m" + less_than_x_seconds: Net + over_x_years: "%{count}j" + x_days: "%{count}d" + x_minutes: "%{count}m" + x_months: "%{count}ma" + x_seconds: "%{count}s" + exports: + blocks: Je blokkeert + csv: CSV + follows: Je volgt + storage: Media-opslag + generic: + changes_saved_msg: Wijzigingen succesvol opgeslagen! + powered_by: powered by %{link} + save_changes: Wijziginen opslaan + validation_errors: + one: Er is iets niet helemaal goed! Bekijk onderstaande fout + other: Er is iets niet helemaal goed! Bekijk onderstaande %{count} fouten + imports: + preface: Je kunt bepaalde gegevens, zoals de mensen die je volgt of blokkeert, importeren voor je account op deze server, als ze zijn geëxporteerd op een andere server. + success: Je gegevens zijn succesvol ge-upload en wordt binnenkort verwerkt + types: + blocking: Blokkadelijst + following: Volglijst + upload: Uploaden + landing_strip_html: %{name} is een gebruiker op %{domain}. Je kunt deze volgen of ermee interacteren als je ergens in deze fediverse een account hebt. Als he dat niet hebt, kun je je hier aanmelden. + notification_mailer: + digest: + body: 'Hier is een korte samenvatting van wat je hebt gemist op %{instance} sinds je laatste bezoek op %{since}:' + mention: "%{name} vermeldde je in:" + new_followers_summary: + one: Je hebt een nieuwe volger! Hoera! + other: Je hebt %{count} nieuwe volgers! Prachtig! + subject: + one: "1 nieuwe melding sinds je laatste bezoek \U0001F418" + other: "%{count} nieuwe meldingen sinds je laatste bezoek \U0001F418" + favourite: + body: 'Je status werd als favoriet gemarkeerd door %{name}:' + subject: "%{name} markeerde je status als favouriet" + follow: + body: "%{name} volgt je nu!" + subject: "%{name} volgt je nu" + follow_request: + body: "%{name} wil je graag volgend" + subject: 'Volgen in afwachting: %{name}' + mention: + body: 'Je werd door %{name} vermeld in:' + subject: Je werd vermeld door %{name} + reblog: + body: 'Je status werd geboost door %{name}:' + subject: "%{name} booste je status" + pagination: + next: Volgende + prev: Vorige + remote_follow: + acct: Geef je gebruikersnaam@domein op waarvandaan je wilt volgen + missing_resource: Kon geen de vereiste doorverwijszings-URL voor je account niet vinden + proceed: Ga door om te volgen + prompt: 'Je gaat volgen:' + settings: + authorized_apps: Geautoriseerde + back: Terug naar Mastodon + edit_profile: Bewerk profiel + export: Gegevensexport + import: Import + preferences: Voorkeuren + settings: Instellingen + two_factor_auth: Twe-factor authenticatie + statuses: + open_in_web: Openen in web + over_character_limit: Tekenlimiet van %{max} overschreden + show_more: Toon meer + visibilities: + private: Toon alleen aan volgers + public: Openbaar + unlisted: Openbaar, maar niet tonen op openbare tijdlijn + stream_entries: + click_to_show: Klik om te tonen + reblogged: boostte + sensitive_content: Gevoelige inhoud + time: + formats: + default: "%b %d, %J, %U:%M" + two_factor_auth: + description_html: Als je twee-factor authenticatie instelt, kun je alleen inloggen als je je mobiele telefoon bij je hebt, waarmee je de in te voeren tokens genereert. + disable: Uitschakelen + enable: Inschakelen + instructions_html: "Scan deze QR-code in Google Authenticator of een soortgelijke app op je mobiele telefoon. Van nu af aan creëert deze app tokens die je bij inloggen moet invoeren." + plaintext_secret_html: 'Gewone-tekst geheim: %{secret}' + warning: Als je nu geen authenticator app kunt installeren, moet je "Uitschakelen" kiezen of je kunt niet meer inloggen. + users: + invalid_email: Het e-mailadres is ongeldig + invalid_otp_token: Ongeldige twe-factor code + will_paginate: + page_gap: "…" diff --git a/config/locales/simple_form.nl.yml b/config/locales/simple_form.nl.yml new file mode 100644 index 00000000..5bc38a87 --- /dev/null +++ b/config/locales/simple_form.nl.yml @@ -0,0 +1,46 @@ +--- +nl: + simple_form: + hints: + defaults: + avatar: PNG, GIF of JPG. Maximaal 2MB. Wordt teruggeschaald naar 120x120px + display_name: Maximaal 30 tekens + header: PNG, GIF of JPG. Maximaal 2MB. Wordt teruggeschaald naar 700x335px + locked: Vereist dat je handmatig volgers accepteert en stelt standaard plaatsen berichten privacy in op alleen-volgers + note: Maximaal 160 characters + imports: + data: CSV file geëxporteerd van een andere Mastodon server + labels: + defaults: + avatar: Avatar + confirm_new_password: Bevestig nieuw wachtwoord + confirm_password: Bevestig wachtwoord + current_password: Huidige wachtwoord + data: Gegevens + display_name: Weergavenaam + email: E-mailadres + header: Kop + locale: Taal + locked: Maak account besloten + new_password: Nieuwe wachtwoord + note: Bio + otp_attempt: Twee-factor code + password: Wachtwoord + setting_default_privacy: Berichten privacy + type: Import type + username: gebruikersnaam + interactions: + must_be_follower: Blokkeermeldingen van niet-volgers + must_be_following: Blokkeer meldingen van mensen die je niet volgt + notification_emails: + digest: Verstuur samenvattingse-mails + favourite: Verstuur een e-mail wanneer iemand je status als favoriet markeert + follow: Verstuur een e-mail wanneer iemand je volgt + follow_request: Verstuur een e-mail wanneer iemand je wil volgen + mention: Verstuur een e-mail wanneer iemand je vermeld + reblog: Verstuur een e-mail wanneer iemand je status boost + 'no': 'Nee' + required: + mark: "*" + text: vereist + 'yes': 'Ja' From 9362700137d7fb4b0cddf425d5a2de353f7ab242 Mon Sep 17 00:00:00 2001 From: Rachel H Date: Thu, 13 Apr 2017 07:03:45 -0700 Subject: [PATCH 28/43] Convert emoji shortnames when sending status (#1666) --- app/assets/javascripts/components/actions/compose.jsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/components/actions/compose.jsx b/app/assets/javascripts/components/actions/compose.jsx index 1b3cc60d..88e91c35 100644 --- a/app/assets/javascripts/components/actions/compose.jsx +++ b/app/assets/javascripts/components/actions/compose.jsx @@ -2,6 +2,8 @@ import api from '../api'; import { updateTimeline } from './timelines'; +import * as emojione from 'emojione'; + export const COMPOSE_CHANGE = 'COMPOSE_CHANGE'; export const COMPOSE_SUBMIT_REQUEST = 'COMPOSE_SUBMIT_REQUEST'; export const COMPOSE_SUBMIT_SUCCESS = 'COMPOSE_SUBMIT_SUCCESS'; @@ -72,9 +74,8 @@ export function mentionCompose(account, router) { export function submitCompose() { return function (dispatch, getState) { dispatch(submitComposeRequest()); - api(getState).post('/api/v1/statuses', { - status: getState().getIn(['compose', 'text'], ''), + status: emojione.shortnameToUnicode(getState().getIn(['compose', 'text'], '')), in_reply_to_id: getState().getIn(['compose', 'in_reply_to'], null), media_ids: getState().getIn(['compose', 'media_attachments']).map(item => item.get('id')), sensitive: getState().getIn(['compose', 'sensitive']), From d7a4e8739a9297c8a4b593c076bdcd7abd881453 Mon Sep 17 00:00:00 2001 From: Lukas Burk Date: Thu, 13 Apr 2017 16:04:20 +0200 Subject: [PATCH 29/43] Ignore postgres/redis folder from docker-compose (#1645) --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index b671bcb9..5c95f780 100644 --- a/.gitignore +++ b/.gitignore @@ -32,3 +32,7 @@ config/deploy/* # Ignore IDE files .vscode/ + +# Ignore postgres + redis volume optionally created by docker-compose +postgres +redis From 5f8155482ab494e9b509f61baad7e3d5303176f1 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 13 Apr 2017 17:01:09 +0200 Subject: [PATCH 30/43] Add overlay style to buttons, continue video after expanding it --- .../components/extended_video_player.jsx | 30 +++++++++++++++++-- .../components/components/icon_button.jsx | 28 ++++++++++++++--- .../components/components/media_gallery.jsx | 8 ++--- .../components/components/video_player.jsx | 26 ++++++++-------- .../containers/status_container.jsx | 4 +-- .../components/features/status/index.jsx | 4 +-- .../features/ui/components/video_modal.jsx | 7 +++-- app/assets/stylesheets/components.scss | 12 ++++++++ 8 files changed, 88 insertions(+), 31 deletions(-) diff --git a/app/assets/javascripts/components/components/extended_video_player.jsx b/app/assets/javascripts/components/components/extended_video_player.jsx index 603f005f..a6451558 100644 --- a/app/assets/javascripts/components/components/extended_video_player.jsx +++ b/app/assets/javascripts/components/components/extended_video_player.jsx @@ -4,16 +4,42 @@ const ExtendedVideoPlayer = React.createClass({ propTypes: { src: React.PropTypes.string.isRequired, + time: React.PropTypes.number, controls: React.PropTypes.bool.isRequired, muted: React.PropTypes.bool.isRequired }, mixins: [PureRenderMixin], + handleLoadedData () { + if (this.props.time) { + this.video.currentTime = this.props.time; + } + }, + + componentDidMount () { + this.video.addEventListener('loadeddata', this.handleLoadedData); + }, + + componentWillUnmount () { + this.video.removeEventListener('loadeddata', this.handleLoadedData); + }, + + setRef (c) { + this.video = c; + }, + render () { return ( -
-