diff --git a/app/javascript/mastodon/service_worker/web_push_notifications.js b/app/javascript/mastodon/service_worker/web_push_notifications.js index acb85f626..f63cff335 100644 --- a/app/javascript/mastodon/service_worker/web_push_notifications.js +++ b/app/javascript/mastodon/service_worker/web_push_notifications.js @@ -31,8 +31,8 @@ const notify = options => const group = cloneNotification(notifications[0]); group.title = formatGroupTitle(group.data.message, group.data.count + 1); - group.body = `${options.title}\n${group.body}`; - group.data = { ...group.data, count: group.data.count + 1 }; + group.body = `${options.title}\n${group.body}`; + group.data = { ...group.data, count: group.data.count + 1 }; return self.registration.showNotification(group.title, group); } @@ -43,18 +43,18 @@ const notify = options => const handlePush = (event) => { const options = event.data.json(); - options.body = options.data.nsfw || options.data.content; - options.image = options.image || undefined; // Null results in a network request (404) + options.body = options.data.nsfw || options.data.content; + options.dir = options.data.dir; + options.image = options.image || undefined; // Null results in a network request (404) options.timestamp = options.timestamp && new Date(options.timestamp); const expandAction = options.data.actions.find(action => action.todo === 'expand'); if (expandAction) { - options.actions = [expandAction]; - options.hiddenActions = options.data.actions.filter(action => action !== expandAction); - + options.actions = [expandAction]; + options.hiddenActions = options.data.actions.filter(action => action !== expandAction); options.data.hiddenImage = options.image; - options.image = undefined; + options.image = undefined; } else { options.actions = options.data.actions; } @@ -75,8 +75,8 @@ const cloneNotification = (notification) => { const expandNotification = (notification) => { const nextNotification = cloneNotification(notification); - nextNotification.body = notification.data.content; - nextNotification.image = notification.data.hiddenImage; + nextNotification.body = notification.data.content; + nextNotification.image = notification.data.hiddenImage; nextNotification.actions = notification.data.actions.filter(action => action.todo !== 'expand'); return self.registration.showNotification(nextNotification.title, nextNotification); @@ -105,8 +105,7 @@ const openUrl = url => const webClients = clientList.filter(client => /\/web\//.test(client.url)); if (webClients.length !== 0) { - const client = findBestClient(webClients); - + const client = findBestClient(webClients); const { pathname } = new URL(url); if (pathname.startsWith('/web/')) { @@ -126,8 +125,7 @@ const openUrl = url => }); const removeActionFromNotification = (notification, action) => { - const actions = notification.actions.filter(act => act.action !== action.action); - + const actions = notification.actions.filter(act => act.action !== action.action); const nextNotification = cloneNotification(notification); nextNotification.actions = actions; diff --git a/app/models/session_activation.rb b/app/models/session_activation.rb index 7eb16af8f..c1645223b 100644 --- a/app/models/session_activation.rb +++ b/app/models/session_activation.rb @@ -25,6 +25,7 @@ # class SessionActivation < ApplicationRecord + belongs_to :user, inverse_of: :session_activations, required: true belongs_to :access_token, class_name: 'Doorkeeper::AccessToken', dependent: :destroy belongs_to :web_push_subscription, class_name: 'Web::PushSubscription', dependent: :destroy diff --git a/app/models/web/push_subscription.rb b/app/models/web/push_subscription.rb index e76f61278..79f782114 100644 --- a/app/models/web/push_subscription.rb +++ b/app/models/web/push_subscription.rb @@ -13,59 +13,14 @@ # require 'webpush' -require_relative '../../models/setting' class Web::PushSubscription < ApplicationRecord - include RoutingHelper - include StreamEntriesHelper - include ActionView::Helpers::TranslationHelper - include ActionView::Helpers::SanitizeHelper - has_one :session_activation - before_create :send_welcome_notification - def push(notification) - name = display_name notification.from_account - title = title_str(name, notification) - body = body_str notification - dir = dir_str body - url = url_str notification - image = image_str notification - actions = actions_arr notification - - access_token = actions.empty? ? nil : find_or_create_access_token(notification).token - nsfw = notification.target_status.nil? || notification.target_status.spoiler_text.empty? ? nil : notification.target_status.spoiler_text - - # TODO: Make sure that the payload does not exceed 4KB - Webpush::PayloadTooLarge - Webpush.payload_send( - message: JSON.generate( - title: title, - dir: dir, - image: image, - badge: full_asset_url('badge.png', skip_pipeline: true), - tag: notification.id, - timestamp: notification.created_at, - icon: notification.from_account.avatar_static_url, - data: { - content: decoder.decode(strip_tags(body)), - nsfw: nsfw.nil? ? nil : decoder.decode(strip_tags(nsfw)), - url: url, - actions: actions, - access_token: access_token, - message: translate('push_notifications.group.title'), # Do not pass count, will be formatted in the ServiceWorker - } - ), - endpoint: endpoint, - p256dh: key_p256dh, - auth: key_auth, - vapid: { - subject: "mailto:#{Setting.site_contact_email}", - private_key: Rails.configuration.x.vapid_private_key, - public_key: Rails.configuration.x.vapid_public_key, - }, - ttl: 40 * 60 * 60 # 48 hours - ) + I18n.with_locale(session_activation.user.locale || I18n.default_locale) do + push_payload(message_from(notification), 48.hours.seconds) + end end def pushable?(notification) @@ -73,120 +28,47 @@ class Web::PushSubscription < ApplicationRecord end def as_payload - payload = { - id: id, - endpoint: endpoint, - } - + payload = { id: id, endpoint: endpoint } payload[:alerts] = data['alerts'] if data && data.key?('alerts') - payload end + def access_token + find_or_create_access_token.token + end + private - def title_str(name, notification) - case notification.type - when :mention then translate('push_notifications.mention.title', name: name) - when :follow then translate('push_notifications.follow.title', name: name) - when :favourite then translate('push_notifications.favourite.title', name: name) - when :reblog then translate('push_notifications.reblog.title', name: name) - end - end + def push_payload(message, ttl = 5.minutes.seconds) + # TODO: Make sure that the payload does not + # exceed 4KB - Webpush::PayloadTooLarge - def body_str(notification) - case notification.type - when :mention then notification.target_status.text - when :follow then notification.from_account.note - when :favourite then notification.target_status.text - when :reblog then notification.target_status.text - end - end - - def url_str(notification) - case notification.type - when :mention then web_url("statuses/#{notification.target_status.id}") - when :follow then web_url("accounts/#{notification.from_account.id}") - when :favourite then web_url("statuses/#{notification.target_status.id}") - when :reblog then web_url("statuses/#{notification.target_status.id}") - end - end - - def actions_arr(notification) - actions = - case notification.type - when :mention then [ - { - title: translate('push_notifications.mention.action_favourite'), - icon: full_asset_url('web-push-icon_favourite.png', skip_pipeline: true), - todo: 'request', - method: 'POST', - action: "/api/v1/statuses/#{notification.target_status.id}/favourite", - }, - ] - else [] - end - - should_hide = notification.type.equal?(:mention) && !notification.target_status.nil? && (notification.target_status.sensitive || !notification.target_status.spoiler_text.empty?) - can_boost = notification.type.equal?(:mention) && !notification.target_status.nil? && !notification.target_status.hidden? - - if should_hide - actions.insert(0, title: translate('push_notifications.mention.action_expand'), icon: full_asset_url('web-push-icon_expand.png', skip_pipeline: true), todo: 'expand', action: 'expand') - end - - if can_boost - actions << { title: translate('push_notifications.mention.action_boost'), icon: full_asset_url('web-push-icon_reblog.png', skip_pipeline: true), todo: 'request', method: 'POST', action: "/api/v1/statuses/#{notification.target_status.id}/reblog" } - end - - actions - end - - def image_str(notification) - return nil if notification.target_status.nil? || notification.target_status.media_attachments.empty? - - full_asset_url(notification.target_status.media_attachments.first.file.url(:small)) - end - - def dir_str(body) - rtl?(body) ? 'rtl' : 'ltr' - end - - def send_welcome_notification Webpush.payload_send( - message: JSON.generate( - title: translate('push_notifications.subscribed.title'), - icon: full_asset_url('android-chrome-192x192.png', skip_pipeline: true), - badge: full_asset_url('badge.png', skip_pipeline: true), - data: { - content: translate('push_notifications.subscribed.body'), - actions: [], - url: web_url('notifications'), - message: translate('push_notifications.group.title'), # Do not pass count, will be formatted in the ServiceWorker - } - ), + message: Oj.dump(message), endpoint: endpoint, p256dh: key_p256dh, auth: key_auth, + ttl: ttl, vapid: { subject: "mailto:#{Setting.site_contact_email}", private_key: Rails.configuration.x.vapid_private_key, public_key: Rails.configuration.x.vapid_public_key, - }, - ttl: 5 * 60 # 5 minutes + } ) end - def find_or_create_access_token(notification) + def message_from(notification) + serializable_resource = ActiveModelSerializers::SerializableResource.new(notification, serializer: Web::NotificationSerializer, scope: self, scope_name: :current_push_subscription) + serializable_resource.as_json + end + + def find_or_create_access_token Doorkeeper::AccessToken.find_or_create_for( Doorkeeper::Application.find_by(superapp: true), - notification.account.user.id, + session_activation.user_id, Doorkeeper::OAuth::Scopes.from_string('read write follow'), Doorkeeper.configuration.access_token_expires_in, Doorkeeper.configuration.refresh_token_enabled? ) end - - def decoder - @decoder ||= HTMLEntities.new - end end diff --git a/app/serializers/web/notification_serializer.rb b/app/serializers/web/notification_serializer.rb new file mode 100644 index 000000000..0fe75f3a8 --- /dev/null +++ b/app/serializers/web/notification_serializer.rb @@ -0,0 +1,168 @@ +# frozen_string_literal: true + +class Web::NotificationSerializer < ActiveModel::Serializer + include StreamEntriesHelper + + class DataSerializer < ActiveModel::Serializer + include RoutingHelper + include StreamEntriesHelper + include ActionView::Helpers::SanitizeHelper + + attributes :content, :nsfw, :url, :actions, + :access_token, :message + + def content + decoder.decode(strip_tags(body)) + end + + def dir + rtl?(body) ? 'rtl' : 'ltr' + end + + def nsfw + return if object.target_status.nil? + object.target_status.spoiler_text.presence + end + + def url + case object.type + when :mention + web_url("statuses/#{object.target_status.id}") + when :follow + web_url("accounts/#{object.from_account.id}") + when :favourite + web_url("statuses/#{object.target_status.id}") + when :reblog + web_url("statuses/#{object.target_status.id}") + end + end + + def actions + return @actions if defined?(@actions) + + @actions = [] + + if object.type == :mention + @actions << expand_action if collapsed? + @actions << favourite_action + @actions << reblog_action if rebloggable? + end + + @actions + end + + def access_token + return if actions.empty? + current_push_subscription.access_token + end + + def message + I18n.t('push_notifications.group.title') + end + + private + + def body + case object.type + when :mention + object.target_status.text + when :follow + object.from_account.note + when :favourite + object.target_status.text + when :reblog + object.target_status.text + end + end + + def decoder + @decoder ||= HTMLEntities.new + end + + def expand_action + { + title: I18n.t('push_notifications.mention.action_expand'), + icon: full_asset_url('web-push-icon_expand.png', skip_pipeline: true), + todo: 'expand', + action: 'expand', + } + end + + def favourite_action + { + title: I18n.t('push_notifications.mention.action_favourite'), + icon: full_asset_url('web-push-icon_favourite.png', skip_pipeline: true), + todo: 'request', + method: 'POST', + action: "/api/v1/statuses/#{object.target_status.id}/favourite", + } + end + + def reblog_action + { + title: I18n.t('push_notifications.mention.action_boost'), + icon: full_asset_url('web-push-icon_reblog.png', skip_pipeline: true), + todo: 'request', + method: 'POST', + action: "/api/v1/statuses/#{object.target_status.id}/reblog", + } + end + + def collapsed? + !object.target_status.nil? && (object.target_status.sensitive? || object.target_status.spoiler_text.present?) + end + + def rebloggable? + !object.target_status.nil? && !object.target_status.hidden? + end + end + + attributes :title, :dir, :image, :badge, :tag, + :timestamp, :icon + + has_one :data + + def title + case object.type + when :mention + I18n.t('push_notifications.mention.title', name: name) + when :follow + I18n.t('push_notifications.follow.title', name: name) + when :favourite + I18n.t('push_notifications.favourite.title', name: name) + when :reblog + I18n.t('push_notifications.reblog.title', name: name) + end + end + + def image + return if object.target_status.nil? || object.target_status.media_attachments.empty? + full_asset_url(object.target_status.media_attachments.first.file.url(:small)) + end + + def badge + full_asset_url('badge.png', skip_pipeline: true) + end + + def tag + object.id + end + + def timestamp + object.created_at + end + + def icon + object.from_account.avatar_static_url + end + + def data + object + end + + private + + def name + display_name(object.from_account) + end +end diff --git a/config/locales/ca.yml b/config/locales/ca.yml index 58d7a6638..089d6dfa6 100644 --- a/config/locales/ca.yml +++ b/config/locales/ca.yml @@ -21,7 +21,7 @@ ca: real_conversation_body: Amb 500 caràcters a la teva disposició i suport per a continguts granulars i avisos multimèdia, pots expressar-te de la manera que vulguis. real_conversation_title: Construït per a converses reals within_reach_body: Diverses aplicacions per a iOS, Android i altres plataformes gràcies a un ecosistema API amable amb el desenvolupador, et permet mantenir-te al dia amb els teus amics en qualsevol lloc.. - within_reach_title: Sempre a l'abast + within_reach_title: Sempre a l'abast find_another_instance: Troba altres instàncies generic_description: "%{domain} és un servidor a la xarxa" hosted_on: Mastodon allotjat a %{domain} @@ -215,7 +215,7 @@ ca: body: "%{reporter} ha informat de %{target}" subject: Nou informe per a %{instance} (#%{id}) application_mailer: - salutation: '%{name},' + salutation: "%{name}," settings: 'Canviar preferències de correu: %{link}' signature: Notificacions de Mastodon desde %{instance} view: 'Vista:' @@ -358,9 +358,6 @@ ca: title: "%{name} t'ha mencionat" reblog: title: "%{name} t'ha retootejat" - subscribed: - body: Ara pots rebre notificacions push. - title: Subscripció registrada remote_follow: acct: Escriu el usuari@domini de la persona que vols seguir missing_resource: No s'ha pogut trobar la URL de redirecció necessaria per el compte. @@ -432,74 +429,7 @@ ca: reblogged: retooteado sensitive_content: Contingut sensible terms: - body_html: | -
Recopilem informació teva quan et registres en aquesta instància i recopilem dades quan participes en el fòrum llegint, escrivint i avaluant el contingut aquí compartit.
- -En registrar-te en aquesta instància, se't pot demanar que introduexisu el teu nom i l'adreça de correu electrònic. També pots visitar el nostre lloc sense registrar-te. La teva adreça de correu electrònic es verificarà mitjançant un correu electrònic que conté un enllaç únic. Si es visita aquest enllaç, sabem que controles l'adreça de correu electrònic.
- -Quan es registra i publica, registrem l'adreça IP de la qual es va originar la publicació. També podrem conservar els registres del servidor que inclouen l'adreça IP de cada sol·licitud al nostre servidor.
- -Qualsevol de la informació que recopilem de tu pot utilitzar-se d'una de les maneres següents:
- -Implementem diverses mesures de seguretat per mantenir la seguretat de la teva informació personal quan introdueixes, envies o accedeixes a la teva informació personal.
- -Farem un esforç de bona fe per a:
- -Sí. Les cookies són fitxers petits que un lloc o el proveïdor de serveis transfereix al disc dur del vostre ordinador a través del navegador web (si ho permet). Aquestes galetes permeten al lloc reconèixer el vostre navegador i, si teniu un compte registrat, associar-lo al vostre compte registrat.
- -Utilitzem cookies per comprendre i desar les vostres preferències per a futures visites i compilar dades agregades sobre el trànsit del lloc i la interacció del lloc, de manera que podrem oferir millors experiències i eines del lloc en el futur. Podem contractar amb proveïdors de serveis de tercers per ajudar-nos a comprendre millor els visitants del nostre lloc. Aquests proveïdors de serveis no estan autoritzats a utilitzar la informació recollida en nom nostre, excepte per ajudar-nos a dur a terme i millorar el nostre negoci.
- -No venem, comercialitzem ni transmetem a tercers la vostra informació d'identificació personal. Això no inclou tercers de confiança que ens ajudin a operar el nostre lloc, a dur a terme el nostre negoci o a fer-ho, sempre que aquestes parts acceptin mantenir confidencial aquesta informació. També podem publicar la vostra informació quan creiem que l'alliberament és apropiat per complir amb la llei, fer complir les polítiques del nostre lloc o protegir els nostres drets o altres drets, propietat o seguretat. No obstant això, la informació de visitant que no sigui personalment identificable es pot proporcionar a altres parts per a la comercialització, la publicitat o altres usos.
- -De tant en tant, segons el nostre criteri, podem incloure o oferir productes o serveis de tercers al nostre lloc. Aquests llocs de tercers tenen polítiques de privadesa separades i independents. Per tant, no tenim responsabilitat ni responsabilitat civil pel contingut i les activitats d'aquests llocs enllaçats. No obstant això, busquem protegir la integritat del nostre lloc i donem la benvinguda a qualsevol comentari sobre aquests llocs.
- -El nostre lloc, productes i serveis estan dirigits a persones que tenen almenys 13 anys. Si aquest servidor es troba als EUA, i teniu menys de 13 anys, segons els requisits de COPPA (Children's Online Privacy Protection Act) no feu servir aquest lloc.
- -Aquesta política de privacitat en línia només s'aplica a la informació recopilada a través del nostre lloc i no a la informació recopilada fora de línia.
- -En utilitzar el nostre lloc, accepta la política de privadesa del nostre lloc web.
- -Si decidim canviar la nostra política de privadesa, publicarem aquests canvis en aquesta pàgina.
- -Aquest document és CC-BY-SA. Es va actualitzar per última vegada el 31 de maig de 2013.
- -Originalment adaptat a la política de privadesa del Discurs.
+ body_html: "Recopilem informació teva quan et registres en aquesta instància i recopilem dades quan participes en el fòrum llegint, escrivint i avaluant el contingut aquí compartit.
\n\nEn registrar-te en aquesta instància, se't pot demanar que introduexisu el teu nom i l'adreça de correu electrònic. També pots visitar el nostre lloc sense registrar-te. La teva adreça de correu electrònic es verificarà mitjançant un correu electrònic que conté un enllaç únic. Si es visita aquest enllaç, sabem que controles l'adreça de correu electrònic.
\n\nQuan es registra i publica, registrem l'adreça IP de la qual es va originar la publicació. També podrem conservar els registres del servidor que inclouen l'adreça IP de cada sol·licitud al nostre servidor.
\n\nQualsevol de la informació que recopilem de tu pot utilitzar-se d'una de les maneres següents:
\n\nImplementem diverses mesures de seguretat per mantenir la seguretat de la teva informació personal quan introdueixes, envies o accedeixes a la teva informació personal.
\n\nFarem un esforç de bona fe per a:
\n\nSí. Les cookies són fitxers petits que un lloc o el proveïdor de serveis transfereix al disc dur del vostre ordinador a través del navegador web (si ho permet). Aquestes galetes permeten al lloc reconèixer el vostre navegador i, si teniu un compte registrat, associar-lo al vostre compte registrat.
\n\nUtilitzem cookies per comprendre i desar les vostres preferències per a futures visites i compilar dades agregades sobre el trànsit del lloc i la interacció del lloc, de manera que podrem oferir millors experiències i eines del lloc en el futur. Podem contractar amb proveïdors de serveis de tercers per ajudar-nos a comprendre millor els visitants del nostre lloc. Aquests proveïdors de serveis no estan autoritzats a utilitzar la informació recollida en nom nostre, excepte per ajudar-nos a dur a terme i millorar el nostre negoci.
\n\nNo venem, comercialitzem ni transmetem a tercers la vostra informació d'identificació personal. Això no inclou tercers de confiança que ens ajudin a operar el nostre lloc, a dur a terme el nostre negoci o a fer-ho, sempre que aquestes parts acceptin mantenir confidencial aquesta informació. També podem publicar la vostra informació quan creiem que l'alliberament és apropiat per complir amb la llei, fer complir les polítiques del nostre lloc o protegir els nostres drets o altres drets, propietat o seguretat. No obstant això, la informació de visitant que no sigui personalment identificable es pot proporcionar a altres parts per a la comercialització, la publicitat o altres usos.
\n\nDe tant en tant, segons el nostre criteri, podem incloure o oferir productes o serveis de tercers al nostre lloc. Aquests llocs de tercers tenen polítiques de privadesa separades i independents. Per tant, no tenim responsabilitat ni responsabilitat civil pel contingut i les activitats d'aquests llocs enllaçats. No obstant això, busquem protegir la integritat del nostre lloc i donem la benvinguda a qualsevol comentari sobre aquests llocs.
\n\nEl nostre lloc, productes i serveis estan dirigits a persones que tenen almenys 13 anys. Si aquest servidor es troba als EUA, i teniu menys de 13 anys, segons els requisits de COPPA (Children's Online Privacy Protection Act) no feu servir aquest lloc.
\n\nAquesta política de privacitat en línia només s'aplica a la informació recopilada a través del nostre lloc i no a la informació recopilada fora de línia.
\n\nEn utilitzar el nostre lloc, accepta la política de privadesa del nostre lloc web.
\n\nSi decidim canviar la nostra política de privadesa, publicarem aquests canvis en aquesta pàgina.
\n\nAquest document és CC-BY-SA. Es va actualitzar per última vegada el 31 de maig de 2013.
\n\nOriginalment adaptat a la política de privadesa del Discurs.
\n" title: "%{instance} Condicions del servei i política de privadesa" time: formats: diff --git a/config/locales/en.yml b/config/locales/en.yml index 1a9926edd..2599b6078 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -382,9 +382,6 @@ en: title: "%{name} mentioned you" reblog: title: "%{name} boosted your status" - subscribed: - body: You can now receive push notifications. - title: Subscription registered! remote_follow: acct: Enter your username@domain you want to follow from missing_resource: Could not find the required redirect URL for your account diff --git a/config/locales/fa.yml b/config/locales/fa.yml index 0c575e23e..6959134a6 100644 --- a/config/locales/fa.yml +++ b/config/locales/fa.yml @@ -357,9 +357,6 @@ fa: title: "%{name} از شما نام برد" reblog: title: "%{name} نوشتهٔ شما را بازبوقید" - subscribed: - body: از این به بعد سرور میتواندبه شما اعلانهای تازه بفرستد . - title: عضویت ثبت شد! remote_follow: acct: نشانی حساب username@domain خود را اینجا بنویسید missing_resource: نشانی اینترنتی برای رسیدن به حساب شما پیدا نشد diff --git a/config/locales/fr.yml b/config/locales/fr.yml index a7c5bf144..6d7479cc9 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -353,9 +353,6 @@ fr: title: "%{name} vous a mentionné·e" reblog: title: "%{name} a partagé⋅e votre statut" - subscribed: - body: Vous pouvez désormais recevoir des notifications push. - title: Abonnements aux notifications push remote_follow: acct: Entrez votre pseudo@instance depuis lequel vous voulez suivre ce⋅tte utilisateur⋅rice missing_resource: L’URL de redirection n’a pas pu être trouvée diff --git a/config/locales/ja.yml b/config/locales/ja.yml index e4b18529c..4f6f92866 100644 --- a/config/locales/ja.yml +++ b/config/locales/ja.yml @@ -381,9 +381,6 @@ ja: title: "%{name} さんから返信がありました" reblog: title: あなたのトゥートが %{name} さんにブーストされました - subscribed: - body: あなたはプッシュ通知を受け取ることが出来ます - title: Subscription が登録されました remote_follow: acct: あなたの ユーザー名@ドメイン を入力してください missing_resource: リダイレクト先が見つかりませんでした diff --git a/config/locales/nl.yml b/config/locales/nl.yml index 6562767a9..e738d5662 100644 --- a/config/locales/nl.yml +++ b/config/locales/nl.yml @@ -353,9 +353,6 @@ nl: title: "%{name} vermeldde jou" reblog: title: "%{name} boostte jouw toot" - subscribed: - body: Je kan nu pushmeldingen ontvangen. - title: Aanmelding bevestigd! remote_follow: acct: Geef jouw account@domein.tld op waarvandaan je wilt volgen missing_resource: Kon vereiste doorverwijzings-URL voor jouw account niet vinden diff --git a/config/locales/oc.yml b/config/locales/oc.yml index 99c377f18..ba7993d7c 100644 --- a/config/locales/oc.yml +++ b/config/locales/oc.yml @@ -448,9 +448,6 @@ oc: title: "%{name} vos a mencionat" reblog: title: "%{name} a partejat vòstre estatut" - subscribed: - body: Podètz ara recebre las notificacions push. - title: Abonament enregistrat ! remote_follow: acct: Picatz vòstre utilizaire@instància que cal utilizar per sègre aqueste utilizaire missing_resource: URL de redireccion pas trobada diff --git a/config/locales/pl.yml b/config/locales/pl.yml index 9f0d9bb29..2b2cbb26b 100644 --- a/config/locales/pl.yml +++ b/config/locales/pl.yml @@ -224,8 +224,6 @@ pl: settings: 'Zmień ustawienia powiadamiania: %{link}' signature: Powiadomienie Mastodona z instancji %{instance} view: 'Zobacz:' - applications: - invalid_url: Ten URL jest nieprawidłowy applications: created: Pomyślnie utworzono aplikację destroyed: Pomyślnie usunięto aplikację @@ -375,9 +373,6 @@ pl: title: "%{name} wspomniał o Tobie" reblog: title: "%{name} podbił Twój status" - subscribed: - body: Otrzymujesz teraz powiadomienia push. - title: Zarejestrowano subskrypcję! remote_follow: acct: Podaj swój adres (nazwa@domena), z którego chcesz śledzić missing_resource: Nie udało się znaleźć adresu przekierowania z Twojej domeny diff --git a/config/locales/ru.yml b/config/locales/ru.yml index 0156f0e95..5c87ebf26 100644 --- a/config/locales/ru.yml +++ b/config/locales/ru.yml @@ -278,9 +278,6 @@ ru: title: Вас упомянул(а) %{name} reblog: title: "%{name} продвинул(а) Ваш статус" - subscribed: - body: Теперь Вы можете получать push-уведомления. - title: Подписка зарегистрирована! remote_follow: acct: Введите username@domain, откуда Вы хотите подписаться missing_resource: Поиск требуемого перенаправления URL для Вашего аккаунта завершился неудачей