From 74437c6bff8d704fbb5664fe7f1b5e78e16ad086 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 1 Sep 2017 13:35:23 +0200 Subject: [PATCH] Refactor Web::PushSubscription, remove welcome message (#4524) * Refactor Web::PushSubscription, remove welcome message * Add missing helper * Use locale of the receiver on push notifications (#4519) * Remove unused translations * Fix dir on notifications --- .../service_worker/web_push_notifications.js | 26 ++- app/models/session_activation.rb | 1 + app/models/web/push_subscription.rb | 160 +++-------------- .../web/notification_serializer.rb | 168 ++++++++++++++++++ config/locales/ca.yml | 76 +------- config/locales/en.yml | 3 - config/locales/fa.yml | 3 - config/locales/fr.yml | 3 - config/locales/ja.yml | 3 - config/locales/nl.yml | 3 - config/locales/oc.yml | 3 - config/locales/pl.yml | 5 - config/locales/ru.yml | 3 - 13 files changed, 205 insertions(+), 252 deletions(-) create mode 100644 app/serializers/web/notification_serializer.rb diff --git a/app/javascript/mastodon/service_worker/web_push_notifications.js b/app/javascript/mastodon/service_worker/web_push_notifications.js index acb85f6262..f63cff335a 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 7eb16af8f4..c1645223bd 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 e76f61278e..79f7821144 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 0000000000..0fe75f3a8d --- /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 58d7a66389..089d6dfa64 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: | -

Política de privacitat

- -

Quina informació recollim?

- -

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.

- -

Per a què utilitzem la teva informació?

- -

Qualsevol de la informació que recopilem de tu pot utilitzar-se d'una de les maneres següents:

- - - -

Com protegim la teva informació?

- -

Implementem diverses mesures de seguretat per mantenir la seguretat de la teva informació personal quan introdueixes, envies o accedeixes a la teva informació personal.

- -

Quina és la nostre política de retenció de dades?

- -

Farem un esforç de bona fe per a:

- - - -

Utilitzem galetes?

- -

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.

- -

Publiquem informació al exterior?

- -

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.

- -

Vincles de tercers

- -

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.

- -

Compliment de la Llei de protecció de la privacitat en línia dels nens

- -

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.

- -

Només la política de privacitat en línia

- -

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.

- -

Canvis a la nostra política de privacitat

- -

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: "

Política de privacitat

\n\n

Quina informació recollim?

\n\n

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\n

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.

\n\n

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.

\n\n

Per a què utilitzem la teva informació?

\n\n

Qualsevol de la informació que recopilem de tu pot utilitzar-se d'una de les maneres següents:

\n\n\n\n

Com protegim la teva informació?

\n\n

Implementem diverses mesures de seguretat per mantenir la seguretat de la teva informació personal quan introdueixes, envies o accedeixes a la teva informació personal.

\n\n

Quina és la nostre política de retenció de dades?

\n\n

Farem un esforç de bona fe per a:

\n\n\n\n

Utilitzem galetes?

\n\n

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.

\n\n

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.

\n\n

Publiquem informació al exterior?

\n\n

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.

\n\n

Vincles de tercers

\n\n

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.

\n\n

Compliment de la Llei de protecció de la privacitat en línia dels nens

\n\n

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.

\n\n

Només la política de privacitat en línia

\n\n

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.

\n\n

El vostre consentiment

\n\n

En utilitzar el nostre lloc, accepta la política de privadesa del nostre lloc web.

\n\n

Canvis a la nostra política de privacitat

\n\n

Si decidim canviar la nostra política de privadesa, publicarem aquests canvis en aquesta pàgina.

\n\n

Aquest document és CC-BY-SA. Es va actualitzar per última vegada el 31 de maig de 2013.

\n\n

Originalment 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 1a9926edd8..2599b6078e 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 0c575e23e2..6959134a67 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 a7c5bf1442..6d7479cc9c 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 e4b18529ce..4f6f92866b 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 6562767a95..e738d5662c 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 99c377f184..ba7993d7cd 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 9f0d9bb29a..2b2cbb26b5 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 0156f0e95f..5c87ebf269 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 для Вашего аккаунта завершился неудачей