Merge branch 'master' into glitch-soc/merge-upstream
Conflicts: - `app/javascript/mastodon/actions/compose.js`: Not a “real” conflict, but change too close to a change we made to fix the vanilla WebUI locally pushing authored local-only toots in the public TL view.
This commit is contained in:
		
						commit
						b9f351d845
					
				| @ -1,4 +1,3 @@ | |||||||
| https://github.com/heroku/heroku-buildpack-apt | https://github.com/heroku/heroku-buildpack-apt | ||||||
| https://github.com/Scalingo/ffmpeg-buildpack | https://github.com/Scalingo/ffmpeg-buildpack | ||||||
| https://github.com/Scalingo/nodejs-buildpack |  | ||||||
| https://github.com/Scalingo/ruby-buildpack | https://github.com/Scalingo/ruby-buildpack | ||||||
|  | |||||||
| @ -72,11 +72,12 @@ aliases: | |||||||
|         - run: |         - run: | ||||||
|             name: Set bundler settings |             name: Set bundler settings | ||||||
|             command: | |             command: | | ||||||
|               bundle config clean 'true' |               bundle config --local clean 'true' | ||||||
|               bundle config deployment 'true' |               bundle config --local deployment 'true' | ||||||
|               bundle config with 'pam_authentication' |               bundle config --local with 'pam_authentication' | ||||||
|               bundle config without 'development production' |               bundle config --local without 'development production' | ||||||
|               bundle config frozen 'true' |               bundle config --local frozen 'true' | ||||||
|  |               bundle config --local path $BUNDLE_PATH | ||||||
|         - run: |         - run: | ||||||
|             name: Install bundler dependencies |             name: Install bundler dependencies | ||||||
|             command: bundle check || (bundle install && bundle clean) |             command: bundle check || (bundle install && bundle clean) | ||||||
|  | |||||||
							
								
								
									
										3
									
								
								app.json
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								app.json
									
									
									
									
									
								
							| @ -88,9 +88,6 @@ | |||||||
