@@ -77,4 +81,4 @@ const ColumnSettings = React.createClass({
});
-export default ColumnSettings;
+export default injectIntl(ColumnSettings);
diff --git a/app/assets/javascripts/components/locales/de.jsx b/app/assets/javascripts/components/locales/de.jsx
index 882c31fa..92897f54 100644
--- a/app/assets/javascripts/components/locales/de.jsx
+++ b/app/assets/javascripts/components/locales/de.jsx
@@ -1,15 +1,15 @@
const en = {
"column_back_button.label": "Zurück",
"lightbox.close": "Schließen",
- "loading_indicator.label": "Lade...",
+ "loading_indicator.label": "Lade…",
"status.mention": "Erwähnen",
"status.delete": "Löschen",
"status.reply": "Antworten",
"status.reblog": "Teilen",
"status.favourite": "Favorisieren",
"status.reblogged_by": "{name} teilte",
- "status.sensitive_warning": "Sensible Inhalte",
- "status.sensitive_toggle": "Klicken um zu zeigen",
+ "status.sensitive_warning": "Heikle Inhalte",
+ "status.sensitive_toggle": "Klicke, um sie zu sehen",
"status.open": "Öffnen",
"video_player.toggle_sound": "Ton umschalten",
"account.mention": "Erwähnen",
@@ -20,17 +20,17 @@ const en = {
"account.follow": "Folgen",
"account.posts": "Beiträge",
"account.follows": "Folgt",
- "account.followers": "Folger",
+ "account.followers": "Folgende",
"account.follows_you": "Folgt dir",
"account.requested": "Warte auf Erlaubnis",
"getting_started.heading": "Erste Schritte",
- "getting_started.about_addressing": "Du kannst Leuten folgen, falls du ihren Nutzernamen und ihre Domain kennst, in dem du eine e-mail-artige Addresse in das Suchfeld oben an der Seite eingibst.",
- "getting_started.about_shortcuts": "Falls der Zielnutzer an derselben Domain ist wie du, funktioniert der Nutzername auch alleine. Das gilt auch für Erwähnungen in Beiträgen.",
+ "getting_started.about_addressing": "Du kannst Leuten folgen, falls du ihren Nutzernamen und ihre Domain kennst, in dem du eine e-mail-artige Addresse in das Suchfeld oben auf der Seite eingibst.",
+ "getting_started.about_shortcuts": "Falls die Person auf derselben Domain ist wie du, reicht auch ihr Nutzername alleine. Das gilt auch für Erwähnungen in Beiträgen.",
"getting_started.about_developer": "Der Entwickler des Projekts kann unter Gargron@mastodon.social gefunden werden",
"getting_started.open_source_notice": "Mastodon ist quelloffene Software. Du kannst auf {github} dazu beitragen oder Probleme melden.",
"column.home": "Home",
"column.mentions": "Erwähnungen",
- "column.public": "Gesamtes Bekanntes Netz",
+ "column.public": "Gesamtes bekanntes Netz",
"column.notifications": "Mitteilungen",
"column.follow_requests": "Folgeanfragen",
"tabs_bar.compose": "Schreiben",
@@ -38,11 +38,11 @@ const en = {
"tabs_bar.mentions": "Erwähnungen",
"tabs_bar.public": "Gesamtes Netz",
"tabs_bar.notifications": "Mitteilungen",
- "compose_form.placeholder": "Worüber möchstest du schreiben?",
+ "compose_form.placeholder": "Worüber möchtest du schreiben?",
"compose_form.publish": "Tröt",
- "compose_form.sensitive": "Medien als sensitiv markieren",
- "compose_form.unlisted": "Öffentlich nicht auflisten",
+ "compose_form.sensitive": "Medien als heikel markieren",
"compose_form.private": "Als privat markieren",
+ "compose_form.unlisted": "Nicht öffentlich auflisten",
"navigation_bar.edit_profile": "Profil bearbeiten",
"navigation_bar.preferences": "Einstellungen",
"navigation_bar.public_timeline": "Öffentlich",
@@ -52,15 +52,15 @@ const en = {
"search.placeholder": "Suche",
"search.account": "Konto",
"search.hashtag": "Hashtag",
- "upload_button.label": "Media-Datei anfügen",
+ "upload_button.label": "Mediendatei hinzufügen",
"upload_form.undo": "Entfernen",
"notification.follow": "{name} folgt dir",
"notification.favourite": "{name} favorisierte deinen Status",
"notification.reblog": "{name} teilte deinen Status",
"notification.mention": "{name} erwähnte dich",
- "notifications.column_settings.alert": "Desktop-Benachrichtigunen",
+ "notifications.column_settings.alert": "Desktop-Benachrichtigungen",
"notifications.column_settings.show": "In der Spalte anzeigen",
- "notifications.column_settings.follow": "Neue Folger:",
+ "notifications.column_settings.follow": "Neue Folgende:",
"notifications.column_settings.favourite": "Favorisierungen:",
"notifications.column_settings.mention": "Erwähnungen:",
"notifications.column_settings.reblog": "Geteilte Beiträge:",
diff --git a/app/assets/javascripts/components/locales/en.jsx b/app/assets/javascripts/components/locales/en.jsx
index 53e2898e..f249b196 100644
--- a/app/assets/javascripts/components/locales/en.jsx
+++ b/app/assets/javascripts/components/locales/en.jsx
@@ -10,6 +10,10 @@ const en = {
"status.reblogged_by": "{name} boosted",
"status.sensitive_warning": "Sensitive content",
"status.sensitive_toggle": "Click to view",
+ "status.show_more": "Show more",
+ "status.show_less": "Show less",
+ "status.open": "Expand this status",
+ "status.report": "Report @{name}",
"video_player.toggle_sound": "Toggle sound",
"account.mention": "Mention @{name}",
"account.edit_profile": "Edit profile",
diff --git a/app/assets/javascripts/components/locales/eo.jsx b/app/assets/javascripts/components/locales/eo.jsx
new file mode 100644
index 00000000..8c118b31
--- /dev/null
+++ b/app/assets/javascripts/components/locales/eo.jsx
@@ -0,0 +1,68 @@
+const eo = {
+ "column_back_button.label": "Reveni",
+ "lightbox.close": "Fermi",
+ "loading_indicator.label": "Ŝarĝanta...",
+ "status.mention": "Mencii @{name}",
+ "status.delete": "Forigi",
+ "status.reply": "Respondi",
+ "status.reblog": "Diskonigi",
+ "status.favourite": "Favori",
+ "status.reblogged_by": "{name} diskonigita",
+ "status.sensitive_warning": "Tikla enhavo",
+ "status.sensitive_toggle": "Alklaki por vidi",
+ "video_player.toggle_sound": "Aktivigi sonojn",
+ "account.mention": "Mencii @{name}",
+ "account.edit_profile": "Redakti la profilon",
+ "account.unblock": "Malbloki @{name}",
+ "account.unfollow": "Malsekvi",
+ "account.block": "Bloki @{name}",
+ "account.follow": "Sekvi",
+ "account.posts": "Mesaĝoj",
+ "account.follows": "Sekvatoj",
+ "account.followers": "Sekvantoj",
+ "account.follows_you": "Sekvas vin",
+ "account.requested": "Atendas aprobon",
+ "getting_started.heading": "Por komenci",
+ "getting_started.about_addressing": "Vi povas sekvi homojn se vi konas la uzantnomon kaj domajnon tajpinte retpoŝtecan adreson en la serĉilon.",
+ "getting_started.about_shortcuts": "Se la celita uzanto troviĝas en la sama domajno de vi, uzi nur la uzantnomon sufiĉos. La sama regulo validas por mencii aliajn uzantojn en mesaĝo.",
+ "getting_started.open_source_notice": "Mastodon estas malfermitkoda programo. Vi povas kontribui aŭ raporti problemojn en github je {github}. {apps}.",
+ "column.home": "Hejmo",
+ "column.community": "Loka tempolinio",
+ "column.public": "Fratara tempolinio",
+ "column.notifications": "Sciigoj",
+ "tabs_bar.compose": "Ekskribi",
+ "tabs_bar.home": "Hejmo",
+ "tabs_bar.mentions": "Sciigoj",
+ "tabs_bar.public": "Fratara tempolinio",
+ "tabs_bar.notifications": "Sciigoj",
+ "compose_form.placeholder": "Pri kio vi pensas?",
+ "compose_form.publish": "Hup",
+ "compose_form.sensitive": "Marki ke la enhavo estas tikla",
+ "compose_form.spoiler": "Kaŝi la tekston malantaŭ averto",
+ "compose_form.private": "Marki ke la enhavo estas privata",
+ "compose_form.privacy_disclaimer": "Via privata mesaĝo estos sendita nur al menciitaj uzantoj en {domains}. Ĉu vi fidas {domainsCount, plural, one {tiun servilon} other {tiujn servilojn}}? Mesaĝa privateco funkcias nur en aperaĵoj de Mastodon. Se {domains} {domainsCount, plural, one {ne estas aperaĵo de Mastodon} other {ne estas aperaĵoj de Mastodon}}, estos neniu indiko ke via mesaĝo estas privata, kaj ĝi povus esti diskonigita aŭ videbligita al necelitaj ricevantoj.",
+ "compose_form.unlisted": "Ne afiŝi en publikaj tempolinioj",
+ "navigation_bar.edit_profile": "Redakti la profilon",
+ "navigation_bar.preferences": "Preferoj",
+ "navigation_bar.community_timeline": "Loka tempolinio",
+ "navigation_bar.public_timeline": "Fratara tempolinio",
+ "navigation_bar.logout": "Elsaluti",
+ "reply_indicator.cancel": "Rezigni",
+ "search.placeholder": "Serĉi",
+ "search.account": "Konto",
+ "search.hashtag": "Kradvorto",
+ "upload_button.label": "Aldoni enhavaĵon",
+ "upload_form.undo": "Malfari",
+ "notification.follow": "{name} sekvis vin",
+ "notification.favourite": "{name} favoris vian mesaĝon",
+ "notification.reblog": "{name} diskonigis vian mesaĝon",
+ "notification.mention": "{name} menciis vin",
+ "notifications.column_settings.alert": "Retumilaj atentigoj",
+ "notifications.column_settings.show": "Montri en kolono",
+ "notifications.column_settings.follow": "Novaj sekvantoj:",
+ "notifications.column_settings.favourite": "Favoroj:",
+ "notifications.column_settings.mention": "Mencioj:",
+ "notifications.column_settings.reblog": "Diskonigoj:",
+};
+
+export default eo;
diff --git a/app/assets/javascripts/components/locales/fr.jsx b/app/assets/javascripts/components/locales/fr.jsx
index 23fa9349..fdd9c0e0 100644
--- a/app/assets/javascripts/components/locales/fr.jsx
+++ b/app/assets/javascripts/components/locales/fr.jsx
@@ -10,6 +10,10 @@ const fr = {
"status.reblogged_by": "{name} a partagé :",
"status.sensitive_warning": "Contenu délicat",
"status.sensitive_toggle": "Cliquer pour dévoiler",
+ "status.show_more": "Déplier",
+ "status.show_less": "Replier",
+ "status.open": "Déplier ce status",
+ "status.report": "Signaler @{name}",
"video_player.toggle_sound": "Mettre/Couper le son",
"account.mention": "Mentionner",
"account.edit_profile": "Modifier le profil",
@@ -35,7 +39,6 @@ const fr = {
"column.community": "Fil public local",
"column.public": "Fil public global",
"column.notifications": "Notifications",
- "column.public": "Fil public",
"column.blocks": "Utilisateurs bloqués",
"column.favourites": "Favoris",
"tabs_bar.compose": "Composer",
@@ -44,9 +47,9 @@ const fr = {
"tabs_bar.public": "Fil public global",
"tabs_bar.notifications": "Notifications",
"compose_form.placeholder": "Qu’avez-vous en tête ?",
- "compose_form.publish": "Pouet ",
+ "compose_form.publish": "Pouet",
"compose_form.sensitive": "Marquer le média comme délicat",
- "compose_form.spoiler": "Masquer le texte par un avertissement",
+ "compose_form.spoiler": "Masquer le texte derrière un avertissement",
"compose_form.private": "Rendre privé",
"compose_form.privacy_disclaimer": "Votre statut privé va être transmis aux personnes mentionnées sur {domains}. Avez-vous confiance en {domainsCount, plural, one {ce serveur} other {ces serveurs}} pour ne pas divulguer votre statut ? Les statuts privés ne fonctionnent que sur les instances de Mastodons. Si {domains} {domainsCount, plural, one {n'est pas une instance de Mastodon} other {ne sont pas des instances de Mastodon}}, il n'y aura aucune indication que votre statut est privé, et il pourrait être partagé ou rendu visible d'une autre manière à d'autres personnes imprévues",
"compose_form.unlisted": "Ne pas afficher dans les fils publics",
@@ -58,7 +61,6 @@ const fr = {
"navigation_bar.blocks": "Utilisateurs bloqués",
"navigation_bar.favourites": "Favoris",
"navigation_bar.info": "Plus d'informations",
- "notification.favourite": "{name} a ajouté à ses favoris :",
"navigation_bar.logout": "Déconnexion",
"reply_indicator.cancel": "Annuler",
"search.placeholder": "Chercher",
diff --git a/app/assets/javascripts/components/locales/index.jsx b/app/assets/javascripts/components/locales/index.jsx
index 72b8a5df..1e7b8b54 100644
--- a/app/assets/javascripts/components/locales/index.jsx
+++ b/app/assets/javascripts/components/locales/index.jsx
@@ -6,6 +6,7 @@ import fr from './fr';
import pt from './pt';
import uk from './uk';
import fi from './fi';
+import eo from './eo';
const locales = {
en,
@@ -15,7 +16,8 @@ const locales = {
fr,
pt,
uk,
- fi
+ fi,
+ eo
};
export default function getMessagesForLocale (locale) {
diff --git a/app/assets/stylesheets/components.scss b/app/assets/stylesheets/components.scss
index d233b347..696e8941 100644
--- a/app/assets/stylesheets/components.scss
+++ b/app/assets/stylesheets/components.scss
@@ -1,5 +1,9 @@
@import 'variables';
+.app-body{
+ -ms-overflow-style: -ms-autohiding-scrollbar;
+}
+
.button {
background-color: darken($color4, 3%);
font-family: inherit;
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index f00f9c1e..61ca7112 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -1,14 +1,13 @@
# frozen_string_literal: true
class ApplicationController < ActionController::Base
- include Localized
-
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
force_ssl if: "Rails.env.production? && ENV['LOCAL_HTTPS'] == 'true'"
+ include Localized
helper_method :current_account
rescue_from ActionController::RoutingError, with: :not_found
@@ -41,7 +40,6 @@ class ApplicationController < ActionController::Base
# If the sign in is after a two week break, we need to regenerate their feed
RegenerationWorker.perform_async(current_user.account_id) if current_user.last_sign_in_at < 14.days.ago
- return
end
def check_suspension
diff --git a/app/controllers/concerns/localized.rb b/app/controllers/concerns/localized.rb
index b6f86809..6528ce45 100644
--- a/app/controllers/concerns/localized.rb
+++ b/app/controllers/concerns/localized.rb
@@ -4,13 +4,25 @@ module Localized
extend ActiveSupport::Concern
included do
- before_action :set_locale
+ around_action :set_locale
end
+ private
+
def set_locale
- I18n.locale = current_user.try(:locale) || default_locale
- rescue I18n::InvalidLocale
- I18n.locale = default_locale
+ locale = default_locale
+
+ if user_signed_in?
+ begin
+ locale = current_user.try(:locale) || default_locale
+ rescue I18n::InvalidLocale
+ locale = default_locale
+ end
+ end
+
+ I18n.with_locale(locale) do
+ yield
+ end
end
def default_locale
diff --git a/app/controllers/oauth/authorizations_controller.rb b/app/controllers/oauth/authorizations_controller.rb
index cdbfde0f..e9cdf9fa 100644
--- a/app/controllers/oauth/authorizations_controller.rb
+++ b/app/controllers/oauth/authorizations_controller.rb
@@ -1,13 +1,13 @@
# frozen_string_literal: true
class Oauth::AuthorizationsController < Doorkeeper::AuthorizationsController
- include Localized
-
skip_before_action :authenticate_resource_owner!
before_action :store_current_location
before_action :authenticate_resource_owner!
+ include Localized
+
private
def store_current_location
diff --git a/app/controllers/oauth/authorized_applications_controller.rb b/app/controllers/oauth/authorized_applications_controller.rb
index 09dd5d3c..395fbc51 100644
--- a/app/controllers/oauth/authorized_applications_controller.rb
+++ b/app/controllers/oauth/authorized_applications_controller.rb
@@ -1,13 +1,13 @@
# frozen_string_literal: true
class Oauth::AuthorizedApplicationsController < Doorkeeper::AuthorizedApplicationsController
- include Localized
-
skip_before_action :authenticate_resource_owner!
before_action :store_current_location
before_action :authenticate_resource_owner!
+ include Localized
+
private
def store_current_location
diff --git a/app/helpers/settings_helper.rb b/app/helpers/settings_helper.rb
index e01f7d0c..74dc0e11 100644
--- a/app/helpers/settings_helper.rb
+++ b/app/helpers/settings_helper.rb
@@ -11,6 +11,7 @@ module SettingsHelper
uk: 'Українська',
'zh-CN': '简体中文',
fi: 'Suomi',
+ eo: 'Esperanto',
}.freeze
def human_locale(locale)
diff --git a/app/helpers/site_title_helper.rb b/app/helpers/site_title_helper.rb
new file mode 100644
index 00000000..d2caa920
--- /dev/null
+++ b/app/helpers/site_title_helper.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+module SiteTitleHelper
+ def site_title
+ Setting.site_title.to_s
+ end
+end
diff --git a/app/helpers/stream_entries_helper.rb b/app/helpers/stream_entries_helper.rb
index a26e912a..38e63ed8 100644
--- a/app/helpers/stream_entries_helper.rb
+++ b/app/helpers/stream_entries_helper.rb
@@ -34,10 +34,6 @@ module StreamEntriesHelper
user_signed_in? && @favourited.key?(status.id) ? 'favourited' : ''
end
- def proper_status(status)
- status.reblog? ? status.reblog : status
- end
-
def rtl?(text)
return false if text.empty?
diff --git a/app/lib/atom_serializer.rb b/app/lib/atom_serializer.rb
index be1cced8..b9dcee6b 100644
--- a/app/lib/atom_serializer.rb
+++ b/app/lib/atom_serializer.rb
@@ -328,7 +328,7 @@ class AtomSerializer
def serialize_status_attributes(entry, status)
append_element(entry, 'summary', status.spoiler_text) unless status.spoiler_text.blank?
- append_element(entry, 'content', Formatter.instance.format(status.reblog? ? status.reblog : status).to_str, type: 'html')
+ append_element(entry, 'content', Formatter.instance.format(status.proper).to_str, type: 'html')
status.mentions.each do |mentioned|
append_element(entry, 'link', nil, rel: :mentioned, 'ostatus:object-type': TagManager::TYPES[:person], href: TagManager.instance.uri_for(mentioned.account))
diff --git a/app/models/account.rb b/app/models/account.rb
index 6968607a..cbba8b5b 100644
--- a/app/models/account.rb
+++ b/app/models/account.rb
@@ -125,11 +125,11 @@ class Account < ApplicationRecord
end
def favourited?(status)
- (status.reblog? ? status.reblog : status).favourites.where(account: self).count.positive?
+ status.proper.favourites.where(account: self).count.positive?
end
def reblogged?(status)
- (status.reblog? ? status.reblog : status).reblogs.where(account: self).count.positive?
+ status.proper.reblogs.where(account: self).count.positive?
end
def keypair
diff --git a/app/models/status.rb b/app/models/status.rb
index 6948ad77..7e3dd3e2 100644
--- a/app/models/status.rb
+++ b/app/models/status.rb
@@ -62,8 +62,12 @@ class Status < ApplicationRecord
reply? ? :comment : :note
end
+ def proper
+ reblog? ? reblog : self
+ end
+
def content
- reblog? ? reblog.text : text
+ proper.text
end
def target
diff --git a/app/services/follow_remote_account_service.rb b/app/services/follow_remote_account_service.rb
index 93695342..443c9c70 100644
--- a/app/services/follow_remote_account_service.rb
+++ b/app/services/follow_remote_account_service.rb
@@ -20,8 +20,6 @@ class FollowRemoteAccountService < BaseService
Rails.logger.debug "Looking up webfinger for #{uri}"
- account = Account.new(username: username, domain: domain)
-
data = Goldfinger.finger("acct:#{uri}")
raise Goldfinger::Error, 'Missing resource links' if data.link('http://schemas.google.com/g/2010#updates-from').nil? || data.link('salmon').nil? || data.link('http://webfinger.net/rel/profile-page').nil? || data.link('magic-public-key').nil?
@@ -37,6 +35,7 @@ class FollowRemoteAccountService < BaseService
domain_block = DomainBlock.find_by(domain: domain)
+ account = Account.new(username: confirmed_username, domain: confirmed_domain)
account.remote_url = data.link('http://schemas.google.com/g/2010#updates-from').href
account.salmon_url = data.link('salmon').href
account.url = data.link('http://webfinger.net/rel/profile-page').href
@@ -51,8 +50,8 @@ class FollowRemoteAccountService < BaseService
account.uri = get_account_uri(xml)
account.hub_url = hubs.first.attribute('href').value
- get_profile(body, account)
account.save!
+ get_profile(body, account)
account
end
diff --git a/app/services/post_status_service.rb b/app/services/post_status_service.rb
index b8179f7d..221aa42a 100644
--- a/app/services/post_status_service.rb
+++ b/app/services/post_status_service.rb
@@ -37,11 +37,11 @@ class PostStatusService < BaseService
def validate_media!(media_ids)
return if media_ids.nil? || !media_ids.is_a?(Enumerable)
- raise Mastodon::ValidationError, 'Cannot attach more than 4 files' if media_ids.size > 4
+ raise Mastodon::ValidationError, I18n.t('media_attachments.validations.too_many') if media_ids.size > 4
media = MediaAttachment.where(status_id: nil).where(id: media_ids.take(4).map(&:to_i))
- raise Mastodon::ValidationError, 'Cannot attach a video to a toot that already contains images' if media.size > 1 && media.find(&:video?)
+ raise Mastodon::ValidationError, I18n.t('media_attachments.validations.images_and_video') if media.size > 1 && media.find(&:video?)
media
end
diff --git a/app/views/about/index.html.haml b/app/views/about/index.html.haml
index ebca4213..f6b0c166 100644
--- a/app/views/about/index.html.haml
+++ b/app/views/about/index.html.haml
@@ -5,7 +5,7 @@
= Rails.configuration.x.local_domain
- content_for :header_tags do
- %meta{ property: 'og:site_name', content: 'Mastodon' }/
+ %meta{ property: 'og:site_name', content: site_title }/
%meta{ property: 'og:type', content: 'website' }/
%meta{ property: 'og:title', content: Rails.configuration.x.local_domain }/
%meta{ property: 'og:description', content: @description.blank? ? "Mastodon is a free, open-source social network server. A decentralized alternative to commercial platforms, it avoids the risks of a single company monopolizing your communication. Anyone can run Mastodon and participate in the social network seamlessly" : strip_tags(@description) }/
diff --git a/app/views/accounts/show.html.haml b/app/views/accounts/show.html.haml
index 3b8c67b4..e9089772 100644
--- a/app/views/accounts/show.html.haml
+++ b/app/views/accounts/show.html.haml
@@ -5,7 +5,7 @@
%link{ rel: 'salmon', href: api_salmon_url(@account.id) }/
%link{ rel: 'alternate', type: 'application/atom+xml', href: account_url(@account, format: 'atom') }/
- %meta{ property: 'og:site_name', content: 'Mastodon' }/
+ %meta{ property: 'og:site_name', content: site_title }/
%meta{ property: 'og:type', content: 'profile' }/
%meta{ property: 'og:title', content: "#{@account.username} on #{Rails.configuration.x.local_domain}" }/
%meta{ property: 'og:description', content: @account.note }/
diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml
index abab14a2..e8253bd6 100644
--- a/app/views/layouts/application.html.haml
+++ b/app/views/layouts/application.html.haml
@@ -15,7 +15,7 @@
- if content_for?(:page_title)
= yield(:page_title)
= ' - '
- = Setting.site_title
+ = site_title
= stylesheet_link_tag 'application', media: 'all'
= csrf_meta_tags
diff --git a/app/views/stream_entries/_status.html.haml b/app/views/stream_entries/_status.html.haml
index cdd0dde3..434c5c8d 100644
--- a/app/views/stream_entries/_status.html.haml
+++ b/app/views/stream_entries/_status.html.haml
@@ -16,7 +16,7 @@
%strong= display_name(status.account)
= t('stream_entries.reblogged')
- = render partial: centered ? 'stream_entries/detailed_status' : 'stream_entries/simple_status', locals: { status: proper_status(status) }
+ = render partial: centered ? 'stream_entries/detailed_status' : 'stream_entries/simple_status', locals: { status: status.proper }
- if include_threads
= render partial: 'stream_entries/status', collection: @descendants, as: :status, locals: { is_successor: true }
diff --git a/app/views/stream_entries/show.html.haml b/app/views/stream_entries/show.html.haml
index c109ff4b..088881b1 100644
--- a/app/views/stream_entries/show.html.haml
+++ b/app/views/stream_entries/show.html.haml
@@ -2,7 +2,7 @@
%link{ rel: 'alternate', type: 'application/atom+xml', href: account_stream_entry_url(@account, @stream_entry, format: 'atom') }/
%link{ rel: 'alternate', type: 'application/json+oembed', href: api_oembed_url(url: account_stream_entry_url(@account, @stream_entry), format: 'json') }/
- %meta{ property: 'og:site_name', content: 'Mastodon' }/
+ %meta{ property: 'og:site_name', content: site_title }/
%meta{ property: 'og:type', content: 'article' }/
%meta{ property: 'og:title', content: "#{@account.username} on #{Rails.configuration.x.local_domain}" }/
diff --git a/app/views/user_mailer/confirmation_instructions.fr.html.erb b/app/views/user_mailer/confirmation_instructions.fr.html.erb
new file mode 100644
index 00000000..2665f1a2
--- /dev/null
+++ b/app/views/user_mailer/confirmation_instructions.fr.html.erb
@@ -0,0 +1,5 @@
+
Bienvenue <%= @resource.email %> !
+
+
Vous pouvez confirmer l'email de votre compte Mastodon en cliquant sur le lien ci-dessous :
+
+
<%= link_to 'Confirmer mon compte', confirmation_url(@resource, confirmation_token: @token) %>
diff --git a/app/views/user_mailer/confirmation_instructions.fr.text.erb b/app/views/user_mailer/confirmation_instructions.fr.text.erb
new file mode 100644
index 00000000..9d33450f
--- /dev/null
+++ b/app/views/user_mailer/confirmation_instructions.fr.text.erb
@@ -0,0 +1,5 @@
+Bienvenue <%= @resource.email %> !
+
+Vous pouvez confirmer l'email de votre compte Mastodon en cliquant sur le lien ci-dessous :
+
+<%= confirmation_url(@resource, confirmation_token: @token) %>
diff --git a/app/views/user_mailer/password_change.fr.html.erb b/app/views/user_mailer/password_change.fr.html.erb
new file mode 100644
index 00000000..cb8a261f
--- /dev/null
+++ b/app/views/user_mailer/password_change.fr.html.erb
@@ -0,0 +1,3 @@
+
Bonjour <%= @resource.email %> !
+
+
Nous vous contactons pour vous informer que votre mot de passe sur Mastodon a bien été modifié.
diff --git a/app/views/user_mailer/password_change.fr.text.erb b/app/views/user_mailer/password_change.fr.text.erb
new file mode 100644
index 00000000..f068f1cd
--- /dev/null
+++ b/app/views/user_mailer/password_change.fr.text.erb
@@ -0,0 +1,3 @@
+Bonjour <%= @resource.email %> !
+
+Nous vous contactons pour vous informer que votre mot de passe sur Mastodon a bien été modifié.
diff --git a/app/views/user_mailer/reset_password_instructions.fr.html.erb b/app/views/user_mailer/reset_password_instructions.fr.html.erb
new file mode 100644
index 00000000..95789e38
--- /dev/null
+++ b/app/views/user_mailer/reset_password_instructions.fr.html.erb
@@ -0,0 +1,8 @@
+
Bonjour <%= @resource.email %> !
+
+
Quelqu'un a demandé à réinitialiser votre mot de passe sur Mastodon. Vous pouvez effectuer la réinitialisation en cliquant sur le lien ci-dessous.
+
+
<%= link_to 'Modifier mon mot de passe', edit_password_url(@resource, reset_password_token: @token) %>
+
+
Si vous n'êtes pas à l'origine de cette demande, vous pouvez ignorer ce message.
+
Votre mot de passe ne sera pas modifié tant que vous n'accéderez pas au lien ci-dessus et n'en choisirez pas un nouveau.
diff --git a/app/views/user_mailer/reset_password_instructions.fr.text.erb b/app/views/user_mailer/reset_password_instructions.fr.text.erb
new file mode 100644
index 00000000..73160cb4
--- /dev/null
+++ b/app/views/user_mailer/reset_password_instructions.fr.text.erb
@@ -0,0 +1,8 @@
+Bonjour <%= @resource.email %> !
+
+Quelqu'un a demandé à réinitialiser votre mot de passe sur Mastodon. Vous pouvez effectuer la réinitialisation en cliquant sur le lien ci-dessous.
+
+<%= edit_password_url(@resource, reset_password_token: @token) %>
+
+Si vous n'êtes pas à l'origine de cette demande, vous pouvez ignorer ce message.
+Votre mot de passe ne sera pas modifié tant que vous n'accéderez pas au lien ci-dessus et n'en choisirez pas un nouveau.
diff --git a/config/application.rb b/config/application.rb
index 17b7a19c..9a5c0d0d 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -24,7 +24,7 @@ module Mastodon
# The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
# config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
- config.i18n.available_locales = [:en, :de, :es, :pt, :fr, :hu, :uk, 'zh-CN', :fi]
+ config.i18n.available_locales = [:en, :de, :es, :pt, :fr, :hu, :uk, 'zh-CN', :fi, :eo]
config.i18n.default_locale = :en
# config.paths.add File.join('app', 'api'), glob: File.join('**', '*.rb')
diff --git a/config/locales/de.yml b/config/locales/de.yml
index d44845c6..ed54bb69 100644
--- a/config/locales/de.yml
+++ b/config/locales/de.yml
@@ -7,8 +7,8 @@ de:
terms: AGB
accounts:
follow: Folgen
- followers: Follower
- following: Gefolgt
+ followers: Folger
+ following: Folgt
nothing_here: Hier gibt es nichts!
people_followed_by: Nutzer, denen %{name} folgt
people_who_follow: Nutzer, die %{name} folgen
diff --git a/config/locales/devise.eo.yml b/config/locales/devise.eo.yml
new file mode 100644
index 00000000..b786647d
--- /dev/null
+++ b/config/locales/devise.eo.yml
@@ -0,0 +1,61 @@
+---
+eo:
+ devise:
+ confirmations:
+ confirmed: Via konto estas konfirmita.
+ send_instructions: Vi ricevos instrukciojn por konfirmi vian konton post kelkaj minutoj.
+ send_paranoid_instructions: Se via retpoŝt-adreso ekzistas en nia datumbazo, vi baldaŭ ricevos retpoŝt-mesaĝon, kiu enhavas la instrukciojn por konfirmi vian konton.
+ failure:
+ already_authenticated: Vi jam estas ensalutita.
+ inactive: Via konto ankoraŭ ne estas konfirmita.
+ invalid: Malĝusta retpoŝt-adreso aŭ pasvorto.
+ last_attempt: Vi ankoraŭ povas provi unufoje antaŭ ol via konto estos ŝlosita.
+ locked: Via konto estas ŝlosita.
+ not_found_in_database: Malĝusta retpoŝt-adreso aŭ pasvorto.
+ timeout: Via sesio eksiĝis. Bonvolu reensaluti por daŭrigi.
+ unauthenticated: Vi devas ensaluti aŭ membriĝi por daŭrigi.
+ unconfirmed: Vi devas konfirmi vian konton por daŭrigi.
+ mailer:
+ confirmation_instructions:
+ subject: Instrukcioj por konfirmi
+ password_change:
+ subject: Via pasvorto estis ŝanĝita senprobleme.
+ reset_password_instructions:
+ subject: Instrukcioj por ŝanĝi la pasvorton
+ unlock_instructions:
+ subject: Instrukcioj por malŝlosi la konton
+ omniauth_callbacks:
+ failure: 'Ni ne povis aŭtentigi vin per %{kind}: ''%{reason}''.'
+ success: Aŭtentigita senprobleme per %{kind}.
+ passwords:
+ no_token: Vi ne povas iri al tiu paĝo per alia vojo ol retpoŝt-mesaĝo por ŝanĝi pasvorton. Se vi venas de tia retpoŝt-mesaĝo, kontrolu ke vi uzis la tutan URL.
+ send_instructions: Vi ricevos retpoŝt-mesaĝon kun instrukcioj por ŝanĝi vian pasvorton post kelkaj minutoj.
+ send_paranoid_instructions: Se via retpoŝt-adreso ekzistas en nia datumbazo, vi ricevos ligilon por ŝanĝi vian pasvorton per retpoŝt-mesaĝo.
+ updated: Via pasvorto estis redaktita senprobleme, vi nun estas ensalutita.
+ updated_not_active: Via pasvorto estis redaktita senprobleme.
+ registrations:
+ destroyed: Ĝis! Via konto estis forigita senprobleme. Ni esperas revidi vin baldaŭ.
+ signed_up: Bonvenon! Vi membriĝis senprobleme.
+ signed_up_but_inactive: Vi bone membriĝis, sed vi ankoraŭ ne povas ensaluti ĉar via konto ne estis konfirmita.
+ signed_up_but_locked: Vi bone membriĝis, sed vi ne povas ensaluti ĉar via konto estas ŝlosita.
+ signed_up_but_unconfirmed: Retpoŝt-mesaĝo kun via ligilo por konfirmi vian konton estis sendita al via retpoŝt-adreso. Bonvolu uzi tiun ligilon por konfirmi vian konton.
+ update_needs_confirmation: Vi bone aktualigis vian konton, sed ni bezonas kontroli vian novan retpoŝt-adreson. Bonvolu kontroli viajn retpoŝt-mesaĝojn kaj uzi la ligilon por konfirmi vian novan retpoŝt-adreson.
+ updated: Via konto estis aktualigita senprobleme.
+ sessions:
+ already_signed_out: Elsalutita.
+ signed_in: Ensalutita.
+ signed_out: Elsalutita.
+ unlocks:
+ send_instructions: Vi ricevos retpoŝt-mesaĝon kun instrukcioj por malŝlosi vian konton post kelkaj minutoj.
+ send_paranoid_instructions: Se via retpoŝt-adreso ekzistas en nia datumbazo, vi ricevos ligilon por malŝlosi vian konton per retpoŝt-mesaĝo.
+ unlocked: Via konto estis malŝlosita senprobleme, vi nun estas ensalutita.
+ errors:
+ messages:
+ already_confirmed: jam estis konfirmita, bonvolu provi ensaluti
+ confirmation_period_expired: devas esti konfirmita en %{period}, bonvolu repeti
+ expired: eksiĝis, bonvolu repeti
+ not_found: ne estis trovita
+ not_locked: ne estis ŝlosita
+ not_saved:
+ one: '1 eraro malpermesis al tiu %{resource} esti konservita:'
+ other: '%{count} eraroj malpermesis al tiu %{resource} esti konservita:'
diff --git a/config/locales/doorkeeper.eo.yml b/config/locales/doorkeeper.eo.yml
new file mode 100644
index 00000000..33cc7cc1
--- /dev/null
+++ b/config/locales/doorkeeper.eo.yml
@@ -0,0 +1,113 @@
+---
+eo:
+ activerecord:
+ attributes:
+ doorkeeper/application:
+ name: Nomo
+ redirect_uri: URI de plusendo
+ errors:
+ models:
+ doorkeeper/application:
+ attributes:
+ redirect_uri:
+ fragment_present: ne povas enhavi eron.
+ invalid_uri: devas esti valida URI.
+ relative_uri: devas esti absoluta URI.
+ secured_uri: devas esti HTTPS/SSL-a URI.
+ doorkeeper:
+ applications:
+ buttons:
+ authorize: Rajtigi
+ cancel: Rezigni
+ destroy: Detrui
+ edit: Redakti
+ submit: Sendi
+ confirmations:
+ destroy: Ĉu vi certas?
+ edit:
+ title: Redakti aplikaĵon
+ form:
+ error: Ups! Kontrolu vian formularon ĉu estas eraroj
+ help:
+ native_redirect_uri: Uzu %{native_redirect_uri} por lokaj provoj
+ redirect_uri: Uzu unu linion por ĉiu URI
+ scopes: Apartigu ampleksojn per spacetoj. Lasu malplena por uzi la senŝanĝajn ampleksojn.
+ index:
+ callback_url: URL vokita per referenco
+ name: Nomo
+ new: Nova Aplikaĵo
+ title: Viaj aplikaĵoj
+ new:
+ title: Nova aplikaĵo
+ show:
+ actions: Agoj
+ application_id: Identigo de la aplikaĵo
+ callback_urls: URL-j vokitaj per referenco
+ scopes: Ampleksoj
+ secret: Sekreto
+ title: 'Aplikaĵo: %{name}'
+ authorizations:
+ buttons:
+ authorize: Rajtigi
+ deny: Rifuzi
+ error:
+ title: Eraro okazis
+ new:
+ able_to: Povos
+ prompt: La aplikaĵo %{client_name} petas aliron al via konto
+ title: Rajtigo bezonata
+ show:
+ title: Rajtiga kodo
+ authorized_applications:
+ buttons:
+ revoke: Malrajtigi
+ confirmations:
+ revoke: Ĉu vi certas?
+ index:
+ application: Aplikaĵo
+ created_at: Rajtigita
+ date_format: "%Y-%m-%d %H:%M:%S"
+ scopes: Ampleksoj
+ title: Viaj rajtigitaj aplikaĵoj
+ errors:
+ messages:
+ access_denied: La posedanto de la rimedo aŭ la rajtiga servilo rifuzis vian peton.
+ credential_flow_not_configured: La sendado de la identigiloj de la posedanto de la rimedo malsukcesis ĉar Doorkeeper.configure.resource_owner_from_credentials ne estis agordita.
+ invalid_client: La aŭtentigo de la kliento malsukcesis ĉar la kliento estas nekonata, aŭ mankis peto aŭtentigi, aŭ la aŭtentig-metodo ne estas subtenata.
+ invalid_grant: La rajtiga konsento ne estas valida, ne plu estas valida, estis forigita, ne kongruas kun la plusenda URI uzita en la aŭtentiga peto, aŭ estis sendita al alia kliento.
+ invalid_redirect_uri: La plusenda URI uzita en estas valida.
+ invalid_request: Mankis al la peto nepra parametro, enhavas nesubtenatan parametran valoron, aŭ la peto simple estas misformita.
+ invalid_resource_owner: La donitaj identigiloj pri la posedanto de la rimedo ne estas validaj, aŭ tiu ne povas esti trovita.
+ invalid_scope: La petita amplekso ne estas valida, estas nekonata, aŭ estas misformita.
+ invalid_token:
+ expired: La atingoĵetono eskiĝis.
+ revoked: La atingoĵetono estis rifuzita.
+ unknown: La atingoĵetono ne estas valida.
+ resource_owner_authenticator_not_configured: La posedanto de la rimedo ne povis esti trovita ĉar Doorkeeper.configure.resource_owner_authenticator ne estas agordita.
+ server_error: La rajtiga servilo rimarkis neatenditan kondiĉon, kiu malpermesis al ĝi plenumi la peton.
+ temporarily_unavailable: La rajtiga servilo ne povas nun plenumi la peton pro dumtempa superŝarĝo aŭ prizorgado de la servilo.
+ unauthorized_client: La kliento ne rajtas fari tian peton uzante tiun metodon.
+ unsupported_grant_type: La tipo de la rajtiga konsento ne estas subtenata de la rajtiga servilo.
+ unsupported_response_type: La rajtiga servilo ne subtenas tian respondon.
+ flash:
+ applications:
+ create:
+ notice: Aplikaĵo kreita.
+ destroy:
+ notice: Aplikaĵo forigita.
+ update:
+ notice: Aplikaĵo aktualigita.
+ authorized_applications:
+ destroy:
+ notice: Aplikaĵo malrajtigita.
+ layouts:
+ admin:
+ nav:
+ applications: Aplikaĵoj
+ oauth2_provider: OAuth2-provizanto
+ application:
+ title: OAuth-a rajtigo bezonata
+ scopes:
+ follow: sekvi, bloki, malbloki kaj malsekvi kontojn
+ read: legi la datumojn de via konto
+ write: mesaĝi kiel vi
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 742219df..aa3a732f 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -163,3 +163,7 @@ en:
invalid_otp_token: Invalid two-factor code
will_paginate:
page_gap: "…"
+ media_attachments:
+ validations:
+ too_many: Cannot attach more than 4 files
+ images_and_video: Cannot attach a video to a status that already contains images
diff --git a/config/locales/eo.yml b/config/locales/eo.yml
new file mode 100644
index 00000000..3644b37b
--- /dev/null
+++ b/config/locales/eo.yml
@@ -0,0 +1,164 @@
+---
+eo:
+ about:
+ about_mastodon: Mastodon estas
senpaga, malfermitkoda socia reto. Ĝi estas
sencentra alia eblo al komercaj servoj. Ĝi evitigas, ke unusola firmao regu vian tutan komunikadon. Elektu servilon, kiun vi fidas. Kiu ajn estas via elekto, vi povas interagi kun ĉiuj aliaj uzantoj. Iu ajn povas krei sian propran aperaĵon de Mastodon en sia servilo, kaj partopreni en la
socia reto tute glate.
+ about_this: Pri tiu aperaĵo
+ apps: Aplikaĵoj
+ business_email: 'Profesia retpoŝt-adreso:'
+ contact: Kontakti
+ description_headline: Kio estas %{domain}?
+ domain_count_after: aliaj aperaĵoj
+ domain_count_before: Konektita al
+ features:
+ api: Malfermita API por aplikaĵoj kaj servoj
+ blocks: Kompletaj iloj por bloki kaj kaŝi
+ characters: Po 500 signoj por ĉiu mesaĝo
+ chronology: Tempolinioj laŭtempaj
+ ethics: 'Etike kreita: neniu reklamo, neniu ŝpurado'
+ gifv: Eblo diskonigi etajn videojn kaj GIFV
+ privacy: Videbleco agordita laŭ la mesaĝo
+ public: Publikaj tempolinioj
+ features_headline: Kiel Mastodon estas malsimila
+ get_started: Komenci
+ links: Ligiloj
+ other_instances: Aliaj aperaĵoj
+ source_code: Fontkodo
+ status_count_after: mesaĝoj
+ status_count_before: Kiu publikigis
+ terms: Terms
+ user_count_after: uzantoj
+ user_count_before: Hejmo de
+ accounts:
+ follow: Sekvi
+ followers: Sekvantoj
+ following: Sekvatoj
+ nothing_here: Estas nenio ĉi tie!
+ people_followed_by: Sekvatoj de %{name}
+ people_who_follow: Sekvantoj de %{name}
+ posts: Mesaĝoj
+ remote_follow: Fore sekvi
+ unfollow: Malsekvi
+ application_mailer:
+ settings: 'Ŝanĝi la retpoŝt-mesaĝajn preferojn: %{link}'
+ signature: Sciigoj de Mastodon el %{instance}
+ view: 'Vidi:'
+ applications:
+ invalid_url: La URL donita ne estas valida
+ auth:
+ change_password: Ŝanĝi pasvorton
+ didnt_get_confirmation: Ĉu vi ne ricevis la instrukciojn por konfirmi?
+ forgot_password: Pasvorto forgesita?
+ login: Ensaluti
+ logout: Elsaluti
+ register: Membriĝi
+ resend_confirmation: Resendi la instrukciojn por konfirmi
+ reset_password: Ŝanĝi la pasvorton
+ set_new_password: Elekti novan pasvorton
+ authorize_follow:
+ error: Bedaŭrinde, okazis eraro provante konsulti la foran konton
+ follow: Sekvi
+ prompt_html: 'Vi (
%{self}) petis sekvi:'
+ title: Sekvi %{acct}
+ datetime:
+ distance_in_words:
+ about_x_hours: "%{count}h"
+ about_x_months: "%{count}mo"
+ about_x_years: "%{count}j"
+ almost_x_years: "%{count}j"
+ half_a_minute: Ĵus
+ less_than_x_minutes: "%{count}m"
+ less_than_x_seconds: Ĵus
+ over_x_years: "%{count}j"
+ x_days: "%{count}t"
+ x_minutes: "%{count}m"
+ x_months: "%{count}mo"
+ x_seconds: "%{count}s"
+ exports:
+ blocks: Vi blokas
+ csv: CSV
+ follows: Vi sekvas
+ storage: Mediaĵa konservado
+ generic:
+ changes_saved_msg: Ŝanĝoj senprobleme konservitaj!
+ powered_by: povigita de %{link}
+ save_changes: Konservi la ŝanĝojn
+ validation_errors:
+ one: Io ne okazis senprobleme! Bonvolu konsulti la suban erar-raporton.
+ other: Io ne okazis senprobleme! Bonvolu konsulti la subajn %{count} erar-raportojn.
+ imports:
+ preface: Vi povas alporti kelkajn datumojn, kiel listojn de ĉiuj homoj kiujn vi sekvas aŭ blokas, al via konto de ĉi tiu aperaĵo, per dosiero elportita de alia aperaĵo.
+ success: Viaj datumoj estis senprobleme alportitaj kaj estos traktitaj kiel planite.
+ types:
+ blocking: Listo de blokitoj
+ following: Listo de sekvatoj
+ upload: Alporti
+ landing_strip_html:
%{name} estas uzanto en
%{domain}. Vi povas sekvi tiun aŭ interagi kun tiu, se vi havas konton ie ajn en la Fediverse. Se vi ne havas, vi povas
membriĝi ĉi tie..
+ notification_mailer:
+ digest:
+ body: 'Jen eta resumo de tio, kio okazis en %{instance}, ekde kiam vi laste vizitis en %{since}:'
+ mention: "%{name} menciis vin en:"
+ new_followers_summary:
+ one: Vi ekhavis novan sekvanton! Jej!
+ other: Vi ekhavis %{count} novajn sekvantojn! Mirinde!
+ subject:
+ one: "1 nova sciigo ekde via lasta vizito \U0001F418"
+ other: "%{count} novaj sciigoj ekde via lasta vizito \U0001F418"
+ favourite:
+ body: '%{name} favoris vian mesaĝon:'
+ subject: "%{name} favoris vian mesaĝon"
+ follow:
+ body: "%{name} eksekvis vin:"
+ subject: "%{name} eksekvis vin"
+ follow_request:
+ body: "%{name} petis sekvi vin:"
+ subject: '%{name} petis sekvi vin'
+ mention:
+ body: '%{name} menciis vin en:'
+ subject: '%{name} menciis vin'
+ reblog:
+ body: '%{name} diskonigis vian mesaĝon:'
+ subject: "%{name} diskonigis vian mesaĝon"
+ pagination:
+ next: Sekva
+ prev: Malsekva
+ remote_follow:
+ acct: Enmetu vian uzantnomo@aperaĵo de kie vi volas sekvi tiun uzanton
+ missing_resource: La URL de plusendado ne povis esti trovita
+ proceed: Daŭrigi por plusendi
+ prompt: 'Vi eksekvos:'
+ settings:
+ authorized_apps: Rajtigitaj aplikaĵoj
+ back: Reveni al Mastodon
+ edit_profile: Redakti la profilon
+ export: Elporti datumojn
+ import: Alporti
+ preferences: Preferoj
+ settings: Agordoj
+ two_factor_auth: Dufaktora aŭtentigo
+ statuses:
+ open_in_web: Malfermi retumile
+ over_character_limit: limo de %{max} signoj trapasita
+ show_more: Montri pli
+ visibilities:
+ private: Montri nur al sekvantoj
+ public: Publika
+ unlisted: Publika, sed ne aperos en publikaj tempolinioj
+ stream_entries:
+ click_to_show: Alklaki por montri
+ reblogged: diskonigita
+ sensitive_content: Tikla enhavo
+ time:
+ formats:
+ default: "%b %d, %Y, %H:%M"
+ two_factor_auth:
+ description_html: Se vi ebligas
dufaktoran aŭtentigon, vi bezonos vian poŝtelefonon por ensaluti, ĉar ĝi kreos nombrojn, kiujn vi devos entajpi.
+ disable: Malebligi
+ enable: Ebligi
+ instructions_html: "
Skanu tiun QR-kodon per Google Authenticator aŭ per simila aplikaĵo de via poŝtelefono. De tiam, la aplikaĵo kreos nombrojn, kiujn vi devos entajpi."
+ plaintext_secret_html: 'Rekte legebla sekreta kodo:
%{secret}'
+ warning: Se vi ne povas agordi aŭtentigan aplikaĵon nun, elektu "malebligi" aŭ vi ne plu povos ensaluti.
+ users:
+ invalid_email: La retpoŝt-adreso ne estas valida
+ invalid_otp_token: La dufaktora aŭtentigila kodo ne estas valida
+ will_paginate:
+ page_gap: "…"
diff --git a/config/locales/fi.yml b/config/locales/fi.yml
index 947d3f64..56aa9df4 100644
--- a/config/locales/fi.yml
+++ b/config/locales/fi.yml
@@ -7,7 +7,7 @@ fi:
business_email: 'Business e-mail:'
contact: Ota yhteyttä
description_headline: Mikä on %{domain}?
- domain_count_after: muut palvelimet
+ domain_count_after: muuhun palvelimeen
domain_count_before: Yhdistyneenä
features:
api: Avoin API ohjelmille ja palveluille
diff --git a/config/locales/fr.yml b/config/locales/fr.yml
index e9989e38..9727f3b7 100644
--- a/config/locales/fr.yml
+++ b/config/locales/fr.yml
@@ -5,13 +5,14 @@ fr:
about_this: À propos de cette instance
apps: Applications
business_email: E-mail professionnel
- closed_registrations: Les inscriptions sont actuellement fermées sur cette instance. .
+ closed_registrations: Les inscriptions sont actuellement fermées sur cette instance.
+ contact: Contact
description_headline: Qu'est-ce que %{domain} ?
domain_count_after: autres instances
domain_count_before: Connectés à
features:
api: API ouverte aux apps et services
- blocking: Outils complets de bloquage et masquage
+ blocks: Outils complets de bloquage et masquage
characters: 500 caractères par post
chronology: Fil chronologique
ethics: 'Pas de pubs, pas de pistage'
@@ -21,6 +22,7 @@ fr:
features_headline: Ce qui rend Mastodon différent
get_started: Rejoindre le réseau
links: Liens
+ other_instances: Autres instances
source_code: Code source
status_count_after: posts
status_count_before: Ayant publié
@@ -54,9 +56,24 @@ fr:
reset_password: Réinitialiser le mot de passe
set_new_password: Définir le nouveau mot de passe
authorize_follow:
+ error: Malheureusement, il y a eu une erreur en cherchant les détails du compte distant
follow: Suivre
prompt_html: 'Vous (
%{self}) avez demandé à suivre:'
title: Suivre %{acct}
+ datetime:
+ distance_in_words:
+ about_x_hours: "%{count}h"
+ about_x_months: "%{count}mo"
+ about_x_years: "%{count}y"
+ almost_x_years: "%{count}y"
+ half_a_minute: A l'instant
+ less_than_x_minutes: "%{count}m"
+ less_than_x_seconds: A l'instant
+ over_x_years: "%{count}y"
+ x_days: "%{count}d"
+ x_minutes: "%{count}m"
+ x_months: "%{count}mo"
+ x_seconds: "%{count}s"
exports:
blocks: Vous bloquez
csv: CSV
@@ -93,6 +110,9 @@ fr:
follow:
body: "%{name} vous suit !"
subject: "%{name} vous suit"
+ follow_request:
+ body: "%{name} a demandé à vous suivre"
+ subject: 'Abonné⋅es en attente : %{name}'
mention:
body: "%{name} vous a mentionné⋅e dans :"
subject: "%{name} vous a mentionné⋅e"
@@ -132,7 +152,7 @@ fr:
formats:
default: '%d %b %Y, %H:%M'
two_factor_auth:
- description_html: Si vous activez
l'identification à deux facteurs vous devrez être en posession de votre téléphone afin de générer un code de connexion.
+ description_html: Si vous activez
l'identification à deux facteurs, vous devrez être en possession de votre téléphone afin de générer un code de connexion.
disable: Désactiver
enable: Activer
instructions_html: "
Scannez ce QR code grâce à Google Authenticator, Authy ou une application similaire sur votre téléphone. Désormais, cette application générera des jetons que vous devrez saisir à chaque connexion."
diff --git a/config/locales/simple_form.de.yml b/config/locales/simple_form.de.yml
index 614cd491..d9de9ea3 100644
--- a/config/locales/simple_form.de.yml
+++ b/config/locales/simple_form.de.yml
@@ -3,7 +3,7 @@ de:
simple_form:
hints:
defaults:
- locked: Erlaubt dir, Folger zu überprüfen, bevor sie dir folgen können
+ locked: Erlaubt dir, Nutzer zu überprüfen, bevor sie dir folgen können
labels:
defaults:
avatar: Avatar
@@ -11,16 +11,16 @@ de:
confirm_password: Passwort bestätigen
current_password: Derzeitiges Passwort
display_name: Anzeigename
- email: E-mail-Addresse
+ email: E-Mail-Addresse
header: Kopfbild
locale: Sprache
- locked: Gesperrter Profil
+ locked: Gesperrtes Profil
new_password: Neues Passwort
note: Über mich
password: Passwort
username: Nutzername
interactions:
- must_be_follower: Benachrichtigungen von nicht-Folgern blockieren
+ must_be_follower: Benachrichtigungen von Nicht-Folgern blockieren
must_be_following: Benachrichtigungen von Nutzern blockieren, denen ich nicht folge
notification_emails:
favourite: E-mail senden, wenn jemand meinen Beitrag favorisiert
diff --git a/config/locales/simple_form.eo.yml b/config/locales/simple_form.eo.yml
new file mode 100644
index 00000000..8c89a56e
--- /dev/null
+++ b/config/locales/simple_form.eo.yml
@@ -0,0 +1,46 @@
+---
+eo:
+ simple_form:
+ hints:
+ defaults:
+ avatar: En la formato PNG, GIF aŭ JPG. Ĝis 2Mo. Estos malgrandigita al 120x120px
+ display_name: 30 signoj pleje
+ header: En la formato PNG, GIF aŭ JPG. Ĝis 2Mo. Estos malgrandigita al 700x335px
+ locked: Vi devos aprobi ĉiun peton de sekvado, kaj viaj mesaĝoj estos senŝanĝe nur por viaj sekvantoj.
+ note: 160 signoj pleje
+ imports:
+ data: Dosiero CSV el alia aperaĵo de Mastodon
+ labels:
+ defaults:
+ avatar: Profilbildo
+ confirm_new_password: Konfirmi novan pasvorton
+ confirm_password: Konfirmi la pasvorton
+ current_password: Nuna pasvorto
+ data: Datumoj
+ display_name: Publika nomo
+ email: Retpoŝt-adreso
+ header: Kapbildo
+ locale: Lingvo
+ locked: Privatigi la konton
+ new_password: Nova pasvorto
+ note: Sinprezento
+ otp_attempt: Dufaktora identigilo
+ password: Pasvorto
+ setting_default_privacy: Videbleco de la mesaĝoj
+ type: Tipo de alportado
+ username: Uzantnomo
+ interactions:
+ must_be_follower: Kaŝi la sciigojn de homoj, kiuj ne sekvas vin
+ must_be_following: Kaŝi la sciigojn de homoj, kiujn vi ne sekas
+ notification_emails:
+ digest: Sendi resumajn retpoŝt-mesaĝojn
+ favourite: Sendi retpoŝt-mesaĝon, kiam iu favoras mesaĝon de vi
+ follow: Sendi retpoŝt-mesaĝon, kiam iu eksekvas vin
+ follow_request: Sendi retpoŝt-mesaĝon, kiam iu petas sekvi vin
+ mention: Sendi retpoŝt-mesaĝon, kiam iu mencias vin
+ reblog: Sendi retpoŝt-mesaĝon, kiam iu diskonigas mesaĝon de vi
+ 'no': 'Ne'
+ required:
+ mark: "*"
+ text: bezonata
+ 'yes': 'Jes'
diff --git a/config/locales/simple_form.fr.yml b/config/locales/simple_form.fr.yml
index fd037343..afcaeae8 100644
--- a/config/locales/simple_form.fr.yml
+++ b/config/locales/simple_form.fr.yml
@@ -33,7 +33,7 @@ fr:
must_be_follower: Masquer les notifications des personnes qui ne vous suivent pas
must_be_following: Masquer les notifications des personnes que vous ne suivez pas
notification_emails:
- digest: Envoyer des emails récapitulatifs
+ digest: Envoyer des courriels récapitulatifs
favourite: Envoyer un courriel lorsque quelqu’un ajoute mes statuts à ses favoris
follow: Envoyer un courriel lorsque quelqu’un me suit
follow_request: Envoyer un courriel lorsque quelqu'un demande à me suivre
diff --git a/docs/Contributing-to-Mastodon/Sponsors.md b/docs/Contributing-to-Mastodon/Sponsors.md
index 47579168..131f5fab 100644
--- a/docs/Contributing-to-Mastodon/Sponsors.md
+++ b/docs/Contributing-to-Mastodon/Sponsors.md
@@ -10,7 +10,7 @@ These people make the development of Mastodon possible through [Patreon](https:/
- [Kurtis Rainbolt-Greene](https://mastodon.social/users/krainboltgreene)
- [Kit Redgrave](https://socially.constructed.space/users/KitRedgrave)
- [Zeipher](https://mastodon.social/users/Zeipher)
-- [Effy Elden](https://toot.zone/users/effy)
+- [Effy Elden](https://mastodon.social/users/effy)
- [Zoë Quinn](https://mastodon.social/users/zoequinn)
**Thank you to the following people**
diff --git a/docs/Running-Mastodon/Administration-guide.md b/docs/Running-Mastodon/Administration-guide.md
index dd69eb30..09b0f1df 100644
--- a/docs/Running-Mastodon/Administration-guide.md
+++ b/docs/Running-Mastodon/Administration-guide.md
@@ -7,7 +7,7 @@ So, you have a working Mastodon instance... now what?
The following rake task:
- rake mastodon:make_admin USERNAME=alice
+ RAILS_ENV=production bundle exec rails mastodon:make_admin USERNAME=alice
Would turn the local user "alice" into an admin.
diff --git a/docs/Running-Mastodon/Heroku-guide.md b/docs/Running-Mastodon/Heroku-guide.md
index 0de26230..4978a20a 100644
--- a/docs/Running-Mastodon/Heroku-guide.md
+++ b/docs/Running-Mastodon/Heroku-guide.md
@@ -3,13 +3,84 @@ Heroku guide
[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://dashboard.heroku.com/new?button-url=https://github.com/tootsuite/mastodon&template=https://github.com/tootsuite/mastodon)
-Mastodon can theoretically run indefinitely on a free [Heroku](https://heroku.com) app. It should be noted this has limited testing and could have unpredictable results.
+Mastodon can be run on a free [Heroku](https://heroku.com) app. It should be
+noted this has limited testing and could have unpredictable results.
-1. Click the above button.
-2. Fill in the options requested.
- * You can use a .herokuapp.com domain, which will be simple to set up, or you can use a custom domain. If you want a custom domain and HTTPS, you will need to upgrade to a paid plan (to use Heroku's SSL features), or set up [CloudFlare](https://cloudflare.com) who offer free "Flexible SSL" (note: CloudFlare have some undefined limits on WebSockets. So far, no one has reported hitting concurrent connection limits).
- * You will want Amazon S3 for file storage. The only exception is for development purposes, where you may not care if files are not saved. Follow a guide online for creating a free Amazon S3 bucket and Access Key, then enter the details.
- * If you want your Mastodon to be able to send emails, configure SMTP settings here (or later). Consider using [Mailgun](https://mailgun.com) or similar, who offer free plans that should suit your interests.
-3. Deploy! The app should be set up, with a working web interface and database. You can change settings and manage versions from the Heroku dashboard.
+## Basic setup
-You may need to use the `heroku` CLI application to run `USERNAME=yourUsername rails mastodon:make_admin` to make yourself an admin.
+Click the button above to start creating a Heroku app with the Mastodon repo as
+the source. This tells Heroku to use the `app.json` file which does things like
+prompt for config variables, set up the right buildpacks, run a postdeploy task,
+and add the appropriate addons.
+
+If you don't use the deploy button and app.json approach, you will need to do
+some of that manually.
+
+## Domain names and SSL
+
+You can add your domain name to the Heroku app's setting, and then also use
+Heroku's (free) auto renewal program for Lets Encrypt certificates, by
+requesting a cert from the settings screen. You'll have to point your hostname
+DNS at Heroku using the values heroku gives you on this screen, using whatever
+method is appropriate for your DNS setup.
+
+You should set the Heroku config vars of `LOCAL_DOMAIN` to your hostname, and
+`LOCAL_HTTPS` to "true" as well.
+
+## Email
+
+Consider using [Mailgun](https://mailgun.com) or similar, who offer free plans
+that should suit your interests. Look in `production.rb` to see which config
+variables need to be set on Heroku for outgoing email to work.
+
+## File storage
+
+You will want Amazon S3 for file storage. The only exception is for development
+purposes, where you may not care if files are not saved. Follow a guide online
+for creating a free Amazon S3 bucket and Access Key, then enter the details.
+
+If you deploy from the web, the format for all the S3 bits use Paperclip conventions:
+
+S3 Bucket is just the name of the bucket, e.g. `bucketname` not the full ARN.
+
+S3 Region is the AWS code for the region e.g. `ap-northeast-1` not the name of the city displayed on the AWS Dashboard.
+
+To protect the privacy of the users of the your instance, you should have permissons on the your S3 bucket set to no-read and no-write for the public and non-application-specific AWS users, with only one authorized IAM user or group set up to be able to upload or display content. This is an example of an IAM policy used for the S3 bucket used Mastadon instance hentai.loan:
+
+ {
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Effect": "Allow",
+ "Action": [
+ "s3:ListAllMyBuckets"
+ ],
+ "Resource": [
+ "arn:aws:s3:::*"
+ ]
+ },
+ {
+ "Effect": "Allow",
+ "Action": [
+ "s3:*"
+ ],
+ "Resource": [
+ "arn:aws:s3:::hentailoan”,
+ "arn:aws:s3:::hentailoan/*"
+ ]
+ }
+ ]
+ }
+
+
+## Deployment
+
+You can deploy from the Heroku web interface or from the command line. Run:
+
+ `heroku run rails db:migrate`
+
+after you first deploy to set up the first database.
+
+To make yourself an admin, you may need to use the `heroku` CLI application after creating an account online:
+
+ `heroku rake mastodon:make_admin USERNAME=yourUsername`
diff --git a/docs/Running-Mastodon/Production-guide.md b/docs/Running-Mastodon/Production-guide.md
index 90e9c0de..785826ac 100644
--- a/docs/Running-Mastodon/Production-guide.md
+++ b/docs/Running-Mastodon/Production-guide.md
@@ -24,7 +24,7 @@ server {
ssl_protocols TLSv1.2;
ssl_ciphers EECDH+AESGCM:EECDH+AES;
- ssl_ecdh_curve secp384r1;
+ ssl_ecdh_curve prime256v1;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
@@ -90,7 +90,9 @@ It is recommended to create a special user for mastodon on the server (you could
sudo apt-get install imagemagick ffmpeg libpq-dev libxml2-dev libxslt1-dev nodejs file git curl
curl -sL https://deb.nodesource.com/setup_4.x | sudo bash -
- apt-get intall nodejs
+
+ sudo apt-get install nodejs
+
sudo npm install -g yarn
## Redis
diff --git a/docs/Using-Mastodon/Apps.md b/docs/Using-Mastodon/Apps.md
index 67b14dc2..b5e1fa36 100644
--- a/docs/Using-Mastodon/Apps.md
+++ b/docs/Using-Mastodon/Apps.md
@@ -13,5 +13,6 @@ Some people have started working on apps for the Mastodon API. Here is a list of
|Albatross|iOS||[@goldie_ice@mastodon.social](https://mastodon.social/users/goldie_ice)|
|Tooter|Chrome|
|[@effy@mastodon.social](https://mastodon.social/users/effy)|
|tootstream|CLI||[@Raccoon@mastodon.social](https://mastodon.social/users/Raccoon)|
+|HackerNewsBot|CLI||[@rayalez@hackertribe.io](https://hackertribe.io/users/rayalez)|
If you have a project like this, let me know so I can add it to the list!
diff --git a/docs/Using-Mastodon/List-of-Mastodon-instances.md b/docs/Using-Mastodon/List-of-Mastodon-instances.md
index 1f5be3a6..a1936e16 100644
--- a/docs/Using-Mastodon/List-of-Mastodon-instances.md
+++ b/docs/Using-Mastodon/List-of-Mastodon-instances.md
@@ -7,6 +7,7 @@ There is also a list at [instances.mastodon.xyz](https://instances.mastodon.xyz)
| -------------|-------------|---|---|
| [mastodon.social](https://mastodon.social) |Flagship, quick updates|No|No|
| [securitymastod.one](https://securitymastod.one/) |Information security enthusiasts and pros|Yes|Yes|
+| [mastodon.nuzgo.net](https://mastodon.nuzgo.net/) |Mastodon instance hosted in Paris |Yes|Yes|
| [mastodon.cx](https://mastodon.cx/) |Alternative Mastodon instance hosted in France|Yes|Yes|
| [mastodon.network](https://mastodon.network) |N/A|Yes|Yes|
| [awoo.space](https://awoo.space) |Intentionally moderated, only federates with mastodon.social|Yes|No|
@@ -17,9 +18,11 @@ There is also a list at [instances.mastodon.xyz](https://instances.mastodon.xyz)
| [gay.crime.team](https://gay.crime.team) |the place for doin' gay crime online (please don't actually do crime here)|No|No|
| [icosahedron.website](https://icosahedron.website/) |Icosahedron-themed (well, visually), open registration.|Yes|No|
| [memetastic.space](https://memetastic.space) |Memes|Yes|No|
+| [masto.razrnet.fr](https://masto.razrnet.fr) |Instance Française pour tout le monde ! Développeurs, gamers, etc...|Yes|No|
| [social.diskseven.com](https://social.diskseven.com) |Single user|No|Yes|
| [social.gestaltzerfall.net](https://social.gestaltzerfall.net) |Single user|No|No|
| [mastodon.xyz](https://mastodon.xyz) |N/A|Yes|Yes|
+| [mastodon.land](https://mastodon.land) |N/A|Yes|Yes|
| [mastodon.partipirate.org](https://mastodon.partipirate.org) |French Pirate Party Instance - Politics and stuff|Yes|No|
| [social.targaryen.house](https://social.targaryen.house) |Federates everywhere, quick updates.|Yes|Yes|
| [masto.themimitoof.fr](https://masto.themimitoof.fr) |N/A|Yes|Yes|
@@ -33,8 +36,8 @@ There is also a list at [instances.mastodon.xyz](https://instances.mastodon.xyz)
| [social.alex73630.xyz](https://social.alex73630.xyz) |Francophones|Yes|Yes|
| [oc.todon.fr](https://oc.todon.fr) |Modérée et principalement francophone, pas de tolérances pour misogynie/LGBTphobies/validisme/etc.|Yes|Yes|
| [maly.io](https://maly.io) |N/A|Yes|No|
-| [social.lou.lt](https://social.lou.lt) |N/A|Yes|No|
-| [mastodon.ninetailed.uk](https://mastodon.ninetailed.uk) |N/A|Yes|No|
+| [social.lou.lt](https://social.lou.lt) |Francophones|Yes|No|
+| [mastodon.ninetailed.uk](https://mastodon.ninetailed.uk) |Open registrations, furry-friendly, UK-based|Yes|No|
| [soc.louiz.org](https://soc.louiz.org) |"Coucou"|Yes|No|
| [7nw.eu](https://7nw.eu) |N/A|Yes|No|
| [mastodon.gougere.fr](https://mastodon.gougere.fr)|N/A|Yes|No|
@@ -47,6 +50,32 @@ There is also a list at [instances.mastodon.xyz](https://instances.mastodon.xyz)
| [status.dissidence.ovh](https://status.dissidence.ovh)|N/A|Yes|Yes|
| [mastodon.cc](https://mastodon.cc)|Art|Yes|No|
| [mastodon.technology](https://mastodon.technology)|Open registrations, federates everywhere, for tech folks|Yes|No|
-| [mastodon.systemlab.fr](https://mastodon.systemlab.fr/)|Le mastodon Français, informatique, jeux-vidéos, gaming et hébergement.|Yes|No|
+| [mastodon.systemlab.fr](https://mastodon.systemlab.fr/)|Le mastodon Français, informatique, jeux-vidéos, gaming et hébergement.|Yes|
+| [mastodon.top](https://mastodon.top) |N/A|Yes|Yes|
+| [niu.moe](https://niu.moe/)|:dolls: The most cutest node ever, FR/EN, anime and computer :balloon:|Yes|Yes|
+| [im-in.space](https://im-in.space/)|SPAAAAACE! Probably with a lot of French people. (Invite-only, might randomly open registrations)|No|Yes|
+| [social.bytestemplar.com](https://social.bytestemplar.com)|N/A|Yes|No|
+| [digitalhumanities.club](http://www.digitalhumanities.club)|[Digital humanities](http://whatisdigitalhumanities.com) community; invitations will open once code of conduct drafted.|No|No
+| [design.vu](https://design.vu)|— what's your design view‽|Yes|No|
+| [masto.raildecake.fr](https://masto.raildecake.fr)|Hebergé chez un FAI associatif dans le sud de la france, grillons & pins en options|Yes|No|
+| [good-dragon.com](https://good-dragon.com/)|Quick updates, Relaxed Moderation, Federates Everywhere, Furries|Yes|No|
+| [rich.gop](https://rich.gop/)|Federates everywhere, Open registration, Privacy respected|Yes|Yes|
+| [social.nowa.re](https://social.nowa.re)|Open Registration|Yes|No|
+| [mastodon.ml](http://mastodon.ml) |A chill place to hangout and chat about anime, programming and movies.|Yes|Yes|
+| [off-the-clock.us](https://off-the-clock.us/)|The work day is over.|Yes|No|
+| [infinimatix.net](https://infinimatix.net)|Informatics|Yes|Yes|
+| [social.0day.agency](https://social.0day.agency)|Infosec, Hacking, Fun (only protonmail)|Yes|Yes|
+| [kagrumez.lerk.io](https://kagrumez.lerk.io)|Open registration. German end english.|Yes|No|
+| [meow.social](https://meow.social)|A furry fandom focused instance|Yes|No|
+| [neumastodon.com](https://neumastodon.com/)|Northeastern University Mastodon |Yes|No|
+| [dancingbanana.party](https://dancingbanana.party)|La banane qui danse.|Yes|No|
+| [mastodon.brussels](https://mastodon.brussels/)|Le mastodon pour les belges, si vous aimez la bonne ambiance venez nous rejoindre !|Yes|Yes|
+| [mastodon.llamasweet.tech](https://mastodon.llamasweet.tech/)|Mastodon about Android developement|Yes|No|
+| [manx.social](https://manx.social/)|Instance for the Isle of Man|Yes|Yes|
+| [mastodon.host](https://mastodon.host/)|Lightly moderated, federates everywhere and has a follow bot ( Huge federated timeline )|Yes|No|
+| [mastodon.fun](https://mastodon.fun/)|Mastodon for everyone ! |Yes|Yes|
+| [oulipo.social](https://oulipo.social/)|An Oulipo Mastodon in which that fifth symbol in Latin script is taboo|Yes|No|
+| [indigo.zone](https://indigo.zone)|Open Registrations, General Purpose|Yes|No|
-Let me know if you start running one so I can add it to the list! (Alternatively, add it yourself as a pull request).
+
+We are no longer maintaining this list as instances are popping up too quickly for using GitHub to be a tenable system for tracking them. Please standby while we work on another solution
diff --git a/docs/Using-the-API/API.md b/docs/Using-the-API/API.md
index e09d8ac9..8a648b6d 100644
--- a/docs/Using-the-API/API.md
+++ b/docs/Using-the-API/API.md
@@ -43,6 +43,7 @@ ___
- [For Python](https://github.com/halcy/Mastodon.py)
- [For JavaScript](https://github.com/Zatnosk/libodonjs)
- [For JavaScript (Node.js)](https://github.com/jessicahayley/node-mastodon)
+- [For Elixir](https://github.com/milmazz/hunter)
___
diff --git a/spec/fabricators/media_attachment_fabricator.rb b/spec/fabricators/media_attachment_fabricator.rb
index 59db2440..dc91d708 100644
--- a/spec/fabricators/media_attachment_fabricator.rb
+++ b/spec/fabricators/media_attachment_fabricator.rb
@@ -1,3 +1,3 @@
Fabricator(:media_attachment) do
-
+ account
end
diff --git a/spec/fabricators/status_fabricator.rb b/spec/fabricators/status_fabricator.rb
index df222fc9..8ec5f4ba 100644
--- a/spec/fabricators/status_fabricator.rb
+++ b/spec/fabricators/status_fabricator.rb
@@ -1,3 +1,4 @@
Fabricator(:status) do
+ account
text "Lorem ipsum dolor sit amet"
end
diff --git a/spec/helpers/site_title_helper_spec.rb b/spec/helpers/site_title_helper_spec.rb
new file mode 100644
index 00000000..8cfd9cba
--- /dev/null
+++ b/spec/helpers/site_title_helper_spec.rb
@@ -0,0 +1,15 @@
+require "rails_helper"
+
+describe "site_title" do
+ it "Uses the Setting.site_title value when it exists" do
+ Setting.site_title = "New site title"
+
+ expect(helper.site_title).to eq "New site title"
+ end
+
+ it "returns empty string when Setting.site_title is nil" do
+ Setting.site_title = nil
+
+ expect(helper.site_title).to eq ""
+ end
+end
diff --git a/spec/models/account_spec.rb b/spec/models/account_spec.rb
index d7f59adb..93a45459 100644
--- a/spec/models/account_spec.rb
+++ b/spec/models/account_spec.rb
@@ -99,11 +99,75 @@ RSpec.describe Account, type: :model do
end
describe '#favourited?' do
- pending
+ let(:original_status) do
+ author = Fabricate(:account, username: 'original')
+ Fabricate(:status, account: author)
+ end
+
+ context 'when the status is a reblog of another status' do
+ let(:original_reblog) do
+ author = Fabricate(:account, username: 'original_reblogger')
+ Fabricate(:status, reblog: original_status, account: author)
+ end
+
+ it 'is is true when this account has favourited it' do
+ Fabricate(:favourite, status: original_reblog, account: subject)
+
+ expect(subject.favourited?(original_status)).to eq true
+ end
+
+ it 'is false when this account has not favourited it' do
+ expect(subject.favourited?(original_status)).to eq false
+ end
+ end
+
+ context 'when the status is an original status' do
+ it 'is is true when this account has favourited it' do
+ Fabricate(:favourite, status: original_status, account: subject)
+
+ expect(subject.favourited?(original_status)).to eq true
+ end
+
+ it 'is false when this account has not favourited it' do
+ expect(subject.favourited?(original_status)).to eq false
+ end
+ end
end
describe '#reblogged?' do
- pending
+ let(:original_status) do
+ author = Fabricate(:account, username: 'original')
+ Fabricate(:status, account: author)
+ end
+
+ context 'when the status is a reblog of another status'do
+ let(:original_reblog) do
+ author = Fabricate(:account, username: 'original_reblogger')
+ Fabricate(:status, reblog: original_status, account: author)
+ end
+
+ it 'is true when this account has reblogged it' do
+ Fabricate(:status, reblog: original_reblog, account: subject)
+
+ expect(subject.reblogged?(original_reblog)).to eq true
+ end
+
+ it 'is false when this account has not reblogged it' do
+ expect(subject.reblogged?(original_reblog)).to eq false
+ end
+ end
+
+ context 'when the status is an original status' do
+ it 'is true when this account has reblogged it' do
+ Fabricate(:status, reblog: original_status, account: subject)
+
+ expect(subject.reblogged?(original_status)).to eq true
+ end
+
+ it 'is false when this account has not reblogged it' do
+ expect(subject.reblogged?(original_status)).to eq false
+ end
+ end
end
describe '.find_local' do
diff --git a/spec/models/status_spec.rb b/spec/models/status_spec.rb
index b9d07952..000bee0f 100644
--- a/spec/models/status_spec.rb
+++ b/spec/models/status_spec.rb
@@ -91,10 +91,31 @@ RSpec.describe Status, type: :model do
end
describe '#reblogs_count' do
- pending
+ it 'is the number of reblogs' do
+ Fabricate(:status, account: bob, reblog: subject)
+ Fabricate(:status, account: alice, reblog: subject)
+
+ expect(subject.reblogs_count).to eq 2
+ end
end
describe '#favourites_count' do
- pending
+ it 'is the number of favorites' do
+ Fabricate(:favourite, account: bob, status: subject)
+ Fabricate(:favourite, account: alice, status: subject)
+
+ expect(subject.favourites_count).to eq 2
+ end
+ end
+
+ describe '#proper' do
+ it 'is itself for original statuses' do
+ expect(subject.proper).to eq subject
+ end
+
+ it 'is the source status for reblogs' do
+ subject.reblog = other
+ expect(subject.proper).to eq other
+ end
end
end
diff --git a/spec/services/post_status_service_spec.rb b/spec/services/post_status_service_spec.rb
index 9ee4daf6..0e39cd96 100644
--- a/spec/services/post_status_service_spec.rb
+++ b/spec/services/post_status_service_spec.rb
@@ -3,8 +3,168 @@ require 'rails_helper'
RSpec.describe PostStatusService do
subject { PostStatusService.new }
- it 'creates a new status'
- it 'creates a new response status'
- it 'processes mentions'
- it 'pings PuSH hubs'
+ it 'creates a new status' do
+ account = Fabricate(:account)
+ text = "test status update"
+
+ status = subject.call(account, text)
+
+ expect(status).to be_persisted
+ expect(status.text).to eq text
+ end
+
+ it 'creates a new response status' do
+ in_reply_to_status = Fabricate(:status)
+ account = Fabricate(:account)
+ text = "test status update"
+
+ status = subject.call(account, text, in_reply_to_status)
+
+ expect(status).to be_persisted
+ expect(status.text).to eq text
+ expect(status.thread).to eq in_reply_to_status
+ end
+
+ it 'creates a sensitive status' do
+ status = create_status_with_options(sensitive: true)
+
+ expect(status).to be_persisted
+ expect(status).to be_sensitive
+ end
+
+ it 'creates a status with spoiler text' do
+ spoiler_text = "spoiler text"
+
+ status = create_status_with_options(spoiler_text: spoiler_text)
+
+ expect(status).to be_persisted
+ expect(status.spoiler_text).to eq spoiler_text
+ end
+
+ it 'creates a status with empty default spoiler text' do
+ status = create_status_with_options(spoiler_text: nil)
+
+ expect(status).to be_persisted
+ expect(status.spoiler_text).to eq ''
+ end
+
+ it 'creates a status with the given visibility' do
+ status = create_status_with_options(visibility: :private)
+
+ expect(status).to be_persisted
+ expect(status.visibility).to eq "private"
+ end
+
+ it 'creates a status for the given application' do
+ application = Fabricate(:application)
+
+ status = create_status_with_options(application: application)
+
+ expect(status).to be_persisted
+ expect(status.application).to eq application
+ end
+
+ it 'processes mentions' do
+ mention_service = double(:process_mentions_service)
+ allow(mention_service).to receive(:call)
+ allow(ProcessMentionsService).to receive(:new).and_return(mention_service)
+ account = Fabricate(:account)
+
+ status = subject.call(account, "test status update")
+
+ expect(ProcessMentionsService).to have_received(:new)
+ expect(mention_service).to have_received(:call).with(status)
+ end
+
+ it 'processes hashtags' do
+ hashtags_service = double(:process_hashtags_service)
+ allow(hashtags_service).to receive(:call)
+ allow(ProcessHashtagsService).to receive(:new).and_return(hashtags_service)
+ account = Fabricate(:account)
+
+ status = subject.call(account, "test status update")
+
+ expect(ProcessHashtagsService).to have_received(:new)
+ expect(hashtags_service).to have_received(:call).with(status)
+ end
+
+ it 'pings PuSH hubs' do
+ allow(DistributionWorker).to receive(:perform_async)
+ allow(Pubsubhubbub::DistributionWorker).to receive(:perform_async)
+ account = Fabricate(:account)
+
+ status = subject.call(account, "test status update")
+
+ expect(DistributionWorker).to have_received(:perform_async).with(status.id)
+ expect(Pubsubhubbub::DistributionWorker).
+ to have_received(:perform_async).with(status.stream_entry.id)
+ end
+
+ it 'crawls links' do
+ allow(LinkCrawlWorker).to receive(:perform_async)
+ account = Fabricate(:account)
+
+ status = subject.call(account, "test status update")
+
+ expect(LinkCrawlWorker).to have_received(:perform_async).with(status.id)
+ end
+
+ it 'attaches the given media to the created status' do
+ account = Fabricate(:account)
+ media = Fabricate(:media_attachment)
+
+ status = subject.call(
+ account,
+ "test status update",
+ nil,
+ media_ids: [media.id],
+ )
+
+ expect(media.reload.status).to eq status
+ end
+
+ it 'does not allow attaching more than 4 files' do
+ account = Fabricate(:account)
+
+ expect do
+ subject.call(
+ account,
+ "test status update",
+ nil,
+ media_ids: [
+ Fabricate(:media_attachment, account: account),
+ Fabricate(:media_attachment, account: account),
+ Fabricate(:media_attachment, account: account),
+ Fabricate(:media_attachment, account: account),
+ Fabricate(:media_attachment, account: account),
+ ].map(&:id),
+ )
+ end.to raise_error(
+ Mastodon::ValidationError,
+ I18n.t('media_attachments.validations.too_many'),
+ )
+ end
+
+ it 'does not allow attaching both videos and images' do
+ account = Fabricate(:account)
+
+ expect do
+ subject.call(
+ account,
+ "test status update",
+ nil,
+ media_ids: [
+ Fabricate(:media_attachment, type: :video, account: account),
+ Fabricate(:media_attachment, type: :image, account: account),
+ ].map(&:id),
+ )
+ end.to raise_error(
+ Mastodon::ValidationError,
+ I18n.t('media_attachments.validations.images_and_video'),
+ )
+ end
+
+ def create_status_with_options(options = {})
+ subject.call(Fabricate(:account), "test", nil, options)
+ end
end