diff --git a/app/javascript/mastodon/service_worker/web_push_notifications.js b/app/javascript/mastodon/service_worker/web_push_notifications.js index acb85f6262bd979962c8e3f6eb6286b9fe01f947..f63cff335a16c970c38fa9b29a72dbb7237e91d2 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 7eb16af8f47dcb13a627e4f4dda7bad8328f26f0..c1645223bda233786566c85a81763af70140bade 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 e76f61278ef0b0e57c1012c50e3a13a54fe4b6ea..79f782114459cf86b2c1b36030e74161a7d77e35 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 - 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 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 + def access_token + find_or_create_access_token.token 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 + private - def dir_str(body) - rtl?(body) ? 'rtl' : 'ltr' - end + def push_payload(message, ttl = 5.minutes.seconds) + # TODO: Make sure that the payload does not + # exceed 4KB - Webpush::PayloadTooLarge - 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 0000000000000000000000000000000000000000..0fe75f3a8d02ca427120203dd509cc7f350422fc --- /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 58d7a66389e71cce97dd64d0f9a57b2b6dd052ce..089d6dfa642c92da66f523e2cabdf91bb35404f5 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: | - <h2>PolÃtica de privacitat</h2> - - <h3 id="collect">Quina informació recollim?</h3> - - <p>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.</p> - - <p>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.</p> - - <p>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.</p> - - <h3 id="use">Per a què utilitzem la teva informació?</h3> - - <p>Qualsevol de la informació que recopilem de tu pot utilitzar-se d'una de les maneres següents:</p> - - <ul> - <li>Per a personalitzar la teva experiència — la teva informació ens ajuda a respondre millor a les teves necessitats individuals.</li> - <li>Per millorar el nostre lloc — ens esforcem contÃnuament per millorar les nostres ofertes de llocs basats en la informació i els comentaris que rebem de tu.</li> - <li>Per millorar el servei al client — la teva informació ens ajuda a respondre més eficaçment a les teves sol·licituds de servei al client i a les necessitats de suport.</li> - <li>Per enviar correus electrònics periòdics — l'adreça electrònica que proporcionis es pot utilitzar per enviar-te informació, notificacions que sol·licitis sobre canvis en temes o en resposta al teu nom d'usuari, respondre a les consultes i/o altres sol·licituds o preguntes.</li> - </ul> - - <h3 id="protect">Com protegim la teva informació?</h3> - - <p>Implementem diverses mesures de seguretat per mantenir la seguretat de la teva informació personal quan introdueixes, envies o accedeixes a la teva informació personal.</p> - - <h3 id="data-retention">Quina és la nostre polÃtica de retenció de dades?</h3> - - <p>Farem un esforç de bona fe per a:</p> - - <ul> - <li>Conserva els registres de servidor que continguin l'adreça IP de totes les sol·licituds a aquest servidor no més de 90 dies.</li> - <li>Conserva les adreces IP associades als usuaris registrats i les seves publicacions no més de 5 anys.</li> - </ul> - - <h3 id="cookies">Utilitzem galetes?</h3> - - <p>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.</p> - - <p>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.</p> - - <h3 id="disclose">Publiquem informació al exterior?</h3> - - <p>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.</p> - - <h3 id="third-party">Vincles de tercers</h3> - - <p>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.</p> - - <h3 id="coppa">Compliment de la Llei de protecció de la privacitat en lÃnia dels nens</h3> - - <p>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 (<a href="https://en.wikipedia.org/wiki/Children%27s_Online_Privacy_Protection_Act">Children's Online Privacy Protection Act</a>) no feu servir aquest lloc.</p> - - <h3 id="online">Només la polÃtica de privacitat en lÃnia</h3> - - <p>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.</p> - - <h3 id="consent">El vostre consentiment</h3> - - <p>En utilitzar el nostre lloc, accepta la polÃtica de privadesa del nostre lloc web.</p> - - <h3 id="changes">Canvis a la nostra polÃtica de privacitat</h3> - - <p>Si decidim canviar la nostra polÃtica de privadesa, publicarem aquests canvis en aquesta pà gina.</p> - - <p>Aquest document és CC-BY-SA. Es va actualitzar per última vegada el 31 de maig de 2013.</p> - - <p>Originalment adaptat a la <a href="https://github.com/discourse/discourse">polÃtica de privadesa del Discurs</a>.</p> + body_html: "<h2>PolÃtica de privacitat</h2>\n\n<h3 id=\"collect\">Quina informació recollim?</h3>\n\n<p>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.</p>\n\n<p>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.</p>\n\n<p>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.</p>\n\n<h3 id=\"use\">Per a què utilitzem la teva informació?</h3>\n\n<p>Qualsevol de la informació que recopilem de tu pot utilitzar-se d'una de les maneres següents:</p>\n\n<ul>\n <li>Per a personalitzar la teva experiència — la teva informació ens ajuda a respondre millor a les teves necessitats individuals.</li>\n <li>Per millorar el nostre lloc — ens esforcem contÃnuament per millorar les nostres ofertes de llocs basats en la informació i els comentaris que rebem de tu.</li>\n <li>Per millorar el servei al client — la teva informació ens ajuda a respondre més eficaçment a les teves sol·licituds de servei al client i a les necessitats de suport.</li>\n <li>Per enviar correus electrònics periòdics — l'adreça electrònica que proporcionis es pot utilitzar per enviar-te informació, notificacions que sol·licitis sobre canvis en temes o en resposta al teu nom d'usuari, respondre a les consultes i/o altres sol·licituds o preguntes.</li>\n</ul>\n\n<h3 id=\"protect\">Com protegim la teva informació?</h3>\n\n<p>Implementem diverses mesures de seguretat per mantenir la seguretat de la teva informació personal quan introdueixes, envies o accedeixes a la teva informació personal.</p>\n\n<h3 id=\"data-retention\">Quina és la nostre polÃtica de retenció de dades?</h3>\n\n<p>Farem un esforç de bona fe per a:</p>\n\n<ul>\n <li>Conserva els registres de servidor que continguin l'adreça IP de totes les sol·licituds a aquest servidor no més de 90 dies.</li>\n <li>Conserva les adreces IP associades als usuaris registrats i les seves publicacions no més de 5 anys.</li>\n</ul>\n\n<h3 id=\"cookies\">Utilitzem galetes?</h3>\n\n<p>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.</p>\n\n<p>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.</p>\n\n<h3 id=\"disclose\">Publiquem informació al exterior?</h3>\n\n<p>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.</p> \n\n<h3 id=\"third-party\">Vincles de tercers</h3>\n\n<p>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.</p>\n\n<h3 id=\"coppa\">Compliment de la Llei de protecció de la privacitat en lÃnia dels nens</h3>\n\n<p>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 (<a href=\"https://en.wikipedia.org/wiki/Children%27s_Online_Privacy_Protection_Act\">Children's Online Privacy Protection Act</a>) no feu servir aquest lloc.</p>\n\n<h3 id=\"online\">Només la polÃtica de privacitat en lÃnia</h3>\n\n<p>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.</p>\n\n<h3 id=\"consent\">El vostre consentiment</h3>\n\n<p>En utilitzar el nostre lloc, accepta la polÃtica de privadesa del nostre lloc web.</p>\n\n<h3 id=\"changes\">Canvis a la nostra polÃtica de privacitat</h3>\n\n<p>Si decidim canviar la nostra polÃtica de privadesa, publicarem aquests canvis en aquesta pà gina.</p>\n\n<p>Aquest document és CC-BY-SA. Es va actualitzar per última vegada el 31 de maig de 2013.</p>\n\n<p>Originalment adaptat a la <a href=\"https://github.com/discourse/discourse\">polÃtica de privadesa del Discurs</a>.</p>\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 1a9926edd8a2ec5ffd07fb867562b20f093df421..2599b6078ec105c239cd4e45e6af8622c7e95741 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 0c575e23e2423e89b3ff1189d39104639be8fc0f..6959134a6770b480558089460310cff6855ee618 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 a7c5bf144258e99490245dc44d3fc805ae32fb00..6d7479cc9ce00ae779bf109e8b0a4107bc9a02b1 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 e4b18529cee2bf31c7243c23c1d8ad62429f6c65..4f6f92866b7e47e568897b9dcc1697fba5f2d229 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 6562767a95acffce20b07564041503c8c5d32fbd..e738d5662cd7576fc94bd7c7b24fe4b6eafb6574 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 99c377f18495093f58f335cce26b72ad248eca47..ba7993d7cd9e2a20b9d1cc864365b6d1d8783ba7 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 9f0d9bb29a63b2206da2f1eb1873a4408ddfb7e0..2b2cbb26b558d6c335e95b4b32a10fa52d074889 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 0156f0e95f691d01c0d9d39c3dd35b6d26b78c2e..5c87ebf2691b0c9353e94179ebc212b8a06dab1c 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 Ð´Ð»Ñ Ð’Ð°ÑˆÐµÐ³Ð¾ аккаунта завершилÑÑ Ð½ÐµÑƒÐ´Ð°Ñ‡ÐµÐ¹