|     { |     { | ||||||
|       "url": "https://github.com/heroku/heroku-buildpack-apt" |       "url": "https://github.com/heroku/heroku-buildpack-apt" | ||||||
|     }, |     }, | ||||||
|     { |  | ||||||
|       "url": "heroku/nodejs" |  | ||||||
|     }, |  | ||||||
|     { |     { | ||||||
|       "url": "heroku/ruby" |       "url": "heroku/ruby" | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -58,6 +58,7 @@ class Api::V1::StatusesController < Api::BaseController | |||||||
| 
 | 
 | ||||||
|     @status.discard |     @status.discard | ||||||
|     RemovalWorker.perform_async(@status.id, redraft: true) |     RemovalWorker.perform_async(@status.id, redraft: true) | ||||||
|  |     @status.account.statuses_count = @status.account.statuses_count - 1 | ||||||
| 
 | 
 | ||||||
|     render json: @status, serializer: REST::StatusSerializer, source_requested: true |     render json: @status, serializer: REST::StatusSerializer, source_requested: true | ||||||
|   end |   end | ||||||
|  | |||||||
| @ -56,7 +56,7 @@ class ApplicationController < ActionController::Base | |||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def store_current_location |   def store_current_location | ||||||
|     store_location_for(:user, request.url) unless request.format == :json |     store_location_for(:user, request.url) unless [:json, :rss].include?(request.format&.to_sym) | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def require_admin! |   def require_admin! | ||||||
|  | |||||||
| @ -163,7 +163,6 @@ export function submitCompose(routerHistory) { | |||||||
| 
 | 
 | ||||||
|       // To make the app more responsive, immediately push the status
 |       // To make the app more responsive, immediately push the status
 | ||||||
|       // into the columns
 |       // into the columns
 | ||||||
| 
 |  | ||||||
|       const insertIfOnline = timelineId => { |       const insertIfOnline = timelineId => { | ||||||
|         const timeline = getState().getIn(['timelines', timelineId]); |         const timeline = getState().getIn(['timelines', timelineId]); | ||||||
| 
 | 
 | ||||||
| @ -181,6 +180,7 @@ export function submitCompose(routerHistory) { | |||||||
|         if (!response.data.local_only) { |         if (!response.data.local_only) { | ||||||
|           insertIfOnline('public'); |           insertIfOnline('public'); | ||||||
|         } |         } | ||||||
|  |         insertIfOnline(`account:${response.data.account.id}`); | ||||||
|       } |       } | ||||||
|     }).catch(function (error) { |     }).catch(function (error) { | ||||||
|       dispatch(submitComposeFail(error)); |       dispatch(submitComposeFail(error)); | ||||||
|  | |||||||
| @ -3,7 +3,7 @@ import openDB from '../storage/db'; | |||||||
| import { evictStatus } from '../storage/modifier'; | import { evictStatus } from '../storage/modifier'; | ||||||
| 
 | 
 | ||||||
| import { deleteFromTimelines } from './timelines'; | import { deleteFromTimelines } from './timelines'; | ||||||
| import { importFetchedStatus, importFetchedStatuses, importAccount, importStatus } from './importer'; | import { importFetchedStatus, importFetchedStatuses, importAccount, importStatus, importFetchedAccount } from './importer'; | ||||||
| import { ensureComposeIsVisible } from './compose'; | import { ensureComposeIsVisible } from './compose'; | ||||||
| 
 | 
 | ||||||
| export const STATUS_FETCH_REQUEST = 'STATUS_FETCH_REQUEST'; | export const STATUS_FETCH_REQUEST = 'STATUS_FETCH_REQUEST'; | ||||||
| @ -155,6 +155,7 @@ export function deleteStatus(id, routerHistory, withRedraft = false) { | |||||||
|       evictStatus(id); |       evictStatus(id); | ||||||
|       dispatch(deleteStatusSuccess(id)); |       dispatch(deleteStatusSuccess(id)); | ||||||
|       dispatch(deleteFromTimelines(id)); |       dispatch(deleteFromTimelines(id)); | ||||||
|  |       dispatch(importFetchedAccount(response.data.account)); | ||||||
| 
 | 
 | ||||||
|       if (withRedraft) { |       if (withRedraft) { | ||||||
|         dispatch(redraft(status, response.data.text)); |         dispatch(redraft(status, response.data.text)); | ||||||
|  | |||||||
| @ -71,9 +71,10 @@ const refreshHomeTimelineAndNotification = (dispatch, done) => { | |||||||
|       dispatch(fetchAnnouncements(done)))))); |       dispatch(fetchAnnouncements(done)))))); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| export const connectUserStream      = () => connectTimelineStream('home', 'user', refreshHomeTimelineAndNotification); | export const connectUserStream         = () => connectTimelineStream('home', 'user', refreshHomeTimelineAndNotification); | ||||||
| export const connectCommunityStream = ({ onlyMedia } = {}) => connectTimelineStream(`community${onlyMedia ? ':media' : ''}`, `public:local${onlyMedia ? ':media' : ''}`); | export const connectUserTimelineStream = (accountId) => connectTimelineStream(`account:${accountId}`, 'user'); | ||||||
| export const connectPublicStream    = ({ onlyMedia, onlyRemote } = {}) => connectTimelineStream(`public${onlyRemote ? ':remote' : ''}${onlyMedia ? ':media' : ''}`, `public${onlyRemote ? ':remote' : ''}${onlyMedia ? ':media' : ''}`); | export const connectCommunityStream    = ({ onlyMedia } = {}) => connectTimelineStream(`community${onlyMedia ? ':media' : ''}`, `public:local${onlyMedia ? ':media' : ''}`); | ||||||
| export const connectHashtagStream   = (id, tag, local, accept) => connectTimelineStream(`hashtag:${id}${local ? ':local' : ''}`, `hashtag${local ? ':local' : ''}&tag=${tag}`, null, accept); | export const connectPublicStream       = ({ onlyMedia, onlyRemote } = {}) => connectTimelineStream(`public${onlyRemote ? ':remote' : ''}${onlyMedia ? ':media' : ''}`, `public${onlyRemote ? ':remote' : ''}${onlyMedia ? ':media' : ''}`); | ||||||
| export const connectDirectStream    = () => connectTimelineStream('direct', 'direct'); | export const connectHashtagStream      = (id, tag, local, accept) => connectTimelineStream(`hashtag:${id}${local ? ':local' : ''}`, `hashtag${local ? ':local' : ''}&tag=${tag}`, null, accept); | ||||||
| export const connectListStream      = id => connectTimelineStream(`list:${id}`, `list&list=${id}`); | export const connectDirectStream       = () => connectTimelineStream('direct', 'direct'); | ||||||
|  | export const connectListStream         = id => connectTimelineStream(`list:${id}`, `list&list=${id}`); | ||||||
|  | |||||||
| @ -37,7 +37,7 @@ export function counterRenderer(counterType, isBold = true) { | |||||||
|     return (displayNumber, pluralReady) => ( |     return (displayNumber, pluralReady) => ( | ||||||
|       <FormattedMessage |       <FormattedMessage | ||||||
|         id='account.following_counter' |         id='account.following_counter' | ||||||
|         defaultMessage='{count, plural, other {{counter} Following}}' |         defaultMessage='{count, plural, one {{counter} Following} other {{counter} Following}}' | ||||||
|         values={{ |         values={{ | ||||||
|           count: pluralReady, |           count: pluralReady, | ||||||
|           counter: renderCounter(displayNumber), |           counter: renderCounter(displayNumber), | ||||||
|  | |||||||
| @ -20,7 +20,7 @@ const mapStateToProps = (state, { scrollKey }) => { | |||||||
|   }; |   }; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| export default @connect(mapStateToProps) | export default @connect(mapStateToProps, null, null, { forwardRef: true }) | ||||||
| class ScrollableList extends PureComponent { | class ScrollableList extends PureComponent { | ||||||
| 
 | 
 | ||||||
|   static contextTypes = { |   static contextTypes = { | ||||||
|  | |||||||
| @ -15,6 +15,8 @@ import { FormattedMessage } from 'react-intl'; | |||||||
| import { fetchAccountIdentityProofs } from '../../actions/identity_proofs'; | import { fetchAccountIdentityProofs } from '../../actions/identity_proofs'; | ||||||
| import MissingIndicator from 'mastodon/components/missing_indicator'; | import MissingIndicator from 'mastodon/components/missing_indicator'; | ||||||
| import TimelineHint from 'mastodon/components/timeline_hint'; | import TimelineHint from 'mastodon/components/timeline_hint'; | ||||||
|  | import { me } from 'mastodon/initial_state'; | ||||||
|  | import { connectUserTimelineStream } from '../../actions/streaming'; | ||||||
| 
 | 
 | ||||||
| const emptyList = ImmutableList(); | const emptyList = ImmutableList(); | ||||||
| 
 | 
 | ||||||
| @ -73,6 +75,12 @@ class AccountTimeline extends ImmutablePureComponent { | |||||||
|     this.props.dispatch(expandAccountTimeline(accountId, { withReplies })); |     this.props.dispatch(expandAccountTimeline(accountId, { withReplies })); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   componentDidMount () { | ||||||
|  |     if (this.props.params.accountId === me) { | ||||||
|  |       this.disconnect = this.props.dispatch(connectUserTimelineStream(me)); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   componentWillReceiveProps (nextProps) { |   componentWillReceiveProps (nextProps) { | ||||||
|     if ((nextProps.params.accountId !== this.props.params.accountId && nextProps.params.accountId) || nextProps.withReplies !== this.props.withReplies) { |     if ((nextProps.params.accountId !== this.props.params.accountId && nextProps.params.accountId) || nextProps.withReplies !== this.props.withReplies) { | ||||||
|       this.props.dispatch(fetchAccount(nextProps.params.accountId)); |       this.props.dispatch(fetchAccount(nextProps.params.accountId)); | ||||||
| @ -86,6 +94,13 @@ class AccountTimeline extends ImmutablePureComponent { | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   componentWillUnmount () { | ||||||
|  |     if (this.disconnect) { | ||||||
|  |       this.disconnect(); | ||||||
|  |       this.disconnect = null; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   handleLoadMore = maxId => { |   handleLoadMore = maxId => { | ||||||
|     this.props.dispatch(expandAccountTimeline(this.props.params.accountId, { maxId, withReplies: this.props.withReplies })); |     this.props.dispatch(expandAccountTimeline(this.props.params.accountId, { maxId, withReplies: this.props.withReplies })); | ||||||
|   } |   } | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ | |||||||
|   "account.followers": "مُتابِعون", |   "account.followers": "مُتابِعون", | ||||||
|   "account.followers.empty": "لا أحد يتبع هذا الحساب بعد.", |   "account.followers.empty": "لا أحد يتبع هذا الحساب بعد.", | ||||||
|   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", |   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", | ||||||
|   "account.following_counter": "{count, plural, other {{counter} Following}}", |   "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", | ||||||
|   "account.follows.empty": "هذا الحساب لا يتبع أحدًا بعد.", |   "account.follows.empty": "هذا الحساب لا يتبع أحدًا بعد.", | ||||||
|   "account.follows_you": "يتابعك", |   "account.follows_you": "يتابعك", | ||||||
|   "account.hide_reblogs": "إخفاء ترقيات @{name}", |   "account.hide_reblogs": "إخفاء ترقيات @{name}", | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ | |||||||
|   "account.followers": "Siguidores", |   "account.followers": "Siguidores", | ||||||
|   "account.followers.empty": "Naide sigue a esti usuariu entá.", |   "account.followers.empty": "Naide sigue a esti usuariu entá.", | ||||||
|   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", |   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", | ||||||
|   "account.following_counter": "{count, plural, other {{counter} Following}}", |   "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", | ||||||
|   "account.follows.empty": "Esti usuariu entá nun sigue a naide.", |   "account.follows.empty": "Esti usuariu entá nun sigue a naide.", | ||||||
|   "account.follows_you": "Síguete", |   "account.follows_you": "Síguete", | ||||||
|   "account.hide_reblogs": "Anubrir les comparticiones de @{name}", |   "account.hide_reblogs": "Anubrir les comparticiones de @{name}", | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ | |||||||
|   "account.followers": "Последователи", |   "account.followers": "Последователи", | ||||||
|   "account.followers.empty": "Все още никой не следва този потребител.", |   "account.followers.empty": "Все още никой не следва този потребител.", | ||||||
|   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", |   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", | ||||||
|   "account.following_counter": "{count, plural, other {{counter} Following}}", |   "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", | ||||||
|   "account.follows.empty": "Този потребител все още не следва никого.", |   "account.follows.empty": "Този потребител все още не следва никого.", | ||||||
|   "account.follows_you": "Твой последовател", |   "account.follows_you": "Твой последовател", | ||||||
|   "account.hide_reblogs": "Hide boosts from @{name}", |   "account.hide_reblogs": "Hide boosts from @{name}", | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ | |||||||
|   "account.followers": "অনুসরণকারী", |   "account.followers": "অনুসরণকারী", | ||||||
|   "account.followers.empty": "এই সদস্যকে এখনো কেউ অনুসরণ করে না।.", |   "account.followers.empty": "এই সদস্যকে এখনো কেউ অনুসরণ করে না।.", | ||||||
|   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", |   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", | ||||||
|   "account.following_counter": "{count, plural, other {{counter} Following}}", |   "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", | ||||||
|   "account.follows.empty": "এই সদস্য কাওকে এখনো অনুসরণ করেন না.", |   "account.follows.empty": "এই সদস্য কাওকে এখনো অনুসরণ করেন না.", | ||||||
|   "account.follows_you": "আপনাকে অনুসরণ করে", |   "account.follows_you": "আপনাকে অনুসরণ করে", | ||||||
|   "account.hide_reblogs": "@{name}'র সমর্থনগুলি লুকিয়ে ফেলুন", |   "account.hide_reblogs": "@{name}'র সমর্থনগুলি লুকিয়ে ফেলুন", | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ | |||||||
|   "account.followers": "Sledující", |   "account.followers": "Sledující", | ||||||
|   "account.followers.empty": "Tohoto uživatele ještě nikdo nesleduje.", |   "account.followers.empty": "Tohoto uživatele ještě nikdo nesleduje.", | ||||||
|   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", |   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", | ||||||
|   "account.following_counter": "{count, plural, other {{counter} Following}}", |   "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", | ||||||
|   "account.follows.empty": "Tento uživatel ještě nikoho nesleduje.", |   "account.follows.empty": "Tento uživatel ještě nikoho nesleduje.", | ||||||
|   "account.follows_you": "Sleduje vás", |   "account.follows_you": "Sleduje vás", | ||||||
|   "account.hide_reblogs": "Skrýt boosty od uživatele @{name}", |   "account.hide_reblogs": "Skrýt boosty od uživatele @{name}", | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ | |||||||
|   "account.followers": "Dilynwyr", |   "account.followers": "Dilynwyr", | ||||||
|   "account.followers.empty": "Nid oes neb yn dilyn y defnyddiwr hwn eto.", |   "account.followers.empty": "Nid oes neb yn dilyn y defnyddiwr hwn eto.", | ||||||
|   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", |   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", | ||||||
|   "account.following_counter": "{count, plural, other {{counter} Following}}", |   "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", | ||||||
|   "account.follows.empty": "Nid yw'r defnyddiwr hwn yn dilyn unrhyw un eto.", |   "account.follows.empty": "Nid yw'r defnyddiwr hwn yn dilyn unrhyw un eto.", | ||||||
|   "account.follows_you": "Yn eich dilyn chi", |   "account.follows_you": "Yn eich dilyn chi", | ||||||
|   "account.hide_reblogs": "Cuddio bwstiau o @{name}", |   "account.hide_reblogs": "Cuddio bwstiau o @{name}", | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ | |||||||
|   "account.followers": "Følgere", |   "account.followers": "Følgere", | ||||||
|   "account.followers.empty": "Der er endnu ingen der følger denne bruger.", |   "account.followers.empty": "Der er endnu ingen der følger denne bruger.", | ||||||
|   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", |   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", | ||||||
|   "account.following_counter": "{count, plural, other {{counter} Following}}", |   "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", | ||||||
|   "account.follows.empty": "Denne bruger følger endnu ikke nogen.", |   "account.follows.empty": "Denne bruger følger endnu ikke nogen.", | ||||||
|   "account.follows_you": "Følger dig", |   "account.follows_you": "Følger dig", | ||||||
|   "account.hide_reblogs": "Skjul fremhævelserne fra @{name}", |   "account.hide_reblogs": "Skjul fremhævelserne fra @{name}", | ||||||
|  | |||||||
| @ -146,7 +146,7 @@ | |||||||
|         "id": "account.statuses_counter" |         "id": "account.statuses_counter" | ||||||
|       }, |       }, | ||||||
|       { |       { | ||||||
|         "defaultMessage": "{count, plural, other {{counter} Following}}", |         "defaultMessage": "{count, plural, one {{counter} Following} other {{counter} Following}}", | ||||||
|         "id": "account.following_counter" |         "id": "account.following_counter" | ||||||
|       }, |       }, | ||||||
|       { |       { | ||||||
| @ -2659,6 +2659,22 @@ | |||||||
|         "defaultMessage": "Boost", |         "defaultMessage": "Boost", | ||||||
|         "id": "status.reblog" |         "id": "status.reblog" | ||||||
|       }, |       }, | ||||||
|  |       { | ||||||
|  |         "defaultMessage": "Public", | ||||||
|  |         "id": "privacy.public.short" | ||||||
|  |       }, | ||||||
|  |       { | ||||||
|  |         "defaultMessage": "Unlisted", | ||||||
|  |         "id": "privacy.unlisted.short" | ||||||
|  |       }, | ||||||
|  |       { | ||||||
|  |         "defaultMessage": "Followers-only", | ||||||
|  |         "id": "privacy.private.short" | ||||||
|  |       }, | ||||||
|  |       { | ||||||
|  |         "defaultMessage": "Direct", | ||||||
|  |         "id": "privacy.direct.short" | ||||||
|  |       }, | ||||||
|       { |       { | ||||||
|         "defaultMessage": "You can press {combo} to skip this next time", |         "defaultMessage": "You can press {combo} to skip this next time", | ||||||
|         "id": "boost_modal.combo" |         "id": "boost_modal.combo" | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ | |||||||
|   "account.followers": "Followers", |   "account.followers": "Followers", | ||||||
|   "account.followers.empty": "No one follows this user yet.", |   "account.followers.empty": "No one follows this user yet.", | ||||||
|   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", |   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", | ||||||
|   "account.following_counter": "{count, plural, other {{counter} Following}}", |   "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", | ||||||
|   "account.follows.empty": "This user doesn't follow anyone yet.", |   "account.follows.empty": "This user doesn't follow anyone yet.", | ||||||
|   "account.follows_you": "Follows you", |   "account.follows_you": "Follows you", | ||||||
|   "account.hide_reblogs": "Hide boosts from @{name}", |   "account.hide_reblogs": "Hide boosts from @{name}", | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ | |||||||
|   "account.followers": "Jälgijad", |   "account.followers": "Jälgijad", | ||||||
|   "account.followers.empty": "Keegi ei jälgi seda kasutajat veel.", |   "account.followers.empty": "Keegi ei jälgi seda kasutajat veel.", | ||||||
|   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", |   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", | ||||||
|   "account.following_counter": "{count, plural, other {{counter} Following}}", |   "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", | ||||||
|   "account.follows.empty": "See kasutaja ei jälgi veel kedagi.", |   "account.follows.empty": "See kasutaja ei jälgi veel kedagi.", | ||||||
|   "account.follows_you": "Jälgib Teid", |   "account.follows_you": "Jälgib Teid", | ||||||
|   "account.hide_reblogs": "Peida upitused kasutajalt @{name}", |   "account.hide_reblogs": "Peida upitused kasutajalt @{name}", | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ | |||||||
|   "account.followers": "Jarraitzaileak", |   "account.followers": "Jarraitzaileak", | ||||||
|   "account.followers.empty": "Ez du inork erabiltzaile hau jarraitzen oraindik.", |   "account.followers.empty": "Ez du inork erabiltzaile hau jarraitzen oraindik.", | ||||||
|   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", |   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", | ||||||
|   "account.following_counter": "{count, plural, other {{counter} Following}}", |   "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", | ||||||
|   "account.follows.empty": "Erabiltzaile honek ez du inor jarraitzen oraindik.", |   "account.follows.empty": "Erabiltzaile honek ez du inor jarraitzen oraindik.", | ||||||
|   "account.follows_you": "Jarraitzen dizu", |   "account.follows_you": "Jarraitzen dizu", | ||||||
|   "account.hide_reblogs": "Ezkutatu @{name}(r)en bultzadak", |   "account.hide_reblogs": "Ezkutatu @{name}(r)en bultzadak", | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ | |||||||
|   "account.followers": "Seuraajaa", |   "account.followers": "Seuraajaa", | ||||||
|   "account.followers.empty": "Tällä käyttäjällä ei ole vielä seuraajia.", |   "account.followers.empty": "Tällä käyttäjällä ei ole vielä seuraajia.", | ||||||
|   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", |   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", | ||||||
|   "account.following_counter": "{count, plural, other {{counter} Following}}", |   "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", | ||||||
|   "account.follows.empty": "Tämä käyttäjä ei vielä seuraa ketään.", |   "account.follows.empty": "Tämä käyttäjä ei vielä seuraa ketään.", | ||||||
|   "account.follows_you": "Seuraa sinua", |   "account.follows_you": "Seuraa sinua", | ||||||
|   "account.hide_reblogs": "Piilota buustaukset käyttäjältä @{name}", |   "account.hide_reblogs": "Piilota buustaukset käyttäjältä @{name}", | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ | |||||||
|   "account.followers": "Followers", |   "account.followers": "Followers", | ||||||
|   "account.followers.empty": "No one follows this user yet.", |   "account.followers.empty": "No one follows this user yet.", | ||||||
|   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", |   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", | ||||||
|   "account.following_counter": "{count, plural, other {{counter} Following}}", |   "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", | ||||||
|   "account.follows.empty": "This user doesn't follow anyone yet.", |   "account.follows.empty": "This user doesn't follow anyone yet.", | ||||||
|   "account.follows_you": "Follows you", |   "account.follows_you": "Follows you", | ||||||
|   "account.hide_reblogs": "Hide boosts from @{name}", |   "account.hide_reblogs": "Hide boosts from @{name}", | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ | |||||||
|   "account.followers": "עוקבים", |   "account.followers": "עוקבים", | ||||||
|   "account.followers.empty": "אף אחד לא עוקב אחר המשתמש הזה עדיין.", |   "account.followers.empty": "אף אחד לא עוקב אחר המשתמש הזה עדיין.", | ||||||
|   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", |   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", | ||||||
|   "account.following_counter": "{count, plural, other {{counter} Following}}", |   "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", | ||||||
|   "account.follows.empty": "משתמש זה לא עוקב אחר אף אחד עדיין.", |   "account.follows.empty": "משתמש זה לא עוקב אחר אף אחד עדיין.", | ||||||
|   "account.follows_you": "במעקב אחריך", |   "account.follows_you": "במעקב אחריך", | ||||||
|   "account.hide_reblogs": "להסתיר הידהודים מאת @{name}", |   "account.hide_reblogs": "להסתיר הידהודים מאת @{name}", | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ | |||||||
|   "account.followers": "फॉलोवर", |   "account.followers": "फॉलोवर", | ||||||
|   "account.followers.empty": "कोई भी इस यूज़र् को फ़ॉलो नहीं करता है", |   "account.followers.empty": "कोई भी इस यूज़र् को फ़ॉलो नहीं करता है", | ||||||
|   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", |   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", | ||||||
|   "account.following_counter": "{count, plural, other {{counter} Following}}", |   "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", | ||||||
|   "account.follows.empty": "यह यूज़र् अभी तक किसी को फॉलो नहीं करता है।", |   "account.follows.empty": "यह यूज़र् अभी तक किसी को फॉलो नहीं करता है।", | ||||||
|   "account.follows_you": "आपको फॉलो करता है", |   "account.follows_you": "आपको फॉलो करता है", | ||||||
|   "account.hide_reblogs": "@{name} के बूस्ट छुपाएं", |   "account.hide_reblogs": "@{name} के बूस्ट छुपाएं", | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ | |||||||
|   "account.followers": "Sljedbenici", |   "account.followers": "Sljedbenici", | ||||||
|   "account.followers.empty": "No one follows this user yet.", |   "account.followers.empty": "No one follows this user yet.", | ||||||
|   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", |   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", | ||||||
|   "account.following_counter": "{count, plural, other {{counter} Following}}", |   "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", | ||||||
|   "account.follows.empty": "This user doesn't follow anyone yet.", |   "account.follows.empty": "This user doesn't follow anyone yet.", | ||||||
|   "account.follows_you": "te slijedi", |   "account.follows_you": "te slijedi", | ||||||
|   "account.hide_reblogs": "Hide boosts from @{name}", |   "account.hide_reblogs": "Hide boosts from @{name}", | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ | |||||||
|   "account.followers": "Pengikut", |   "account.followers": "Pengikut", | ||||||
|   "account.followers.empty": "Tidak ada satupun yang mengkuti pengguna ini saat ini.", |   "account.followers.empty": "Tidak ada satupun yang mengkuti pengguna ini saat ini.", | ||||||
|   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", |   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", | ||||||
|   "account.following_counter": "{count, plural, other {{counter} Following}}", |   "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", | ||||||
|   "account.follows.empty": "Pengguna ini belum mengikuti siapapun.", |   "account.follows.empty": "Pengguna ini belum mengikuti siapapun.", | ||||||
|   "account.follows_you": "Mengikuti anda", |   "account.follows_you": "Mengikuti anda", | ||||||
|   "account.hide_reblogs": "Sembunyikan boosts dari @{name}", |   "account.hide_reblogs": "Sembunyikan boosts dari @{name}", | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ | |||||||
|   "account.followers": "Sequanti", |   "account.followers": "Sequanti", | ||||||
|   "account.followers.empty": "No one follows this user yet.", |   "account.followers.empty": "No one follows this user yet.", | ||||||
|   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", |   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", | ||||||
|   "account.following_counter": "{count, plural, other {{counter} Following}}", |   "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", | ||||||
|   "account.follows.empty": "This user doesn't follow anyone yet.", |   "account.follows.empty": "This user doesn't follow anyone yet.", | ||||||
|   "account.follows_you": "Sequas tu", |   "account.follows_you": "Sequas tu", | ||||||
|   "account.hide_reblogs": "Hide boosts from @{name}", |   "account.hide_reblogs": "Hide boosts from @{name}", | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ | |||||||
|   "account.followers": "Fylgjendur", |   "account.followers": "Fylgjendur", | ||||||
|   "account.followers.empty": "Ennþá fylgist enginn með þessum notanda.", |   "account.followers.empty": "Ennþá fylgist enginn með þessum notanda.", | ||||||
|   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", |   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", | ||||||
|   "account.following_counter": "{count, plural, other {{counter} Following}}", |   "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", | ||||||
|   "account.follows.empty": "Þessi notandi fylgist ennþá ekki með neinum.", |   "account.follows.empty": "Þessi notandi fylgist ennþá ekki með neinum.", | ||||||
|   "account.follows_you": "Fylgir þér", |   "account.follows_you": "Fylgir þér", | ||||||
|   "account.hide_reblogs": "Fela endurbirtingar fyrir @{name}", |   "account.hide_reblogs": "Fela endurbirtingar fyrir @{name}", | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ | |||||||
|   "account.followers": "მიმდევრები", |   "account.followers": "მიმდევრები", | ||||||
|   "account.followers.empty": "No one follows this user yet.", |   "account.followers.empty": "No one follows this user yet.", | ||||||
|   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", |   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", | ||||||
|   "account.following_counter": "{count, plural, other {{counter} Following}}", |   "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", | ||||||
|   "account.follows.empty": "This user doesn't follow anyone yet.", |   "account.follows.empty": "This user doesn't follow anyone yet.", | ||||||
|   "account.follows_you": "მოგყვებათ", |   "account.follows_you": "მოგყვებათ", | ||||||
|   "account.hide_reblogs": "დაიმალოს ბუსტები @{name}-სგან", |   "account.hide_reblogs": "დაიმალოს ბუსტები @{name}-სგან", | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ | |||||||
|   "account.followers": "Imeḍfaren", |   "account.followers": "Imeḍfaren", | ||||||
|   "account.followers.empty": "Ar tura, ulac yiwen i yeṭṭafaṛen amseqdac-agi.", |   "account.followers.empty": "Ar tura, ulac yiwen i yeṭṭafaṛen amseqdac-agi.", | ||||||
|   "account.followers_counter": "{count, plural, one {{count} n umeḍfar} other {{count} n imeḍfaren}}", |   "account.followers_counter": "{count, plural, one {{count} n umeḍfar} other {{count} n imeḍfaren}}", | ||||||
|   "account.following_counter": "{count, plural, other {{counter} Following}}", |   "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", | ||||||
|   "account.follows.empty": "Ar tura, amseqdac-agi ur yeṭṭafaṛ yiwen.", |   "account.follows.empty": "Ar tura, amseqdac-agi ur yeṭṭafaṛ yiwen.", | ||||||
|   "account.follows_you": "Yeṭṭafaṛ-ik", |   "account.follows_you": "Yeṭṭafaṛ-ik", | ||||||
|   "account.hide_reblogs": "Ffer ayen i ibeṭṭu @{name}", |   "account.hide_reblogs": "Ffer ayen i ibeṭṭu @{name}", | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ | |||||||
|   "account.followers": "Оқырмандар", |   "account.followers": "Оқырмандар", | ||||||
|   "account.followers.empty": "Әлі ешкім жазылмаған.", |   "account.followers.empty": "Әлі ешкім жазылмаған.", | ||||||
|   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", |   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", | ||||||
|   "account.following_counter": "{count, plural, other {{counter} Following}}", |   "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", | ||||||
|   "account.follows.empty": "Ешкімге жазылмапты.", |   "account.follows.empty": "Ешкімге жазылмапты.", | ||||||
|   "account.follows_you": "Сізге жазылыпты", |   "account.follows_you": "Сізге жазылыпты", | ||||||
|   "account.hide_reblogs": "@{name} атты қолданушының әрекеттерін жасыру", |   "account.hide_reblogs": "@{name} атты қолданушының әрекеттерін жасыру", | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ | |||||||
|   "account.followers": "Followers", |   "account.followers": "Followers", | ||||||
|   "account.followers.empty": "No one follows this user yet.", |   "account.followers.empty": "No one follows this user yet.", | ||||||
|   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", |   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", | ||||||
|   "account.following_counter": "{count, plural, other {{counter} Following}}", |   "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", | ||||||
|   "account.follows.empty": "This user doesn't follow anyone yet.", |   "account.follows.empty": "This user doesn't follow anyone yet.", | ||||||
|   "account.follows_you": "Follows you", |   "account.follows_you": "Follows you", | ||||||
|   "account.hide_reblogs": "Hide boosts from @{name}", |   "account.hide_reblogs": "Hide boosts from @{name}", | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ | |||||||
|   "account.followers": "Followers", |   "account.followers": "Followers", | ||||||
|   "account.followers.empty": "No one follows this user yet.", |   "account.followers.empty": "No one follows this user yet.", | ||||||
|   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", |   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", | ||||||
|   "account.following_counter": "{count, plural, other {{counter} Following}}", |   "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", | ||||||
|   "account.follows.empty": "This user doesn't follow anyone yet.", |   "account.follows.empty": "This user doesn't follow anyone yet.", | ||||||
|   "account.follows_you": "Follows you", |   "account.follows_you": "Follows you", | ||||||
|   "account.hide_reblogs": "Hide boosts from @{name}", |   "account.hide_reblogs": "Hide boosts from @{name}", | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ | |||||||
|   "account.followers": "Followers", |   "account.followers": "Followers", | ||||||
|   "account.followers.empty": "No one follows this user yet.", |   "account.followers.empty": "No one follows this user yet.", | ||||||
|   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", |   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", | ||||||
|   "account.following_counter": "{count, plural, other {{counter} Following}}", |   "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", | ||||||
|   "account.follows.empty": "This user doesn't follow anyone yet.", |   "account.follows.empty": "This user doesn't follow anyone yet.", | ||||||
|   "account.follows_you": "Follows you", |   "account.follows_you": "Follows you", | ||||||
|   "account.hide_reblogs": "Hide boosts from @{name}", |   "account.hide_reblogs": "Hide boosts from @{name}", | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ | |||||||
|   "account.followers": "Sekotāji", |   "account.followers": "Sekotāji", | ||||||
|   "account.followers.empty": "Šim lietotājam nav sekotāju.", |   "account.followers.empty": "Šim lietotājam nav sekotāju.", | ||||||
|   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", |   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", | ||||||
|   "account.following_counter": "{count, plural, other {{counter} Following}}", |   "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", | ||||||
|   "account.follows.empty": "Šis lietotājs pagaidām nevienam neseko.", |   "account.follows.empty": "Šis lietotājs pagaidām nevienam neseko.", | ||||||
|   "account.follows_you": "Seko tev", |   "account.follows_you": "Seko tev", | ||||||
|   "account.hide_reblogs": "Paslēpt paceltos ierakstus no lietotāja @{name}", |   "account.hide_reblogs": "Paslēpt paceltos ierakstus no lietotāja @{name}", | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ | |||||||
|   "account.followers": "Следбеници", |   "account.followers": "Следбеници", | ||||||
|   "account.followers.empty": "Никој не го следи овој корисник сеуште.", |   "account.followers.empty": "Никој не го следи овој корисник сеуште.", | ||||||
|   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", |   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", | ||||||
|   "account.following_counter": "{count, plural, other {{counter} Following}}", |   "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", | ||||||
|   "account.follows.empty": "Корисникот не следи никој сеуште.", |   "account.follows.empty": "Корисникот не следи никој сеуште.", | ||||||
|   "account.follows_you": "Те следи тебе", |   "account.follows_you": "Те следи тебе", | ||||||
|   "account.hide_reblogs": "Сокриј буст од @{name}", |   "account.hide_reblogs": "Сокриј буст од @{name}", | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ | |||||||
|   "account.followers": "പിന്തുടരുന്നവർ", |   "account.followers": "പിന്തുടരുന്നവർ", | ||||||
|   "account.followers.empty": "ഈ ഉപയോക്താവിനെ ആരും ഇതുവരെ പിന്തുടരുന്നില്ല.", |   "account.followers.empty": "ഈ ഉപയോക്താവിനെ ആരും ഇതുവരെ പിന്തുടരുന്നില്ല.", | ||||||
|   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", |   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", | ||||||
|   "account.following_counter": "{count, plural, other {{counter} Following}}", |   "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", | ||||||
|   "account.follows.empty": "ഈ ഉപയോക്താവ് ആരേയും ഇതുവരെ പിന്തുടരുന്നില്ല.", |   "account.follows.empty": "ഈ ഉപയോക്താവ് ആരേയും ഇതുവരെ പിന്തുടരുന്നില്ല.", | ||||||
|   "account.follows_you": "നിങ്ങളെ പിന്തുടരുന്നു", |   "account.follows_you": "നിങ്ങളെ പിന്തുടരുന്നു", | ||||||
|   "account.hide_reblogs": "@{name} ബൂസ്റ്റ് ചെയ്തവ മറയ്കുക", |   "account.hide_reblogs": "@{name} ബൂസ്റ്റ് ചെയ്തവ മറയ്കുക", | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ | |||||||
|   "account.followers": "अनुयायी", |   "account.followers": "अनुयायी", | ||||||
|   "account.followers.empty": "ह्या वापरकर्त्याचा आतापर्यंत कोणी अनुयायी नाही.", |   "account.followers.empty": "ह्या वापरकर्त्याचा आतापर्यंत कोणी अनुयायी नाही.", | ||||||
|   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", |   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", | ||||||
|   "account.following_counter": "{count, plural, other {{counter} Following}}", |   "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", | ||||||
|   "account.follows.empty": "हा वापरकर्ता अजूनपर्यंत कोणाचा अनुयायी नाही.", |   "account.follows.empty": "हा वापरकर्ता अजूनपर्यंत कोणाचा अनुयायी नाही.", | ||||||
|   "account.follows_you": "तुमचा अनुयायी आहे", |   "account.follows_you": "तुमचा अनुयायी आहे", | ||||||
|   "account.hide_reblogs": "@{name} पासून सर्व बूस्ट लपवा", |   "account.hide_reblogs": "@{name} पासून सर्व बूस्ट लपवा", | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ | |||||||
|   "account.followers": "Followers", |   "account.followers": "Followers", | ||||||
|   "account.followers.empty": "No one follows this user yet.", |   "account.followers.empty": "No one follows this user yet.", | ||||||
|   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", |   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", | ||||||
|   "account.following_counter": "{count, plural, other {{counter} Following}}", |   "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", | ||||||
|   "account.follows.empty": "This user doesn't follow anyone yet.", |   "account.follows.empty": "This user doesn't follow anyone yet.", | ||||||
|   "account.follows_you": "Follows you", |   "account.follows_you": "Follows you", | ||||||
|   "account.hide_reblogs": "Hide boosts from @{name}", |   "account.hide_reblogs": "Hide boosts from @{name}", | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ | |||||||
|   "account.followers": "Volgers", |   "account.followers": "Volgers", | ||||||
|   "account.followers.empty": "Niemand volgt nog deze gebruiker.", |   "account.followers.empty": "Niemand volgt nog deze gebruiker.", | ||||||
|   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", |   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", | ||||||
|   "account.following_counter": "{count, plural, other {{counter} Following}}", |   "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", | ||||||
|   "account.follows.empty": "Deze gebruiker volgt nog niemand.", |   "account.follows.empty": "Deze gebruiker volgt nog niemand.", | ||||||
|   "account.follows_you": "Volgt jou", |   "account.follows_you": "Volgt jou", | ||||||
|   "account.hide_reblogs": "Verberg boosts van @{name}", |   "account.hide_reblogs": "Verberg boosts van @{name}", | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ | |||||||
|   "account.followers": "Fylgjarar", |   "account.followers": "Fylgjarar", | ||||||
|   "account.followers.empty": "Ingen fylgjer denne brukaren enno.", |   "account.followers.empty": "Ingen fylgjer denne brukaren enno.", | ||||||
|   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", |   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", | ||||||
|   "account.following_counter": "{count, plural, other {{counter} Following}}", |   "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", | ||||||
|   "account.follows.empty": "Denne brukaren fylgjer ikkje nokon enno.", |   "account.follows.empty": "Denne brukaren fylgjer ikkje nokon enno.", | ||||||
|   "account.follows_you": "Fylgjer deg", |   "account.follows_you": "Fylgjer deg", | ||||||
|   "account.hide_reblogs": "Gøym fremhevingar frå @{name}", |   "account.hide_reblogs": "Gøym fremhevingar frå @{name}", | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ | |||||||
|   "account.followers": "Følgere", |   "account.followers": "Følgere", | ||||||
|   "account.followers.empty": "Ingen følger denne brukeren ennå.", |   "account.followers.empty": "Ingen følger denne brukeren ennå.", | ||||||
|   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", |   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", | ||||||
|   "account.following_counter": "{count, plural, other {{counter} Following}}", |   "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", | ||||||
|   "account.follows.empty": "Denne brukeren følger ikke noen enda.", |   "account.follows.empty": "Denne brukeren følger ikke noen enda.", | ||||||
|   "account.follows_you": "Følger deg", |   "account.follows_you": "Følger deg", | ||||||
|   "account.hide_reblogs": "Skjul fremhevinger fra @{name}", |   "account.hide_reblogs": "Skjul fremhevinger fra @{name}", | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ | |||||||
|   "account.followers": "Seguidors", |   "account.followers": "Seguidors", | ||||||
|   "account.followers.empty": "Degun sèc pas aqueste utilizaire pel moment.", |   "account.followers.empty": "Degun sèc pas aqueste utilizaire pel moment.", | ||||||
|   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", |   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", | ||||||
|   "account.following_counter": "{count, plural, other {{counter} Following}}", |   "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", | ||||||
|   "account.follows.empty": "Aqueste utilizaire sèc pas degun pel moment.", |   "account.follows.empty": "Aqueste utilizaire sèc pas degun pel moment.", | ||||||
|   "account.follows_you": "Vos sèc", |   "account.follows_you": "Vos sèc", | ||||||
|   "account.hide_reblogs": "Rescondre los partatges de @{name}", |   "account.hide_reblogs": "Rescondre los partatges de @{name}", | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ | |||||||
|   "account.followers": "Śledzący", |   "account.followers": "Śledzący", | ||||||
|   "account.followers.empty": "Nikt jeszcze nie śledzi tego użytkownika.", |   "account.followers.empty": "Nikt jeszcze nie śledzi tego użytkownika.", | ||||||
|   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", |   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", | ||||||
|   "account.following_counter": "{count, plural, other {{counter} Following}}", |   "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", | ||||||
|   "account.follows.empty": "Ten użytkownik nie śledzi jeszcze nikogo.", |   "account.follows.empty": "Ten użytkownik nie śledzi jeszcze nikogo.", | ||||||
|   "account.follows_you": "Śledzi Cię", |   "account.follows_you": "Śledzi Cię", | ||||||
|   "account.hide_reblogs": "Ukryj podbicia od @{name}", |   "account.hide_reblogs": "Ukryj podbicia od @{name}", | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ | |||||||
|   "account.followers": "Urmăritori", |   "account.followers": "Urmăritori", | ||||||
|   "account.followers.empty": "Acest utilizator nu are încă urmăritori.", |   "account.followers.empty": "Acest utilizator nu are încă urmăritori.", | ||||||
|   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", |   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", | ||||||
|   "account.following_counter": "{count, plural, other {{counter} Following}}", |   "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", | ||||||
|   "account.follows.empty": "Acest utilizator nu urmărește pe nimeni încă.", |   "account.follows.empty": "Acest utilizator nu urmărește pe nimeni încă.", | ||||||
|   "account.follows_you": "Te urmărește", |   "account.follows_you": "Te urmărește", | ||||||
|   "account.hide_reblogs": "Ascunde impulsurile de la @{name}", |   "account.hide_reblogs": "Ascunde impulsurile de la @{name}", | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ | |||||||
|   "account.followers": "Sighiduras", |   "account.followers": "Sighiduras", | ||||||
|   "account.followers.empty": "Nemos sighit ancora custa persone.", |   "account.followers.empty": "Nemos sighit ancora custa persone.", | ||||||
|   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", |   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", | ||||||
|   "account.following_counter": "{count, plural, other {{counter} Following}}", |   "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", | ||||||
|   "account.follows.empty": "Custa persone non sighit ancora a nemos.", |   "account.follows.empty": "Custa persone non sighit ancora a nemos.", | ||||||
|   "account.follows_you": "Ti sighit", |   "account.follows_you": "Ti sighit", | ||||||
|   "account.hide_reblogs": "Cua is cumpartziduras de @{name}", |   "account.hide_reblogs": "Cua is cumpartziduras de @{name}", | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ | |||||||
|   "account.followers": "Sledujúci", |   "account.followers": "Sledujúci", | ||||||
|   "account.followers.empty": "Tohto používateľa ešte nikto nenásleduje.", |   "account.followers.empty": "Tohto používateľa ešte nikto nenásleduje.", | ||||||
|   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", |   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", | ||||||
|   "account.following_counter": "{count, plural, other {{counter} Following}}", |   "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", | ||||||
|   "account.follows.empty": "Tento používateľ ešte nikoho nenasleduje.", |   "account.follows.empty": "Tento používateľ ešte nikoho nenasleduje.", | ||||||
|   "account.follows_you": "Nasleduje ťa", |   "account.follows_you": "Nasleduje ťa", | ||||||
|   "account.hide_reblogs": "Skry vyzdvihnutia od @{name}", |   "account.hide_reblogs": "Skry vyzdvihnutia od @{name}", | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ | |||||||
|   "account.followers": "Sledilci", |   "account.followers": "Sledilci", | ||||||
|   "account.followers.empty": "Nihče ne sledi temu uporabniku.", |   "account.followers.empty": "Nihče ne sledi temu uporabniku.", | ||||||
|   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", |   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", | ||||||
|   "account.following_counter": "{count, plural, other {{counter} Following}}", |   "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", | ||||||
|   "account.follows.empty": "Ta uporabnik še ne sledi nikomur.", |   "account.follows.empty": "Ta uporabnik še ne sledi nikomur.", | ||||||
|   "account.follows_you": "Sledi tebi", |   "account.follows_you": "Sledi tebi", | ||||||
|   "account.hide_reblogs": "Skrij spodbude od @{name}", |   "account.hide_reblogs": "Skrij spodbude od @{name}", | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ | |||||||
|   "account.followers": "Pratioca", |   "account.followers": "Pratioca", | ||||||
|   "account.followers.empty": "No one follows this user yet.", |   "account.followers.empty": "No one follows this user yet.", | ||||||
|   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", |   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", | ||||||
|   "account.following_counter": "{count, plural, other {{counter} Following}}", |   "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", | ||||||
|   "account.follows.empty": "This user doesn't follow anyone yet.", |   "account.follows.empty": "This user doesn't follow anyone yet.", | ||||||
|   "account.follows_you": "Prati Vas", |   "account.follows_you": "Prati Vas", | ||||||
|   "account.hide_reblogs": "Sakrij podrške koje daje korisnika @{name}", |   "account.hide_reblogs": "Sakrij podrške koje daje korisnika @{name}", | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ | |||||||
|   "account.followers": "Пратиоци", |   "account.followers": "Пратиоци", | ||||||
|   "account.followers.empty": "Тренутно нико не прати овог корисника.", |   "account.followers.empty": "Тренутно нико не прати овог корисника.", | ||||||
|   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", |   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", | ||||||
|   "account.following_counter": "{count, plural, other {{counter} Following}}", |   "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", | ||||||
|   "account.follows.empty": "Корисник тренутно не прати никога.", |   "account.follows.empty": "Корисник тренутно не прати никога.", | ||||||
|   "account.follows_you": "Прати Вас", |   "account.follows_you": "Прати Вас", | ||||||
|   "account.hide_reblogs": "Сакриј подршке које даје корисника @{name}", |   "account.hide_reblogs": "Сакриј подршке које даје корисника @{name}", | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ | |||||||
|   "account.followers": "Följare", |   "account.followers": "Följare", | ||||||
|   "account.followers.empty": "Ingen följer denna användare än.", |   "account.followers.empty": "Ingen följer denna användare än.", | ||||||
|   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", |   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", | ||||||
|   "account.following_counter": "{count, plural, other {{counter} Following}}", |   "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", | ||||||
|   "account.follows.empty": "Denna användare följer inte någon än.", |   "account.follows.empty": "Denna användare följer inte någon än.", | ||||||
|   "account.follows_you": "Följer dig", |   "account.follows_you": "Följer dig", | ||||||
|   "account.hide_reblogs": "Dölj knuffar från @{name}", |   "account.hide_reblogs": "Dölj knuffar från @{name}", | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ | |||||||
|   "account.followers": "Followers", |   "account.followers": "Followers", | ||||||
|   "account.followers.empty": "No one follows this user yet.", |   "account.followers.empty": "No one follows this user yet.", | ||||||
|   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", |   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", | ||||||
|   "account.following_counter": "{count, plural, other {{counter} Following}}", |   "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", | ||||||
|   "account.follows.empty": "This user doesn't follow anyone yet.", |   "account.follows.empty": "This user doesn't follow anyone yet.", | ||||||
|   "account.follows_you": "Follows you", |   "account.follows_you": "Follows you", | ||||||
|   "account.hide_reblogs": "Hide boosts from @{name}", |   "account.hide_reblogs": "Hide boosts from @{name}", | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ | |||||||
|   "account.followers": "பின்தொடர்பவர்கள்", |   "account.followers": "பின்தொடர்பவர்கள்", | ||||||
|   "account.followers.empty": "இதுவரை யாரும் இந்த பயனரைப் பின்தொடரவில்லை.", |   "account.followers.empty": "இதுவரை யாரும் இந்த பயனரைப் பின்தொடரவில்லை.", | ||||||
|   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", |   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", | ||||||
|   "account.following_counter": "{count, plural, other {{counter} Following}}", |   "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", | ||||||
|   "account.follows.empty": "இந்த பயனர் இதுவரை யாரையும் பின்தொடரவில்லை.", |   "account.follows.empty": "இந்த பயனர் இதுவரை யாரையும் பின்தொடரவில்லை.", | ||||||
|   "account.follows_you": "உங்களைப் பின்தொடர்கிறார்", |   "account.follows_you": "உங்களைப் பின்தொடர்கிறார்", | ||||||
|   "account.hide_reblogs": "இருந்து ஊக்கியாக மறை @{name}", |   "account.hide_reblogs": "இருந்து ஊக்கியாக மறை @{name}", | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ | |||||||
|   "account.followers": "Followers", |   "account.followers": "Followers", | ||||||
|   "account.followers.empty": "No one follows this user yet.", |   "account.followers.empty": "No one follows this user yet.", | ||||||
|   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", |   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", | ||||||
|   "account.following_counter": "{count, plural, other {{counter} Following}}", |   "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", | ||||||
|   "account.follows.empty": "This user doesn't follow anyone yet.", |   "account.follows.empty": "This user doesn't follow anyone yet.", | ||||||
|   "account.follows_you": "Follows you", |   "account.follows_you": "Follows you", | ||||||
|   "account.hide_reblogs": "Hide boosts from @{name}", |   "account.hide_reblogs": "Hide boosts from @{name}", | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ | |||||||
|   "account.followers": "అనుచరులు", |   "account.followers": "అనుచరులు", | ||||||
|   "account.followers.empty": "ఈ వినియోగదారుడిని ఇంకా ఎవరూ అనుసరించడంలేదు.", |   "account.followers.empty": "ఈ వినియోగదారుడిని ఇంకా ఎవరూ అనుసరించడంలేదు.", | ||||||
|   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", |   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", | ||||||
|   "account.following_counter": "{count, plural, other {{counter} Following}}", |   "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", | ||||||
|   "account.follows.empty": "ఈ వినియోగదారి ఇంకా ఎవరినీ అనుసరించడంలేదు.", |   "account.follows.empty": "ఈ వినియోగదారి ఇంకా ఎవరినీ అనుసరించడంలేదు.", | ||||||
|   "account.follows_you": "మిమ్మల్ని అనుసరిస్తున్నారు", |   "account.follows_you": "మిమ్మల్ని అనుసరిస్తున్నారు", | ||||||
|   "account.hide_reblogs": "@{name} నుంచి బూస్ట్ లను దాచిపెట్టు", |   "account.hide_reblogs": "@{name} నుంచి బూస్ట్ లను దాచిపెట్టు", | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ | |||||||
|   "account.followers": "ผู้ติดตาม", |   "account.followers": "ผู้ติดตาม", | ||||||
|   "account.followers.empty": "ยังไม่มีใครติดตามผู้ใช้นี้", |   "account.followers.empty": "ยังไม่มีใครติดตามผู้ใช้นี้", | ||||||
|   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", |   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", | ||||||
|   "account.following_counter": "{count, plural, other {{counter} Following}}", |   "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", | ||||||
|   "account.follows.empty": "ผู้ใช้นี้ยังไม่ได้ติดตามใคร", |   "account.follows.empty": "ผู้ใช้นี้ยังไม่ได้ติดตามใคร", | ||||||
|   "account.follows_you": "ติดตามคุณ", |   "account.follows_you": "ติดตามคุณ", | ||||||
|   "account.hide_reblogs": "ซ่อนการดันจาก @{name}", |   "account.hide_reblogs": "ซ่อนการดันจาก @{name}", | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ | |||||||
|   "account.followers": "Takipçi", |   "account.followers": "Takipçi", | ||||||
|   "account.followers.empty": "Henüz kimse bu kullanıcıyı takip etmiyor.", |   "account.followers.empty": "Henüz kimse bu kullanıcıyı takip etmiyor.", | ||||||
|   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", |   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", | ||||||
|   "account.following_counter": "{count, plural, other {{counter} Following}}", |   "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", | ||||||
|   "account.follows.empty": "Bu kullanıcı henüz kimseyi takip etmiyor.", |   "account.follows.empty": "Bu kullanıcı henüz kimseyi takip etmiyor.", | ||||||
|   "account.follows_you": "Seni takip ediyor", |   "account.follows_you": "Seni takip ediyor", | ||||||
|   "account.hide_reblogs": "@{name} kişisinin yinelemelerini gizle", |   "account.hide_reblogs": "@{name} kişisinin yinelemelerini gizle", | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ | |||||||
|   "account.followers": "Followers", |   "account.followers": "Followers", | ||||||
|   "account.followers.empty": "No one follows this user yet.", |   "account.followers.empty": "No one follows this user yet.", | ||||||
|   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", |   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", | ||||||
|   "account.following_counter": "{count, plural, other {{counter} Following}}", |   "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", | ||||||
|   "account.follows.empty": "This user doesn't follow anyone yet.", |   "account.follows.empty": "This user doesn't follow anyone yet.", | ||||||
|   "account.follows_you": "Follows you", |   "account.follows_you": "Follows you", | ||||||
|   "account.hide_reblogs": "Hide boosts from @{name}", |   "account.hide_reblogs": "Hide boosts from @{name}", | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ | |||||||
|   "account.followers": "Підписники", |   "account.followers": "Підписники", | ||||||
|   "account.followers.empty": "Ніхто ще не підписався на цього користувача.", |   "account.followers.empty": "Ніхто ще не підписався на цього користувача.", | ||||||
|   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", |   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", | ||||||
|   "account.following_counter": "{count, plural, other {{counter} Following}}", |   "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", | ||||||
|   "account.follows.empty": "Цей користувач ще ні на кого не підписався.", |   "account.follows.empty": "Цей користувач ще ні на кого не підписався.", | ||||||
|   "account.follows_you": "Підписаний(-а) на вас", |   "account.follows_you": "Підписаний(-а) на вас", | ||||||
|   "account.hide_reblogs": "Сховати передмухи від @{name}", |   "account.hide_reblogs": "Сховати передмухи від @{name}", | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ | |||||||
|   "account.followers": "پیروکار", |   "account.followers": "پیروکار", | ||||||
|   "account.followers.empty": "\"ہنوز اس صارف کی کوئی پیروی نہیں کرتا\".", |   "account.followers.empty": "\"ہنوز اس صارف کی کوئی پیروی نہیں کرتا\".", | ||||||
|   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", |   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", | ||||||
|   "account.following_counter": "{count, plural, other {{counter} Following}}", |   "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", | ||||||
|   "account.follows.empty": "\"یہ صارف ہنوز کسی کی پیروی نہیں کرتا ہے\".", |   "account.follows.empty": "\"یہ صارف ہنوز کسی کی پیروی نہیں کرتا ہے\".", | ||||||
|   "account.follows_you": "آپ کا پیروکار ہے", |   "account.follows_you": "آپ کا پیروکار ہے", | ||||||
|   "account.hide_reblogs": "@{name} سے فروغ چھپائیں", |   "account.hide_reblogs": "@{name} سے فروغ چھپائیں", | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ | |||||||
|   "account.followers": "關注的人", |   "account.followers": "關注的人", | ||||||
|   "account.followers.empty": "尚沒有人關注這位使用者。", |   "account.followers.empty": "尚沒有人關注這位使用者。", | ||||||
|   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", |   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", | ||||||
|   "account.following_counter": "{count, plural, other {{counter} Following}}", |   "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", | ||||||
|   "account.follows.empty": "這位使用者尚未關注任何使用者。", |   "account.follows.empty": "這位使用者尚未關注任何使用者。", | ||||||
|   "account.follows_you": "關注你", |   "account.follows_you": "關注你", | ||||||
|   "account.hide_reblogs": "隱藏 @{name} 的轉推", |   "account.hide_reblogs": "隱藏 @{name} 的轉推", | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ | |||||||
|   "account.followers": "關注者", |   "account.followers": "關注者", | ||||||
|   "account.followers.empty": "尚沒有人關注這位使用者。", |   "account.followers.empty": "尚沒有人關注這位使用者。", | ||||||
|   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", |   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", | ||||||
|   "account.following_counter": "{count, plural, other {{counter} Following}}", |   "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", | ||||||
|   "account.follows.empty": "這位使用者尚未關注任何使用者。", |   "account.follows.empty": "這位使用者尚未關注任何使用者。", | ||||||
|   "account.follows_you": "關注了你", |   "account.follows_you": "關注了你", | ||||||
|   "account.hide_reblogs": "隱藏來自 @{name} 的轉推", |   "account.hide_reblogs": "隱藏來自 @{name} 的轉推", | ||||||
|  | |||||||
| @ -767,10 +767,3 @@ html { | |||||||
| .compose-form .compose-form__warning { | .compose-form .compose-form__warning { | ||||||
|   box-shadow: none; |   box-shadow: none; | ||||||
| } | } | ||||||
| 
 |  | ||||||
| .audio-player .video-player__controls button, |  | ||||||
| .audio-player .video-player__time-sep, |  | ||||||
| .audio-player .video-player__time-current, |  | ||||||
| .audio-player .video-player__time-total { |  | ||||||
|   color: $primary-text-color; |  | ||||||
| } |  | ||||||
|  | |||||||
| @ -157,6 +157,34 @@ class ActivityPub::Activity | |||||||
|     fetch_remote_original_status |     fetch_remote_original_status | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|  |   def dereference_object! | ||||||
|  |     return unless @object.is_a?(String) | ||||||
|  |     return if invalid_origin?(@object) | ||||||
|  | 
 | ||||||
|  |     object = fetch_resource(@object, true, signed_fetch_account) | ||||||
|  |     return unless object.present? && object.is_a?(Hash) && supported_context?(object) | ||||||
|  | 
 | ||||||
|  |     @object = object | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def signed_fetch_account | ||||||
|  |     first_mentioned_local_account || first_local_follower | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def first_mentioned_local_account | ||||||
|  |     audience = (as_array(@json['to']) + as_array(@json['cc'])).uniq | ||||||
|  |     local_usernames = audience.select { |uri| ActivityPub::TagManager.instance.local_uri?(uri) } | ||||||
|  |                               .map { |uri| ActivityPub::TagManager.instance.uri_to_local_id(uri, :username) } | ||||||
|  | 
 | ||||||
|  |     return if local_usernames.empty? | ||||||
|  | 
 | ||||||
|  |     Account.local.where(username: local_usernames).first | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def first_local_follower | ||||||
|  |     @account.followers.local.first | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|   def follow_request_from_object |   def follow_request_from_object | ||||||
|     @follow_request ||= FollowRequest.find_by(target_account: @account, uri: object_uri) unless object_uri.nil? |     @follow_request ||= FollowRequest.find_by(target_account: @account, uri: object_uri) unless object_uri.nil? | ||||||
|   end |   end | ||||||
|  | |||||||
| @ -4,25 +4,32 @@ class ActivityPub::Activity::Announce < ActivityPub::Activity | |||||||
|   def perform |   def perform | ||||||
|     return reject_payload! if delete_arrived_first?(@json['id']) || !related_to_local_activity? |     return reject_payload! if delete_arrived_first?(@json['id']) || !related_to_local_activity? | ||||||
| 
 | 
 | ||||||
|     original_status = status_from_object |     RedisLock.acquire(lock_options) do |lock| | ||||||
|  |       if lock.acquired? | ||||||
|  |         original_status = status_from_object | ||||||
| 
 | 
 | ||||||
|     return reject_payload! if original_status.nil? || !announceable?(original_status) |         return reject_payload! if original_status.nil? || !announceable?(original_status) | ||||||
| 
 | 
 | ||||||
|     status = Status.find_by(account: @account, reblog: original_status) |         @status = Status.find_by(account: @account, reblog: original_status) | ||||||
| 
 | 
 | ||||||
|     return status unless status.nil? |         return @status unless @status.nil? | ||||||
| 
 | 
 | ||||||
|     status = Status.create!( |         @status = Status.create!( | ||||||
|       account: @account, |           account: @account, | ||||||
|       reblog: original_status, |           reblog: original_status, | ||||||
|       uri: @json['id'], |           uri: @json['id'], | ||||||
|       created_at: @json['published'], |           created_at: @json['published'], | ||||||
|       override_timestamps: @options[:override_timestamps], |           override_timestamps: @options[:override_timestamps], | ||||||
|       visibility: visibility_from_audience |           visibility: visibility_from_audience | ||||||
|     ) |         ) | ||||||
| 
 | 
 | ||||||
|     distribute(status) |         distribute(@status) | ||||||
|     status |       else | ||||||
|  |         raise Mastodon::RaceConditionError | ||||||
|  |       end | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     @status | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   private |   private | ||||||
| @ -54,4 +61,8 @@ class ActivityPub::Activity::Announce < ActivityPub::Activity | |||||||
|   def reblog_of_local_status? |   def reblog_of_local_status? | ||||||
|     status_from_uri(object_uri)&.account&.local? |     status_from_uri(object_uri)&.account&.local? | ||||||
|   end |   end | ||||||
|  | 
 | ||||||
|  |   def lock_options | ||||||
|  |     { redis: Redis.current, key: "announce:#{@object['id']}" } | ||||||
|  |   end | ||||||
| end | end | ||||||
|  | |||||||
| @ -4,7 +4,12 @@ class ActivityPub::Activity::Block < ActivityPub::Activity | |||||||
|   def perform |   def perform | ||||||
|     target_account = account_from_uri(object_uri) |     target_account = account_from_uri(object_uri) | ||||||
| 
 | 
 | ||||||
|     return if target_account.nil? || !target_account.local? || @account.blocking?(target_account) |     return if target_account.nil? || !target_account.local? | ||||||
|  | 
 | ||||||
|  |     if @account.blocking?(target_account) | ||||||
|  |       @account.block_relationships.find_by(target_account: target_account).update(uri: @json['id']) if @json['id'].present? | ||||||
|  |       return | ||||||
|  |     end | ||||||
| 
 | 
 | ||||||
|     UnfollowService.new.call(target_account, @account) if target_account.following?(@account) |     UnfollowService.new.call(target_account, @account) if target_account.following?(@account) | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -2,6 +2,8 @@ | |||||||
| 
 | 
 | ||||||
| class ActivityPub::Activity::Create < ActivityPub::Activity | class ActivityPub::Activity::Create < ActivityPub::Activity | ||||||
|   def perform |   def perform | ||||||
|  |     dereference_object! | ||||||
|  | 
 | ||||||
|     case @object['type'] |     case @object['type'] | ||||||
|     when 'EncryptedMessage' |     when 'EncryptedMessage' | ||||||
|       create_encrypted_message |       create_encrypted_message | ||||||
|  | |||||||
| @ -13,11 +13,62 @@ class ActivityPub::Activity::Undo < ActivityPub::Activity | |||||||
|       undo_like |       undo_like | ||||||
|     when 'Block' |     when 'Block' | ||||||
|       undo_block |       undo_block | ||||||
|  |     when nil | ||||||
|  |       handle_reference | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   private |   private | ||||||
| 
 | 
 | ||||||
|  |   def handle_reference | ||||||
|  |     # Some implementations do not inline the object, and as we don't have a | ||||||
|  |     # global index, we have to guess what object it is. | ||||||
|  |     return if object_uri.nil? | ||||||
|  | 
 | ||||||
|  |     try_undo_announce || try_undo_accept || try_undo_follow || try_undo_like || try_undo_block || delete_later!(object_uri) | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def try_undo_announce | ||||||
|  |     status = Status.where.not(reblog_of_id: nil).find_by(uri: object_uri, account: @account) | ||||||
|  |     if status.present? | ||||||
|  |       RemoveStatusService.new.call(status) | ||||||
|  |       true | ||||||
|  |     else | ||||||
|  |       false | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def try_undo_accept | ||||||
|  |     # We can't currently handle `Undo Accept` as we don't record `Accept`'s uri | ||||||
|  |     false | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def try_undo_follow | ||||||
|  |     follow = @account.follow_requests.find_by(uri: object_uri) || @account.active_relationships.find_by(uri: object_uri) | ||||||
|  | 
 | ||||||
|  |     if follow.present? | ||||||
|  |       follow.destroy | ||||||
|  |       true | ||||||
|  |     else | ||||||
|  |       false | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def try_undo_like | ||||||
|  |     # There is an index on accounts, but an account may have *many* favs, so this may be too costly | ||||||
|  |     false | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def try_undo_block | ||||||
|  |     block = @account.block_relationships.find_by(uri: object_uri) | ||||||
|  |     if block.present? | ||||||
|  |       UnblockService.new.call(@account, block.target_account) | ||||||
|  |       true | ||||||
|  |     else | ||||||
|  |       false | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|   def undo_announce |   def undo_announce | ||||||
|     return if object_uri.nil? |     return if object_uri.nil? | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -4,6 +4,8 @@ class ActivityPub::Activity::Update < ActivityPub::Activity | |||||||
|   SUPPORTED_TYPES = %w(Application Group Organization Person Service).freeze |   SUPPORTED_TYPES = %w(Application Group Organization Person Service).freeze | ||||||
| 
 | 
 | ||||||
|   def perform |   def perform | ||||||
|  |     dereference_object! | ||||||
|  | 
 | ||||||
|     if equals_or_includes_any?(@object['type'], SUPPORTED_TYPES) |     if equals_or_includes_any?(@object['type'], SUPPORTED_TYPES) | ||||||
|       update_account |       update_account | ||||||
|     elsif equals_or_includes_any?(@object['type'], %w(Question)) |     elsif equals_or_includes_any?(@object['type'], %w(Question)) | ||||||
|  | |||||||
| @ -7,6 +7,7 @@ module Mastodon | |||||||
|   class HostValidationError < ValidationError; end |   class HostValidationError < ValidationError; end | ||||||
|   class LengthValidationError < ValidationError; end |   class LengthValidationError < ValidationError; end | ||||||
|   class DimensionsValidationError < ValidationError; end |   class DimensionsValidationError < ValidationError; end | ||||||
|  |   class StreamValidationError < ValidationError; end | ||||||
|   class RaceConditionError < Error; end |   class RaceConditionError < Error; end | ||||||
|   class RateLimitExceededError < Error; end |   class RateLimitExceededError < Error; end | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -139,9 +139,15 @@ class FeedManager | |||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def clear_from_timeline(account, target_account) |   def clear_from_timeline(account, target_account) | ||||||
|  |     # Clear from timeline all statuses from or mentionning target_account | ||||||
|     timeline_key        = key(:home, account.id) |     timeline_key        = key(:home, account.id) | ||||||
|     timeline_status_ids = redis.zrange(timeline_key, 0, -1) |     timeline_status_ids = redis.zrange(timeline_key, 0, -1) | ||||||
|     target_statuses     = Status.where(id: timeline_status_ids, account: target_account) |     statuses            = Status.where(id: timeline_status_ids).select(:id, :reblog_of_id, :account_id).to_a | ||||||
|  |     reblogged_ids       = Status.where(id: statuses.map(&:reblog_of_id).compact, account: target_account).pluck(:id) | ||||||
|  |     with_mentions_ids   = Mention.active.where(status_id: statuses.flat_map { |s| [s.id, s.reblog_of_id] }.compact, account: target_account).pluck(:status_id) | ||||||
|  |     target_statuses     = statuses.filter do |status| | ||||||
|  |       status.account_id == target_account.id || reblogged_ids.include?(status.reblog_of_id) || with_mentions_ids.include?(status.id) || with_mentions_ids.include?(status.reblog_of_id) | ||||||
|  |     end | ||||||
| 
 | 
 | ||||||
|     target_statuses.each do |status| |     target_statuses.each do |status| | ||||||
|       unpush_from_home(account, status) |       unpush_from_home(account, status) | ||||||
|  | |||||||
| @ -29,7 +29,7 @@ module Remotable | |||||||
|         rescue Mastodon::UnexpectedResponseError, HTTP::TimeoutError, HTTP::ConnectionError, OpenSSL::SSL::SSLError => e |         rescue Mastodon::UnexpectedResponseError, HTTP::TimeoutError, HTTP::ConnectionError, OpenSSL::SSL::SSLError => e | ||||||
|           Rails.logger.debug "Error fetching remote #{attachment_name}: #{e}" |           Rails.logger.debug "Error fetching remote #{attachment_name}: #{e}" | ||||||
|           raise e unless suppress_errors |           raise e unless suppress_errors | ||||||
|         rescue Paperclip::Errors::NotIdentifiedByImageMagickError, Addressable::URI::InvalidURIError, Mastodon::HostValidationError, Mastodon::LengthValidationError, Paperclip::Error, Mastodon::DimensionsValidationError => e |         rescue Paperclip::Errors::NotIdentifiedByImageMagickError, Addressable::URI::InvalidURIError, Mastodon::HostValidationError, Mastodon::LengthValidationError, Paperclip::Error, Mastodon::DimensionsValidationError, Mastodon::StreamValidationError => e | ||||||
|           Rails.logger.debug "Error fetching remote #{attachment_name}: #{e}" |           Rails.logger.debug "Error fetching remote #{attachment_name}: #{e}" | ||||||
|         end |         end | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -336,6 +336,7 @@ class MediaAttachment < ApplicationRecord | |||||||
| 
 | 
 | ||||||
|     return unless movie.valid? |     return unless movie.valid? | ||||||
| 
 | 
 | ||||||
|  |     raise Mastodon::StreamValidationError, 'Video has no video stream' if movie.width.nil? || movie.frame_rate.nil? | ||||||
|     raise Mastodon::DimensionsValidationError, "#{movie.width}x#{movie.height} videos are not supported" if movie.width * movie.height > MAX_VIDEO_MATRIX_LIMIT |     raise Mastodon::DimensionsValidationError, "#{movie.width}x#{movie.height} videos are not supported" if movie.width * movie.height > MAX_VIDEO_MATRIX_LIMIT | ||||||
|     raise Mastodon::DimensionsValidationError, "#{movie.frame_rate.to_i}fps videos are not supported" if movie.frame_rate > MAX_VIDEO_FRAME_RATE |     raise Mastodon::DimensionsValidationError, "#{movie.frame_rate.to_i}fps videos are not supported" if movie.frame_rate > MAX_VIDEO_FRAME_RATE | ||||||
|   end |   end | ||||||
|  | |||||||
| @ -4,7 +4,7 @@ class REST::MediaAttachmentSerializer < ActiveModel::Serializer | |||||||
|   include RoutingHelper |   include RoutingHelper | ||||||
| 
 | 
 | ||||||
|   attributes :id, :type, :url, :preview_url, |   attributes :id, :type, :url, :preview_url, | ||||||
|              :remote_url, :text_url, :meta, |              :remote_url, :preview_remote_url, :text_url, :meta, | ||||||
|              :description, :blurhash |              :description, :blurhash | ||||||
| 
 | 
 | ||||||
|   def id |   def id | ||||||
| @ -35,6 +35,10 @@ class REST::MediaAttachmentSerializer < ActiveModel::Serializer | |||||||
|     end |     end | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|  |   def preview_remote_url | ||||||
|  |     object.thumbnail_remote_url.presence | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|   def text_url |   def text_url | ||||||
|     object.local? ? medium_url(object) : nil |     object.local? ? medium_url(object) : nil | ||||||
|   end |   end | ||||||
|  | |||||||
| @ -12,7 +12,7 @@ class UpdateAccountService < BaseService | |||||||
|       check_links(account) |       check_links(account) | ||||||
|       process_hashtags(account) |       process_hashtags(account) | ||||||
|     end |     end | ||||||
|   rescue Mastodon::DimensionsValidationError => de |   rescue Mastodon::DimensionsValidationError, Mastodon::StreamValidationError => de | ||||||
|     account.errors.add(:avatar, de.message) |     account.errors.add(:avatar, de.message) | ||||||
|     false |     false | ||||||
|   end |   end | ||||||
|  | |||||||
| @ -3,7 +3,7 @@ | |||||||
| class ActivityPub::ProcessingWorker | class ActivityPub::ProcessingWorker | ||||||
|   include Sidekiq::Worker |   include Sidekiq::Worker | ||||||
| 
 | 
 | ||||||
|   sidekiq_options backtrace: true |   sidekiq_options backtrace: true, retry: 8 | ||||||
| 
 | 
 | ||||||
|   def perform(account_id, body, delivered_to_account_id = nil) |   def perform(account_id, body, delivered_to_account_id = nil) | ||||||
|     ActivityPub::ProcessCollectionService.new.call(body, Account.find(account_id), override_timestamps: true, delivered_to_account_id: delivered_to_account_id, delivery: true) |     ActivityPub::ProcessCollectionService.new.call(body, Account.find(account_id), override_timestamps: true, delivered_to_account_id: delivered_to_account_id, delivery: true) | ||||||
|  | |||||||
| @ -16,6 +16,12 @@ ingress: | |||||||
|     kubernetes.io/ingress.class: nginx |     kubernetes.io/ingress.class: nginx | ||||||
|     kubernetes.io/tls-acme: "true" |     kubernetes.io/tls-acme: "true" | ||||||
|     # cert-manager.io/cluster-issuer: "letsencrypt" |     # cert-manager.io/cluster-issuer: "letsencrypt" | ||||||
|  |     # | ||||||
|  |     # ensure that NGINX's upload size matches Mastodon's | ||||||
|  |     #   for the K8s ingress controller: | ||||||
|  |     # nginx.ingress.kubernetes.io/proxy-body-size: 40m | ||||||
|  |     #   for the NGINX ingress controller: | ||||||
|  |     # nginx.org/client-max-body-size: 40m | ||||||
|   # this value is used for LOCAL_DOMAIN |   # this value is used for LOCAL_DOMAIN | ||||||
|   hostname: mastodon.local |   hostname: mastodon.local | ||||||
|   tls: |   tls: | ||||||
|  | |||||||
| @ -18,7 +18,7 @@ module Paperclip | |||||||
|       @type_from_mime_magic ||= begin |       @type_from_mime_magic ||= begin | ||||||
|         begin |         begin | ||||||
|           File.open(@file.path) do |file| |           File.open(@file.path) do |file| | ||||||
|             MimeMagic.by_magic(file)&.type |             MimeMagic.by_magic(file)&.type || '' | ||||||
|           end |           end | ||||||
|         rescue Errno::ENOENT |         rescue Errno::ENOENT | ||||||
|           '' |           '' | ||||||
|  | |||||||
| @ -110,7 +110,7 @@ | |||||||
|     "intl-relativeformat": "^6.4.3", |     "intl-relativeformat": "^6.4.3", | ||||||
|     "is-nan": "^1.3.0", |     "is-nan": "^1.3.0", | ||||||
|     "js-yaml": "^3.13.1", |     "js-yaml": "^3.13.1", | ||||||
|     "lodash": "^4.17.14", |     "lodash": "^4.17.19", | ||||||
|     "mark-loader": "^0.1.6", |     "mark-loader": "^0.1.6", | ||||||
|     "marky": "^1.2.1", |     "marky": "^1.2.1", | ||||||
|     "mini-css-extract-plugin": "^0.9.0", |     "mini-css-extract-plugin": "^0.9.0", | ||||||
|  | |||||||
| @ -5,6 +5,21 @@ RSpec.describe AccountsController, type: :controller do | |||||||
| 
 | 
 | ||||||
|   let(:account) { Fabricate(:user).account } |   let(:account) { Fabricate(:user).account } | ||||||
| 
 | 
 | ||||||
|  |   shared_examples 'cachable response' do | ||||||
|  |     it 'does not set cookies' do | ||||||
|  |       expect(response.cookies).to be_empty | ||||||
|  |       expect(response.headers['Set-Cookies']).to be nil | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     it 'does not set sessions' do | ||||||
|  |       expect(session).to be_empty | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     it 'returns public Cache-Control header' do | ||||||
|  |       expect(response.headers['Cache-Control']).to include 'public' | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|   describe 'GET #show' do |   describe 'GET #show' do | ||||||
|     let(:format) { 'html' } |     let(:format) { 'html' } | ||||||
| 
 | 
 | ||||||
| @ -323,9 +338,7 @@ RSpec.describe AccountsController, type: :controller do | |||||||
|           expect(response.content_type).to eq 'application/activity+json' |           expect(response.content_type).to eq 'application/activity+json' | ||||||
|         end |         end | ||||||
| 
 | 
 | ||||||
|         it 'returns public Cache-Control header' do |         it_behaves_like 'cachable response' | ||||||
|           expect(response.headers['Cache-Control']).to include 'public' |  | ||||||
|         end |  | ||||||
| 
 | 
 | ||||||
|         it 'renders account' do |         it 'renders account' do | ||||||
|           json = body_as_json |           json = body_as_json | ||||||
| @ -343,9 +356,7 @@ RSpec.describe AccountsController, type: :controller do | |||||||
|             expect(response.content_type).to eq 'application/activity+json' |             expect(response.content_type).to eq 'application/activity+json' | ||||||
|           end |           end | ||||||
| 
 | 
 | ||||||
|           it 'returns public Cache-Control header' do |           it_behaves_like 'cachable response' | ||||||
|             expect(response.headers['Cache-Control']).to include 'public' |  | ||||||
|           end |  | ||||||
| 
 | 
 | ||||||
|           it 'returns Vary header with Signature' do |           it 'returns Vary header with Signature' do | ||||||
|             expect(response.headers['Vary']).to include 'Signature' |             expect(response.headers['Vary']).to include 'Signature' | ||||||
| @ -401,9 +412,7 @@ RSpec.describe AccountsController, type: :controller do | |||||||
|           expect(response.content_type).to eq 'application/activity+json' |           expect(response.content_type).to eq 'application/activity+json' | ||||||
|         end |         end | ||||||
| 
 | 
 | ||||||
|         it 'returns public Cache-Control header' do |         it_behaves_like 'cachable response' | ||||||
|           expect(response.headers['Cache-Control']).to include 'public' |  | ||||||
|         end |  | ||||||
| 
 | 
 | ||||||
|         it 'renders account' do |         it 'renders account' do | ||||||
|           json = body_as_json |           json = body_as_json | ||||||
| @ -447,9 +456,7 @@ RSpec.describe AccountsController, type: :controller do | |||||||
|           expect(response).to have_http_status(200) |           expect(response).to have_http_status(200) | ||||||
|         end |         end | ||||||
| 
 | 
 | ||||||
|         it 'returns public Cache-Control header' do |         it_behaves_like 'cachable response' | ||||||
|           expect(response.headers['Cache-Control']).to include 'public' |  | ||||||
|         end |  | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       context do |       context do | ||||||
|  | |||||||
| @ -6,6 +6,21 @@ RSpec.describe ActivityPub::CollectionsController, type: :controller do | |||||||
|   let!(:account) { Fabricate(:account) } |   let!(:account) { Fabricate(:account) } | ||||||
|   let(:remote_account) { nil } |   let(:remote_account) { nil } | ||||||
| 
 | 
 | ||||||
|  |   shared_examples 'cachable response' do | ||||||
|  |     it 'does not set cookies' do | ||||||
|  |       expect(response.cookies).to be_empty | ||||||
|  |       expect(response.headers['Set-Cookies']).to be nil | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     it 'does not set sessions' do | ||||||
|  |       expect(session).to be_empty | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     it 'returns public Cache-Control header' do | ||||||
|  |       expect(response.headers['Cache-Control']).to include 'public' | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|   before do |   before do | ||||||
|     allow(controller).to receive(:signed_request_account).and_return(remote_account) |     allow(controller).to receive(:signed_request_account).and_return(remote_account) | ||||||
| 
 | 
 | ||||||
| @ -31,9 +46,7 @@ RSpec.describe ActivityPub::CollectionsController, type: :controller do | |||||||
|           expect(response.content_type).to eq 'application/activity+json' |           expect(response.content_type).to eq 'application/activity+json' | ||||||
|         end |         end | ||||||
| 
 | 
 | ||||||
|         it 'returns public Cache-Control header' do |         it_behaves_like 'cachable response' | ||||||
|           expect(response.headers['Cache-Control']).to include 'public' |  | ||||||
|         end |  | ||||||
| 
 | 
 | ||||||
|         it 'returns orderedItems with pinned statuses' do |         it 'returns orderedItems with pinned statuses' do | ||||||
|           json = body_as_json |           json = body_as_json | ||||||
| @ -58,9 +71,7 @@ RSpec.describe ActivityPub::CollectionsController, type: :controller do | |||||||
|             expect(response.content_type).to eq 'application/activity+json' |             expect(response.content_type).to eq 'application/activity+json' | ||||||
|           end |           end | ||||||
| 
 | 
 | ||||||
|           it 'returns public Cache-Control header' do |           it_behaves_like 'cachable response' | ||||||
|             expect(response.headers['Cache-Control']).to include 'public' |  | ||||||
|           end |  | ||||||
| 
 | 
 | ||||||
|           it 'returns orderedItems with pinned statuses' do |           it 'returns orderedItems with pinned statuses' do | ||||||
|             json = body_as_json |             json = body_as_json | ||||||
|  | |||||||
| @ -3,6 +3,21 @@ require 'rails_helper' | |||||||
| RSpec.describe ActivityPub::OutboxesController, type: :controller do | RSpec.describe ActivityPub::OutboxesController, type: :controller do | ||||||
|   let!(:account) { Fabricate(:account) } |   let!(:account) { Fabricate(:account) } | ||||||
| 
 | 
 | ||||||
|  |   shared_examples 'cachable response' do | ||||||
|  |     it 'does not set cookies' do | ||||||
|  |       expect(response.cookies).to be_empty | ||||||
|  |       expect(response.headers['Set-Cookies']).to be nil | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     it 'does not set sessions' do | ||||||
|  |       expect(session).to be_empty | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     it 'returns public Cache-Control header' do | ||||||
|  |       expect(response.headers['Cache-Control']).to include 'public' | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|   before do |   before do | ||||||
|     Fabricate(:status, account: account, visibility: :public) |     Fabricate(:status, account: account, visibility: :public) | ||||||
|     Fabricate(:status, account: account, visibility: :unlisted) |     Fabricate(:status, account: account, visibility: :unlisted) | ||||||
| @ -39,9 +54,7 @@ RSpec.describe ActivityPub::OutboxesController, type: :controller do | |||||||
|           expect(json[:totalItems]).to eq 4 |           expect(json[:totalItems]).to eq 4 | ||||||
|         end |         end | ||||||
| 
 | 
 | ||||||
|         it 'returns public Cache-Control header' do |         it_behaves_like 'cachable response' | ||||||
|           expect(response.headers['Cache-Control']).to include 'public' |  | ||||||
|         end |  | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       context 'with page requested' do |       context 'with page requested' do | ||||||
| @ -62,9 +75,7 @@ RSpec.describe ActivityPub::OutboxesController, type: :controller do | |||||||
|           expect(json[:orderedItems].all? { |item| item[:to].include?(ActivityPub::TagManager::COLLECTIONS[:public]) || item[:cc].include?(ActivityPub::TagManager::COLLECTIONS[:public]) }).to be true |           expect(json[:orderedItems].all? { |item| item[:to].include?(ActivityPub::TagManager::COLLECTIONS[:public]) || item[:cc].include?(ActivityPub::TagManager::COLLECTIONS[:public]) }).to be true | ||||||
|         end |         end | ||||||
| 
 | 
 | ||||||
|         it 'returns public Cache-Control header' do |         it_behaves_like 'cachable response' | ||||||
|           expect(response.headers['Cache-Control']).to include 'public' |  | ||||||
|         end |  | ||||||
|       end |       end | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -7,6 +7,21 @@ RSpec.describe ActivityPub::RepliesController, type: :controller do | |||||||
|   let(:remote_reply_id) { nil } |   let(:remote_reply_id) { nil } | ||||||
|   let(:remote_account) { nil } |   let(:remote_account) { nil } | ||||||
| 
 | 
 | ||||||
|  |   shared_examples 'cachable response' do | ||||||
|  |     it 'does not set cookies' do | ||||||
|  |       expect(response.cookies).to be_empty | ||||||
|  |       expect(response.headers['Set-Cookies']).to be nil | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     it 'does not set sessions' do | ||||||
|  |       expect(session).to be_empty | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     it 'returns public Cache-Control header' do | ||||||
|  |       expect(response.headers['Cache-Control']).to include 'public' | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|   before do |   before do | ||||||
|     allow(controller).to receive(:signed_request_account).and_return(remote_account) |     allow(controller).to receive(:signed_request_account).and_return(remote_account) | ||||||
| 
 | 
 | ||||||
| @ -36,9 +51,7 @@ RSpec.describe ActivityPub::RepliesController, type: :controller do | |||||||
|           expect(response.content_type).to eq 'application/activity+json' |           expect(response.content_type).to eq 'application/activity+json' | ||||||
|         end |         end | ||||||
| 
 | 
 | ||||||
|         it 'returns public Cache-Control header' do |         it_behaves_like 'cachable response' | ||||||
|           expect(response.headers['Cache-Control']).to include 'public' |  | ||||||
|         end |  | ||||||
| 
 | 
 | ||||||
|         it 'returns items with account\'s own replies' do |         it 'returns items with account\'s own replies' do | ||||||
|           json = body_as_json |           json = body_as_json | ||||||
| @ -87,9 +100,7 @@ RSpec.describe ActivityPub::RepliesController, type: :controller do | |||||||
|             expect(response.content_type).to eq 'application/activity+json' |             expect(response.content_type).to eq 'application/activity+json' | ||||||
|           end |           end | ||||||
| 
 | 
 | ||||||
|           it 'returns public Cache-Control header' do |           it_behaves_like 'cachable response' | ||||||
|             expect(response.headers['Cache-Control']).to include 'public' |  | ||||||
|           end |  | ||||||
| 
 | 
 | ||||||
|           context 'without only_other_accounts' do |           context 'without only_other_accounts' do | ||||||
|             it 'returns items with account\'s own replies' do |             it 'returns items with account\'s own replies' do | ||||||
|  | |||||||
| @ -5,6 +5,21 @@ require 'rails_helper' | |||||||
| describe StatusesController do | describe StatusesController do | ||||||
|   render_views |   render_views | ||||||
| 
 | 
 | ||||||
|  |   shared_examples 'cachable response' do | ||||||
|  |     it 'does not set cookies' do | ||||||
|  |       expect(response.cookies).to be_empty | ||||||
|  |       expect(response.headers['Set-Cookies']).to be nil | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     it 'does not set sessions' do | ||||||
|  |       expect(session).to be_empty | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     it 'returns public Cache-Control header' do | ||||||
|  |       expect(response.headers['Cache-Control']).to include 'public' | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|   describe 'GET #show' do |   describe 'GET #show' do | ||||||
|     let(:account) { Fabricate(:account) } |     let(:account) { Fabricate(:account) } | ||||||
|     let(:status)  { Fabricate(:status, account: account) } |     let(:status)  { Fabricate(:status, account: account) } | ||||||
| @ -80,9 +95,7 @@ describe StatusesController do | |||||||
|           expect(response.headers['Vary']).to eq 'Accept' |           expect(response.headers['Vary']).to eq 'Accept' | ||||||
|         end |         end | ||||||
| 
 | 
 | ||||||
|         it 'returns public Cache-Control header' do |         it_behaves_like 'cachable response' | ||||||
|           expect(response.headers['Cache-Control']).to include 'public' |  | ||||||
|         end |  | ||||||
| 
 | 
 | ||||||
|         it 'returns Content-Type header' do |         it 'returns Content-Type header' do | ||||||
|           expect(response.headers['Content-Type']).to include 'application/activity+json' |           expect(response.headers['Content-Type']).to include 'application/activity+json' | ||||||
| @ -470,9 +483,7 @@ describe StatusesController do | |||||||
|             expect(response.headers['Vary']).to eq 'Accept' |             expect(response.headers['Vary']).to eq 'Accept' | ||||||
|           end |           end | ||||||
| 
 | 
 | ||||||
|           it 'returns public Cache-Control header' do |           it_behaves_like 'cachable response' | ||||||
|             expect(response.headers['Cache-Control']).to include 'public' |  | ||||||
|           end |  | ||||||
| 
 | 
 | ||||||
|           it 'returns Content-Type header' do |           it 'returns Content-Type header' do | ||||||
|             expect(response.headers['Content-Type']).to include 'application/activity+json' |             expect(response.headers['Content-Type']).to include 'application/activity+json' | ||||||
|  | |||||||
| @ -28,6 +28,28 @@ RSpec.describe ActivityPub::Activity::Block do | |||||||
|     end |     end | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|  |   context 'when the recipient is already blocked' do | ||||||
|  |     before do | ||||||
|  |       sender.block!(recipient, uri: 'old') | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     describe '#perform' do | ||||||
|  |       subject { described_class.new(json, sender) } | ||||||
|  | 
 | ||||||
|  |       before do | ||||||
|  |         subject.perform | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       it 'creates a block from sender to recipient' do | ||||||
|  |         expect(sender.blocking?(recipient)).to be true | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       it 'sets the uri to that of last received block activity' do | ||||||
|  |         expect(sender.block_relationships.find_by(target_account: recipient).uri).to eq 'foo' | ||||||
|  |       end | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|   context 'when the recipient follows the sender' do |   context 'when the recipient follows the sender' do | ||||||
|     before do |     before do | ||||||
|       recipient.follow!(sender) |       recipient.follow!(sender) | ||||||
|  | |||||||
| @ -50,6 +50,19 @@ RSpec.describe ActivityPub::Activity::Undo do | |||||||
|           expect(sender.reblogged?(status)).to be false |           expect(sender.reblogged?(status)).to be false | ||||||
|         end |         end | ||||||
|       end |       end | ||||||
|  | 
 | ||||||
|  |       context 'with only object uri' do | ||||||
|  |         let(:object_json) { 'bar' } | ||||||
|  | 
 | ||||||
|  |         before do | ||||||
|  |           Fabricate(:status, reblog: status, account: sender, uri: 'bar') | ||||||
|  |         end | ||||||
|  | 
 | ||||||
|  |         it 'deletes the reblog by uri' do | ||||||
|  |           subject.perform | ||||||
|  |           expect(sender.reblogged?(status)).to be false | ||||||
|  |         end | ||||||
|  |       end | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     context 'with Accept' do |     context 'with Accept' do | ||||||
| @ -91,13 +104,22 @@ RSpec.describe ActivityPub::Activity::Undo do | |||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       before do |       before do | ||||||
|         sender.block!(recipient) |         sender.block!(recipient, uri: 'bar') | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       it 'deletes block from sender to recipient' do |       it 'deletes block from sender to recipient' do | ||||||
|         subject.perform |         subject.perform | ||||||
|         expect(sender.blocking?(recipient)).to be false |         expect(sender.blocking?(recipient)).to be false | ||||||
|       end |       end | ||||||
|  | 
 | ||||||
|  |       context 'with only object uri' do | ||||||
|  |         let(:object_json) { 'bar' } | ||||||
|  | 
 | ||||||
|  |         it 'deletes block from sender to recipient' do | ||||||
|  |           subject.perform | ||||||
|  |           expect(sender.blocking?(recipient)).to be false | ||||||
|  |         end | ||||||
|  |       end | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     context 'with Follow' do |     context 'with Follow' do | ||||||
| @ -113,13 +135,22 @@ RSpec.describe ActivityPub::Activity::Undo do | |||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       before do |       before do | ||||||
|         sender.follow!(recipient) |         sender.follow!(recipient, uri: 'bar') | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       it 'deletes follow from sender to recipient' do |       it 'deletes follow from sender to recipient' do | ||||||
|         subject.perform |         subject.perform | ||||||
|         expect(sender.following?(recipient)).to be false |         expect(sender.following?(recipient)).to be false | ||||||
|       end |       end | ||||||
|  | 
 | ||||||
|  |       context 'with only object uri' do | ||||||
|  |         let(:object_json) { 'bar' } | ||||||
|  | 
 | ||||||
|  |         it 'deletes follow from sender to recipient' do | ||||||
|  |           subject.perform | ||||||
|  |           expect(sender.following?(recipient)).to be false | ||||||
|  |         end | ||||||
|  |       end | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     context 'with Like' do |     context 'with Like' do | ||||||
|  | |||||||
| @ -531,4 +531,29 @@ RSpec.describe FeedManager do | |||||||
|       expect(Redis.current).to have_received(:publish).with("timeline:#{receiver.id}", deletion) |       expect(Redis.current).to have_received(:publish).with("timeline:#{receiver.id}", deletion) | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
|  | 
 | ||||||
|  |   describe '#clear_from_timeline' do | ||||||
|  |     let(:account)          { Fabricate(:account) } | ||||||
|  |     let(:followed_account) { Fabricate(:account) } | ||||||
|  |     let(:target_account)   { Fabricate(:account) } | ||||||
|  |     let(:status_1)         { Fabricate(:status, account: followed_account) } | ||||||
|  |     let(:status_2)         { Fabricate(:status, account: target_account) } | ||||||
|  |     let(:status_3)         { Fabricate(:status, account: followed_account, mentions: [Fabricate(:mention, account: target_account)]) } | ||||||
|  |     let(:status_4)         { Fabricate(:status, mentions: [Fabricate(:mention, account: target_account)]) } | ||||||
|  |     let(:status_5)         { Fabricate(:status, account: followed_account, reblog: status_4) } | ||||||
|  |     let(:status_6)         { Fabricate(:status, account: followed_account, reblog: status_2) } | ||||||
|  |     let(:status_7)         { Fabricate(:status, account: followed_account) } | ||||||
|  | 
 | ||||||
|  |     before do | ||||||
|  |       [status_1, status_3, status_5, status_6, status_7].each do |status| | ||||||
|  |         Redis.current.zadd("feed:home:#{account.id}", status.id, status.id) | ||||||
|  |       end | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     it 'correctly cleans the timeline' do | ||||||
|  |       FeedManager.instance.clear_from_timeline(account, target_account) | ||||||
|  | 
 | ||||||
|  |       expect(Redis.current.zrange("feed:home:#{account.id}", 0, -1)).to eq [status_1.id.to_s, status_7.id.to_s] | ||||||
|  |     end | ||||||
|  |   end | ||||||
| end | end | ||||||
|  | |||||||
| @ -6979,10 +6979,10 @@ lodash.uniq@^4.5.0: | |||||||
|   resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" |   resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" | ||||||
|   integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= |   integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= | ||||||
| 
 | 
 | ||||||
| lodash@^4.0.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.3.0, lodash@~4.17.12: | lodash@^4.0.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.3.0, lodash@~4.17.12: | ||||||
|   version "4.17.15" |   version "4.17.19" | ||||||
|   resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" |   resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.19.tgz#e48ddedbe30b3321783c5b4301fbd353bc1e4a4b" | ||||||
|   integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== |   integrity sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ== | ||||||
| 
 | 
 | ||||||
| loglevel@^1.6.8: | loglevel@^1.6.8: | ||||||
|   version "1.6.8" |   version "1.6.8" | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user