diff --git a/.env.production.sample b/.env.production.sample
index 1d8a177aa2..3e054db844 100644
--- a/.env.production.sample
+++ b/.env.production.sample
@@ -26,7 +26,7 @@ LOCAL_HTTPS=true
# ALTERNATE_DOMAINS=example1.com,example2.com
# Application secrets
-# Generate each with the `rake secret` task (`docker-compose run --rm web rake secret` if you use docker compose)
+# Generate each with the `RAILS_ENV=production bundle exec rake secret` task (`docker-compose run --rm web rake secret` if you use docker compose)
PAPERCLIP_SECRET=
SECRET_KEY_BASE=
OTP_SECRET=
@@ -36,7 +36,7 @@ OTP_SECRET=
# You should only generate this once per instance. If you later decide to change it, all push subscription will
# be invalidated, requiring the users to access the website again to resubscribe.
#
-# Generate with `rake mastodon:webpush:generate_vapid_key` task (`docker-compose run --rm web rake mastodon:webpush:generate_vapid_key` if you use docker compose)
+# Generate with `RAILS_ENV=production bundle exec rake mastodon:webpush:generate_vapid_key` task (`docker-compose run --rm web rake mastodon:webpush:generate_vapid_key` if you use docker compose)
#
# For more information visit https://rossta.net/blog/using-the-web-push-api-with-vapid.html
VAPID_PRIVATE_KEY=
@@ -98,6 +98,15 @@ SMTP_FROM_ADDRESS=notifications@example.com
# S3_ENDPOINT=
# S3_SIGNATURE_VERSION=
+# Swift (optional)
+# SWIFT_ENABLED=true
+# SWIFT_USERNAME=
+# SWIFT_TENANT=
+# SWIFT_PASSWORD=
+# SWIFT_AUTH_URL=
+# SWIFT_CONTAINER=
+# SWIFT_OBJECT_URL=
+
# Optional alias for S3 if you want to use Cloudfront or Cloudflare in front
# S3_CLOUDFRONT_HOST=
diff --git a/Gemfile b/Gemfile
index ae90697f1d..486e72cc4a 100644
--- a/Gemfile
+++ b/Gemfile
@@ -15,6 +15,7 @@ gem 'pghero', '~> 1.7'
gem 'dotenv-rails', '~> 2.2'
gem 'aws-sdk', '~> 2.9'
+gem 'fog-openstack', '~> 0.1'
gem 'paperclip', '~> 5.1'
gem 'paperclip-av-transcoder', '~> 0.6'
diff --git a/Gemfile.lock b/Gemfile.lock
index 4a3f20e09d..ef99e0d7b3 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -154,12 +154,25 @@ GEM
erubis (2.7.0)
et-orbi (1.0.5)
tzinfo
+ excon (0.58.0)
execjs (2.7.0)
fabrication (2.16.2)
faker (1.7.3)
i18n (~> 0.5)
fast_blank (1.0.0)
ffi (1.9.18)
+ fog-core (1.45.0)
+ builder
+ excon (~> 0.58)
+ formatador (~> 0.2)
+ fog-json (1.0.2)
+ fog-core (~> 1.0)
+ multi_json (~> 1.10)
+ fog-openstack (0.1.21)
+ fog-core (>= 1.40)
+ fog-json (>= 1.0)
+ ipaddress (>= 0.8)
+ formatador (0.2.5)
fuubar (2.2.0)
rspec-core (~> 3.0)
ruby-progressbar (~> 1.4)
@@ -211,6 +224,7 @@ GEM
rainbow (~> 2.2)
terminal-table (>= 1.5.1)
idn-ruby (0.1.0)
+ ipaddress (0.8.3)
jmespath (1.3.1)
json (2.1.0)
json-ld (2.1.5)
@@ -535,6 +549,7 @@ DEPENDENCIES
fabrication (~> 2.16)
faker (~> 1.7)
fast_blank (~> 1.0)
+ fog-openstack (~> 0.1)
fuubar (~> 2.2)
goldfinger (~> 2.0)
hamlit-rails (~> 0.2)
diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb
index 8dad12f115..26ab6636b5 100644
--- a/app/controllers/accounts_controller.rb
+++ b/app/controllers/accounts_controller.rb
@@ -14,7 +14,7 @@ class AccountsController < ApplicationController
return
end
- @pinned_statuses = cache_collection(@account.pinned_statuses, Status) unless media_requested?
+ @pinned_statuses = cache_collection(@account.pinned_statuses, Status) if show_pinned_statuses?
@statuses = filtered_statuses.paginate_by_max_id(20, params[:max_id], params[:since_id])
@statuses = cache_collection(@statuses, Status)
@next_url = next_url unless @statuses.empty?
@@ -22,7 +22,7 @@ class AccountsController < ApplicationController
format.atom do
@entries = @account.stream_entries.where(hidden: false).with_includes.paginate_by_max_id(20, params[:max_id], params[:since_id])
- render xml: OStatus::AtomSerializer.render(OStatus::AtomSerializer.new.feed(@account, @entries.to_a))
+ render xml: OStatus::AtomSerializer.render(OStatus::AtomSerializer.new.feed(@account, @entries.reject { |entry| entry.status.nil? }))
end
format.json do
@@ -33,6 +33,10 @@ class AccountsController < ApplicationController
private
+ def show_pinned_statuses?
+ [replies_requested?, media_requested?, params[:max_id].present?, params[:since_id].present?].none?
+ end
+
def filtered_statuses
default_statuses.tap do |statuses|
statuses.merge!(only_media_scope) if media_requested?
diff --git a/app/controllers/activitypub/inboxes_controller.rb b/app/controllers/activitypub/inboxes_controller.rb
index 5fce505fd2..b37910b364 100644
--- a/app/controllers/activitypub/inboxes_controller.rb
+++ b/app/controllers/activitypub/inboxes_controller.rb
@@ -26,8 +26,12 @@ class ActivityPub::InboxesController < Api::BaseController
end
def upgrade_account
- return unless signed_request_account.subscribed?
- Pubsubhubbub::UnsubscribeWorker.perform_async(signed_request_account.id)
+ if signed_request_account.ostatus?
+ signed_request_account.update(last_webfingered_at: nil)
+ ResolveRemoteAccountWorker.perform_async(signed_request_account.acct)
+ end
+
+ Pubsubhubbub::UnsubscribeWorker.perform_async(signed_request_account.id) if signed_request_account.subscribed?
end
def process_payload
diff --git a/app/controllers/api/v1/accounts_controller.rb b/app/controllers/api/v1/accounts_controller.rb
index f621aa245d..656cacd8ab 100644
--- a/app/controllers/api/v1/accounts_controller.rb
+++ b/app/controllers/api/v1/accounts_controller.rb
@@ -14,6 +14,16 @@ class Api::V1::AccountsController < Api::BaseController
def follow
FollowService.new.call(current_user.account, @account.acct)
+
+ unless @account.locked?
+ relationships = AccountRelationshipsPresenter.new(
+ [@account.id],
+ current_user.account_id,
+ following_map: { @account.id => true },
+ requested_map: { @account.id => false }
+ )
+ end
+
render json: @account, serializer: REST::RelationshipSerializer, relationships: relationships
end
diff --git a/app/helpers/routing_helper.rb b/app/helpers/routing_helper.rb
index 1fbf77ec31..f4693358c7 100644
--- a/app/helpers/routing_helper.rb
+++ b/app/helpers/routing_helper.rb
@@ -12,8 +12,14 @@ module RoutingHelper
end
def full_asset_url(source, options = {})
- source = ActionController::Base.helpers.asset_url(source, options) unless Rails.configuration.x.use_s3
+ source = ActionController::Base.helpers.asset_url(source, options) unless use_storage?
URI.join(root_url, source).to_s
end
+
+ private
+
+ def use_storage?
+ Rails.configuration.x.use_s3 || Rails.configuration.x.use_swift
+ end
end
diff --git a/app/javascript/mastodon/components/scrollable_list.js b/app/javascript/mastodon/components/scrollable_list.js
index 1a122dbe58..e47b1e9aa5 100644
--- a/app/javascript/mastodon/components/scrollable_list.js
+++ b/app/javascript/mastodon/components/scrollable_list.js
@@ -5,6 +5,7 @@ import IntersectionObserverArticle from './intersection_observer_article';
import LoadMore from './load_more';
import IntersectionObserverWrapper from '../features/ui/util/intersection_observer_wrapper';
import { throttle } from 'lodash';
+import { List as ImmutableList } from 'immutable';
export default class ScrollableList extends PureComponent {
@@ -95,7 +96,12 @@ export default class ScrollableList extends PureComponent {
getFirstChildKey (props) {
const { children } = props;
- const firstChild = Array.isArray(children) ? children[0] : children;
+ let firstChild = children;
+ if (children instanceof ImmutableList) {
+ firstChild = children.get(0);
+ } else if (Array.isArray(children)) {
+ firstChild = children[0];
+ }
return firstChild && firstChild.key;
}
diff --git a/app/javascript/mastodon/components/video_player.js b/app/javascript/mastodon/components/video_player.js
index 5f2447c6d7..f499e3e01f 100644
--- a/app/javascript/mastodon/components/video_player.js
+++ b/app/javascript/mastodon/components/video_player.js
@@ -149,7 +149,7 @@ export default class VideoPlayer extends React.PureComponent {
if (!this.state.visible) {
if (sensitive) {
return (
-
+
{spoilerButton}
@@ -157,7 +157,7 @@ export default class VideoPlayer extends React.PureComponent {
);
} else {
return (
-
+
{spoilerButton}
diff --git a/app/javascript/mastodon/features/favourited_statuses/index.js b/app/javascript/mastodon/features/favourited_statuses/index.js
index 82b16b3698..1e1f5873c2 100644
--- a/app/javascript/mastodon/features/favourited_statuses/index.js
+++ b/app/javascript/mastodon/features/favourited_statuses/index.js
@@ -77,6 +77,7 @@ export default class Favourites extends ImmutablePureComponent {
onClick={this.handleHeaderClick}
pinned={pinned}
multiColumn={multiColumn}
+ showBackButton
/>
Scan this QR code into Google Authenticator or a similiar TOTP app on your phone. From now on, that app will generate tokens that you will have to enter when logging in."
manual_instructions: 'If you can''t scan the QR code and need to enter it manually, here is the plain-text secret:'
- setup: Set up
+ setup: تنشيط
wrong_code: الرمز الذي أدخلته غير صالح. تحقق من صحة الوقت على الخادم و الجهاز.
users:
invalid_email: عنوان البريد الإلكتروني غير صالح
diff --git a/config/locales/bg.yml b/config/locales/bg.yml
index e7c3e1ef64..13d0394a38 100644
--- a/config/locales/bg.yml
+++ b/config/locales/bg.yml
@@ -108,6 +108,17 @@ bg:
reblog:
body: 'Твоята публикация беше споделена от %{name}:'
subject: "%{name} сподели публикацията ти"
+ number:
+ human:
+ decimal_units:
+ format: "%n%u"
+ units:
+ billion: B
+ million: M
+ quadrillion: Q
+ thousand: K
+ trillion: T
+ unit: ''
pagination:
next: Напред
prev: Назад
diff --git a/config/locales/ca.yml b/config/locales/ca.yml
index b6bff82880..6a92b7f1b4 100644
--- a/config/locales/ca.yml
+++ b/config/locales/ca.yml
@@ -340,6 +340,17 @@ ca:
reblog:
body: "%{name} ha retootejat el teu estat"
subject: "%{name} ha retootejat el teu estat"
+ number:
+ human:
+ decimal_units:
+ format: "%n%u"
+ units:
+ billion: B
+ million: M
+ quadrillion: Q
+ thousand: K
+ trillion: T
+ unit: ''
pagination:
next: Pròxim
prev: Anterior
diff --git a/config/locales/de.yml b/config/locales/de.yml
index 1f3675f477..de6c86737b 100644
--- a/config/locales/de.yml
+++ b/config/locales/de.yml
@@ -12,15 +12,15 @@ de:
source_code: Quellcode
status_count_after: Beiträge verfassten
status_count_before: die
- user_count_after: Benutzer
+ user_count_after: Profile
user_count_before: Heimat für
accounts:
follow: Folgen
followers: Folgende
following: Folgt
nothing_here: Hier gibt es nichts!
- people_followed_by: Nutzer, denen %{name} folgt
- people_who_follow: Nutzer, die %{name} folgen
+ people_followed_by: Profile, denen %{name} folgt
+ people_who_follow: Profile, die %{name} folgen
posts: Beiträge
remote_follow: Folgen
unfollow: Entfolgen
@@ -67,7 +67,7 @@ de:
title: Konten
undo_silenced: Stummschaltung zurücknehmen
undo_suspension: Sperre zurücknehmen
- username: Benutzername
+ username: Profilname
web: Web
domain_blocks:
add_new: Neu hinzufügen
@@ -124,7 +124,7 @@ de:
settings:
contact_information:
email: Eine öffentliche E-Mail-Adresse angeben
- username: Einen Benutzernamen angeben
+ username: Einen Profilnamen angeben
registrations:
closed_message:
desc_html: Wird auf der Frontseite angezeigt, wenn die Registrierung geschlossen ist
Du kannst HTML-Tags benutzen
@@ -208,7 +208,7 @@ de:
following: Folgeliste
muting: Stummschaltungsliste
upload: Hochladen
- landing_strip_html: "%{name} ist ein Benutzer auf %{link_to_root_path}. Du kannst ihm folgen oder mit ihm interagieren, sofern du ein Konto irgendwo in der Fediverse hast."
+ landing_strip_html: "%{name} hat ein Profil auf %{link_to_root_path}. Du kannst folgen oder interagieren, sofern du ein Konto irgendwo im Fediversum hast."
landing_strip_signup_html: Wenn nicht, kannst du dich hier anmelden.
media_attachments:
validations:
@@ -239,12 +239,23 @@ de:
reblog:
body: 'Dein Beitrag wurde von %{name} geteilt:'
subject: "%{name} teilte deinen Beitrag."
+ number:
+ human:
+ decimal_units:
+ format: "%n%u"
+ units:
+ billion: B
+ million: M
+ quadrillion: Q
+ thousand: K
+ trillion: T
+ unit: ''
pagination:
next: Vorwärts
prev: Zurück
truncate: "…"
remote_follow:
- acct: Dein Nutzername@Domain, von dem aus du dieser Person folgen möchtest.
+ acct: Dein Profilname@Domain, von dem aus du dieser Person folgen möchtest.
missing_resource: Die erforderliche Weiterleitungs-URL konnte leider in deinem Profil nicht gefunden werden.
proceed: Weiter
prompt: 'Du wirst dieser Person folgen:'
diff --git a/config/locales/doorkeeper.de.yml b/config/locales/doorkeeper.de.yml
index b37ba1dbeb..b0ba2fb98b 100644
--- a/config/locales/doorkeeper.de.yml
+++ b/config/locales/doorkeeper.de.yml
@@ -77,7 +77,7 @@ de:
invalid_grant: Die bereitgestellte Autorisierung ist inkorrekt, abgelaufen, widerrufen, ist mit einem anderen Client verknüpft oder der Redirection URI stimmt nicht mit der Autorisierungs-Anfrage überein.
invalid_redirect_uri: Der Redirect-URI in der Anfrage ist ungültig.
invalid_request: Die Anfrage enthält einen nicht-unterstützten Parameter, ein Parameter fehlt oder sie ist anderweitig fehlerhaft.
- invalid_resource_owner: Die angegebenen Zugangsdaten für den "Resource Owner" sind inkorrekt oder dieser Benutzer existiert nicht.
+ invalid_resource_owner: Die angegebenen Zugangsdaten für den "Resource Owner" sind inkorrekt oder dieses Profil existiert nicht.
invalid_scope: Der angeforderte Scope ist inkorrekt, unbekannt oder fehlerhaft.
invalid_token:
expired: Der Zugriffstoken ist abgelaufen
@@ -108,6 +108,6 @@ de:
application:
title: OAuth-Autorisierung nötig
scopes:
- follow: Nutzer folgen, blocken, entblocken und entfolgen
+ follow: Profil folgen, blocken, entblocken und entfolgen
read: deine Daten lesen
write: Beiträge von deinem Konto aus veröffentlichen
diff --git a/config/locales/doorkeeper.fa.yml b/config/locales/doorkeeper.fa.yml
index 33f453a3f0..3435805307 100644
--- a/config/locales/doorkeeper.fa.yml
+++ b/config/locales/doorkeeper.fa.yml
@@ -3,8 +3,10 @@ fa:
activerecord:
attributes:
doorkeeper/application:
- name: Name
+ name: Application name
redirect_uri: Redirect URI
+ scopes: Scopes
+ website: Application website
errors:
models:
doorkeeper/application:
@@ -33,18 +35,22 @@ fa:
redirect_uri: Use one line per URI
scopes: Separate scopes with spaces. Leave blank to use the default scopes.
index:
+ application: Application
callback_url: Callback URL
+ delete: Delete
name: Name
- new: New Application
+ new: New application
+ scopes: Scopes
+ show: Show
title: Your applications
new:
- title: New Application
+ title: New application
show:
actions: Actions
- application_id: Application Id
- callback_urls: Callback urls
+ application_id: Client key
+ callback_urls: Callback URLs
scopes: Scopes
- secret: Secret
+ secret: Client secret
title: 'Application: %{name}'
authorizations:
buttons:
diff --git a/config/locales/doorkeeper.oc.yml b/config/locales/doorkeeper.oc.yml
index 3d12c95881..b6aebea487 100644
--- a/config/locales/doorkeeper.oc.yml
+++ b/config/locales/doorkeeper.oc.yml
@@ -5,6 +5,8 @@ oc:
doorkeeper/application:
name: Nom
redirect_uri: URL de redireccion
+ scopes: Encastres
+ website: Aplicacion web
errors:
models:
doorkeeper/application:
@@ -33,9 +35,13 @@ oc:
redirect_uri: Utilizatz una linha per URI
scopes: Separatz los encastres amb d’espacis. Daissatz void per utilizar l’encastre per defaut.
index:
+ application: Aplicacion
callback_url: URL de rapèl
+ delete: Suprimir
name: Nom
new: Nòva aplicacion
+ scopes: Encastres
+ show: Veire
title: Vòstras aplicacions
new:
title: Nòva aplicacion
diff --git a/config/locales/eo.yml b/config/locales/eo.yml
index f8b5ec0acf..21def0c5f4 100644
--- a/config/locales/eo.yml
+++ b/config/locales/eo.yml
@@ -103,6 +103,17 @@ eo:
reblog:
body: "%{name} diskonigis vian mesaĝon:"
subject: "%{name} diskonigis vian mesaĝon"
+ number:
+ human:
+ decimal_units:
+ format: "%n%u"
+ units:
+ billion: B
+ million: M
+ quadrillion: Q
+ thousand: K
+ trillion: T
+ unit: ''
pagination:
next: Sekva
prev: Malsekva
diff --git a/config/locales/es.yml b/config/locales/es.yml
index d2d1de14f8..a02330521b 100644
--- a/config/locales/es.yml
+++ b/config/locales/es.yml
@@ -108,6 +108,17 @@ es:
reblog:
body: "%{name} ha retooteado tu estado"
subject: "%{name} ha retooteado tu estado"
+ number:
+ human:
+ decimal_units:
+ format: "%n%u"
+ units:
+ billion: B
+ million: M
+ quadrillion: Q
+ thousand: K
+ trillion: T
+ unit: ''
pagination:
next: Próximo
prev: Anterior
diff --git a/config/locales/fa.yml b/config/locales/fa.yml
index 08ffb44849..ba726fc75a 100644
--- a/config/locales/fa.yml
+++ b/config/locales/fa.yml
@@ -339,6 +339,17 @@ fa:
reblog:
body: "%{name} نوشتهٔ شما را بازبوقید:"
subject: "%{name} نوشتهٔ شما را بازبوقید"
+ number:
+ human:
+ decimal_units:
+ format: "%n%u"
+ units:
+ billion: B
+ million: M
+ quadrillion: Q
+ thousand: K
+ trillion: T
+ unit: ''
pagination:
next: بعدی
prev: قبلی
diff --git a/config/locales/fi.yml b/config/locales/fi.yml
index b748f71846..08ae904471 100644
--- a/config/locales/fi.yml
+++ b/config/locales/fi.yml
@@ -103,6 +103,17 @@ fi:
reblog:
body: 'Sinun statustasi boostasi %{name}:'
subject: "%{name} boostasi statustasi"
+ number:
+ human:
+ decimal_units:
+ format: "%n%u"
+ units:
+ billion: B
+ million: M
+ quadrillion: Q
+ thousand: K
+ trillion: T
+ unit: ''
pagination:
next: Seuraava
prev: Edellinen
diff --git a/config/locales/fr.yml b/config/locales/fr.yml
index 8029d8bd59..6198a54545 100644
--- a/config/locales/fr.yml
+++ b/config/locales/fr.yml
@@ -358,6 +358,17 @@ fr:
reblog:
body: "%{name} a partagé votre statut :"
subject: "%{name} a partagé votre statut"
+ number:
+ human:
+ decimal_units:
+ format: "%n%u"
+ units:
+ billion: B
+ million: M
+ quadrillion: Q
+ thousand: K
+ trillion: T
+ unit: ''
pagination:
next: Suivant
prev: Précédent
diff --git a/config/locales/he.yml b/config/locales/he.yml
index f04e8ad621..84d6d8468e 100644
--- a/config/locales/he.yml
+++ b/config/locales/he.yml
@@ -264,6 +264,17 @@ he:
reblog:
body: 'חצרוצך הודהד על ידי %{name}:'
subject: חצרוצך הודהד על ידי%{name}
+ number:
+ human:
+ decimal_units:
+ format: "%n%u"
+ units:
+ billion: B
+ million: M
+ quadrillion: Q
+ thousand: K
+ trillion: T
+ unit: ''
pagination:
next: הבא
prev: הקודם
diff --git a/config/locales/hr.yml b/config/locales/hr.yml
index 52a8bd35f8..581912420d 100644
--- a/config/locales/hr.yml
+++ b/config/locales/hr.yml
@@ -105,6 +105,17 @@ hr:
reblog:
body: 'Tvoj status je potaknut od %{name}:'
subject: "%{name} je potakao tvoj status"
+ number:
+ human:
+ decimal_units:
+ format: "%n%u"
+ units:
+ billion: B
+ million: M
+ quadrillion: Q
+ thousand: K
+ trillion: T
+ unit: ''
pagination:
next: Sljedeći
prev: Prošli
diff --git a/config/locales/hu.yml b/config/locales/hu.yml
index 53319a673e..77551223f3 100644
--- a/config/locales/hu.yml
+++ b/config/locales/hu.yml
@@ -45,6 +45,17 @@ hu:
reblog:
body: 'Az állapotod reblogolta %{name}:'
subject: "%{name} reblogolta az állapotod"
+ number:
+ human:
+ decimal_units:
+ format: "%n%u"
+ units:
+ billion: B
+ million: M
+ quadrillion: Q
+ thousand: K
+ trillion: T
+ unit: ''
pagination:
next: Következő
prev: Előző
diff --git a/config/locales/id.yml b/config/locales/id.yml
index c76b3d6bbe..f3a6649d1c 100644
--- a/config/locales/id.yml
+++ b/config/locales/id.yml
@@ -254,6 +254,17 @@ id:
reblog:
body: 'Status anda di-boost oleh %{name}:'
subject: "%{name} mem-boost status anda"
+ number:
+ human:
+ decimal_units:
+ format: "%n%u"
+ units:
+ billion: B
+ million: M
+ quadrillion: Q
+ thousand: K
+ trillion: T
+ unit: ''
pagination:
next: Selanjutnya
prev: Sebelumnya
diff --git a/config/locales/io.yml b/config/locales/io.yml
index 112771ee4f..4114e52312 100644
--- a/config/locales/io.yml
+++ b/config/locales/io.yml
@@ -239,6 +239,17 @@ io:
reblog:
body: "%{name} diskonocigis tua mesajo:"
subject: "%{name} diskonocigis tua mesajo"
+ number:
+ human:
+ decimal_units:
+ format: "%n%u"
+ units:
+ billion: B
+ million: M
+ quadrillion: Q
+ thousand: K
+ trillion: T
+ unit: ''
pagination:
next: Sequanta
prev: Preiranta
diff --git a/config/locales/it.yml b/config/locales/it.yml
index 75d56362a6..ec0209bc19 100644
--- a/config/locales/it.yml
+++ b/config/locales/it.yml
@@ -108,6 +108,17 @@ it:
reblog:
body: 'Il tuo status è stato condiviso da %{name}:'
subject: "%{name} ha condiviso il tuo status"
+ number:
+ human:
+ decimal_units:
+ format: "%n%u"
+ units:
+ billion: B
+ million: M
+ quadrillion: Q
+ thousand: K
+ trillion: T
+ unit: ''
pagination:
next: Avanti
prev: Indietro
diff --git a/config/locales/ko.yml b/config/locales/ko.yml
index f980595269..6fdc3b9855 100644
--- a/config/locales/ko.yml
+++ b/config/locales/ko.yml
@@ -1,29 +1,52 @@
---
ko:
about:
- about_mastodon_html: Mastodon 은자유로운 오픈 소스소셜 네트워크입니다. 상용 플랫폼의 대체로써 분산형 구조를 채택해, 여러분의 대화가 한 회사에 독점되는 것을 방지합니다. 신뢰할 수 있는 인스턴스를 선택하세요 — 어떤 인스턴스를 고르더라도, 누구와도 대화할 수 있습니다. 누구나 자신만의 Mastodon 인스턴스를 만들 수 있으며, Seamless하게 소셜 네트워크에 참가할 수 있습니다.
+ about_mastodon_html: Mastodon은 오픈 소스 기반의 소셜 네트워크 서비스 입니다. 상용 플랫폼의 대체로서 분산형 구조를 채택해, 여러분의 대화가 한 회사에 독점되는 것을 방지합니다. 신뢰할 수 있는 인스턴스를 선택하세요 — 어떤 인스턴스를 고르더라도, 누구와도 대화할 수 있습니다. 누구나 자신만의 Mastodon 인스턴스를 만들 수 있으며, Seamless하게 소셜 네트워크에 참가할 수 있습니다.
about_this: 이 인스턴스에 대해서
closed_registrations: 현재 이 인스턴스에서는 신규 등록을 받고 있지 않습니다.
contact: 연락처
- description_headline: "%{domain} 는 무엇인가요?"
+ contact_missing: 미설정
+ contact_unavailable: N/A
+ description_headline: "%{domain} (은)는 무엇인가요?"
domain_count_after: 개의 인스턴스
- domain_count_before: 연결됨
+ domain_count_before: 연결된
+ extended_description_html: |
+ 룰을 작성하는 장소
+ 아직 설명이 작성되지 않았습니다.
+ features:
+ humane_approach_body: 다른 SNS의 실패를 교훈삼아, Mastodon은 소셜미디어가 잘못 사용되는 것을 막기 위하여 윤리적인 설계를 추구합니다.
+ humane_approach_title: 보다 배려를 의식한 설계를 추구
+ not_a_product_body: Mastodon은 이익을 추구하는 SNS가 아닙니다. 그러므로 광고와 데이터의 수집 및 분석이 존재하지 않고, 유저를 구속하지도 않습니다.
+ not_a_product_title: 여러분은 사람이며, 상품이 아닙니다.
+ real_conversation_body: 자유롭게 사용할 수 있는 500문자의 메세지와 미디어 경고 내용을 바탕으로, 자기자신을 자유롭게 표현할 수 있습니다.
+ real_conversation_title: 진정한 커뮤니케이션을 위하여
+ within_reach_body: 개발자 친화적인 API에 의해서 실현된 iOS나 Android, 그 외의 여러 Platform들 덕분에 어디서든 친구들과 자유롭게 메세지를 주고 받을 수 있습니다.
+ within_reach_title: 언제나 유저의 곁에서
+ find_another_instance: 다른 인스턴스 찾기
+ generic_description: "%{domain} 은 Mastodon의 인스턴스 입니다."
+ hosted_on: Mastodon hosted on %{domain}
+ learn_more: 자세히
other_instances: 다른 인스턴스
source_code: 소스 코드
status_count_after: Toot
status_count_before: Toot 수
user_count_after: 명
user_count_before: 사용자 수
+ what_is_mastodon: Mastodon이란?
accounts:
follow: 팔로우
followers: 팔로워
following: 팔로잉
+ media: 미디어
nothing_here: 아무 것도 없습니다.
people_followed_by: "%{name} 님이 팔로우 중인 계정"
people_who_follow: "%{name} 님을 팔로우 중인 계정"
- posts: 포스트
+ posts: Toot
+ posts_with_replies: Toot와 답장
remote_follow: 리모트 팔로우
reserved_username: 이 아이디는 예약되어 있습니다.
+ roles:
+ admin: Admin
unfollow: 팔로우 해제
admin:
accounts:
@@ -38,6 +61,7 @@ ko:
feed_url: 피드 URL
followers: 팔로워 수
follows: 팔로잉 수
+ inbox_url: Inbox URL
ip: IP
location:
all: 전체
@@ -57,8 +81,10 @@ ko:
alphabetic: 알파벳 순
most_recent: 최근 활동 순
title: 순서
+ outbox_url: Outbox URL
perform_full_suspension: 완전히 정지시키기
profile_url: 프로필 URL
+ protocol: Protocol
public: 전체 공개
push_subscription_expires: PuSH 구독 기간 만료
redownload: 아바타 업데이트
@@ -90,12 +116,14 @@ ko:
hint: 도메인 차단은 내부 데이터베이스에 계정이 생성되는 것까지는 막을 수 없지만, 그 도메인에서 생성된 계정에 자동적으로 특정한 모더레이션을 적용하게 할 수 있습니다.
severity:
desc_html: "침묵은 계정을 팔로우 하지 않고 있는 사람들에겐 계정의 Toot을 보이지 않게 합니다. 정지는 계정의 컨텐츠, 미디어, 프로필 데이터를 삭제합니다."
+ noop: 없음
silence: 침묵
suspend: 정지
title: 새로운 도메인 차단
reject_media: 미디어 파일 거부하기
reject_media_hint: 로컬에 저장된 미디어 파일을 삭제하고, 이후로도 다운로드를 거부합니다. 정지하고는 관계 없습니다.
severities:
+ noop: 없음
silence: 침묵
suspend: 정지
severity: 심각도
@@ -146,16 +174,41 @@ ko:
closed_message:
desc_html: 신규 등록을 받지 않을 때 프론트 페이지에 표시됩니다.
HTML 태그를 사용할 수 있습니다.
title: 신규 등록 정지 시 메시지
+ deletion:
+ desc_html: 유저가 자신의 계정을 삭제할 수 있도록 설정합니다.
+ title: 계정 삭제를 허가함
open:
- title: 신규 등록을 받음
+ desc_html: 유저가 자신의 계정을 생성할 수 있도록 설정합니다.
+ title: 신규 계정 등록을 받음
site_description:
desc_html: 탑 페이지와 meta 태그에 사용됩니다.
HTML 태그, 예를 들어<a>
태그와 <em>
태그를 사용할 수 있습니다.
title: 사이트 설명
site_description_extended:
desc_html: 인스턴스 정보 페이지에 표시됩니다.
HTML 태그를 사용할 수 있습니다.
title: 사이트 상세 설명
+ site_terms:
+ desc_html: 당신은 독자적인 개인정보 취급 방침이나 이용약관, 그 외의 법적 근거를 작성할 수 있습니다. 또한 HTML태그를 사용할 수 있습니다.
+ title: 커스텀 서비스 이용 약관
site_title: 사이트 이름
+ timeline_preview:
+ desc_html: Landing page에 공개 타임라인을 표시합니다.
+ title: 타임라인 프리뷰
title: 사이트 설정
+ statuses:
+ back_to_account: 계정으로 돌아가기
+ batch:
+ delete: 삭제
+ nsfw_off: NSFW 끄기
+ nsfw_on: NSFW 켜기
+ execute: 실행
+ failed_to_execute: 실행이 실패하였습니다.
+ media:
+ hide: 미디어 숨기기
+ show: 미디어 보여주기
+ title: 미디어
+ no_media: 미디어 없음
+ title: 계정 Toot
+ with_media: 미디어 있음
subscriptions:
callback_url: 콜백 URL
confirmed: 확인됨
@@ -173,13 +226,21 @@ ko:
signature: Mastodon %{instance} 인스턴스로에서 알림
view: 'View:'
applications:
+ created: 어플리케이션이 작성되었습니다.
+ destroyed: 어플리케이션이 삭제되었습니다.
invalid_url: 올바르지 않은 URL입니다
+ regenerate_token: 토큰 재생성
+ token_regenerated: 액세스 토큰이 재생성되었습니다.
+ warning: 이 데이터는 다른 사람들과 절대로 공유하지 마세요.
+ your_token: 액세스 토큰
auth:
+ agreement_html: 이 등록으로 이용규약 과 개인정보 취급 방침에 동의하는 것으로 간주됩니다.
change_password: 보안
delete_account: 계정 삭제
delete_account_html: 계정을 삭제하고 싶은 경우, 여기서 삭제할 수 있습니다. 삭제 전 확인 화면이 표시됩니다.
didnt_get_confirmation: 확인 메일을 받지 못하셨습니까?
forgot_password: 비밀번호를 잊어버리셨습니까?
+ invalid_reset_password_token: 비밀번호 리셋 토큰이 올바르지 못하거나 기간이 만료되었습니다. 다시 요청해주세요.
login: 로그인
logout: 로그아웃
register: 등록하기
@@ -189,6 +250,12 @@ ko:
authorize_follow:
error: 리모트 팔로우 도중 오류가 발생했습니다.
follow: 팔로우
+ follow_request: '당신은 다음 계정에 팔로우 신청을 했습니다:'
+ following: '성공! 당신은 다음 계정을 팔로우 하고 있습니다:'
+ post_follow:
+ close: 혹은, 당신은 이 윈도우를 닫을 수 있습니다
+ return: 유저 프로필로 돌아가기
+ web: 웹으로 가기
title: "%{acct} 를 팔로우"
datetime:
distance_in_words:
@@ -271,8 +338,8 @@ ko:
one: "1건의 새로운 알림 \U0001F418"
other: "%{count}건의 새로운 알림 \U0001F418"
favourite:
- body: "%{name} 님이 내 Toot을 즐겨찾기에 등록했습니다."
- subject: "%{name} 님이 내 Toot을 즐겨찾기에 등록했습니다"
+ body: "%{name} 님이 내 Toot를 즐겨찾기에 등록했습니다."
+ subject: "%{name} 님이 내 Toot를 즐겨찾기에 등록했습니다"
follow:
body: "%{name} 님이 나를 팔로우 했습니다"
subject: "%{name} 님이 나를 팔로우 했습니다"
@@ -285,10 +352,35 @@ ko:
reblog:
body: "%{name} 님이 내 Toot을 부스트 했습니다:"
subject: "%{name} 님이 내 Toot을 부스트 했습니다"
+ number:
+ human:
+ decimal_units:
+ format: "%n%u"
+ units:
+ billion: B
+ million: M
+ quadrillion: Q
+ thousand: K
+ trillion: T
+ unit: ''
pagination:
next: 다음
prev: 이전
truncate: "…"
+ push_notifications:
+ favourite:
+ title: "%{name} 님이 당신의 Toot를 즐겨찾기에 등록했습니다."
+ follow:
+ title: "%{name} 님이 나를 팔로우 하고 있습니다."
+ group:
+ title: "%{count} 건의 알림"
+ mention:
+ action_boost: 부스트
+ action_expand: 더보기
+ action_favourite: 즐겨찾기
+ title: "%{name} 님이 답장을 보냈습니다"
+ reblog:
+ title: "%{name} 님이 당신의 Toot를 부스트 했습니다."
remote_follow:
acct: 아이디@도메인을 입력해 주십시오
missing_resource: 리디렉션 대상을 찾을 수 없습니다
@@ -330,11 +422,14 @@ ko:
windows: Windows
windows_mobile: Windows Mobile
windows_phone: Windows Phone
+ revoke: 삭제
+ revoke_success: 세션이 삭제되었습니다.
title: 세션
settings:
authorized_apps: 인증된 어플리케이션
back: 돌아가기
delete: 계정 삭제
+ development: 개발
edit_profile: 프로필 편집
export: 데이터 내보내기
followers: 신뢰 중인 인스턴스
@@ -342,9 +437,14 @@ ko:
preferences: 사용자 설정
settings: 설정
two_factor_authentication: 2단계 인증
+ your_apps: 애플리케이션
statuses:
open_in_web: Web으로 열기
over_character_limit: 최대 %{max}자까지 입력할 수 있습니다
+ pin_errors:
+ ownership: 다른 사람의 Toot는 고정될 수 없습니다.
+ private: 비공개 Toot는 고정될 수 없습니다.
+ reblog: 부스트는 고정될 수 없습니다.
show_more: 더 보기
visibilities:
private: 비공개
@@ -355,8 +455,11 @@ ko:
unlisted_long: 누구나 볼 수 있지만, 공개 타임라인에는 표시되지 않습니다
stream_entries:
click_to_show: 클릭해서 표시
+ pinned: 고정된 Toot
reblogged: 님이 부스트 했습니다
sensitive_content: 민감한 컨텐츠
+ terms:
+ title: "%{instance} 이용약관과 개인정보 취급 방침"
time:
formats:
default: "%Y년 %m월 %d일 %H:%M"
@@ -379,3 +482,4 @@ ko:
users:
invalid_email: 메일 주소가 올바르지 않습니다
invalid_otp_token: 2단계 인증 코드가 올바르지 않습니다
+ signed_in_as: '다음과 같이 로그인 중:'
diff --git a/config/locales/nl.yml b/config/locales/nl.yml
index 50ae5508b7..2b7a1a5115 100644
--- a/config/locales/nl.yml
+++ b/config/locales/nl.yml
@@ -337,6 +337,17 @@ nl:
reblog:
body: 'Jouw toot werd door %{name} geboost:'
subject: "%{name} boostte jouw toot"
+ number:
+ human:
+ decimal_units:
+ format: "%n%u"
+ units:
+ billion: B
+ million: M
+ quadrillion: Q
+ thousand: K
+ trillion: T
+ unit: ''
pagination:
next: Volgende
prev: Vorige
diff --git a/config/locales/no.yml b/config/locales/no.yml
index 996ea1d97f..207f86afcd 100644
--- a/config/locales/no.yml
+++ b/config/locales/no.yml
@@ -257,6 +257,17 @@
reblog:
body: 'Din status ble fremhevd av %{name}:'
subject: "%{name} fremhevde din status"
+ number:
+ human:
+ decimal_units:
+ format: "%n%u"
+ units:
+ billion: B
+ million: M
+ quadrillion: Q
+ thousand: K
+ trillion: T
+ unit: ''
pagination:
next: Neste
prev: Forrige
diff --git a/config/locales/oc.yml b/config/locales/oc.yml
index 019d3b196e..c3807428b1 100644
--- a/config/locales/oc.yml
+++ b/config/locales/oc.yml
@@ -103,6 +103,7 @@ oc:
title: Comptes
undo_silenced: Levar lo silenci
undo_suspension: Levar la suspension
+ unsubscribe: Se desabonar
username: Nom d’utilizaire
web: Web
domain_blocks:
@@ -430,6 +431,17 @@ oc:
reblog:
body: "%{name} a tornat partejar vòstre estatut :"
subject: "%{name} a tornat partejar vòstre estatut"
+ number:
+ human:
+ decimal_units:
+ format: "%n%u"
+ units:
+ billion: B
+ million: M
+ quadrillion: Q
+ thousand: K
+ trillion: T
+ unit: ''
pagination:
next: Seguent
prev: Precedent
diff --git a/config/locales/pl.yml b/config/locales/pl.yml
index 246028f9b8..842baef451 100644
--- a/config/locales/pl.yml
+++ b/config/locales/pl.yml
@@ -355,6 +355,17 @@ pl:
reblog:
body: 'Twój wpis został podbity przez %{name}:'
subject: Twój wpis został podbity przez %{name}
+ number:
+ human:
+ decimal_units:
+ format: "%n%u"
+ units:
+ billion: B
+ million: M
+ quadrillion: Q
+ thousand: K
+ trillion: T
+ unit: ''
pagination:
next: Następna
prev: Poprzednia
diff --git a/config/locales/pt-BR.yml b/config/locales/pt-BR.yml
index 6dec2b50a6..7501202995 100644
--- a/config/locales/pt-BR.yml
+++ b/config/locales/pt-BR.yml
@@ -255,6 +255,17 @@ pt-BR:
reblog:
body: 'O seu post foi reblogado por %{name}:'
subject: "%{name} reblogou o seu post"
+ number:
+ human:
+ decimal_units:
+ format: "%n%u"
+ units:
+ billion: B
+ million: M
+ quadrillion: Q
+ thousand: K
+ trillion: T
+ unit: ''
pagination:
next: Next
prev: Prev
diff --git a/config/locales/pt.yml b/config/locales/pt.yml
index f6dd322005..140f6b71bb 100644
--- a/config/locales/pt.yml
+++ b/config/locales/pt.yml
@@ -182,6 +182,17 @@ pt:
reblog:
body: 'O teu post foi partilhado por %{name}:'
subject: "%{name} partilhou o teu post"
+ number:
+ human:
+ decimal_units:
+ format: "%n%u"
+ units:
+ billion: B
+ million: M
+ quadrillion: Q
+ thousand: K
+ trillion: T
+ unit: ''
pagination:
next: Seguinte
prev: Anterior
diff --git a/config/locales/ru.yml b/config/locales/ru.yml
index 52cb71c60f..9ca08831e0 100644
--- a/config/locales/ru.yml
+++ b/config/locales/ru.yml
@@ -262,6 +262,17 @@ ru:
reblog:
body: 'Ваш статус был продвинут %{name}:'
subject: "%{name} продвинул(а) Ваш статус"
+ number:
+ human:
+ decimal_units:
+ format: "%n%u"
+ units:
+ billion: B
+ million: M
+ quadrillion: Q
+ thousand: K
+ trillion: T
+ unit: ''
pagination:
next: След
prev: Пред
diff --git a/config/locales/simple_form.de.yml b/config/locales/simple_form.de.yml
index 85ec0e4fc7..c07dc28464 100644
--- a/config/locales/simple_form.de.yml
+++ b/config/locales/simple_form.de.yml
@@ -6,7 +6,7 @@ de:
avatar: PNG, GIF oder JPG. Maximal 2MB. Wird auf 120x120px herunterskaliert
display_name: '%{count} Zeichen verbleiben'
header: PNG, GIF oder JPG. Maximal 2MB. Wird auf 700x335px herunterskaliert
- locked: Erlaubt dir, Nutzer zu überprüfen, bevor sie dir folgen können
+ locked: Erlaubt dir, Profile zu überprüfen, bevor sie dir folgen können
note: '%{count} Zeichen verbleiben'
imports:
data: CSV-Datei, die von einer anderen Mastodon-Instanz exportiert wurde
@@ -33,10 +33,10 @@ de:
setting_default_privacy: Beitragsprivatspäre
severity: Gewichtung
type: Importtyp
- username: Nutzername
+ username: Profilname
interactions:
must_be_follower: Benachrichtigungen von Nicht-Folgern blockieren
- must_be_following: Benachrichtigungen von Nutzern blockieren, denen ich nicht folge
+ must_be_following: Benachrichtigungen von Profilen blockieren, denen ich nicht folge
notification_emails:
digest: Schicke Übersichts-E-Mails
favourite: E-Mail senden, wenn jemand meinen Beitrag favorisiert
diff --git a/config/locales/th.yml b/config/locales/th.yml
index 9d08879282..2db3aee8a4 100644
--- a/config/locales/th.yml
+++ b/config/locales/th.yml
@@ -257,6 +257,17 @@ th:
reblog:
body: 'Your status was boosted by %{name}:'
subject: "%{name} boosted your status"
+ number:
+ human:
+ decimal_units:
+ format: "%n%u"
+ units:
+ billion: B
+ million: M
+ quadrillion: Q
+ thousand: K
+ trillion: T
+ unit: ''
pagination:
next: ต่อไป
prev: ย้อนกลับ
diff --git a/config/locales/tr.yml b/config/locales/tr.yml
index 91ef9544cf..6aff78fa16 100644
--- a/config/locales/tr.yml
+++ b/config/locales/tr.yml
@@ -255,6 +255,17 @@ tr:
reblog:
body: "%{name} durumunuzu boost etti:"
subject: "%{name} durumunuzu boost etti"
+ number:
+ human:
+ decimal_units:
+ format: "%n%u"
+ units:
+ billion: B
+ million: M
+ quadrillion: Q
+ thousand: K
+ trillion: T
+ unit: ''
pagination:
next: Sonraki
prev: Önceki
diff --git a/config/locales/uk.yml b/config/locales/uk.yml
index 4d12ddf4e8..995a682a7c 100644
--- a/config/locales/uk.yml
+++ b/config/locales/uk.yml
@@ -250,6 +250,17 @@ uk:
reblog:
body: 'Ваш статус було передмухнуто %{name}:'
subject: "%{name} передмухнув ваш статус"
+ number:
+ human:
+ decimal_units:
+ format: "%n%u"
+ units:
+ billion: B
+ million: M
+ quadrillion: Q
+ thousand: K
+ trillion: T
+ unit: ''
pagination:
next: Далі
prev: Назад
diff --git a/config/locales/zh-CN.yml b/config/locales/zh-CN.yml
index 0672202a21..95c24d0bc6 100644
--- a/config/locales/zh-CN.yml
+++ b/config/locales/zh-CN.yml
@@ -261,6 +261,17 @@ zh-CN:
reblog:
body: 你的嘟文得到 %{name} 的转嘟
subject: "%{name} 转嘟(嘟嘟滴)了你的嘟文"
+ number:
+ human:
+ decimal_units:
+ format: "%n%u"
+ units:
+ billion: B
+ million: M
+ quadrillion: Q
+ thousand: K
+ trillion: T
+ unit: ''
pagination:
next: 下一页
prev: 上一页
diff --git a/config/locales/zh-HK.yml b/config/locales/zh-HK.yml
index 9d6c74008a..aa6b1ea6af 100644
--- a/config/locales/zh-HK.yml
+++ b/config/locales/zh-HK.yml
@@ -256,6 +256,17 @@ zh-HK:
reblog:
body: 你的文章得到 %{name} 的轉推
subject: "%{name} 轉推了你的文章"
+ number:
+ human:
+ decimal_units:
+ format: "%n%u"
+ units:
+ billion: B
+ million: M
+ quadrillion: Q
+ thousand: K
+ trillion: T
+ unit: ''
pagination:
next: 下一頁
prev: 上一頁
diff --git a/config/locales/zh-TW.yml b/config/locales/zh-TW.yml
index 7065acf9ab..299a92da7b 100644
--- a/config/locales/zh-TW.yml
+++ b/config/locales/zh-TW.yml
@@ -211,6 +211,17 @@ zh-TW:
reblog:
body: 您的文章被 %{name} 轉推
subject: "%{name} 轉推了您的文章"
+ number:
+ human:
+ decimal_units:
+ format: "%n%u"
+ units:
+ billion: B
+ million: M
+ quadrillion: Q
+ thousand: K
+ trillion: T
+ unit: ''
pagination:
next: 下一頁
prev: 上一頁
diff --git a/db/migrate/20170905044538_add_index_id_account_id_activity_type_on_notifications.rb b/db/migrate/20170905044538_add_index_id_account_id_activity_type_on_notifications.rb
new file mode 100644
index 0000000000..c47cea9e26
--- /dev/null
+++ b/db/migrate/20170905044538_add_index_id_account_id_activity_type_on_notifications.rb
@@ -0,0 +1,5 @@
+class AddIndexIdAccountIdActivityTypeOnNotifications < ActiveRecord::Migration[5.1]
+ def change
+ add_index :notifications, [:id, :account_id, :activity_type], order: { id: :desc }
+ end
+end
diff --git a/db/migrate/20170905165803_add_local_to_statuses.rb b/db/migrate/20170905165803_add_local_to_statuses.rb
new file mode 100644
index 0000000000..fb4e7019df
--- /dev/null
+++ b/db/migrate/20170905165803_add_local_to_statuses.rb
@@ -0,0 +1,5 @@
+class AddLocalToStatuses < ActiveRecord::Migration[5.1]
+ def change
+ add_column :statuses, :local, :boolean, null: true, default: nil
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index c3a2581e3d..d8af0a1f8e 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 20170901142658) do
+ActiveRecord::Schema.define(version: 20170905165803) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -180,6 +180,7 @@ ActiveRecord::Schema.define(version: 20170901142658) do
t.integer "from_account_id"
t.index ["account_id", "activity_id", "activity_type"], name: "account_activity", unique: true
t.index ["activity_id", "activity_type"], name: "index_notifications_on_activity_id_and_activity_type"
+ t.index ["id", "account_id", "activity_type"], name: "index_notifications_on_id_and_account_id_and_activity_type", order: { id: :desc }
end
create_table "oauth_access_grants", id: :serial, force: :cascade do |t|
@@ -314,6 +315,7 @@ ActiveRecord::Schema.define(version: 20170901142658) do
t.integer "reblogs_count", default: 0, null: false
t.string "language"
t.bigint "conversation_id"
+ t.boolean "local"
t.index ["account_id", "id"], name: "index_statuses_on_account_id_id"
t.index ["conversation_id"], name: "index_statuses_on_conversation_id"
t.index ["in_reply_to_id"], name: "index_statuses_on_in_reply_to_id"
diff --git a/lib/mastodon/unique_retry_job_middleware.rb b/lib/mastodon/unique_retry_job_middleware.rb
new file mode 100644
index 0000000000..75da8a0c94
--- /dev/null
+++ b/lib/mastodon/unique_retry_job_middleware.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+class Mastodon::UniqueRetryJobMiddleware
+ def call(_worker_class, item, _queue, _redis_pool)
+ return if item['unique_retry'] && retried?(item)
+ yield
+ end
+
+ private
+
+ def retried?(item)
+ # Use unique digest key of SidekiqUniqueJobs
+ unique_key = SidekiqUniqueJobs::UNIQUE_DIGEST_KEY
+ unique_digest = item[unique_key]
+ class_name = item['class']
+ retries = Sidekiq::RetrySet.new
+
+ retries.any? { |job| job.item['class'] == class_name && job.item[unique_key] == unique_digest }
+ end
+end
diff --git a/lib/mastodon/version.rb b/lib/mastodon/version.rb
index fcca875d9b..de2516d6c2 100644
--- a/lib/mastodon/version.rb
+++ b/lib/mastodon/version.rb
@@ -9,11 +9,11 @@ module Mastodon
end
def minor
- 5
+ 6
end
def patch
- 1
+ 0
end
def pre
@@ -21,7 +21,7 @@ module Mastodon
end
def flags
- ''
+ 'rc2'
end
def to_a
diff --git a/lib/tasks/mastodon.rake b/lib/tasks/mastodon.rake
index f04201a3cd..307bc240db 100644
--- a/lib/tasks/mastodon.rake
+++ b/lib/tasks/mastodon.rake
@@ -273,10 +273,17 @@ namespace :mastodon do
desc 'Remove deprecated preview cards'
task remove_deprecated_preview_cards: :environment do
- return unless ActiveRecord::Base.connection.table_exists? 'deprecated_preview_cards'
+ next unless ActiveRecord::Base.connection.table_exists? 'deprecated_preview_cards'
- class DeprecatedPreviewCard < PreviewCard
- self.table_name = 'deprecated_preview_cards'
+ class DeprecatedPreviewCard < ActiveRecord::Base
+ self.inheritance_column = false
+
+ path = '/preview_cards/:attachment/:id_partition/:style/:filename'
+ if ENV['S3_ENABLED'] != 'true'
+ path = (ENV['PAPERCLIP_ROOT_PATH'] || ':rails_root/public/system') + path
+ end
+
+ has_attached_file :image, styles: { original: '280x120>' }, convert_options: { all: '-quality 80 -strip' }, path: path
end
puts 'Delete records and associated files from deprecated preview cards? [y/N]: '
diff --git a/package.json b/package.json
index 5fdd491ee7..228dd1f257 100644
--- a/package.json
+++ b/package.json
@@ -85,7 +85,7 @@
"react-dom": "^15.6.1",
"react-immutable-proptypes": "^2.1.0",
"react-immutable-pure-component": "^1.0.0",
- "react-intl": "^2.3.0",
+ "react-intl": "^2.4.0",
"react-motion": "^0.5.0",
"react-notification": "^6.7.1",
"react-redux": "^5.0.4",
diff --git a/spec/controllers/accounts_controller_spec.rb b/spec/controllers/accounts_controller_spec.rb
index 4e37b1b5fc..92f8885907 100644
--- a/spec/controllers/accounts_controller_spec.rb
+++ b/spec/controllers/accounts_controller_spec.rb
@@ -61,7 +61,29 @@ RSpec.describe AccountsController, type: :controller do
end
end
- context 'html' do
+ context 'html without since_id nor max_id' do
+ before do
+ get :show, params: { username: alice.username }
+ end
+
+ it 'assigns @account' do
+ expect(assigns(:account)).to eq alice
+ end
+
+ it 'assigns @pinned_statuses' do
+ pinned_statuses = assigns(:pinned_statuses).to_a
+ expect(pinned_statuses.size).to eq 3
+ expect(pinned_statuses[0]).to eq status7
+ expect(pinned_statuses[1]).to eq status5
+ expect(pinned_statuses[2]).to eq status6
+ end
+
+ it 'returns http success' do
+ expect(response).to have_http_status(:success)
+ end
+ end
+
+ context 'html with since_id and max_id' do
before do
get :show, params: { username: alice.username, max_id: status4.id, since_id: status1.id }
end
@@ -77,12 +99,9 @@ RSpec.describe AccountsController, type: :controller do
expect(statuses[1]).to eq status2
end
- it 'assigns @pinned_statuses' do
+ it 'assigns an empty array to @pinned_statuses' do
pinned_statuses = assigns(:pinned_statuses).to_a
- expect(pinned_statuses.size).to eq 3
- expect(pinned_statuses[0]).to eq status7
- expect(pinned_statuses[1]).to eq status5
- expect(pinned_statuses[2]).to eq status6
+ expect(pinned_statuses.size).to eq 0
end
it 'returns http success' do
diff --git a/spec/controllers/api/v1/accounts_controller_spec.rb b/spec/controllers/api/v1/accounts_controller_spec.rb
index c13509e7bb..05df2f8444 100644
--- a/spec/controllers/api/v1/accounts_controller_spec.rb
+++ b/spec/controllers/api/v1/accounts_controller_spec.rb
@@ -28,6 +28,13 @@ RSpec.describe Api::V1::AccountsController, type: :controller do
expect(response).to have_http_status(:success)
end
+ it 'returns JSON with following=true and requested=false' do
+ json = body_as_json
+
+ expect(json[:following]).to be true
+ expect(json[:requested]).to be false
+ end
+
it 'creates a following relation between user and target user' do
expect(user.account.following?(other_account)).to be true
end
diff --git a/spec/fabricators/status_fabricator.rb b/spec/fabricators/status_fabricator.rb
index 8ec5f4ba79..04bbbcf4b0 100644
--- a/spec/fabricators/status_fabricator.rb
+++ b/spec/fabricators/status_fabricator.rb
@@ -1,4 +1,8 @@
Fabricator(:status) do
account
text "Lorem ipsum dolor sit amet"
+
+ after_build do |status|
+ status.uri = Faker::Internet.device_token if !status.account.local? && status.uri.nil?
+ end
end
diff --git a/spec/lib/activitypub/activity/delete_spec.rb b/spec/lib/activitypub/activity/delete_spec.rb
index 65e743abb2..38254e31c3 100644
--- a/spec/lib/activitypub/activity/delete_spec.rb
+++ b/spec/lib/activitypub/activity/delete_spec.rb
@@ -1,7 +1,7 @@
require 'rails_helper'
RSpec.describe ActivityPub::Activity::Delete do
- let(:sender) { Fabricate(:account) }
+ let(:sender) { Fabricate(:account, domain: 'example.com') }
let(:status) { Fabricate(:status, account: sender, uri: 'foobar') }
let(:json) do
diff --git a/spec/lib/activitypub/activity/undo_spec.rb b/spec/lib/activitypub/activity/undo_spec.rb
index 4629a033f2..14c68efe5f 100644
--- a/spec/lib/activitypub/activity/undo_spec.rb
+++ b/spec/lib/activitypub/activity/undo_spec.rb
@@ -1,7 +1,7 @@
require 'rails_helper'
RSpec.describe ActivityPub::Activity::Undo do
- let(:sender) { Fabricate(:account) }
+ let(:sender) { Fabricate(:account, domain: 'example.com') }
let(:json) do
{
diff --git a/spec/lib/formatter_spec.rb b/spec/lib/formatter_spec.rb
index dfe1d8b8fe..ab04ccbabb 100644
--- a/spec/lib/formatter_spec.rb
+++ b/spec/lib/formatter_spec.rb
@@ -178,7 +178,7 @@ RSpec.describe Formatter do
end
context 'with remote status' do
- let(:status) { Fabricate(:status, text: 'Beep boop', uri: 'beepboop') }
+ let(:status) { Fabricate(:status, account: remote_account, text: 'Beep boop') }
it 'reformats' do
is_expected.to eq 'Beep boop'
@@ -226,7 +226,7 @@ RSpec.describe Formatter do
end
context 'with remote status' do
- let(:status) { Fabricate(:status, text: '', uri: 'beep boop') }
+ let(:status) { Fabricate(:status, account: remote_account, text: '') }
it 'returns tag-stripped text' do
is_expected.to eq ''
diff --git a/spec/lib/ostatus/atom_serializer_spec.rb b/spec/lib/ostatus/atom_serializer_spec.rb
index 301a0ce30d..0451eceeb4 100644
--- a/spec/lib/ostatus/atom_serializer_spec.rb
+++ b/spec/lib/ostatus/atom_serializer_spec.rb
@@ -403,8 +403,7 @@ RSpec.describe OStatus::AtomSerializer do
it 'returns element whose rendered view triggers creation when processed' do
remote_account = Account.create!(username: 'username')
- remote_status = Fabricate(:status, account: remote_account)
- remote_status.stream_entry.update!(created_at: '2000-01-01T00:00:00Z')
+ remote_status = Fabricate(:status, account: remote_account, created_at: '2000-01-01T00:00:00Z')
entry = OStatus::AtomSerializer.new.entry(remote_status.stream_entry, true)
entry.nodes.delete_if { |node| node[:type] == 'application/activity+json' } # Remove ActivityPub link to simplify test
@@ -421,7 +420,7 @@ RSpec.describe OStatus::AtomSerializer do
ProcessFeedService.new.call(xml, account)
- expect(Status.find_by(uri: "tag:remote,2000-01-01:objectId=#{remote_status.id}:objectType=Status")).to be_instance_of Status
+ expect(Status.find_by(uri: "https://remote/users/#{remote_status.account.to_param}/statuses/#{remote_status.id}")).to be_instance_of Status
end
end
@@ -465,12 +464,11 @@ RSpec.describe OStatus::AtomSerializer do
end
it 'appends id element with unique tag' do
- status = Fabricate(:status, reblog_of_id: nil)
- status.stream_entry.update!(created_at: '2000-01-01T00:00:00Z')
+ status = Fabricate(:status, reblog_of_id: nil, created_at: '2000-01-01T00:00:00Z')
entry = OStatus::AtomSerializer.new.entry(status.stream_entry)
- expect(entry.id.text).to eq "tag:cb6e6126.ngrok.io,2000-01-01:objectId=#{status.id}:objectType=Status"
+ expect(entry.id.text).to eq "https://cb6e6126.ngrok.io/users/#{status.account.to_param}/statuses/#{status.id}"
end
it 'appends published element with created date' do
@@ -515,7 +513,7 @@ RSpec.describe OStatus::AtomSerializer do
entry = OStatus::AtomSerializer.new.entry(reblog.stream_entry)
object = entry.nodes.find { |node| node.name == 'activity:object' }
- expect(object.id.text).to eq "tag:cb6e6126.ngrok.io,2000-01-01:objectId=#{reblogged.id}:objectType=Status"
+ expect(object.id.text).to eq "https://cb6e6126.ngrok.io/users/#{reblogged.account.to_param}/statuses/#{reblogged.id}"
end
it 'does not append activity:object element if target is not present' do
@@ -532,7 +530,7 @@ RSpec.describe OStatus::AtomSerializer do
link = entry.nodes.find { |node| node.name == 'link' && node[:rel] == 'alternate' && node[:type] == 'text/html' }
expect(link[:type]).to eq 'text/html'
- expect(link[:href]).to eq "https://cb6e6126.ngrok.io/users/username/updates/#{status.stream_entry.id}"
+ expect(link[:href]).to eq "https://cb6e6126.ngrok.io/@username/#{status.id}"
end
it 'appends link element for itself' do
@@ -553,7 +551,7 @@ RSpec.describe OStatus::AtomSerializer do
entry = OStatus::AtomSerializer.new.entry(reply_status.stream_entry)
in_reply_to = entry.nodes.find { |node| node.name == 'thr:in-reply-to' }
- expect(in_reply_to[:ref]).to eq "tag:cb6e6126.ngrok.io,2000-01-01:objectId=#{in_reply_to_status.id}:objectType=Status"
+ expect(in_reply_to[:ref]).to eq "https://cb6e6126.ngrok.io/users/#{in_reply_to_status.account.to_param}/statuses/#{in_reply_to_status.id}"
end
it 'does not append thr:in-reply-to element if not threaded' do
@@ -934,7 +932,7 @@ RSpec.describe OStatus::AtomSerializer do
favourite_salmon = OStatus::AtomSerializer.new.favourite_salmon(favourite)
object = favourite_salmon.nodes.find { |node| node.name == 'activity:object' }
- expect(object.id.text).to eq "tag:cb6e6126.ngrok.io,2000-01-01:objectId=#{status.id}:objectType=Status"
+ expect(object.id.text).to eq "https://cb6e6126.ngrok.io/users/#{status.account.to_param}/statuses/#{status.id}"
end
it 'appends thr:in-reply-to element for status' do
@@ -945,7 +943,7 @@ RSpec.describe OStatus::AtomSerializer do
favourite_salmon = OStatus::AtomSerializer.new.favourite_salmon(favourite)
in_reply_to = favourite_salmon.nodes.find { |node| node.name == 'thr:in-reply-to' }
- expect(in_reply_to.ref).to eq "tag:cb6e6126.ngrok.io,2000-01-01:objectId=#{status.id}:objectType=Status"
+ expect(in_reply_to.ref).to eq "https://cb6e6126.ngrok.io/users/#{status.account.to_param}/statuses/#{status.id}"
expect(in_reply_to.href).to eq "https://cb6e6126.ngrok.io/@username/#{status.id}"
end
@@ -1034,7 +1032,7 @@ RSpec.describe OStatus::AtomSerializer do
unfavourite_salmon = OStatus::AtomSerializer.new.unfavourite_salmon(favourite)
object = unfavourite_salmon.nodes.find { |node| node.name == 'activity:object' }
- expect(object.id.text).to eq "tag:cb6e6126.ngrok.io,2000-01-01:objectId=#{status.id}:objectType=Status"
+ expect(object.id.text).to eq "https://cb6e6126.ngrok.io/users/#{status.account.to_param}/statuses/#{status.id}"
end
it 'appends thr:in-reply-to element for status' do
@@ -1045,7 +1043,7 @@ RSpec.describe OStatus::AtomSerializer do
unfavourite_salmon = OStatus::AtomSerializer.new.unfavourite_salmon(favourite)
in_reply_to = unfavourite_salmon.nodes.find { |node| node.name == 'thr:in-reply-to' }
- expect(in_reply_to.ref).to eq "tag:cb6e6126.ngrok.io,2000-01-01:objectId=#{status.id}:objectType=Status"
+ expect(in_reply_to.ref).to eq "https://cb6e6126.ngrok.io/users/#{status.account.to_param}/statuses/#{status.id}"
expect(in_reply_to.href).to eq "https://cb6e6126.ngrok.io/@username/#{status.id}"
end
@@ -1453,7 +1451,7 @@ RSpec.describe OStatus::AtomSerializer do
it 'appends id element with URL for status' do
status = Fabricate(:status, created_at: '2000-01-01T00:00:00Z')
object = OStatus::AtomSerializer.new.object(status)
- expect(object.id.text).to eq "tag:cb6e6126.ngrok.io,2000-01-01:objectId=#{status.id}:objectType=Status"
+ expect(object.id.text).to eq "https://cb6e6126.ngrok.io/users/#{status.account.to_param}/statuses/#{status.id}"
end
it 'appends published element with created date' do
@@ -1463,7 +1461,8 @@ RSpec.describe OStatus::AtomSerializer do
end
it 'appends updated element with updated date' do
- status = Fabricate(:status, updated_at: '2000-01-01T00:00:00Z')
+ status = Fabricate(:status)
+ status.updated_at = '2000-01-01T00:00:00Z'
object = OStatus::AtomSerializer.new.object(status)
expect(object.updated.text).to eq '2000-01-01T00:00:00Z'
end
@@ -1523,7 +1522,7 @@ RSpec.describe OStatus::AtomSerializer do
entry = OStatus::AtomSerializer.new.object(reply)
in_reply_to = entry.nodes.find { |node| node.name == 'thr:in-reply-to' }
- expect(in_reply_to.ref).to eq "tag:cb6e6126.ngrok.io,2000-01-01:objectId=#{thread.id}:objectType=Status"
+ expect(in_reply_to.ref).to eq "https://cb6e6126.ngrok.io/users/#{thread.account.to_param}/statuses/#{thread.id}"
expect(in_reply_to.href).to eq "https://cb6e6126.ngrok.io/@username/#{thread.id}"
end
diff --git a/spec/lib/tag_manager_spec.rb b/spec/lib/tag_manager_spec.rb
index 1fae6bec45..1cd6e0a6fe 100644
--- a/spec/lib/tag_manager_spec.rb
+++ b/spec/lib/tag_manager_spec.rb
@@ -157,23 +157,12 @@ RSpec.describe TagManager do
describe '#uri_for' do
subject { TagManager.instance.uri_for(target) }
- context 'activity object' do
- let(:target) { Fabricate(:status, reblog: Fabricate(:status)).stream_entry }
-
- before { target.update!(created_at: '2000-01-01T00:00:00Z') }
-
- it 'returns the unique tag for status' do
- expect(target.object_type).to eq :activity
- is_expected.to eq "tag:cb6e6126.ngrok.io,2000-01-01:objectId=#{target.id}:objectType=Status"
- end
- end
-
context 'comment object' do
let(:target) { Fabricate(:status, created_at: '2000-01-01T00:00:00Z', reply: true) }
it 'returns the unique tag for status' do
expect(target.object_type).to eq :comment
- is_expected.to eq "tag:cb6e6126.ngrok.io,2000-01-01:objectId=#{target.id}:objectType=Status"
+ is_expected.to eq target.uri
end
end
@@ -182,7 +171,7 @@ RSpec.describe TagManager do
it 'returns the unique tag for status' do
expect(target.object_type).to eq :note
- is_expected.to eq "tag:cb6e6126.ngrok.io,2000-01-01:objectId=#{target.id}:objectType=Status"
+ is_expected.to eq target.uri
end
end
diff --git a/spec/models/status_spec.rb b/spec/models/status_spec.rb
index 626fc3f985..484effd5e1 100644
--- a/spec/models/status_spec.rb
+++ b/spec/models/status_spec.rb
@@ -13,9 +13,15 @@ RSpec.describe Status, type: :model do
end
it 'returns false if a remote URI is set' do
- subject.uri = 'a'
+ alice.update(domain: 'example.com')
+ subject.save
expect(subject.local?).to be false
end
+
+ it 'returns true if a URI is set and `local` is true' do
+ subject.update(uri: 'example.com', local: true)
+ expect(subject.local?).to be true
+ end
end
describe '#reblog?' do
@@ -495,7 +501,7 @@ RSpec.describe Status, type: :model do
end
end
- describe 'before_create' do
+ describe 'before_validation' do
it 'sets account being replied to correctly over intermediary nodes' do
first_status = Fabricate(:status, account: bob)
intermediary = Fabricate(:status, thread: first_status, account: alice)
@@ -512,5 +518,22 @@ RSpec.describe Status, type: :model do
parent = Fabricate(:status, text: 'First')
expect(Status.create(account: alice, thread: parent, text: 'Response').conversation_id).to eq parent.conversation_id
end
+
+ it 'sets `local` to true for status by local account' do
+ expect(Status.create(account: alice, text: 'foo').local).to be true
+ end
+
+ it 'sets `local` to false for status by remote account' do
+ alice.update(domain: 'example.com')
+ expect(Status.create(account: alice, text: 'foo').local).to be false
+ end
+ end
+
+ describe 'after_create' do
+ it 'saves ActivityPub uri as uri for local status' do
+ status = Status.create(account: alice, text: 'foo')
+ status.reload
+ expect(status.uri).to start_with('https://')
+ end
end
end
diff --git a/spec/services/fetch_link_card_service_spec.rb b/spec/services/fetch_link_card_service_spec.rb
index 3a0786d03c..b0aa740ac9 100644
--- a/spec/services/fetch_link_card_service_spec.rb
+++ b/spec/services/fetch_link_card_service_spec.rb
@@ -55,7 +55,7 @@ RSpec.describe FetchLinkCardService do
end
context 'in a remote status' do
- let(:status) { Fabricate(:status, uri: 'abc', text: 'Habt ihr ein paar gute Links zu #Wannacry herumfliegen? Ich will mal unter
https://github.com/qbi/WannaCry was sammeln. !security ') }
+ let(:status) { Fabricate(:status, account: Fabricate(:account, domain: 'example.com'), text: 'Habt ihr ein paar gute Links zu #Wannacry herumfliegen? Ich will mal unter
https://github.com/qbi/WannaCry was sammeln. !security ') }
it 'parses out URLs' do
expect(a_request(:head, 'https://github.com/qbi/WannaCry')).to have_been_made.at_least_once
diff --git a/streaming/index.js b/streaming/index.js
index c7e0de96c2..3e80c8b308 100644
--- a/streaming/index.js
+++ b/streaming/index.js
@@ -403,11 +403,11 @@ const startWorker = (workerId) => {
});
app.get('/api/v1/streaming/hashtag', (req, res) => {
- streamFrom(`timeline:hashtag:${req.query.tag}`, req, streamToHttp(req, res), streamHttpEnd(req), true);
+ streamFrom(`timeline:hashtag:${req.query.tag.toLowerCase()}`, req, streamToHttp(req, res), streamHttpEnd(req), true);
});
app.get('/api/v1/streaming/hashtag/local', (req, res) => {
- streamFrom(`timeline:hashtag:${req.query.tag}:local`, req, streamToHttp(req, res), streamHttpEnd(req), true);
+ streamFrom(`timeline:hashtag:${req.query.tag.toLowerCase()}:local`, req, streamToHttp(req, res), streamHttpEnd(req), true);
});
const wss = new WebSocket.Server({ server, verifyClient: wsVerifyClient });
@@ -438,10 +438,10 @@ const startWorker = (workerId) => {
streamFrom('timeline:public:local', req, streamToWs(req, ws), streamWsEnd(req, ws), true);
break;
case 'hashtag':
- streamFrom(`timeline:hashtag:${location.query.tag}`, req, streamToWs(req, ws), streamWsEnd(req, ws), true);
+ streamFrom(`timeline:hashtag:${location.query.tag.toLowerCase()}`, req, streamToWs(req, ws), streamWsEnd(req, ws), true);
break;
case 'hashtag:local':
- streamFrom(`timeline:hashtag:${location.query.tag}:local`, req, streamToWs(req, ws), streamWsEnd(req, ws), true);
+ streamFrom(`timeline:hashtag:${location.query.tag.toLowerCase()}:local`, req, streamToWs(req, ws), streamWsEnd(req, ws), true);
break;
default:
ws.close();
diff --git a/yarn.lock b/yarn.lock
index cfb0f51752..c1c27a615c 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3130,23 +3130,17 @@ intl-messageformat-parser@^1.2.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/intl-messageformat-parser/-/intl-messageformat-parser-1.3.0.tgz#c5d26ffb894c7d9c2b9fa444c67f417ab2594268"
-intl-messageformat@1.3.0, intl-messageformat@^1.3.0:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/intl-messageformat/-/intl-messageformat-1.3.0.tgz#f7d926aded7a3ab19b2dc601efd54e99a4bd4eae"
- dependencies:
- intl-messageformat-parser "1.2.0"
-
intl-messageformat@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/intl-messageformat/-/intl-messageformat-2.0.0.tgz#3d56982583425aee23b76c8b985fb9b0aae5be3c"
dependencies:
intl-messageformat-parser "1.2.0"
-intl-relativeformat@^1.3.0:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/intl-relativeformat/-/intl-relativeformat-1.3.0.tgz#893dc7076fccd380cf091a2300c380fa57ace45b"
+intl-messageformat@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/intl-messageformat/-/intl-messageformat-2.1.0.tgz#1c51da76f02a3f7b360654cdc51bbc4d3fa6c72c"
dependencies:
- intl-messageformat "1.3.0"
+ intl-messageformat-parser "1.2.0"
intl-relativeformat@^2.0.0:
version "2.0.0"
@@ -5312,13 +5306,13 @@ react-intl-translations-manager@^5.0.0:
json-stable-stringify "^1.0.1"
mkdirp "^0.5.1"
-react-intl@^2.3.0:
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/react-intl/-/react-intl-2.3.0.tgz#e1df6af5667fdf01cbe4aab20e137251e2ae5142"
+react-intl@^2.4.0:
+ version "2.4.0"
+ resolved "https://registry.yarnpkg.com/react-intl/-/react-intl-2.4.0.tgz#66c14dc9df9a73b2fbbfbd6021726e80a613eb15"
dependencies:
intl-format-cache "^2.0.5"
- intl-messageformat "^1.3.0"
- intl-relativeformat "^1.3.0"
+ intl-messageformat "^2.1.0"
+ intl-relativeformat "^2.0.0"
invariant "^2.1.1"
react-motion@^0.5.0: