Merge remote-tracking branch 'parent/main' into upstream-20240112
This commit is contained in:
commit
e65fb9fb51
333 changed files with 2661 additions and 1461 deletions
|
@ -70,7 +70,7 @@ services:
|
|||
hard: -1
|
||||
|
||||
libretranslate:
|
||||
image: libretranslate/libretranslate:v1.5.2
|
||||
image: libretranslate/libretranslate:v1.5.3
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- lt-data:/home/libretranslate/.local
|
||||
|
|
11
.eslintrc.js
11
.eslintrc.js
|
@ -245,7 +245,7 @@ module.exports = defineConfig({
|
|||
},
|
||||
// Immutable / Redux / data store
|
||||
{
|
||||
pattern: '{immutable,react-redux,react-immutable-proptypes,react-immutable-pure-component,reselect}',
|
||||
pattern: '{immutable,@reduxjs/toolkit,react-redux,react-immutable-proptypes,react-immutable-pure-component}',
|
||||
group: 'external',
|
||||
position: 'before',
|
||||
},
|
||||
|
@ -353,7 +353,14 @@ module.exports = defineConfig({
|
|||
'@typescript-eslint/consistent-type-exports': 'error',
|
||||
'@typescript-eslint/consistent-type-imports': 'error',
|
||||
"@typescript-eslint/prefer-nullish-coalescing": ['error', { ignorePrimitives: { boolean: true } }],
|
||||
|
||||
"@typescript-eslint/no-restricted-imports": [
|
||||
"warn",
|
||||
{
|
||||
"name": "react-redux",
|
||||
"importNames": ["useSelector", "useDispatch"],
|
||||
"message": "Use typed hooks `useAppDispatch` and `useAppSelector` instead."
|
||||
}
|
||||
],
|
||||
'jsdoc/require-jsdoc': 'off',
|
||||
|
||||
// Those rules set stricter rules for TS files
|
||||
|
|
|
@ -1,28 +1,16 @@
|
|||
# This configuration was generated by
|
||||
# `haml-lint --auto-gen-config`
|
||||
# on 2023-12-15 11:02:19 -0500 using Haml-Lint version 0.52.0.
|
||||
# on 2024-01-09 11:30:07 -0500 using Haml-Lint version 0.53.0.
|
||||
# The point is for the user to remove these configuration records
|
||||
# one by one as the lints are removed from the code base.
|
||||
# Note that changes in the inspected code, or installation of new
|
||||
# versions of Haml-Lint, may require this file to be generated again.
|
||||
|
||||
linters:
|
||||
# Offense count: 11
|
||||
# Offense count: 1
|
||||
LineLength:
|
||||
exclude:
|
||||
- 'app/views/admin/roles/_form.html.haml'
|
||||
- 'app/views/auth/registrations/edit.html.haml'
|
||||
- 'app/views/auth/registrations/new.html.haml'
|
||||
- 'app/views/media/player.html.haml'
|
||||
- 'app/views/settings/applications/_fields.html.haml'
|
||||
- 'app/views/settings/imports/index.html.haml'
|
||||
- 'app/views/settings/preferences/appearance/show.html.haml'
|
||||
- 'app/views/settings/preferences/notifications/show.html.haml'
|
||||
- 'app/views/settings/preferences/other/show.html.haml'
|
||||
- 'app/views/settings/preferences/reaching/show.html.haml'
|
||||
- 'app/views/settings/privacy/show.html.haml'
|
||||
- 'app/views/settings/privacy_extra/show.html.haml'
|
||||
- 'app/views/settings/profiles/show.html.haml'
|
||||
|
||||
# Offense count: 9
|
||||
RuboCop:
|
||||
|
@ -32,6 +20,8 @@ linters:
|
|||
ViewLength:
|
||||
exclude:
|
||||
- 'app/views/admin/instances/show.html.haml'
|
||||
- 'app/views/settings/preferences/appearance/show.html.haml'
|
||||
- 'app/views/settings/preferences/other/show.html.haml'
|
||||
|
||||
InstanceVariables:
|
||||
exclude:
|
||||
|
|
2
.nvmrc
2
.nvmrc
|
@ -1 +1 @@
|
|||
20.10
|
||||
20.11
|
||||
|
|
|
@ -130,15 +130,10 @@ Rails/UnusedIgnoredColumns:
|
|||
Rails/NegateInclude:
|
||||
Enabled: false
|
||||
|
||||
# Reason: Some single letter camel case files shouldn't be split
|
||||
# Reason: Deprecated cop, will be removed in 3.0, replaced by SpecFilePathFormat
|
||||
# https://docs.rubocop.org/rubocop-rspec/cops_rspec.html#rspecfilepath
|
||||
RSpec/FilePath:
|
||||
CustomTransform:
|
||||
ActivityPub: activitypub
|
||||
DeepL: deepl
|
||||
FetchOEmbedService: fetch_oembed_service
|
||||
OEmbedController: oembed_controller
|
||||
OStatus: ostatus
|
||||
Enabled: false
|
||||
|
||||
# Reason:
|
||||
# https://docs.rubocop.org/rubocop-rspec/cops_rspec.html#rspecnamedsubject
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# This configuration was generated by
|
||||
# `rubocop --auto-gen-config --auto-gen-only-exclude --no-exclude-limit --no-offense-counts --no-auto-gen-timestamp`
|
||||
# using RuboCop version 1.57.2.
|
||||
# using RuboCop version 1.59.0.
|
||||
# The point is for the user to remove these configuration records
|
||||
# one by one as the offenses are removed from the code base.
|
||||
# Note that changes in the inspected code, or installation of new
|
||||
|
@ -26,7 +26,7 @@ Lint/NonLocalExitFromIterator:
|
|||
|
||||
# Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes.
|
||||
Metrics/AbcSize:
|
||||
Max: 100
|
||||
Max: 82
|
||||
|
||||
# Configuration parameters: CountBlocks, Max.
|
||||
Metrics/BlockNesting:
|
||||
|
@ -50,9 +50,10 @@ RSpec/MultipleExpectations:
|
|||
|
||||
# Configuration parameters: AllowSubject.
|
||||
RSpec/MultipleMemoizedHelpers:
|
||||
Max: 21
|
||||
Max: 17
|
||||
Exclude:
|
||||
- 'spec/services/delete_account_service_spec.rb'
|
||||
- 'spec/services/fan_out_on_write_service_spec.rb'
|
||||
|
||||
# Configuration parameters: AllowedGroups.
|
||||
RSpec/NestedGroups:
|
||||
|
@ -68,7 +69,6 @@ Rails/ApplicationController:
|
|||
Rails/HasAndBelongsToMany:
|
||||
Exclude:
|
||||
- 'app/models/concerns/account/associations.rb'
|
||||
- 'app/models/preview_card.rb'
|
||||
- 'app/models/status.rb'
|
||||
- 'app/models/tag.rb'
|
||||
|
||||
|
@ -146,7 +146,6 @@ Rails/WhereExists:
|
|||
Exclude:
|
||||
- 'app/controllers/activitypub/inboxes_controller.rb'
|
||||
- 'app/controllers/admin/email_domain_blocks_controller.rb'
|
||||
- 'app/controllers/auth/registrations_controller.rb'
|
||||
- 'app/lib/activitypub/activity/create.rb'
|
||||
- 'app/lib/delivery_failure_tracker.rb'
|
||||
- 'app/lib/feed_manager.rb'
|
||||
|
@ -162,7 +161,6 @@ Rails/WhereExists:
|
|||
- 'app/serializers/rest/announcement_serializer.rb'
|
||||
- 'app/serializers/rest/tag_serializer.rb'
|
||||
- 'app/services/activitypub/fetch_remote_status_service.rb'
|
||||
- 'app/services/app_sign_up_service.rb'
|
||||
- 'app/services/vote_service.rb'
|
||||
- 'app/validators/reaction_validator.rb'
|
||||
- 'app/validators/vote_validator.rb'
|
||||
|
@ -173,12 +171,6 @@ Rails/WhereExists:
|
|||
- 'spec/services/purge_domain_service_spec.rb'
|
||||
- 'spec/services/unallow_domain_service_spec.rb'
|
||||
|
||||
# This cop supports safe autocorrection (--autocorrect).
|
||||
# Configuration parameters: AllowOnConstant, AllowOnSelfClass.
|
||||
Style/CaseEquality:
|
||||
Exclude:
|
||||
- 'config/initializers/trusted_proxies.rb'
|
||||
|
||||
# This cop supports unsafe autocorrection (--autocorrect-all).
|
||||
# Configuration parameters: AllowedMethods, AllowedPatterns.
|
||||
# AllowedMethods: ==, equal?, eql?
|
||||
|
@ -206,8 +198,8 @@ Style/FetchEnvVar:
|
|||
- 'config/initializers/devise.rb'
|
||||
- 'config/initializers/paperclip.rb'
|
||||
- 'config/initializers/vapid.rb'
|
||||
- 'lib/premailer_webpack_strategy.rb'
|
||||
- 'lib/mastodon/redis_config.rb'
|
||||
- 'lib/premailer_webpack_strategy.rb'
|
||||
- 'lib/tasks/repo.rake'
|
||||
- 'spec/features/profile_spec.rb'
|
||||
|
||||
|
@ -224,7 +216,6 @@ Style/FormatStringToken:
|
|||
# This cop supports unsafe autocorrection (--autocorrect-all).
|
||||
Style/GlobalStdStream:
|
||||
Exclude:
|
||||
- 'config/boot.rb'
|
||||
- 'config/environments/development.rb'
|
||||
- 'config/environments/production.rb'
|
||||
|
||||
|
@ -414,8 +405,8 @@ Style/TrailingCommaInHashLiteral:
|
|||
- 'config/environments/test.rb'
|
||||
|
||||
# This cop supports safe autocorrection (--autocorrect).
|
||||
# Configuration parameters: EnforcedStyle, MinSize, WordRegex.
|
||||
# Configuration parameters: WordRegex.
|
||||
# SupportedStyles: percent, brackets
|
||||
Style/WordArray:
|
||||
Exclude:
|
||||
- 'app/helpers/languages_helper.rb'
|
||||
EnforcedStyle: percent
|
||||
MinSize: 3
|
||||
|
|
9
Gemfile
9
Gemfile
|
@ -39,15 +39,15 @@ end
|
|||
|
||||
gem 'net-ldap', '~> 0.18'
|
||||
|
||||
# TODO: Point back at released omniauth-cas gem when PR merged
|
||||
# https://github.com/dlindahl/omniauth-cas/pull/68
|
||||
gem 'omniauth-cas', github: 'stanhu/omniauth-cas', ref: '4211e6d05941b4a981f9a36b49ec166cecd0e271'
|
||||
# TODO: Point back at released omniauth-cas gem when new version is released
|
||||
gem 'omniauth-cas', github: 'dlindahl/omniauth-cas', ref: '9d9d3a91b316c55d49ab6e621977f2067010c5bf'
|
||||
gem 'omniauth-saml', '~> 2.0'
|
||||
gem 'omniauth_openid_connect', '~> 0.6.1'
|
||||
gem 'omniauth', '~> 2.0'
|
||||
gem 'omniauth-rails_csrf_protection', '~> 1.0'
|
||||
|
||||
gem 'color_diff', '~> 0.1'
|
||||
gem 'csv', '~> 3.2'
|
||||
gem 'discard', '~> 1.2'
|
||||
gem 'doorkeeper', '~> 5.6'
|
||||
gem 'ed25519', '~> 1.3'
|
||||
|
@ -75,7 +75,6 @@ gem 'premailer-rails'
|
|||
gem 'rack-attack', '~> 6.6'
|
||||
gem 'rack-cors', '~> 2.0', require: 'rack/cors'
|
||||
gem 'rails-i18n', '~> 7.0'
|
||||
gem 'rails-settings-cached', '~> 0.6', git: 'https://github.com/mastodon/rails-settings-cached.git', branch: 'v0.6.6-aliases-true'
|
||||
gem 'redcarpet', '~> 3.6'
|
||||
gem 'redis', '~> 4.5', require: ['redis', 'redis/connection/hiredis']
|
||||
gem 'mario-redis-lock', '~> 1.2', require: 'redis_lock'
|
||||
|
@ -90,7 +89,7 @@ gem 'sidekiq-bulk', '~> 0.2.0'
|
|||
gem 'simple-navigation', '~> 4.4'
|
||||
gem 'simple_form', '~> 5.2'
|
||||
gem 'stoplight', '~> 3.0.1'
|
||||
gem 'strong_migrations', '1.6.4'
|
||||
gem 'strong_migrations', '1.7.0'
|
||||
gem 'tty-prompt', '~> 0.23', require: false
|
||||
gem 'twitter-text', '~> 3.1.0'
|
||||
gem 'tzinfo-data', '~> 1.2023'
|
||||
|
|
63
Gemfile.lock
63
Gemfile.lock
|
@ -7,6 +7,16 @@ GIT
|
|||
hkdf (~> 0.2)
|
||||
jwt (~> 2.0)
|
||||
|
||||
GIT
|
||||
remote: https://github.com/dlindahl/omniauth-cas.git
|
||||
revision: 9d9d3a91b316c55d49ab6e621977f2067010c5bf
|
||||
ref: 9d9d3a91b316c55d49ab6e621977f2067010c5bf
|
||||
specs:
|
||||
omniauth-cas (3.0.0)
|
||||
addressable (~> 2.8)
|
||||
nokogiri (~> 1.12)
|
||||
omniauth (~> 2.1)
|
||||
|
||||
GIT
|
||||
remote: https://github.com/jhawthorn/nsa.git
|
||||
revision: e020fcc3a54d993ab45b7194d89ab720296c111b
|
||||
|
@ -18,24 +28,6 @@ GIT
|
|||
sidekiq (>= 3.5)
|
||||
statsd-ruby (~> 1.4, >= 1.4.0)
|
||||
|
||||
GIT
|
||||
remote: https://github.com/mastodon/rails-settings-cached.git
|
||||
revision: 86328ef0bd04ce21cc0504ff5e334591e8c2ccab
|
||||
branch: v0.6.6-aliases-true
|
||||
specs:
|
||||
rails-settings-cached (0.6.6)
|
||||
rails (>= 4.2.0)
|
||||
|
||||
GIT
|
||||
remote: https://github.com/stanhu/omniauth-cas.git
|
||||
revision: 4211e6d05941b4a981f9a36b49ec166cecd0e271
|
||||
ref: 4211e6d05941b4a981f9a36b49ec166cecd0e271
|
||||
specs:
|
||||
omniauth-cas (2.0.0)
|
||||
addressable (~> 2.3)
|
||||
nokogiri (~> 1.5)
|
||||
omniauth (>= 1.2, < 3)
|
||||
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
|
@ -216,6 +208,7 @@ GEM
|
|||
crass (1.0.6)
|
||||
css_parser (1.14.0)
|
||||
addressable
|
||||
csv (3.2.8)
|
||||
database_cleaner-active_record (2.1.0)
|
||||
activerecord (>= 5.a)
|
||||
database_cleaner-core (~> 2.0.0)
|
||||
|
@ -272,7 +265,7 @@ GEM
|
|||
erubi (1.12.0)
|
||||
et-orbi (1.2.7)
|
||||
tzinfo
|
||||
excon (0.104.0)
|
||||
excon (0.109.0)
|
||||
fabrication (2.31.0)
|
||||
faker (3.2.2)
|
||||
i18n (>= 1.8.11, < 2)
|
||||
|
@ -307,7 +300,7 @@ GEM
|
|||
ffi-compiler (1.0.1)
|
||||
ffi (>= 1.0.0)
|
||||
rake
|
||||
fog-core (2.3.0)
|
||||
fog-core (2.4.0)
|
||||
builder
|
||||
excon (~> 0.71)
|
||||
formatador (>= 0.2, < 2.0)
|
||||
|
@ -336,8 +329,8 @@ GEM
|
|||
activesupport (>= 5.1)
|
||||
haml (>= 4.0.6)
|
||||
railties (>= 5.1)
|
||||
haml_lint (0.52.0)
|
||||
haml (>= 4.0)
|
||||
haml_lint (0.53.0)
|
||||
haml (>= 5.0)
|
||||
parallel (~> 1.10)
|
||||
rainbow
|
||||
rubocop (>= 1.0)
|
||||
|
@ -378,9 +371,9 @@ GEM
|
|||
terminal-table (>= 1.5.1)
|
||||
idn-ruby (0.1.5)
|
||||
io-console (0.7.1)
|
||||
irb (1.11.0)
|
||||
irb (1.11.1)
|
||||
rdoc
|
||||
reline (>= 0.3.8)
|
||||
reline (>= 0.4.2)
|
||||
jmespath (1.6.2)
|
||||
json (2.7.1)
|
||||
json-canonicalization (1.0.0)
|
||||
|
@ -467,7 +460,7 @@ GEM
|
|||
multi_json (1.15.0)
|
||||
multipart-post (2.3.0)
|
||||
mutex_m (0.2.0)
|
||||
net-http (0.4.0)
|
||||
net-http (0.4.1)
|
||||
uri
|
||||
net-http-persistent (4.0.2)
|
||||
connection_pool (~> 2.2)
|
||||
|
@ -544,7 +537,7 @@ GEM
|
|||
psych (5.1.2)
|
||||
stringio
|
||||
public_suffix (5.0.4)
|
||||
puma (6.4.1)
|
||||
puma (6.4.2)
|
||||
nio4r (~> 2.0)
|
||||
pundit (2.3.1)
|
||||
activesupport (>= 3.0.0)
|
||||
|
@ -624,7 +617,7 @@ GEM
|
|||
redlock (1.3.2)
|
||||
redis (>= 3.0.0, < 6.0)
|
||||
regexp_parser (2.8.3)
|
||||
reline (0.4.1)
|
||||
reline (0.4.2)
|
||||
io-console (~> 0.5)
|
||||
request_store (1.5.1)
|
||||
rack (>= 1.4)
|
||||
|
@ -680,9 +673,9 @@ GEM
|
|||
parser (>= 3.2.1.0)
|
||||
rubocop-capybara (2.20.0)
|
||||
rubocop (~> 1.41)
|
||||
rubocop-factory_bot (2.24.0)
|
||||
rubocop-factory_bot (2.25.0)
|
||||
rubocop (~> 1.33)
|
||||
rubocop-performance (1.20.1)
|
||||
rubocop-performance (1.20.2)
|
||||
rubocop (>= 1.48.1, < 2.0)
|
||||
rubocop-ast (>= 1.30.0, < 2.0)
|
||||
rubocop-rails (2.23.1)
|
||||
|
@ -690,11 +683,11 @@ GEM
|
|||
rack (>= 1.1)
|
||||
rubocop (>= 1.33.0, < 2.0)
|
||||
rubocop-ast (>= 1.30.0, < 2.0)
|
||||
rubocop-rspec (2.25.0)
|
||||
rubocop-rspec (2.26.1)
|
||||
rubocop (~> 1.40)
|
||||
rubocop-capybara (~> 2.17)
|
||||
rubocop-factory_bot (~> 2.22)
|
||||
ruby-prof (1.6.3)
|
||||
ruby-prof (1.7.0)
|
||||
ruby-progressbar (1.13.0)
|
||||
ruby-saml (1.15.0)
|
||||
nokogiri (>= 1.13.10)
|
||||
|
@ -726,7 +719,7 @@ GEM
|
|||
rufus-scheduler (~> 3.2)
|
||||
sidekiq (>= 6, < 8)
|
||||
tilt (>= 1.4.0)
|
||||
sidekiq-unique-jobs (7.1.30)
|
||||
sidekiq-unique-jobs (7.1.31)
|
||||
brpoplpush-redis_script (> 0.1.1, <= 2.0.0)
|
||||
concurrent-ruby (~> 1.0, >= 1.0.5)
|
||||
redis (< 5.0)
|
||||
|
@ -750,7 +743,7 @@ GEM
|
|||
stoplight (3.0.2)
|
||||
redlock (~> 1.0)
|
||||
stringio (3.1.0)
|
||||
strong_migrations (1.6.4)
|
||||
strong_migrations (1.7.0)
|
||||
activerecord (>= 5.2)
|
||||
swd (1.3.0)
|
||||
activesupport (>= 3)
|
||||
|
@ -855,6 +848,7 @@ DEPENDENCIES
|
|||
color_diff (~> 0.1)
|
||||
concurrent-ruby
|
||||
connection_pool
|
||||
csv (~> 3.2)
|
||||
database_cleaner-active_record
|
||||
debug (~> 1.8)
|
||||
devise (~> 4.9)
|
||||
|
@ -924,7 +918,6 @@ DEPENDENCIES
|
|||
rails (~> 7.1.1)
|
||||
rails-controller-testing (~> 1.0)
|
||||
rails-i18n (~> 7.0)
|
||||
rails-settings-cached (~> 0.6)!
|
||||
rdf-normalize (~> 0.5)
|
||||
redcarpet (~> 3.6)
|
||||
redis (~> 4.5)
|
||||
|
@ -955,7 +948,7 @@ DEPENDENCIES
|
|||
simplecov-lcov (~> 0.8)
|
||||
stackprof
|
||||
stoplight (~> 3.0.1)
|
||||
strong_migrations (= 1.6.4)
|
||||
strong_migrations (= 1.7.0)
|
||||
test-prof
|
||||
thor (~> 1.2)
|
||||
tty-prompt (~> 0.23)
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
class Api::V1::StreamingController < Api::BaseController
|
||||
def index
|
||||
if Rails.configuration.x.streaming_api_base_url == request.host
|
||||
if same_host?
|
||||
not_found
|
||||
else
|
||||
redirect_to streaming_api_url, status: 301, allow_other_host: true
|
||||
|
@ -11,6 +11,11 @@ class Api::V1::StreamingController < Api::BaseController
|
|||
|
||||
private
|
||||
|
||||
def same_host?
|
||||
base_url = Addressable::URI.parse(Rails.configuration.x.streaming_api_base_url)
|
||||
request.host == base_url.host && request.port == (base_url.port || 80)
|
||||
end
|
||||
|
||||
def streaming_api_url
|
||||
Addressable::URI.parse(request.url).tap do |uri|
|
||||
base_url = Addressable::URI.parse(Rails.configuration.x.streaming_api_base_url)
|
||||
|
|
|
@ -3,150 +3,6 @@
|
|||
module CacheConcern
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
module ActiveRecordCoder
|
||||
EMPTY_HASH = {}.freeze
|
||||
|
||||
class << self
|
||||
def dump(record)
|
||||
instances = InstanceTracker.new
|
||||
serialized_associations = serialize_associations(record, instances)
|
||||
serialized_records = instances.map { |r| serialize_record(r) }
|
||||
[serialized_associations, *serialized_records]
|
||||
end
|
||||
|
||||
def load(payload)
|
||||
instances = InstanceTracker.new
|
||||
serialized_associations, *serialized_records = payload
|
||||
serialized_records.each { |attrs| instances.push(deserialize_record(*attrs)) }
|
||||
deserialize_associations(serialized_associations, instances)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Records without associations, or which have already been visited before,
|
||||
# are serialized by their id alone.
|
||||
#
|
||||
# Records with associations are serialized as a two-element array including
|
||||
# their id and the record's association cache.
|
||||
#
|
||||
def serialize_associations(record, instances)
|
||||
return unless record
|
||||
|
||||
if (id = instances.lookup(record))
|
||||
payload = id
|
||||
else
|
||||
payload = instances.push(record)
|
||||
|
||||
cached_associations = record.class.reflect_on_all_associations.select do |reflection|
|
||||
record.association_cached?(reflection.name)
|
||||
end
|
||||
|
||||
unless cached_associations.empty?
|
||||
serialized_associations = cached_associations.map do |reflection|
|
||||
association = record.association(reflection.name)
|
||||
|
||||
serialized_target = if reflection.collection?
|
||||
association.target.map { |target_record| serialize_associations(target_record, instances) }
|
||||
else
|
||||
serialize_associations(association.target, instances)
|
||||
end
|
||||
|
||||
[reflection.name, serialized_target]
|
||||
end
|
||||
|
||||
payload = [payload, serialized_associations]
|
||||
end
|
||||
end
|
||||
|
||||
payload
|
||||
end
|
||||
|
||||
def deserialize_associations(payload, instances)
|
||||
return unless payload
|
||||
|
||||
id, associations = payload
|
||||
record = instances.fetch(id)
|
||||
|
||||
associations&.each do |name, serialized_target|
|
||||
begin
|
||||
association = record.association(name)
|
||||
rescue ActiveRecord::AssociationNotFoundError
|
||||
raise AssociationMissingError, "undefined association: #{name}"
|
||||
end
|
||||
|
||||
target = if association.reflection.collection?
|
||||
serialized_target.map! { |serialized_record| deserialize_associations(serialized_record, instances) }
|
||||
else
|
||||
deserialize_associations(serialized_target, instances)
|
||||
end
|
||||
|
||||
association.target = target
|
||||
end
|
||||
|
||||
record
|
||||
end
|
||||
|
||||
def serialize_record(record)
|
||||
arguments = [record.class.name, attributes_for_database(record)]
|
||||
arguments << true if record.new_record?
|
||||
arguments
|
||||
end
|
||||
|
||||
def attributes_for_database(record)
|
||||
attributes = record.attributes_for_database
|
||||
attributes.transform_values! { |attr| attr.is_a?(::ActiveModel::Type::Binary::Data) ? attr.to_s : attr }
|
||||
attributes
|
||||
end
|
||||
|
||||
def deserialize_record(class_name, attributes_from_database, new_record = false) # rubocop:disable Style/OptionalBooleanParameter
|
||||
begin
|
||||
klass = Object.const_get(class_name)
|
||||
rescue NameError
|
||||
raise ClassMissingError, "undefined class: #{class_name}"
|
||||
end
|
||||
|
||||
# Ideally we'd like to call `klass.instantiate`, however it doesn't allow to pass
|
||||
# wether the record was persisted or not.
|
||||
attributes = klass.attributes_builder.build_from_database(attributes_from_database, EMPTY_HASH)
|
||||
klass.allocate.init_with_attributes(attributes, new_record)
|
||||
end
|
||||
end
|
||||
|
||||
class Error < StandardError
|
||||
end
|
||||
|
||||
class ClassMissingError < Error
|
||||
end
|
||||
|
||||
class AssociationMissingError < Error
|
||||
end
|
||||
|
||||
class InstanceTracker
|
||||
def initialize
|
||||
@instances = []
|
||||
@ids = {}.compare_by_identity
|
||||
end
|
||||
|
||||
def map(&block)
|
||||
@instances.map(&block)
|
||||
end
|
||||
|
||||
def fetch(...)
|
||||
@instances.fetch(...)
|
||||
end
|
||||
|
||||
def push(instance)
|
||||
id = @ids[instance] = @instances.size
|
||||
@instances << instance
|
||||
id
|
||||
end
|
||||
|
||||
def lookup(instance)
|
||||
@ids[instance]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class_methods do
|
||||
def vary_by(value, **kwargs)
|
||||
before_action(**kwargs) do |controller|
|
||||
|
@ -206,11 +62,7 @@ module CacheConcern
|
|||
raw = raw.cache_ids.to_a if raw.is_a?(ActiveRecord::Relation)
|
||||
return [] if raw.empty?
|
||||
|
||||
cached_keys_with_value = begin
|
||||
Rails.cache.read_multi(*raw).transform_keys(&:id).transform_values { |r| ActiveRecordCoder.load(r) }
|
||||
rescue ActiveRecordCoder::Error
|
||||
{} # The serialization format may have changed, let's pretend it's a cache miss.
|
||||
end
|
||||
cached_keys_with_value = Rails.cache.read_multi(*raw).transform_keys(&:id)
|
||||
|
||||
uncached_ids = raw.map(&:id) - cached_keys_with_value.keys
|
||||
|
||||
|
@ -218,10 +70,7 @@ module CacheConcern
|
|||
|
||||
unless uncached_ids.empty?
|
||||
uncached = klass.where(id: uncached_ids).with_includes.index_by(&:id)
|
||||
|
||||
uncached.each_value do |item|
|
||||
Rails.cache.write(item, ActiveRecordCoder.dump(item))
|
||||
end
|
||||
Rails.cache.write_multi(uncached.values.to_h { |i| [i, i] })
|
||||
end
|
||||
|
||||
raw.filter_map { |item| cached_keys_with_value[item.id] || uncached[item.id] }
|
||||
|
|
|
@ -4,4 +4,60 @@ module Admin::SettingsHelper
|
|||
def captcha_available?
|
||||
ENV['HCAPTCHA_SECRET_KEY'].present? && ENV['HCAPTCHA_SITE_KEY'].present?
|
||||
end
|
||||
|
||||
def login_activity_title(activity)
|
||||
t(
|
||||
"login_activities.#{login_activity_key(activity)}",
|
||||
method: login_activity_method(activity),
|
||||
ip: login_activity_ip(activity),
|
||||
browser: login_activity_browser(activity)
|
||||
)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def login_activity_key(activity)
|
||||
activity.success? ? 'successful_sign_in_html' : 'failed_sign_in_html'
|
||||
end
|
||||
|
||||
def login_activity_method(activity)
|
||||
content_tag(
|
||||
:span,
|
||||
login_activity_method_string(activity),
|
||||
class: 'target'
|
||||
)
|
||||
end
|
||||
|
||||
def login_activity_ip(activity)
|
||||
content_tag(
|
||||
:span,
|
||||
activity.ip,
|
||||
class: 'target'
|
||||
)
|
||||
end
|
||||
|
||||
def login_activity_browser(activity)
|
||||
content_tag(
|
||||
:span,
|
||||
login_activity_browser_description(activity),
|
||||
class: 'target',
|
||||
title: activity.user_agent
|
||||
)
|
||||
end
|
||||
|
||||
def login_activity_method_string(activity)
|
||||
if activity.omniauth?
|
||||
t("auth.providers.#{activity.provider}")
|
||||
else
|
||||
t("login_activities.authentication_methods.#{activity.authentication_method}")
|
||||
end
|
||||
end
|
||||
|
||||
def login_activity_browser_description(activity)
|
||||
t(
|
||||
'sessions.description',
|
||||
browser: t(activity.browser, scope: 'sessions.browsers', default: activity.browser.to_s),
|
||||
platform: t(activity.platform, scope: 'sessions.platforms', default: activity.platform.to_s)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -224,7 +224,7 @@ module LanguagesHelper
|
|||
'en-GB': 'English (British)',
|
||||
'es-AR': 'Español (Argentina)',
|
||||
'es-MX': 'Español (México)',
|
||||
'fr-QC': 'Français (Canadien)',
|
||||
'fr-CA': 'Français (Canadien)',
|
||||
'pt-BR': 'Português (Brasil)',
|
||||
'pt-PT': 'Português (Portugal)',
|
||||
'sr-Latn': 'Srpski (latinica)',
|
||||
|
|
|
@ -9,6 +9,19 @@ module SettingsHelper
|
|||
LanguagesHelper.sorted_locale_keys(I18n.available_locales)
|
||||
end
|
||||
|
||||
def featured_tags_hint(recently_used_tags)
|
||||
safe_join(
|
||||
[
|
||||
t('simple_form.hints.featured_tag.name'),
|
||||
safe_join(
|
||||
links_for_featured_tags(recently_used_tags),
|
||||
', '
|
||||
),
|
||||
],
|
||||
' '
|
||||
)
|
||||
end
|
||||
|
||||
def session_device_icon(session)
|
||||
device = session.detection.device
|
||||
|
||||
|
@ -28,4 +41,18 @@ module SettingsHelper
|
|||
safe_join([image_tag(account.avatar.url, width: 15, height: 15, alt: '', class: 'avatar'), content_tag(:span, account.acct, class: 'username')], ' ')
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def links_for_featured_tags(tags)
|
||||
tags.map { |tag| post_link_to_featured_tag(tag) }
|
||||
end
|
||||
|
||||
def post_link_to_featured_tag(tag)
|
||||
link_to(
|
||||
"##{tag.display_name}",
|
||||
settings_featured_tags_path(featured_tag: { name: tag.name }),
|
||||
method: :post
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { Map as ImmutableMap, List as ImmutableList } from 'immutable';
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
|
||||
|
||||
import { isHideItem } from 'mastodon/initial_state';
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { Map as ImmutableMap } from 'immutable';
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
|
||||
|
||||
import { changeComposeLanguage } from 'mastodon/actions/compose';
|
||||
import { useLanguage } from 'mastodon/actions/languages';
|
||||
|
|
|
@ -14,8 +14,8 @@ const emojiFilenames = (emojis) => {
|
|||
};
|
||||
|
||||
// Emoji requiring extra borders depending on theme
|
||||
const darkEmoji = emojiFilenames(['🎱', '🐜', '⚫', '🖤', '⬛', '◼️', '◾', '◼️', '✒️', '▪️', '💣', '🎳', '📷', '📸', '♣️', '🕶️', '✴️', '🔌', '💂♀️', '📽️', '🍳', '🦍', '💂', '🔪', '🕳️', '🕹️', '🕋', '🖊️', '🖋️', '💂♂️', '🎤', '🎓', '🎥', '🎼', '♠️', '🎩', '🦃', '📼', '📹', '🎮', '🐃', '🏴', '🐞', '🕺', '📱', '📲', '🚲']);
|
||||
const lightEmoji = emojiFilenames(['👽', '⚾', '🐔', '☁️', '💨', '🕊️', '👀', '🍥', '👻', '🐐', '❕', '❔', '⛸️', '🌩️', '🔊', '🔇', '📃', '🌧️', '🐏', '🍚', '🍙', '🐓', '🐑', '💀', '☠️', '🌨️', '🔉', '🔈', '💬', '💭', '🏐', '🏳️', '⚪', '⬜', '◽', '◻️', '▫️']);
|
||||
const darkEmoji = emojiFilenames(['🎱', '🐜', '⚫', '🖤', '⬛', '◼️', '◾', '◼️', '✒️', '▪️', '💣', '🎳', '📷', '📸', '♣️', '🕶️', '✴️', '🔌', '💂♀️', '📽️', '🍳', '🦍', '💂', '🔪', '🕳️', '🕹️', '🕋', '🖊️', '🖋️', '💂♂️', '🎤', '🎓', '🎥', '🎼', '♠️', '🎩', '🦃', '📼', '📹', '🎮', '🐃', '🏴', '🐞', '🕺', '📱', '📲', '🚲', '🪮', '🐦⬛']);
|
||||
const lightEmoji = emojiFilenames(['👽', '⚾', '🐔', '☁️', '💨', '🕊️', '👀', '🍥', '👻', '🐐', '❕', '❔', '⛸️', '🌩️', '🔊', '🔇', '📃', '🌧️', '🐏', '🍚', '🍙', '🐓', '🐑', '💀', '☠️', '🌨️', '🔉', '🔈', '💬', '💭', '🏐', '🏳️', '⚪', '⬜', '◽', '◻️', '▫️', '🪽', '🪿']);
|
||||
|
||||
const emojiFilename = (filename) => {
|
||||
const borderedEmoji = (document.body && document.body.classList.contains('theme-mastodon-light')) ? lightEmoji : darkEmoji;
|
||||
|
|
|
@ -7,6 +7,10 @@
|
|||
// It's designed to be emitted in an array format to take up less space
|
||||
// over the wire.
|
||||
|
||||
// This version comment should be bumped each time the emoji data is changed
|
||||
// to ensure that the prevaled file is regenerated by Babel
|
||||
// version: 2
|
||||
|
||||
const { emojiIndex } = require('emoji-mart');
|
||||
let data = require('emoji-mart/data/all.json');
|
||||
const { uncompress: emojiMartUncompress } = require('emoji-mart/dist/utils/data');
|
||||
|
@ -15,7 +19,6 @@ const emojiMap = require('./emoji_map.json');
|
|||
const { unicodeToFilename } = require('./unicode_to_filename_s');
|
||||
const { unicodeToUnifiedName } = require('./unicode_to_unified_name_s');
|
||||
|
||||
|
||||
if(data.compressed) {
|
||||
data = emojiMartUncompress(data);
|
||||
}
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1,6 +1,7 @@
|
|||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { Map as ImmutableMap } from 'immutable';
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
|
||||
|
||||
import { addReaction, removeReaction, dismissAnnouncement } from 'mastodon/actions/announcements';
|
||||
|
||||
|
|
|
@ -6,9 +6,9 @@ import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
|||
import classNames from 'classnames';
|
||||
import { Helmet } from 'react-helmet';
|
||||
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { List as ImmutableList } from 'immutable';
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
|
||||
import { ReactComponent as CampaignIcon } from '@material-symbols/svg-600/outlined/campaign.svg';
|
||||
import { ReactComponent as HomeIcon } from '@material-symbols/svg-600/outlined/home-fill.svg';
|
||||
|
|
|
@ -4,10 +4,10 @@ import PropTypes from 'prop-types';
|
|||
|
||||
import { injectIntl } from 'react-intl';
|
||||
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
|
||||
import { setupListAdder, resetListAdder } from '../../actions/lists';
|
||||
import NewListForm from '../lists/components/new_list_form';
|
||||
|
|
|
@ -6,10 +6,10 @@ import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
|||
|
||||
import { Helmet } from 'react-helmet';
|
||||
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
|
||||
import { ReactComponent as ListAltIcon } from '@material-symbols/svg-600/outlined/list_alt.svg';
|
||||
|
||||
|
|
|
@ -5,10 +5,10 @@ import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
|||
|
||||
import { Helmet } from 'react-helmet';
|
||||
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { List as ImmutableList } from 'immutable';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
|
||||
import { ReactComponent as DoneAllIcon } from '@material-symbols/svg-600/outlined/done_all.svg';
|
||||
import { ReactComponent as NotificationsIcon } from '@material-symbols/svg-600/outlined/notifications-fill.svg';
|
||||
|
|
|
@ -3,10 +3,10 @@ import { useCallback, useEffect, useRef } from 'react';
|
|||
|
||||
import { useIntl, defineMessages, FormattedMessage } from 'react-intl';
|
||||
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { OrderedSet, List as ImmutableList } from 'immutable';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import { shallowEqual } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
|
||||
import Toggle from 'react-toggle';
|
||||
|
||||
|
|
|
@ -6,11 +6,11 @@ import classNames from 'classnames';
|
|||
import { Helmet } from 'react-helmet';
|
||||
import { withRouter } from 'react-router-dom';
|
||||
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import Immutable from 'immutable';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
|
||||
import { ReactComponent as VisibilityIcon } from '@material-symbols/svg-600/outlined/visibility.svg';
|
||||
import { ReactComponent as VisibilityOffIcon } from '@material-symbols/svg-600/outlined/visibility_off.svg';
|
||||
|
|
|
@ -2,11 +2,11 @@ import PropTypes from 'prop-types';
|
|||
|
||||
import { defineMessages, FormattedMessage, injectIntl } from 'react-intl';
|
||||
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { is, List as ImmutableList, Set as ImmutableSet } from 'immutable';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
|
||||
import { ReactComponent as CloseIcon } from '@material-symbols/svg-600/outlined/close.svg';
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import PropTypes from 'prop-types';
|
||||
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
|
||||
import { ReactComponent as ListAltIcon } from '@material-symbols/svg-600/outlined/list_alt.svg';
|
||||
import { ReactComponent as AntennaIcon } from '@material-symbols/svg-600/outlined/wifi.svg';
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { Map as ImmutableMap, List as ImmutableList } from 'immutable';
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
|
||||
import { debounce } from 'lodash';
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"about.blocks": "Servijerioù habaskaet",
|
||||
"about.blocks": "Servijerioù evezhiet",
|
||||
"about.contact": "Darempred :",
|
||||
"about.disclaimer": "Mastodon zo ur meziant frank, open-source hag ur merk marilhet eus Mastodon gGmbH.",
|
||||
"about.domain_blocks.no_reason_available": "Abeg dihegerz",
|
||||
|
@ -21,6 +21,8 @@
|
|||
"account.blocked": "Stanket",
|
||||
"account.browse_more_on_origin_server": "Furchal pelloc'h war ar profil orin",
|
||||
"account.cancel_follow_request": "Nullañ ar reked heuliañ",
|
||||
"account.copy": "Eilañ al liamm war-zu ho profil",
|
||||
"account.direct": "Menegiñ @{name} ent-prevez",
|
||||
"account.disable_notifications": "Paouez d'am c'hemenn pa vez embannet traoù gant @{name}",
|
||||
"account.domain_blocked": "Domani stanket",
|
||||
"account.edit_profile": "Kemmañ ar profil",
|
||||
|
@ -28,8 +30,9 @@
|
|||
"account.endorse": "Lakaat war-wel war ar profil",
|
||||
"account.featured_tags.last_status_at": "Toud diwezhañ : {date}",
|
||||
"account.featured_tags.last_status_never": "Toud ebet",
|
||||
"account.featured_tags.title": "Penngerioù-klik {name}",
|
||||
"account.featured_tags.title": "Hashtagoù pennañ {name}",
|
||||
"account.follow": "Heuliañ",
|
||||
"account.follow_back": "Heuliañ d'ho tro",
|
||||
"account.followers": "Tud koumanantet",
|
||||
"account.followers.empty": "Den na heul an implijer·ez-mañ c'hoazh.",
|
||||
"account.followers_counter": "{count, plural, other{{counter} Heulier·ez}}",
|
||||
|
@ -38,6 +41,7 @@
|
|||
"account.follows.empty": "An implijer·ez-mañ na heul den ebet.",
|
||||
"account.go_to_profile": "Gwelet ar profil",
|
||||
"account.hide_reblogs": "Kuzh skignadennoù gant @{name}",
|
||||
"account.in_memoriam": "E koun.",
|
||||
"account.joined_short": "Amañ abaoe",
|
||||
"account.languages": "Cheñch ar yezhoù koumanantet",
|
||||
"account.link_verified_on": "Gwiriet eo bet perc'hennidigezh al liamm d'an deiziad-mañ : {date}",
|
||||
|
@ -49,11 +53,13 @@
|
|||
"account.mute_notifications_short": "Kuzhat ar c'hemennoù",
|
||||
"account.mute_short": "Kuzhat",
|
||||
"account.muted": "Kuzhet",
|
||||
"account.no_bio": "Deskrivadur ebet da gaout.",
|
||||
"account.open_original_page": "Digeriñ ar bajenn orin",
|
||||
"account.posts": "Toudoù",
|
||||
"account.posts_with_replies": "Toudoù ha respontoù",
|
||||
"account.posts": "Embannadurioù",
|
||||
"account.posts_with_replies": "Embannadurioù ha respontoù",
|
||||
"account.report": "Disklêriañ @{name}",
|
||||
"account.requested": "O c'hortoz an asant. Klikit evit nullañ ar goulenn heuliañ",
|
||||
"account.requested_follow": "Gant {name} eo bet goulennet ho heuliañ",
|
||||
"account.share": "Skignañ profil @{name}",
|
||||
"account.show_reblogs": "Diskouez skignadennoù @{name}",
|
||||
"account.statuses_counter": "{count, plural, one {{counter} Toud} two {{counter} Doud} other {{counter} a Doudoù}}",
|
||||
|
@ -63,6 +69,7 @@
|
|||
"account.unendorse": "Paouez da lakaat war-wel war ar profil",
|
||||
"account.unfollow": "Diheuliañ",
|
||||
"account.unmute": "Diguzhat @{name}",
|
||||
"account.unmute_notifications_short": "Diguzhat ar c'hemennoù",
|
||||
"account.unmute_short": "Diguzhat",
|
||||
"account_note.placeholder": "Klikit evit ouzhpennañ un notenn",
|
||||
"admin.dashboard.daily_retention": "Feur azdalc'h an implijerien·ezed dre zeiz goude bezañ lakaet o anv",
|
||||
|
@ -70,6 +77,9 @@
|
|||
"admin.dashboard.retention.average": "Keidenn",
|
||||
"admin.dashboard.retention.cohort": "Miz an enrolladur",
|
||||
"admin.dashboard.retention.cohort_size": "Implijerien.erezed nevez",
|
||||
"admin.impact_report.instance_accounts": "Profiloù kontoù a vefe dilamet",
|
||||
"admin.impact_report.instance_followers": "Heulierien a gollfe hon implijerien",
|
||||
"admin.impact_report.instance_follows": "Heulierien a gollfe o implijerien",
|
||||
"alert.rate_limited.message": "Klaskit en-dro a-benn {retry_time, time, medium}.",
|
||||
"alert.rate_limited.title": "Feur bevennet",
|
||||
"alert.unexpected.message": "Ur fazi dic'hortozet zo degouezhet.",
|
||||
|
@ -100,8 +110,10 @@
|
|||
"column.blocks": "Implijer·ezed·ien berzet",
|
||||
"column.bookmarks": "Sinedoù",
|
||||
"column.community": "Red-amzer lec'hel",
|
||||
"column.direct": "Menegoù prevez",
|
||||
"column.directory": "Mont a-dreuz ar profiloù",
|
||||
"column.domain_blocks": "Domani berzet",
|
||||
"column.favourites": "Muiañ-karet",
|
||||
"column.follow_requests": "Rekedoù heuliañ",
|
||||
"column.home": "Degemer",
|
||||
"column.lists": "Listennoù",
|
||||
|
@ -122,6 +134,9 @@
|
|||
"community.column_settings.remote_only": "Nemet a-bell",
|
||||
"compose.language.change": "Cheñch yezh",
|
||||
"compose.language.search": "Klask yezhoù...",
|
||||
"compose.published.body": "Embannet.",
|
||||
"compose.published.open": "Digeriñ",
|
||||
"compose.saved.body": "Enrollet.",
|
||||
"compose_form.direct_message_warning_learn_more": "Gouzout hiroc'h",
|
||||
"compose_form.encryption_warning": "Toudoù war Mastodon na vezont ket sifret penn-da-benn. Na rannit ket titouroù kizidik dre Mastodon.",
|
||||
"compose_form.hashtag_warning": "This post won't be listed under any hashtag as it is unlisted. Only public posts can be searched by hashtag.",
|
||||
|
@ -158,6 +173,7 @@
|
|||
"confirmations.discard_edit_media.message": "Bez ez eus kemmoù n'int ket enrollet e deskrivadur ar media pe ar rakwel, nullañ anezho evelato?",
|
||||
"confirmations.domain_block.confirm": "Berzañ an domani a-bezh",
|
||||
"confirmations.domain_block.message": "Ha sur oc'h e fell deoc'h berzañ an {domain} a-bezh? Peurvuiañ eo trawalc'h berzañ pe mudañ un nebeud implijer·ezed·ien. Ne welot danvez ebet o tont eus an domani-mañ. Dilamet e vo ar c'houmanantoù war an domani-mañ.",
|
||||
"confirmations.edit.confirm": "Kemmañ",
|
||||
"confirmations.logout.confirm": "Digevreañ",
|
||||
"confirmations.logout.message": "Ha sur oc'h e fell deoc'h digevreañ ?",
|
||||
"confirmations.mute.confirm": "Kuzhat",
|
||||
|
@ -172,7 +188,9 @@
|
|||
"conversation.mark_as_read": "Merkañ evel lennet",
|
||||
"conversation.open": "Gwelout ar gaozeadenn",
|
||||
"conversation.with": "Gant {names}",
|
||||
"copy_icon_button.copied": "Eilet er golver",
|
||||
"copypaste.copied": "Eilet",
|
||||
"copypaste.copy_to_clipboard": "Eilañ er golver",
|
||||
"directory.federated": "Eus ar fedibed anavezet",
|
||||
"directory.local": "Eus {domain} hepken",
|
||||
"directory.new_arrivals": "Degouezhet a-nevez",
|
||||
|
@ -209,7 +227,8 @@
|
|||
"empty_column.domain_blocks": "N'eus domani kuzh ebet c'hoazh.",
|
||||
"empty_column.explore_statuses": "N'eus tuadur ebet evit c'hoazh. Distroit diwezhatoc'h !",
|
||||
"empty_column.follow_requests": "N'ho peus reked heuliañ ebet c'hoazh. Pa vo resevet unan e teuio war wel amañ.",
|
||||
"empty_column.hashtag": "N'eus netra er ger-klik-mañ c'hoazh.",
|
||||
"empty_column.followed_tags": "N'emaoc'h oc'h heuliañ hashtag ebet evit poent. Pa vioc'h e vo d'o gwelet amañ.",
|
||||
"empty_column.hashtag": "N'eus netra en hashtag-mañ c'hoazh.",
|
||||
"empty_column.home": "Goullo eo ho red-amzer degemer! Kit da weladenniñ {public} pe implijit ar c'hlask evit kregiñ ganti ha kejañ gant implijer·ien·ezed all.",
|
||||
"empty_column.list": "Goullo eo al listenn-mañ evit c'hoazh. Pa vo embannet toudoù nevez gant e izili e teuint war wel amañ.",
|
||||
"empty_column.lists": "N'ho peus roll ebet c'hoazh. Pa vo krouet unan ganeoc'h e vo diskouezet amañ.",
|
||||
|
@ -223,7 +242,11 @@
|
|||
"errors.unexpected_crash.copy_stacktrace": "Eilañ ar roudoù diveugañ er golver",
|
||||
"errors.unexpected_crash.report_issue": "Danevellañ ur fazi",
|
||||
"explore.search_results": "Disoc'hoù an enklask",
|
||||
"explore.suggested_follows": "Tud",
|
||||
"explore.title": "Furchal",
|
||||
"explore.trending_links": "Keleier",
|
||||
"explore.trending_statuses": "Embannadurioù",
|
||||
"explore.trending_tags": "Hashtagoù",
|
||||
"filter_modal.added.context_mismatch_title": "Kenarroud digenglotus !",
|
||||
"filter_modal.added.expired_title": "Sil deuet d'e dermen !",
|
||||
"filter_modal.added.review_and_configure_title": "Arventennoù ar sil",
|
||||
|
@ -237,9 +260,13 @@
|
|||
"filter_modal.select_filter.subtitle": "Implijout ur rummad a zo anezhañ pe krouiñ unan nevez",
|
||||
"filter_modal.select_filter.title": "Silañ an toud-mañ",
|
||||
"filter_modal.title.status": "Silañ un toud",
|
||||
"firehose.all": "Pep tra",
|
||||
"firehose.local": "Ar servijer-mañ",
|
||||
"firehose.remote": "Servijerioù all",
|
||||
"follow_request.authorize": "Aotren",
|
||||
"follow_request.reject": "Nac'hañ",
|
||||
"follow_requests.unlocked_explanation": "Daoust ma n'eo ket ho kont prennet, skipailh {domain} a soñj e fellfe deoc'h gwiriekaat pedadennoù heuliañ deus ar c'hontoù-se diwar-zorn.",
|
||||
"followed_tags": "Hashtagoù o heuliañ",
|
||||
"footer.about": "Diwar-benn",
|
||||
"footer.directory": "Kavlec'h ar profiloù",
|
||||
"footer.get_app": "Pellgargañ an arload",
|
||||
|
@ -247,29 +274,40 @@
|
|||
"footer.keyboard_shortcuts": "Berradennoù klavier",
|
||||
"footer.privacy_policy": "Reolennoù prevezded",
|
||||
"footer.source_code": "Gwelet kod mammenn",
|
||||
"footer.status": "Statud",
|
||||
"generic.saved": "Enrollet",
|
||||
"getting_started.heading": "Loc'hañ",
|
||||
"hashtag.column_header.tag_mode.all": "ha {additional}",
|
||||
"hashtag.column_header.tag_mode.all": "ha(g) {additional}",
|
||||
"hashtag.column_header.tag_mode.any": "pe {additional}",
|
||||
"hashtag.column_header.tag_mode.none": "hep {additional}",
|
||||
"hashtag.column_settings.select.no_options_message": "N'eus bet kavet ali ebet",
|
||||
"hashtag.column_settings.select.placeholder": "Ouzhpennañ gerioù-klik…",
|
||||
"hashtag.column_settings.tag_mode.all": "An holl elfennoù-mañ",
|
||||
"hashtag.column_settings.select.placeholder": "Ouzhpennañ hashtagoù…",
|
||||
"hashtag.column_settings.tag_mode.all": "An holl anezho",
|
||||
"hashtag.column_settings.tag_mode.any": "Unan e mesk anezho",
|
||||
"hashtag.column_settings.tag_mode.none": "Hini ebet anezho",
|
||||
"hashtag.column_settings.tag_toggle": "Endelc'her gerioù-alc'hwez ouzhpenn evit ar bannad-mañ",
|
||||
"hashtag.counter_by_uses": "{count, plural, one {{counter} embannadur} other {{counter} embannadur}}",
|
||||
"hashtag.counter_by_uses_today": "{count, plural, one {{counter} embannadur} other {{counter} embannadur}} hiziv",
|
||||
"hashtag.follow": "Heuliañ ar ger-klik",
|
||||
"hashtag.unfollow": "Diheuliañ ar ger-klik",
|
||||
"hashtag.unfollow": "Paouez heuliañ an hashtag",
|
||||
"hashtags.and_other": "…{count, plural, one {hag # all} other {ha # all}}",
|
||||
"home.actions.go_to_explore": "Gwelet petra zo diouzh ar c'hiz",
|
||||
"home.actions.go_to_suggestions": "Kavout tud da heuliañ",
|
||||
"home.column_settings.basic": "Diazez",
|
||||
"home.column_settings.show_reblogs": "Diskouez ar skignadennoù",
|
||||
"home.column_settings.show_replies": "Diskouez ar respontoù",
|
||||
"home.explore_prompt.title": "Homañ eo ho pajenn degemer e-barzh Mastodon.",
|
||||
"home.hide_announcements": "Kuzhat ar c'hemennoù",
|
||||
"home.pending_critical_update.body": "Hizivait ho servijer Mastodon kerkent ha ma c'hallit mar plij!",
|
||||
"home.pending_critical_update.link": "Gwelet an hizivadennoù",
|
||||
"home.show_announcements": "Diskouez ar c'hemennoù",
|
||||
"interaction_modal.description.follow": "Gant ur gont Mastodon e c'hellit heuliañ {name} evit resev an toudoù a embann war ho red degemer.",
|
||||
"interaction_modal.description.reblog": "Gant ur gont Mastodon e c'hellit skignañ an toud-mañ evit rannañ anezhañ gant ho heulierien·ezed.",
|
||||
"interaction_modal.description.reply": "Gant ur gont Mastodon e c'hellit respont d'an toud-mañ.",
|
||||
"interaction_modal.no_account_yet": "N'eo ket war vMastodon?",
|
||||
"interaction_modal.on_another_server": "War ur servijer all",
|
||||
"interaction_modal.on_this_server": "War ar servijer-mañ",
|
||||
"interaction_modal.title.favourite": "Ouzhpennañ embannadur {name} d'ar re vuiañ-karet",
|
||||
"interaction_modal.title.follow": "Heuliañ {name}",
|
||||
"interaction_modal.title.reblog": "Skignañ toud {name}",
|
||||
"interaction_modal.title.reply": "Respont da doud {name}",
|
||||
|
@ -285,6 +323,8 @@
|
|||
"keyboard_shortcuts.direct": "to open direct messages column",
|
||||
"keyboard_shortcuts.down": "Diskennañ er roll",
|
||||
"keyboard_shortcuts.enter": "Digeriñ an toud",
|
||||
"keyboard_shortcuts.favourite": "Ouzhpennañ an embannadur d'ar re vuiañ-karet",
|
||||
"keyboard_shortcuts.favourites": "Digeriñ roll an embannadurioù muiañ-karet",
|
||||
"keyboard_shortcuts.federated": "Digeriñ ar red-amzer kevredet",
|
||||
"keyboard_shortcuts.heading": "Berradennoù klavier",
|
||||
"keyboard_shortcuts.home": "Digeriñ ho red-amzer degemer",
|
||||
|
@ -314,6 +354,8 @@
|
|||
"lightbox.next": "Da-heul",
|
||||
"lightbox.previous": "A-raok",
|
||||
"limited_account_hint.action": "Diskouez an aelad memes tra",
|
||||
"limited_account_hint.title": "Kuzhet eo bet ar profil-mañ gant an evezhierien eus {domain}.",
|
||||
"link_preview.author": "Gant {name}",
|
||||
"lists.account.add": "Ouzhpennañ d'al listenn",
|
||||
"lists.account.remove": "Lemel kuit eus al listenn",
|
||||
"lists.delete": "Dilemel al listenn",
|
||||
|
@ -328,6 +370,7 @@
|
|||
"lists.search": "Klask e-touez tud heuliet ganeoc'h",
|
||||
"lists.subheading": "Ho listennoù",
|
||||
"load_pending": "{count, plural, one {# dra nevez} other {# dra nevez}}",
|
||||
"loading_indicator.label": "O kargañ…",
|
||||
"media_gallery.toggle_visible": "{number, plural, one {Kuzhat ar skeudenn} other {Kuzhat ar skeudenn}}",
|
||||
"mute_modal.duration": "Padelezh",
|
||||
"mute_modal.hide_notifications": "Kuzhat kemenadennoù eus an implijer-se ?",
|
||||
|
@ -337,12 +380,15 @@
|
|||
"navigation_bar.bookmarks": "Sinedoù",
|
||||
"navigation_bar.community_timeline": "Red-amzer lec'hel",
|
||||
"navigation_bar.compose": "Skrivañ un toud nevez",
|
||||
"navigation_bar.direct": "Menegoù prevez",
|
||||
"navigation_bar.discover": "Dizoleiñ",
|
||||
"navigation_bar.domain_blocks": "Domanioù kuzhet",
|
||||
"navigation_bar.edit_profile": "Kemmañ ar profil",
|
||||
"navigation_bar.explore": "Furchal",
|
||||
"navigation_bar.favourites": "Muiañ-karet",
|
||||
"navigation_bar.filters": "Gerioù kuzhet",
|
||||
"navigation_bar.follow_requests": "Pedadoù heuliañ",
|
||||
"navigation_bar.followed_tags": "Hashtagoù o heuliañ",
|
||||
"navigation_bar.follows_and_followers": "Heuliadennoù ha heulier·ezed·ien",
|
||||
"navigation_bar.lists": "Listennoù",
|
||||
"navigation_bar.logout": "Digennaskañ",
|
||||
|
@ -369,6 +415,7 @@
|
|||
"notifications.column_settings.admin.report": "Disklêriadurioù nevez :",
|
||||
"notifications.column_settings.admin.sign_up": "Enskrivadurioù nevez :",
|
||||
"notifications.column_settings.alert": "Kemennoù war ar burev",
|
||||
"notifications.column_settings.favourite": "Muiañ-karet:",
|
||||
"notifications.column_settings.filter_bar.advanced": "Skrammañ an-holl rummadoù",
|
||||
"notifications.column_settings.filter_bar.category": "Barrenn siloù prim",
|
||||
"notifications.column_settings.filter_bar.show_bar": "Diskouezh barrenn siloù",
|
||||
|
@ -386,6 +433,7 @@
|
|||
"notifications.column_settings.update": "Kemmoù :",
|
||||
"notifications.filter.all": "Pep tra",
|
||||
"notifications.filter.boosts": "Skignadennoù",
|
||||
"notifications.filter.favourites": "Muiañ-karet",
|
||||
"notifications.filter.follows": "Heuliañ",
|
||||
"notifications.filter.mentions": "Menegoù",
|
||||
"notifications.filter.polls": "Disoc'hoù ar sontadegoù",
|
||||
|
@ -399,22 +447,38 @@
|
|||
"notifications_permission_banner.enable": "Lezel kemennoù war ar burev",
|
||||
"notifications_permission_banner.how_to_control": "Evit reseviñ kemennoù pa ne vez ket digoret Mastodon, lezelit kemennoù war ar burev. Gallout a rit kontrollañ peseurt eskemmoù a c'henel kemennoù war ar burev gant ar {icon} nozelenn a-us kentre ma'z int lezelet.",
|
||||
"notifications_permission_banner.title": "Na vankit netra morse",
|
||||
"onboarding.action.back": "Distreiñ",
|
||||
"onboarding.actions.back": "Distreiñ",
|
||||
"onboarding.actions.go_to_explore": "See what's trending",
|
||||
"onboarding.actions.go_to_home": "Go to your home feed",
|
||||
"onboarding.compose.template": "Salud #Mastodon!",
|
||||
"onboarding.follows.lead": "You curate your own home feed. The more people you follow, the more active and interesting it will be. These profiles may be a good starting point—you can always unfollow them later!",
|
||||
"onboarding.follows.title": "Popular on Mastodon",
|
||||
"onboarding.profile.display_name": "Anv diskouezet",
|
||||
"onboarding.profile.display_name_hint": "Hoc'h anv klok pe hoc'h anv fentus…",
|
||||
"onboarding.profile.note": "Berr-ha-berr",
|
||||
"onboarding.profile.note_hint": "Gallout a rit @menegiñ tud all pe #hashtagoù…",
|
||||
"onboarding.profile.save_and_continue": "Enrollañ ha kenderc'hel",
|
||||
"onboarding.profile.upload_avatar": "Enporzhiañ ur skeudenn profil",
|
||||
"onboarding.share.lead": "Roit da c'houzout d'an dud e c'hallont ho kavout war vMastondon!",
|
||||
"onboarding.share.message": "Me a zo {username} war #Mastodon! Heuilhit ac'hanon war {url}",
|
||||
"onboarding.share.title": "Skignañ ho profil",
|
||||
"onboarding.start.lead": "Your new Mastodon account is ready to go. Here's how you can make the most of it:",
|
||||
"onboarding.start.skip": "Want to skip right ahead?",
|
||||
"onboarding.start.title": "Deuet oc'h a-benn!",
|
||||
"onboarding.steps.follow_people.body": "You curate your own feed. Lets fill it with interesting people.",
|
||||
"onboarding.steps.follow_people.title": "Follow {count, plural, one {one person} other {# people}}",
|
||||
"onboarding.steps.publish_status.body": "Say hello to the world.",
|
||||
"onboarding.steps.publish_status.title": "Grit hoc'h embannadur kentañ",
|
||||
"onboarding.steps.setup_profile.body": "Others are more likely to interact with you with a filled out profile.",
|
||||
"onboarding.steps.setup_profile.title": "Customize your profile",
|
||||
"onboarding.steps.share_profile.body": "Let your friends know how to find you on Mastodon!",
|
||||
"onboarding.steps.share_profile.title": "Share your profile",
|
||||
"password_confirmation.mismatching": "Disheñvel eo an daou c'her-termen-se",
|
||||
"picture_in_picture.restore": "Adlakaat",
|
||||
"poll.closed": "Serret",
|
||||
"poll.refresh": "Azbevaat",
|
||||
"poll.reveal": "Gwelet an disoc'hoù",
|
||||
"poll.total_people": "{count, plural, one {# den} other {# a zen}}",
|
||||
"poll.total_votes": "{count, plural, one {# votadenn} other {# votadenn}}",
|
||||
"poll.vote": "Mouezhiañ",
|
||||
|
@ -433,6 +497,7 @@
|
|||
"privacy.unlisted.short": "Anlistennet",
|
||||
"privacy_policy.last_updated": "Hizivadenn ziwezhañ {date}",
|
||||
"privacy_policy.title": "Reolennoù Prevezded",
|
||||
"recommended": "Erbedet",
|
||||
"refresh": "Freskaat",
|
||||
"regeneration_indicator.label": "O kargañ…",
|
||||
"regeneration_indicator.sublabel": "War brientiñ emañ ho red degemer!",
|
||||
|
@ -450,6 +515,7 @@
|
|||
"reply_indicator.cancel": "Nullañ",
|
||||
"report.block": "Stankañ",
|
||||
"report.block_explanation": "Ne vo ket gwelet toudoù ar gont-se ken. Ne welo ket ho toudoù ha ne c'hello ket ho heuliañ ken. Gouzout a raio eo bet stanket ganeoc'h.",
|
||||
"report.categories.legal": "Lezennel",
|
||||
"report.categories.other": "All",
|
||||
"report.categories.spam": "Spam",
|
||||
"report.categories.violation": "Torret e vez gant an endalc'had unan pe meur a reolenn",
|
||||
|
@ -467,6 +533,7 @@
|
|||
"report.placeholder": "Askelennoù ouzhpenn",
|
||||
"report.reasons.dislike": "Ne blij ket din",
|
||||
"report.reasons.dislike_description": "An dra-se na fell ket deoc'h gwelet",
|
||||
"report.reasons.legal": "Enep al lezenn eo",
|
||||
"report.reasons.other": "Un abeg all eo",
|
||||
"report.reasons.other_description": "Ar gudenn na glot ket gant ar rummadoù all",
|
||||
"report.reasons.spam": "Spam eo",
|
||||
|
@ -482,16 +549,32 @@
|
|||
"report.thanks.title": "Ne fell ket deoc'h gwelet an dra-se ?",
|
||||
"report.thanks.title_actionable": "Trugarez evit bezañ disklêriet, emaomp o vont da glask pelloc'h.",
|
||||
"report.unfollow": "Diheuliañ @{name}",
|
||||
"report_notification.attached_statuses": "{count, plural, one {# post} other {# posts}} attached",
|
||||
"report_notification.attached_statuses": "{count, plural, one {{count} embannadur} other {{count} embannadur}} stag",
|
||||
"report_notification.categories.legal": "Lezennel",
|
||||
"report_notification.categories.other": "All",
|
||||
"report_notification.categories.spam": "Spam",
|
||||
"report_notification.categories.violation": "Torradur da reolennoù ar servijer",
|
||||
"report_notification.open": "Digeriñ an disklêriadur",
|
||||
"search.no_recent_searches": "Klask nevez ebet",
|
||||
"search.placeholder": "Klask",
|
||||
"search.quick_action.account_search": "Profiloù a glot gant {x}",
|
||||
"search.quick_action.go_to_account": "Mont d'ar profil {x}",
|
||||
"search.quick_action.go_to_hashtag": "Mont d'an hashtag {x}",
|
||||
"search.quick_action.open_url": "Digeriñ an URL e-barzh Mastodon",
|
||||
"search.quick_action.status_search": "Embannadurioù a glot gant {x}",
|
||||
"search.search_or_paste": "Klask pe pegañ un URL",
|
||||
"search_popout.full_text_search_disabled_message": "N'eo ket da gaout war {domain}.",
|
||||
"search_popout.language_code": "Kod yezh ISO",
|
||||
"search_popout.options": "Dibarzhioù klask",
|
||||
"search_popout.quick_actions": "Oberoù prim",
|
||||
"search_popout.recent": "Klaskoù nevesañ",
|
||||
"search_popout.specific_date": "deiziad resis",
|
||||
"search_popout.user": "implijer·ez",
|
||||
"search_results.accounts": "Profiloù",
|
||||
"search_results.all": "Pep tra",
|
||||
"search_results.hashtags": "Gerioù-klik",
|
||||
"search_results.hashtags": "Hashtagoù",
|
||||
"search_results.nothing_found": "Disoc'h ebet gant ar gerioù-se",
|
||||
"search_results.see_all": "Gwelet pep tra",
|
||||
"search_results.statuses": "Toudoù",
|
||||
"search_results.title": "Klask {q}",
|
||||
"server_banner.active_users": "implijerien·ezed oberiant",
|
||||
|
@ -500,8 +583,10 @@
|
|||
"server_banner.server_stats": "Stadegoù ar servijer :",
|
||||
"sign_in_banner.create_account": "Krouiñ ur gont",
|
||||
"sign_in_banner.sign_in": "Kevreañ",
|
||||
"status.admin_account": "Digeriñ etrefas evezherezh evit @{name}",
|
||||
"status.admin_status": "Digeriñ an toud e-barzh an etrefas evezherezh",
|
||||
"sign_in_banner.sso_redirect": "Kennaskañ pe lakaat hoc'h anv",
|
||||
"status.admin_account": "Digeriñ etrefas evezhiañ evit @{name}",
|
||||
"status.admin_domain": "Digeriñ an etrefas evezhiañ evit {domain}",
|
||||
"status.admin_status": "Digeriñ an embannadenn e-barzh an etrefas evezhiañ",
|
||||
"status.block": "Berzañ @{name}",
|
||||
"status.bookmark": "Ouzhpennañ d'ar sinedoù",
|
||||
"status.cancel_reblog_private": "Nac'hañ ar skignadenn",
|
||||
|
@ -509,15 +594,21 @@
|
|||
"status.copy": "Eilañ liamm ar c'hannad",
|
||||
"status.delete": "Dilemel",
|
||||
"status.detailed_status": "Gwel kaozeadenn munudek",
|
||||
"status.direct": "Menegiñ @{name} ent-prevez",
|
||||
"status.direct_indicator": "Meneg prevez",
|
||||
"status.edit": "Kemmañ",
|
||||
"status.edited": "Aozet {date}",
|
||||
"status.edited_x_times": "Edited {count, plural, one {# time} other {# times}}",
|
||||
"status.embed": "Enframmañ",
|
||||
"status.favourite": "Muiañ-karet",
|
||||
"status.filter": "Silañ ar c'hannad-mañ",
|
||||
"status.filtered": "Silet",
|
||||
"status.hide": "Kuzhat an embannadur",
|
||||
"status.history.created": "Krouet gant {name} {date}",
|
||||
"status.history.edited": "Kemmet gant {name} {date}",
|
||||
"status.load_more": "Kargañ muioc'h",
|
||||
"status.media.open": "Klikit evit digeriñ",
|
||||
"status.media.show": "Klikit evit diskouez",
|
||||
"status.media_hidden": "Media kuzhet",
|
||||
"status.mention": "Menegiñ @{name}",
|
||||
"status.more": "Muioc'h",
|
||||
|
@ -548,6 +639,7 @@
|
|||
"status.title.with_attachments": "{user} posted {attachmentCount, plural, one {an attachment} other {# attachments}}",
|
||||
"status.translate": "Treiñ",
|
||||
"status.translated_from_with": "Troet diwar {lang} gant {provider}",
|
||||
"status.uncached_media_warning": "Rakwel n'eo ket da gaout",
|
||||
"status.unmute_conversation": "Diguzhat ar gaozeadenn",
|
||||
"status.unpin": "Dispilhennañ eus ar profil",
|
||||
"subscribed_languages.save": "Enrollañ ar cheñchamantoù",
|
||||
|
@ -592,6 +684,7 @@
|
|||
"upload_modal.preview_label": "Rakwel ({ratio})",
|
||||
"upload_progress.label": "O pellgargañ...",
|
||||
"upload_progress.processing": "War ober…",
|
||||
"username.taken": "Tapet eo an anv implijer-mañ dija. Klaskit skrivañ unan all",
|
||||
"video.close": "Serriñ ar video",
|
||||
"video.download": "Pellgargañ ar restr",
|
||||
"video.exit_fullscreen": "Kuitaat ar mod skramm leun",
|
||||
|
|
|
@ -62,7 +62,7 @@
|
|||
"account.requested": "Die Genehmigung steht noch aus. Klicke hier, um die Follower-Anfrage zurückzuziehen",
|
||||
"account.requested_follow": "{name} möchte dir folgen",
|
||||
"account.share": "Profil von @{name} teilen",
|
||||
"account.show_reblogs": "Geteilte Beiträge von @{name} wieder anzeigen",
|
||||
"account.show_reblogs": "Geteilte Beiträge von @{name} anzeigen",
|
||||
"account.statuses_counter": "{count, plural, one {{counter} Beitrag} other {{counter} Beiträge}}",
|
||||
"account.unblock": "Blockierung von @{name} aufheben",
|
||||
"account.unblock_domain": "Blockierung von {domain} aufheben",
|
||||
|
|
|
@ -260,6 +260,9 @@
|
|||
"filter_modal.select_filter.subtitle": "Χρησιμοποιήστε μια υπάρχουσα κατηγορία ή δημιουργήστε μια νέα",
|
||||
"filter_modal.select_filter.title": "Φιλτράρισμα αυτής της ανάρτησης",
|
||||
"filter_modal.title.status": "Φιλτράρισμα μιας ανάρτησης",
|
||||
"firehose.all": "Όλα",
|
||||
"firehose.local": "Αυτός ο διακομιστής",
|
||||
"firehose.remote": "Άλλοι διακομιστές",
|
||||
"follow_request.authorize": "Εξουσιοδότησε",
|
||||
"follow_request.reject": "Απέρριψε",
|
||||
"follow_requests.unlocked_explanation": "Παρόλο που ο λογαριασμός σου δεν είναι κλειδωμένος, το προσωπικό του {domain} θεώρησαν πως ίσως να θέλεις να ελέγξεις χειροκίνητα αυτά τα αιτήματα ακολούθησης.",
|
||||
|
@ -285,11 +288,15 @@
|
|||
"hashtag.column_settings.tag_toggle": "Προσθήκη επιπλέον ταμπελών για την κολώνα",
|
||||
"hashtag.follow": "Παρακολούθηση ετικέτας",
|
||||
"hashtag.unfollow": "Διακοπή παρακολούθησης ετικέτας",
|
||||
"home.actions.go_to_suggestions": "Βρείτε άτομα για να ακολουθήσετε",
|
||||
"home.column_settings.basic": "Βασικές ρυθμίσεις",
|
||||
"home.column_settings.show_reblogs": "Εμφάνιση προωθήσεων",
|
||||
"home.column_settings.show_replies": "Εμφάνιση απαντήσεων",
|
||||
"home.explore_prompt.body": "Your home feed will have a mix of posts from the hashtags you've chosen to follow, the people you've chosen to follow, and the posts they boost. If that feels too quiet, you may want to:\nΗ τροφοδοσία της αρχικής σελίδας σας είναι ένα μίγμα από αναρτήσεις με τις ετικέτες και τα άτομα που επιλέξατε να ακολουθείτε, και τις αναρτήσεις που προωθούν. Εάν αυτό σας φαίνεται πολύ ήσυχο, μπορεί να θέλετε:",
|
||||
"home.explore_prompt.title": "Αυτό είναι το σπίτι σας στο Mastodon.",
|
||||
"home.hide_announcements": "Απόκρυψη ανακοινώσεων",
|
||||
"home.pending_critical_update.link": "Δείτε ενημερώσεις",
|
||||
"home.pending_critical_update.title": "Κρίσιμη ενημέρωση ασφαλείας διαθέσιμη!",
|
||||
"home.show_announcements": "Εμφάνιση ανακοινώσεων",
|
||||
"interaction_modal.description.follow": "Με έναν λογαριασμό Mastodon, μπορείς να ακολουθήσεις τον/την {name} ώστε να λαμβάνεις τις αναρτήσεις του/της στη δική σου ροή.",
|
||||
"interaction_modal.description.reblog": "Με ένα λογαριασμό Mastodon, μπορείς να ενισχύσεις αυτή την ανάρτηση για να τη μοιραστείς με τους δικούς σου ακολούθους.",
|
||||
|
@ -314,6 +321,7 @@
|
|||
"keyboard_shortcuts.direct": "για το άνοιγμα της στήλης ιδιωτικών επισημάνσεων",
|
||||
"keyboard_shortcuts.down": "κίνηση προς τα κάτω στη λίστα",
|
||||
"keyboard_shortcuts.enter": "Εμφάνιση ανάρτησης",
|
||||
"keyboard_shortcuts.favourite": "Αγαπημένη δημοσίευση",
|
||||
"keyboard_shortcuts.federated": "Άνοιγμα ροής συναλλαγών",
|
||||
"keyboard_shortcuts.heading": "Συντομεύσεις πληκτρολογίου",
|
||||
"keyboard_shortcuts.home": "Άνοιγμα ροής αρχικής σελίδας",
|
||||
|
@ -358,6 +366,7 @@
|
|||
"lists.search": "Αναζήτησε μεταξύ των ανθρώπων που ακουλουθείς",
|
||||
"lists.subheading": "Οι λίστες σου",
|
||||
"load_pending": "{count, plural, one {# νέο στοιχείο} other {# νέα στοιχεία}}",
|
||||
"loading_indicator.label": "Φόρτωση…",
|
||||
"media_gallery.toggle_visible": "{number, plural, one {Απόκρυψη εικόνας} other {Απόκρυψη εικόνων}}",
|
||||
"moved_to_account_banner.text": "Ο λογαριασμός σου {disabledAccount} είναι προσωρινά απενεργοποιημένος επειδή μεταφέρθηκες στον {movedToAccount}.",
|
||||
"mute_modal.duration": "Διάρκεια",
|
||||
|
@ -380,6 +389,7 @@
|
|||
"navigation_bar.lists": "Λίστες",
|
||||
"navigation_bar.logout": "Αποσύνδεση",
|
||||
"navigation_bar.mutes": "Αποσιωπημένοι χρήστες",
|
||||
"navigation_bar.opened_in_classic_interface": "Δημοσιεύσεις, λογαριασμοί και άλλες συγκεκριμένες σελίδες ανοίγονται από προεπιλογή στην κλασική διεπαφή ιστού.",
|
||||
"navigation_bar.personal": "Προσωπικά",
|
||||
"navigation_bar.pins": "Καρφιτσωμένες αναρτήσεις",
|
||||
"navigation_bar.preferences": "Προτιμήσεις",
|
||||
|
@ -403,6 +413,7 @@
|
|||
"notifications.column_settings.admin.report": "Νέες αναφορές:",
|
||||
"notifications.column_settings.admin.sign_up": "Νέες εγγραφές:",
|
||||
"notifications.column_settings.alert": "Ειδοποιήσεις επιφάνειας εργασίας",
|
||||
"notifications.column_settings.favourite": "Αγαπημένα:",
|
||||
"notifications.column_settings.filter_bar.advanced": "Εμφάνιση όλων των κατηγοριών",
|
||||
"notifications.column_settings.filter_bar.category": "Μπάρα γρήγορου φίλτρου",
|
||||
"notifications.column_settings.filter_bar.show_bar": "Εμφάνιση μπάρας φίλτρου",
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
"account.blocked": "Estetty",
|
||||
"account.browse_more_on_origin_server": "Selaile lisää alkuperäisellä palvelimella",
|
||||
"account.cancel_follow_request": "Peruuta seurantapyyntö",
|
||||
"account.copy": "Kopioi profiililinkki",
|
||||
"account.copy": "Kopioi linkki profiiliin",
|
||||
"account.direct": "Mainitse @{name} yksityisesti",
|
||||
"account.disable_notifications": "Lopeta ilmoittamasta minulle, kun @{name} julkaisee",
|
||||
"account.domain_blocked": "Verkkotunnus estetty",
|
||||
|
@ -53,7 +53,7 @@
|
|||
"account.mute_notifications_short": "Mykistä ilmoitukset",
|
||||
"account.mute_short": "Mykistä",
|
||||
"account.muted": "Mykistetty",
|
||||
"account.mutual": "Molemmat",
|
||||
"account.mutual": "Seuraatte toisianne",
|
||||
"account.no_bio": "Kuvausta ei ole annettu.",
|
||||
"account.open_original_page": "Avaa alkuperäinen sivu",
|
||||
"account.posts": "Julkaisut",
|
||||
|
@ -193,7 +193,7 @@
|
|||
"conversation.mark_as_read": "Merkitse luetuksi",
|
||||
"conversation.open": "Näytä keskustelu",
|
||||
"conversation.with": "{names} kanssa",
|
||||
"copy_icon_button.copied": "Kopioitiin leikepöydälle",
|
||||
"copy_icon_button.copied": "Sisältö kopioitiin leikepöydälle",
|
||||
"copypaste.copied": "Kopioitu",
|
||||
"copypaste.copy_to_clipboard": "Kopioi leikepöydälle",
|
||||
"directory.federated": "Koko tunnettu fediversumi",
|
||||
|
@ -483,10 +483,10 @@
|
|||
"onboarding.follows.lead": "Kokoat oman kotisyötteesi itse. Mitä enemmän ihmisiä seuraat, sitä aktiivisempi ja kiinnostavampi syöte on. Nämä profiilit voivat olla alkuun hyvä lähtökohta — voit aina lopettaa niiden seuraamisen myöhemmin!",
|
||||
"onboarding.follows.title": "Mukauta kotisyötettäsi",
|
||||
"onboarding.profile.discoverable": "Aseta profiilini löydettäväksi",
|
||||
"onboarding.profile.discoverable_hint": "Kun olet määrittänyt itsesi löydettäväksi Mastodonista, julkaisusi voivat näkyä hakutuloksissa ja suosituissa kohteissa ja profiiliasi voidaan ehdottaa käyttäjille, jotka ovat kiinnostuneet samoista aiheista kuin sinä.",
|
||||
"onboarding.profile.discoverable_hint": "Kun olet määrittänyt itsesi löydettäväksi Mastodonista, julkaisusi voivat näkyä hakutuloksissa ja suosituissa kohteissa. Lisäksi profiiliasi voidaan ehdottaa käyttäjille, jotka ovat kiinnostuneita kanssasi samoista aiheista.",
|
||||
"onboarding.profile.display_name": "Näyttönimi",
|
||||
"onboarding.profile.display_name_hint": "Koko nimesi tai lempinimesi…",
|
||||
"onboarding.profile.lead": "Voit viimeistellä tämän milloin tahansa asetuksista, jotka tarjoavat vielä enemmän mukautusvalintoja.",
|
||||
"onboarding.profile.lead": "Voit viimeistellä tämän milloin tahansa asetuksista. Sieltä löydät myös lisää mukautusvaihtoehtoja.",
|
||||
"onboarding.profile.note": "Elämäkerta",
|
||||
"onboarding.profile.note_hint": "Voit @mainita muita käyttäjiä tai #aihetunnisteita…",
|
||||
"onboarding.profile.save_and_continue": "Tallenna ja jatka",
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
{
|
||||
"about.blocks": "Servitores moderate",
|
||||
"about.contact": "Contacto:",
|
||||
"about.disclaimer": "Mastodon es software libere, de codice aperte, e un marca de Mastodon gGmbH.",
|
||||
"about.rules": "Regulas del servitor",
|
||||
"account.account_note_header": "Nota",
|
||||
"account.add_or_remove_from_list": "Adder o remover ab listas",
|
||||
"account.badges.group": "Gruppo",
|
||||
"account.block": "Blocar @{name}",
|
||||
|
@ -6,14 +11,43 @@
|
|||
"account.blocked": "Blocate",
|
||||
"account.copy": "Copiar ligamine a profilo",
|
||||
"account.edit_profile": "Modificar profilo",
|
||||
"account.endorse": "Evidentiar sur le profilo",
|
||||
"account.featured_tags.last_status_at": "Ultime message in {date}",
|
||||
"account.featured_tags.last_status_never": "Necun messages",
|
||||
"account.follow": "Sequer",
|
||||
"account.follow_back": "Sequer etiam",
|
||||
"account.followers": "Sequitores",
|
||||
"account.following": "Sequente",
|
||||
"account.go_to_profile": "Vader al profilo",
|
||||
"account.hide_reblogs": "Celar boosts de @{name}",
|
||||
"account.languages": "Cambiar le linguas subscribite",
|
||||
"account.link_verified_on": "Le proprietate de iste ligamine esseva verificate le {date}",
|
||||
"account.locked_info": "Le stato de confidentialitate de iste conto es definite a blocate. Le proprietario revisa manualmente qui pote sequer lo.",
|
||||
"account.mention": "Mentionar @{name}",
|
||||
"account.moved_to": "{name} indicava que lor nove conto ora es:",
|
||||
"account.mute": "Silentiar @{name}",
|
||||
"account.mute_notifications_short": "Silentiar le notificationes",
|
||||
"account.mute_short": "Silentiar",
|
||||
"account.muted": "Silentiate",
|
||||
"account.no_bio": "Nulle description fornite.",
|
||||
"account.posts": "Messages",
|
||||
"account.posts_with_replies": "Messages e responsas",
|
||||
"account.share": "Compartir profilo de @{name}",
|
||||
"account.show_reblogs": "Monstrar responsas de @{name}",
|
||||
"account.unblock": "Disblocar @{name}",
|
||||
"account.unblock_domain": "Disblocar dominio {domain}",
|
||||
"account.unblock_short": "Disblocar",
|
||||
"account.unendorse": "Non evidentiar sur le profilo",
|
||||
"account.unmute": "Non plus silentiar @{name}",
|
||||
"account.unmute_notifications_short": "Non plus silentiar le notificationes",
|
||||
"account.unmute_short": "Non plus silentiar",
|
||||
"account_note.placeholder": "Clicca pro adder un nota",
|
||||
"admin.dashboard.retention.cohort_size": "Nove usatores",
|
||||
"admin.impact_report.instance_followers": "Sequitores que nostre usatores poterea perder",
|
||||
"admin.impact_report.instance_follows": "Sequitores que lor usatores poterea perder",
|
||||
"alert.rate_limited.message": "Retenta depost {retry_time, time, medium}.",
|
||||
"alert.unexpected.message": "Ocurreva un error inexpectate.",
|
||||
"announcement.announcement": "Annuncio",
|
||||
"audio.hide": "Celar audio",
|
||||
"autosuggest_hashtag.per_week": "{count} per septimana",
|
||||
"bundle_column_error.network.title": "Error de rete",
|
||||
|
@ -21,87 +55,260 @@
|
|||
"bundle_column_error.return": "Retornar al initio",
|
||||
"bundle_modal_error.close": "Clauder",
|
||||
"bundle_modal_error.retry": "Tentar novemente",
|
||||
"closed_registrations_modal.find_another_server": "Trovar altere servitor",
|
||||
"column.about": "A proposito de",
|
||||
"column.blocks": "Usatores blocate",
|
||||
"column.bookmarks": "Marcapaginas",
|
||||
"column.community": "Chronologia local",
|
||||
"column.direct": "Mentiones private",
|
||||
"column.directory": "Navigar profilos",
|
||||
"column.domain_blocks": "Dominios blocate",
|
||||
"column.favourites": "Favoritos",
|
||||
"column.firehose": "Fluxos in directe",
|
||||
"column.home": "Initio",
|
||||
"column.lists": "Listas",
|
||||
"column.mutes": "Usatores silentiate",
|
||||
"column.notifications": "Notificationes",
|
||||
"column.public": "Chronologia federate",
|
||||
"column_header.hide_settings": "Celar le parametros",
|
||||
"column_header.moveLeft_settings": "Mover columna al sinistra",
|
||||
"column_header.moveRight_settings": "Mover columna al dextra",
|
||||
"column_header.show_settings": "Monstrar le parametros",
|
||||
"column_subheading.settings": "Parametros",
|
||||
"compose.language.change": "Cambiar le lingua",
|
||||
"compose.language.search": "Cercar linguas...",
|
||||
"compose.published.body": "Message publicate.",
|
||||
"compose.published.open": "Aperir",
|
||||
"compose.saved.body": "Message salvate.",
|
||||
"compose_form.direct_message_warning_learn_more": "Apprender plus",
|
||||
"compose_form.lock_disclaimer": "Tu conto non es {locked}. Quicunque pote sequer te pro vider tu messages solo pro sequitores.",
|
||||
"compose_form.lock_disclaimer.lock": "blocate",
|
||||
"compose_form.poll.add_option": "Adder un option",
|
||||
"compose_form.poll.remove_option": "Remover iste option",
|
||||
"compose_form.publish": "Publicar",
|
||||
"compose_form.publish_form": "Nove message",
|
||||
"compose_form.publish_loud": "{publish}!",
|
||||
"compose_form.save_changes": "Salvar le cambiamentos",
|
||||
"compose_form.spoiler.marked": "Remover advertimento de contento",
|
||||
"compose_form.spoiler.unmarked": "Adder advertimento de contento",
|
||||
"compose_form.spoiler_placeholder": "Scribe tu advertimento hic",
|
||||
"confirmation_modal.cancel": "Cancellar",
|
||||
"confirmations.block.confirm": "Blocar",
|
||||
"confirmations.delete.confirm": "Deler",
|
||||
"confirmations.delete.message": "Es tu secur que tu vole deler iste message?",
|
||||
"confirmations.delete_list.confirm": "Deler",
|
||||
"confirmations.delete_list.message": "Es tu secur que tu vole deler permanentemente iste lista?",
|
||||
"confirmations.domain_block.confirm": "Blocar le dominio complete",
|
||||
"confirmations.edit.confirm": "Modificar",
|
||||
"confirmations.logout.confirm": "Clauder le session",
|
||||
"confirmations.logout.message": "Es tu secur que tu vole clauder le session?",
|
||||
"confirmations.mute.confirm": "Silentiar",
|
||||
"confirmations.mute.message": "Es tu secur que tu vole silentiar {name}?",
|
||||
"confirmations.reply.confirm": "Responder",
|
||||
"conversation.delete": "Deler conversation",
|
||||
"conversation.mark_as_read": "Marcar como legite",
|
||||
"conversation.open": "Vider conversation",
|
||||
"conversation.with": "Con {names}",
|
||||
"copy_icon_button.copied": "Copiate al area de transferentia",
|
||||
"copypaste.copied": "Copiate",
|
||||
"copypaste.copy_to_clipboard": "Copiar al area de transferentia",
|
||||
"directory.federated": "Ab le fediverso cognoscite",
|
||||
"directory.local": "Solmente ab {domain}",
|
||||
"directory.recently_active": "Recentemente active",
|
||||
"disabled_account_banner.account_settings": "Parametros de conto",
|
||||
"disabled_account_banner.text": "Tu conto {disabledAccount} es actualmente disactivate.",
|
||||
"dismissable_banner.dismiss": "Dimitter",
|
||||
"emoji_button.activity": "Activitate",
|
||||
"emoji_button.clear": "Rader",
|
||||
"emoji_button.custom": "Personalisate",
|
||||
"emoji_button.recent": "Frequentemente usate",
|
||||
"emoji_button.search": "Cercar...",
|
||||
"emoji_button.search_results": "Resultatos de recerca",
|
||||
"empty_column.account_suspended": "Conto suspendite",
|
||||
"empty_column.account_timeline": "Nulle messages hic!",
|
||||
"empty_column.account_unavailable": "Profilo non disponibile",
|
||||
"empty_column.blocks": "Tu non ha blocate alcun usator ancora.",
|
||||
"errors.unexpected_crash.report_issue": "Signalar un defecto",
|
||||
"explore.search_results": "Resultatos de recerca",
|
||||
"explore.title": "Explorar",
|
||||
"explore.trending_links": "Novas",
|
||||
"explore.trending_statuses": "Messages",
|
||||
"explore.trending_tags": "Hashtags",
|
||||
"filter_modal.added.review_and_configure_title": "Parametros de filtro",
|
||||
"filter_modal.added.settings_link": "pagina de parametros",
|
||||
"filter_modal.added.short_explanation": "Iste message esseva addite al sequente categoria de filtros: {title}.",
|
||||
"filter_modal.added.title": "Filtro addite!",
|
||||
"filter_modal.select_filter.prompt_new": "Nove categoria: {name}",
|
||||
"filter_modal.select_filter.search": "Cercar o crear",
|
||||
"filter_modal.select_filter.title": "Filtrar iste message",
|
||||
"filter_modal.title.status": "Filtrar un message",
|
||||
"firehose.all": "Toto",
|
||||
"firehose.local": "Iste servitor",
|
||||
"firehose.remote": "Altere servitores",
|
||||
"footer.about": "A proposito de",
|
||||
"footer.directory": "Directorio de profilos",
|
||||
"footer.get_app": "Obtene le application",
|
||||
"footer.keyboard_shortcuts": "Accessos directe de claviero",
|
||||
"footer.privacy_policy": "Politica de confidentialitate",
|
||||
"footer.source_code": "Vider le codice fonte",
|
||||
"footer.status": "Stato",
|
||||
"generic.saved": "Salvate",
|
||||
"getting_started.heading": "Prime passos",
|
||||
"hashtag.column_header.tag_mode.all": "e {additional}",
|
||||
"hashtag.column_header.tag_mode.any": "o {additional}",
|
||||
"hashtag.column_settings.select.no_options_message": "Nulle suggestiones trovate",
|
||||
"hashtag.column_settings.select.placeholder": "Insere hashtags…",
|
||||
"hashtag.follow": "Sequer hashtag",
|
||||
"home.column_settings.show_reblogs": "Monstrar boosts",
|
||||
"home.column_settings.show_replies": "Monstrar responsas",
|
||||
"home.hide_announcements": "Celar annuncios",
|
||||
"home.pending_critical_update.body": "Actualisa tu servitor de Mastodon le plus tosto possibile!",
|
||||
"home.pending_critical_update.link": "Vider actualisationes",
|
||||
"home.show_announcements": "Monstrar annuncios",
|
||||
"interaction_modal.no_account_yet": "Non sur Mstodon?",
|
||||
"interaction_modal.on_another_server": "In un servitor differente",
|
||||
"interaction_modal.on_this_server": "In iste servitor",
|
||||
"interaction_modal.title.follow": "Sequer {name}",
|
||||
"interaction_modal.title.reblog": "Facer boost al message de {name}",
|
||||
"interaction_modal.title.reply": "Responder al message de {name}",
|
||||
"keyboard_shortcuts.blocked": "Aperir lista de usatores blocate",
|
||||
"keyboard_shortcuts.boost": "Facer boost al message",
|
||||
"keyboard_shortcuts.description": "Description",
|
||||
"keyboard_shortcuts.enter": "Aperir message",
|
||||
"keyboard_shortcuts.favourites": "Aperir lista de favoritos",
|
||||
"keyboard_shortcuts.federated": "Aperir le chronologia federate",
|
||||
"keyboard_shortcuts.heading": "Accessos directe de claviero",
|
||||
"keyboard_shortcuts.home": "Aperir le chronologia de initio",
|
||||
"keyboard_shortcuts.local": "Aperir le chronologia local",
|
||||
"keyboard_shortcuts.muted": "Aperir lista de usatores silentiate",
|
||||
"keyboard_shortcuts.my_profile": "Aperir tu profilo",
|
||||
"keyboard_shortcuts.notifications": "Aperir columna de notificationes",
|
||||
"keyboard_shortcuts.reply": "Responder al message",
|
||||
"keyboard_shortcuts.spoilers": "Monstrar/celar le campo CW",
|
||||
"keyboard_shortcuts.toot": "Initiar un nove message",
|
||||
"lightbox.close": "Clauder",
|
||||
"lightbox.next": "Sequente",
|
||||
"lightbox.previous": "Precedente",
|
||||
"link_preview.author": "Per {name}",
|
||||
"lists.account.add": "Adder al lista",
|
||||
"lists.account.remove": "Remover ab le lista",
|
||||
"lists.delete": "Deler lista",
|
||||
"lists.edit": "Modificar lista",
|
||||
"lists.edit.submit": "Cambiar titulo",
|
||||
"lists.exclusive": "Celar iste messages ab le initio",
|
||||
"lists.new.create": "Adder lista",
|
||||
"lists.new.title_placeholder": "Nove titulo del lista",
|
||||
"lists.replies_policy.title": "Monstrar responsas a:",
|
||||
"lists.subheading": "Tu listas",
|
||||
"mute_modal.duration": "Duration",
|
||||
"mute_modal.hide_notifications": "Celar notificationes de iste usator?",
|
||||
"navigation_bar.about": "A proposito de",
|
||||
"navigation_bar.advanced_interface": "Aperir in un interfacie web avantiate",
|
||||
"navigation_bar.blocks": "Usatores blocate",
|
||||
"navigation_bar.bookmarks": "Marcapaginas",
|
||||
"navigation_bar.community_timeline": "Chronologia local",
|
||||
"navigation_bar.direct": "Mentiones private",
|
||||
"navigation_bar.discover": "Discoperir",
|
||||
"navigation_bar.domain_blocks": "Dominios blocate",
|
||||
"navigation_bar.edit_profile": "Modificar profilo",
|
||||
"navigation_bar.favourites": "Favoritos",
|
||||
"navigation_bar.filters": "Parolas silentiate",
|
||||
"navigation_bar.lists": "Listas",
|
||||
"navigation_bar.logout": "Clauder le session",
|
||||
"navigation_bar.mutes": "Usatores silentiate",
|
||||
"navigation_bar.preferences": "Preferentias",
|
||||
"navigation_bar.public_timeline": "Chronologia federate",
|
||||
"navigation_bar.search": "Cercar",
|
||||
"navigation_bar.security": "Securitate",
|
||||
"notification.update": "{name} modificava un message",
|
||||
"notifications.clear": "Rader notificationes",
|
||||
"notifications.column_settings.alert": "Notificationes de scriptorio",
|
||||
"notifications.column_settings.filter_bar.advanced": "Monstrar tote le categorias",
|
||||
"notifications.column_settings.follow": "Nove sequitores:",
|
||||
"notifications.column_settings.mention": "Mentiones:",
|
||||
"notifications.column_settings.push": "Notificationes push",
|
||||
"notifications.column_settings.sound": "Reproducer sono",
|
||||
"notifications.column_settings.status": "Nove messages:",
|
||||
"notifications.filter.all": "Toto",
|
||||
"notifications.filter.favourites": "Favoritos",
|
||||
"notifications.filter.mentions": "Mentiones",
|
||||
"notifications.grant_permission": "Conceder permission.",
|
||||
"notifications.group": "{count} notificationes",
|
||||
"onboarding.compose.template": "Salute #Mastodon!",
|
||||
"onboarding.profile.save_and_continue": "Salvar e continuar",
|
||||
"onboarding.share.next_steps": "Sequente passos possibile:",
|
||||
"onboarding.share.title": "Compartir tu profilo",
|
||||
"onboarding.steps.follow_people.title": "Personalisa tu fluxo de initio",
|
||||
"onboarding.steps.publish_status.title": "Face tu prime message",
|
||||
"onboarding.steps.setup_profile.title": "Personalisa tu profilo",
|
||||
"onboarding.steps.share_profile.title": "Compartir tu profilo de Mastodon",
|
||||
"poll.closed": "Claudite",
|
||||
"poll.reveal": "Vider le resultatos",
|
||||
"privacy.change": "Cambiar privacitate del message",
|
||||
"privacy.private.long": "Visibile solmente pro sequitores",
|
||||
"privacy.public.long": "Visibile pro totos",
|
||||
"privacy.public.short": "Public",
|
||||
"privacy_policy.last_updated": "Ultime actualisation {date}",
|
||||
"privacy_policy.title": "Politica de confidentialitate",
|
||||
"relative_time.just_now": "ora",
|
||||
"relative_time.today": "hodie",
|
||||
"reply_indicator.cancel": "Cancellar",
|
||||
"report.block": "Blocar",
|
||||
"report.categories.other": "Alteres",
|
||||
"report.category.title_account": "profilo",
|
||||
"report.category.title_status": "message",
|
||||
"report.close": "Preste",
|
||||
"report.mute": "Silentiar",
|
||||
"report.next": "Sequente",
|
||||
"report.placeholder": "Commentos additional",
|
||||
"report.reasons.dislike": "Non me place",
|
||||
"report_notification.categories.other": "Alteres",
|
||||
"search.quick_action.go_to_account": "Vader al profilo {x}",
|
||||
"search.quick_action.go_to_hashtag": "Vader al hashtag {x}",
|
||||
"search.quick_action.open_url": "Aperir URL in Mastodon",
|
||||
"search_popout.full_text_search_disabled_message": "Non disponibile sur {domain}.",
|
||||
"search_popout.language_code": "Codice de lingua ISO",
|
||||
"search_popout.options": "Optiones de recerca",
|
||||
"search_popout.quick_actions": "Actiones rapide",
|
||||
"search_popout.recent": "Recercas recente",
|
||||
"search_popout.user": "usator",
|
||||
"search_results.accounts": "Profilos",
|
||||
"search_results.hashtags": "Hashtags",
|
||||
"search_results.see_all": "Vider toto",
|
||||
"search_results.statuses": "Messages",
|
||||
"server_banner.learn_more": "Apprender plus",
|
||||
"sign_in_banner.create_account": "Crear un conto",
|
||||
"sign_in_banner.sign_in": "Initiar le session",
|
||||
"status.block": "Blocar @{name}",
|
||||
"status.copy": "Copiar ligamine a message",
|
||||
"status.delete": "Deler",
|
||||
"status.direct_indicator": "Mention private",
|
||||
"status.edit": "Modificar",
|
||||
"status.filter": "Filtrar iste message",
|
||||
"status.hide": "Celar le message",
|
||||
"status.history.created": "create per {name} le {date}",
|
||||
"status.history.edited": "modificate per {name} le {date}",
|
||||
"status.media.open": "Clicca pro aperir",
|
||||
"status.media.show": "Clicca pro monstrar",
|
||||
"status.more": "Plus",
|
||||
"status.mute_conversation": "Silentiar conversation",
|
||||
"status.read_more": "Leger plus",
|
||||
"status.share": "Compartir",
|
||||
"status.translate": "Traducer",
|
||||
"status.translated_from_with": "Traducite ab {lang} usante {provider}",
|
||||
"tabs_bar.home": "Initio",
|
||||
"tabs_bar.notifications": "Notificationes"
|
||||
"tabs_bar.notifications": "Notificationes",
|
||||
"timeline_hint.resources.statuses": "Messages ancian",
|
||||
"trends.trending_now": "Ora in tendentias",
|
||||
"upload_form.undo": "Deler",
|
||||
"upload_modal.choose_image": "Seliger un imagine",
|
||||
"upload_modal.detect_text": "Deteger texto ab un pictura",
|
||||
"video.close": "Clauder le video",
|
||||
"video.download": "Discargar le file",
|
||||
"video.fullscreen": "Schermo plen",
|
||||
"video.hide": "Celar video",
|
||||
"video.mute": "Silentiar le sono",
|
||||
"video.pause": "Pausa",
|
||||
"video.play": "Reproducer",
|
||||
"video.unmute": "Non plus silentiar le sono"
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
"account.featured_tags.last_status_never": "投稿がありません",
|
||||
"account.featured_tags.title": "{name}の注目ハッシュタグ",
|
||||
"account.follow": "フォロー",
|
||||
"account.follow_back": "フォローバック",
|
||||
"account.followers": "フォロワー",
|
||||
"account.followers.empty": "まだ誰もフォローしていません。",
|
||||
"account.followers_counter": "{counter} フォロワー",
|
||||
|
@ -61,6 +62,7 @@
|
|||
"account.mute_notifications_short": "通知をオフにする",
|
||||
"account.mute_short": "ミュート",
|
||||
"account.muted": "ミュート済み",
|
||||
"account.mutual": "相互フォロー中",
|
||||
"account.no_bio": "説明が提供されていません。",
|
||||
"account.open_original_page": "元のページを開く",
|
||||
"account.posts": "投稿",
|
||||
|
@ -594,7 +596,7 @@
|
|||
"onboarding.profile.display_name_hint": "フルネーム、あるいは面白い名前など",
|
||||
"onboarding.profile.lead": "あとでいつでも修正できますし、設定画面にはこれ以外のカスタマイズ項目もあります。",
|
||||
"onboarding.profile.note": "自己紹介",
|
||||
"onboarding.profile.note_hint": "ほかの人に @言及 したり、#ハッシュタグ を付けたりできます",
|
||||
"onboarding.profile.note_hint": "ほかのユーザーへのメンション (@mention) や、 #ハッシュタグ が使用できます",
|
||||
"onboarding.profile.save_and_continue": "保存して続ける",
|
||||
"onboarding.profile.title": "プロフィールの設定",
|
||||
"onboarding.profile.upload_avatar": "プロフィール画像をアップロード",
|
||||
|
|
|
@ -501,6 +501,7 @@
|
|||
"onboarding.steps.setup_profile.title": "Personaliza tu profil",
|
||||
"onboarding.steps.share_profile.body": "Informe a tus amigos komo toparte en Mastodon",
|
||||
"onboarding.steps.share_profile.title": "Partaja tu profil de Mastodon",
|
||||
"password_confirmation.exceeds_maxlength": "La konfirmasyon de kod es demaziado lunga",
|
||||
"password_confirmation.mismatching": "Los dos kodes son desferentes",
|
||||
"picture_in_picture.restore": "Restora",
|
||||
"poll.closed": "Serrado",
|
||||
|
|
|
@ -42,7 +42,7 @@
|
|||
"account.go_to_profile": "Przejdź do profilu",
|
||||
"account.hide_reblogs": "Ukryj podbicia od @{name}",
|
||||
"account.in_memoriam": "Ku pamięci.",
|
||||
"account.joined_short": "Dołączony",
|
||||
"account.joined_short": "Dołączył(a)",
|
||||
"account.languages": "Zmień subskrybowane języki",
|
||||
"account.link_verified_on": "Własność tego odnośnika została potwierdzona {date}",
|
||||
"account.locked_info": "To konto jest prywatne. Właściciel ręcznie wybiera kto może go obserwować.",
|
||||
|
@ -492,7 +492,7 @@
|
|||
"onboarding.profile.save_and_continue": "Zapisz i kontynuuj",
|
||||
"onboarding.profile.title": "Ustawienia profilu",
|
||||
"onboarding.profile.upload_avatar": "Dodaj zdjęcie profilowe",
|
||||
"onboarding.profile.upload_header": "Dodaj zdjęcie nagłówkowe",
|
||||
"onboarding.profile.upload_header": "Dodaj banner profilu",
|
||||
"onboarding.share.lead": "Daj znać ludziom, jak mogą cię znaleźć na Mastodonie!",
|
||||
"onboarding.share.message": "Jestem {username} na #Mastodon! Śledź mnie tutaj {url}",
|
||||
"onboarding.share.next_steps": "Możliwe dalsze kroki:",
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
"account.featured_tags.last_status_never": "Pa postime",
|
||||
"account.featured_tags.title": "Hashtagë të zgjedhur të {name}",
|
||||
"account.follow": "Ndiqeni",
|
||||
"account.follow_back": "Ndiqe gjithashtu",
|
||||
"account.followers": "Ndjekës",
|
||||
"account.followers.empty": "Këtë përdorues ende s’e ndjek kush.",
|
||||
"account.followers_counter": "{count, plural, one {{counter} Ndjekës} other {{counter} Ndjekës}}",
|
||||
|
@ -52,6 +53,7 @@
|
|||
"account.mute_notifications_short": "Mos shfaq njoftime",
|
||||
"account.mute_short": "Mos i shfaq",
|
||||
"account.muted": "Heshtuar",
|
||||
"account.mutual": "Reciproke",
|
||||
"account.no_bio": "S’u dha përshkrim.",
|
||||
"account.open_original_page": "Hap faqen origjinale",
|
||||
"account.posts": "Mesazhe",
|
||||
|
|
|
@ -240,7 +240,7 @@
|
|||
"empty_column.follow_requests": "Bạn chưa có yêu cầu theo dõi nào.",
|
||||
"empty_column.followed_tags": "Bạn chưa theo dõi hashtag nào. Khi bạn theo dõi, chúng sẽ hiện lên ở đây.",
|
||||
"empty_column.hashtag": "Chưa có tút nào dùng hashtag này.",
|
||||
"empty_column.home": "Trang chính của bạn đang trống! Hãy theo dõi nhiều người hơn để lấp đầy.",
|
||||
"empty_column.home": "Trang chủ của bạn đang trống! Hãy theo dõi nhiều người hơn để lấp đầy.",
|
||||
"empty_column.list": "Chưa có tút. Khi những người trong danh sách này đăng tút mới, chúng sẽ xuất hiện ở đây.",
|
||||
"empty_column.lists": "Bạn chưa tạo danh sách nào.",
|
||||
"empty_column.mutes": "Bạn chưa ẩn bất kỳ ai.",
|
||||
|
@ -336,38 +336,38 @@
|
|||
"intervals.full.days": "{number, plural, other {# ngày}}",
|
||||
"intervals.full.hours": "{number, plural, other {# giờ}}",
|
||||
"intervals.full.minutes": "{number, plural, other {# phút}}",
|
||||
"keyboard_shortcuts.back": "trở lại",
|
||||
"keyboard_shortcuts.back": "quay lại",
|
||||
"keyboard_shortcuts.blocked": "mở danh sách người đã chặn",
|
||||
"keyboard_shortcuts.boost": "đăng lại",
|
||||
"keyboard_shortcuts.column": "mở các mục",
|
||||
"keyboard_shortcuts.column": "mở các cột",
|
||||
"keyboard_shortcuts.compose": "mở khung soạn tút",
|
||||
"keyboard_shortcuts.description": "Mô tả",
|
||||
"keyboard_shortcuts.direct": "mở mục nhắn riêng",
|
||||
"keyboard_shortcuts.direct": "mở nhắn riêng",
|
||||
"keyboard_shortcuts.down": "di chuyển xuống dưới danh sách",
|
||||
"keyboard_shortcuts.enter": "viết tút mới",
|
||||
"keyboard_shortcuts.enter": "mở tút",
|
||||
"keyboard_shortcuts.favourite": "thích tút",
|
||||
"keyboard_shortcuts.favourites": "mở lượt thích",
|
||||
"keyboard_shortcuts.federated": "mở mạng liên hợp",
|
||||
"keyboard_shortcuts.heading": "Danh sách phím tắt",
|
||||
"keyboard_shortcuts.home": "mở trang chính",
|
||||
"keyboard_shortcuts.home": "mở trang chủ",
|
||||
"keyboard_shortcuts.hotkey": "Phím tắt",
|
||||
"keyboard_shortcuts.legend": "hiện bảng hướng dẫn này",
|
||||
"keyboard_shortcuts.local": "mở máy chủ của bạn",
|
||||
"keyboard_shortcuts.mention": "nhắc đến ai đó",
|
||||
"keyboard_shortcuts.muted": "mở danh sách người đã ẩn",
|
||||
"keyboard_shortcuts.my_profile": "mở hồ sơ của bạn",
|
||||
"keyboard_shortcuts.notifications": "mở mục thông báo",
|
||||
"keyboard_shortcuts.notifications": "mở thông báo",
|
||||
"keyboard_shortcuts.open_media": "mở ảnh hoặc video",
|
||||
"keyboard_shortcuts.pinned": "mở danh sách tút ghim",
|
||||
"keyboard_shortcuts.profile": "mở hồ sơ của người viết tút",
|
||||
"keyboard_shortcuts.pinned": "mở những tút đã ghim",
|
||||
"keyboard_shortcuts.profile": "mở trang của người đăng tút",
|
||||
"keyboard_shortcuts.reply": "trả lời",
|
||||
"keyboard_shortcuts.requests": "mở danh sách yêu cầu theo dõi",
|
||||
"keyboard_shortcuts.search": "mở tìm kiếm",
|
||||
"keyboard_shortcuts.spoilers": "hiện/ẩn nội dung nhạy cảm",
|
||||
"keyboard_shortcuts.start": "mở mục \"Dành cho người mới\"",
|
||||
"keyboard_shortcuts.toggle_hidden": "ẩn/hiện văn bản bên dưới spoil",
|
||||
"keyboard_shortcuts.start": "mở \"Dành cho người mới\"",
|
||||
"keyboard_shortcuts.toggle_hidden": "ẩn/hiện nội dung ẩn",
|
||||
"keyboard_shortcuts.toggle_sensitivity": "ẩn/hiện ảnh hoặc video",
|
||||
"keyboard_shortcuts.toot": "viết tút mới",
|
||||
"keyboard_shortcuts.toot": "soạn tút mới",
|
||||
"keyboard_shortcuts.unfocus": "đưa con trỏ ra khỏi ô soạn thảo hoặc ô tìm kiếm",
|
||||
"keyboard_shortcuts.up": "di chuyển lên trên danh sách",
|
||||
"lightbox.close": "Đóng",
|
||||
|
@ -404,7 +404,7 @@
|
|||
"navigation_bar.blocks": "Người đã chặn",
|
||||
"navigation_bar.bookmarks": "Đã lưu",
|
||||
"navigation_bar.community_timeline": "Cộng đồng",
|
||||
"navigation_bar.compose": "Viết tút mới",
|
||||
"navigation_bar.compose": "Soạn tút mới",
|
||||
"navigation_bar.direct": "Nhắn riêng",
|
||||
"navigation_bar.discover": "Khám phá",
|
||||
"navigation_bar.domain_blocks": "Máy chủ đã ẩn",
|
||||
|
@ -436,7 +436,7 @@
|
|||
"notification.poll": "Cuộc bình chọn đã kết thúc",
|
||||
"notification.reblog": "{name} đăng lại tút của bạn",
|
||||
"notification.status": "{name} đăng tút mới",
|
||||
"notification.update": "{name} đã viết lại một tút",
|
||||
"notification.update": "{name} đã sửa tút",
|
||||
"notifications.clear": "Xóa hết thông báo",
|
||||
"notifications.clear_confirmation": "Bạn thật sự muốn xóa vĩnh viễn tất cả thông báo của mình?",
|
||||
"notifications.column_settings.admin.report": "Báo cáo mới:",
|
||||
|
@ -477,7 +477,7 @@
|
|||
"onboarding.action.back": "Quay lại",
|
||||
"onboarding.actions.back": "Quay lại",
|
||||
"onboarding.actions.go_to_explore": "Xem những gì đang thịnh hành",
|
||||
"onboarding.actions.go_to_home": "Đến trang chính",
|
||||
"onboarding.actions.go_to_home": "Đến trang chủ",
|
||||
"onboarding.compose.template": "Xin chào #Mastodon!",
|
||||
"onboarding.follows.empty": "Không có kết quả có thể được hiển thị lúc này. Bạn có thể thử sử dụng tính năng tìm kiếm hoặc duyệt qua trang khám phá để tìm những người theo dõi hoặc thử lại sau.",
|
||||
"onboarding.follows.lead": "Bạn quản lý bảng tin của riêng bạn. Bạn càng theo dõi nhiều người, nó sẽ càng sôi động và thú vị. Để bắt đầu, đây là vài gợi ý:",
|
||||
|
@ -501,7 +501,7 @@
|
|||
"onboarding.start.skip": "Muốn bỏ qua luôn?",
|
||||
"onboarding.start.title": "Xong rồi bạn!",
|
||||
"onboarding.steps.follow_people.body": "Theo dõi những người thú vị trên Mastodon.",
|
||||
"onboarding.steps.follow_people.title": "Cá nhân hóa trang chính",
|
||||
"onboarding.steps.follow_people.title": "Cá nhân hóa trang chủ",
|
||||
"onboarding.steps.publish_status.body": "Chào cộng đồng bằng lời nói, ảnh hoặc video {emoji}",
|
||||
"onboarding.steps.publish_status.title": "Đăng tút đầu tiên",
|
||||
"onboarding.steps.setup_profile.body": "Tạo sự tương tác bằng một hồ sơ hoàn chỉnh.",
|
||||
|
@ -539,7 +539,7 @@
|
|||
"recommended": "Đề xuất",
|
||||
"refresh": "Làm mới",
|
||||
"regeneration_indicator.label": "Đang tải…",
|
||||
"regeneration_indicator.sublabel": "Trang chính của bạn đang được cập nhật!",
|
||||
"regeneration_indicator.sublabel": "Trang chủ của bạn đang được cập nhật!",
|
||||
"relative_time.days": "{number} ngày",
|
||||
"relative_time.full.days": "{number, plural, other {# ngày}}",
|
||||
"relative_time.full.hours": "{number, plural, other {# giờ}}",
|
||||
|
@ -591,7 +591,7 @@
|
|||
"report.thanks.title": "Không muốn xem thứ này?",
|
||||
"report.thanks.title_actionable": "Cảm ơn đã báo cáo, chúng tôi sẽ xem xét kỹ.",
|
||||
"report.unfollow": "Bỏ theo dõi @{name}",
|
||||
"report.unfollow_explanation": "Bạn đang theo dõi người này. Để không thấy tút của họ trên trang chính nữa, hãy bỏ theo dõi.",
|
||||
"report.unfollow_explanation": "Bạn đang theo dõi người này. Để không thấy tút của họ trên trang chủ nữa, hãy bỏ theo dõi.",
|
||||
"report_notification.attached_statuses": "{count, plural, other {{count} tút}} đính kèm",
|
||||
"report_notification.categories.legal": "Pháp lý",
|
||||
"report_notification.categories.other": "Khác",
|
||||
|
@ -692,7 +692,7 @@
|
|||
"subscribed_languages.lead": "Chỉ các tút đăng bằng các ngôn ngữ đã chọn mới được xuất hiện trên bảng tin của bạn. Không chọn gì cả để đọc tút đăng bằng mọi ngôn ngữ.",
|
||||
"subscribed_languages.save": "Lưu thay đổi",
|
||||
"subscribed_languages.target": "Đổi ngôn ngữ mong muốn cho {target}",
|
||||
"tabs_bar.home": "Trang chính",
|
||||
"tabs_bar.home": "Trang chủ",
|
||||
"tabs_bar.notifications": "Thông báo",
|
||||
"time_remaining.days": "{number, plural, other {# ngày}}",
|
||||
"time_remaining.hours": "{number, plural, other {# giờ}}",
|
||||
|
|
|
@ -53,7 +53,7 @@
|
|||
"account.mute_notifications_short": "关闭通知",
|
||||
"account.mute_short": "隐藏",
|
||||
"account.muted": "已隐藏",
|
||||
"account.mutual": "互相关注",
|
||||
"account.mutual": "互粉好友",
|
||||
"account.no_bio": "未提供描述。",
|
||||
"account.open_original_page": "打开原始页面",
|
||||
"account.posts": "嘟文",
|
||||
|
@ -446,7 +446,7 @@
|
|||
"notifications.column_settings.filter_bar.advanced": "显示所有类别",
|
||||
"notifications.column_settings.filter_bar.category": "快速过滤栏",
|
||||
"notifications.column_settings.filter_bar.show_bar": "显示过滤栏",
|
||||
"notifications.column_settings.follow": "新关注者:",
|
||||
"notifications.column_settings.follow": "新粉丝:",
|
||||
"notifications.column_settings.follow_request": "新关注请求:",
|
||||
"notifications.column_settings.mention": "提及:",
|
||||
"notifications.column_settings.poll": "投票结果:",
|
||||
|
@ -700,7 +700,7 @@
|
|||
"time_remaining.moments": "即将结束",
|
||||
"time_remaining.seconds": "剩余 {number, plural, one {# 秒} other {# 秒}}",
|
||||
"timeline_hint.remote_resource_not_displayed": "不会显示来自其它服务器的{resource}",
|
||||
"timeline_hint.resources.followers": "关注者",
|
||||
"timeline_hint.resources.followers": "粉丝",
|
||||
"timeline_hint.resources.follows": "关注",
|
||||
"timeline_hint.resources.statuses": "更早的嘟文",
|
||||
"trends.counter_by_accounts": "过去 {days, plural, other {{days} 天}}有{count, plural, other { {counter} 人}}讨论",
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import type { Reducer } from '@reduxjs/toolkit';
|
||||
import { Map as ImmutableMap } from 'immutable';
|
||||
|
||||
import type { Reducer } from 'redux';
|
||||
|
||||
import {
|
||||
followAccountSuccess,
|
||||
unfollowAccountSuccess,
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import { Record as ImmutableRecord, Stack } from 'immutable';
|
||||
|
||||
import type { Reducer } from '@reduxjs/toolkit';
|
||||
import { Record as ImmutableRecord, Stack } from 'immutable';
|
||||
|
||||
import { COMPOSE_UPLOAD_CHANGE_SUCCESS } from '../actions/compose';
|
||||
import type { ModalType } from '../actions/modal';
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import { Map as ImmutableMap } from 'immutable';
|
||||
|
||||
import { isFulfilled } from '@reduxjs/toolkit';
|
||||
import type { Reducer } from 'redux';
|
||||
import type { Reducer } from '@reduxjs/toolkit';
|
||||
import { Map as ImmutableMap } from 'immutable';
|
||||
|
||||
import type { ApiRelationshipJSON } from 'mastodon/api_types/relationships';
|
||||
import type { Account } from 'mastodon/models/account';
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { Record as ImmutableRecord } from 'immutable';
|
||||
import { createSelector } from 'reselect';
|
||||
|
||||
import { accountDefaultValues } from 'mastodon/models/account';
|
||||
import type { Account, AccountShape } from 'mastodon/models/account';
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { List as ImmutableList, Map as ImmutableMap } from 'immutable';
|
||||
import { createSelector } from 'reselect';
|
||||
|
||||
import { toServerSideType } from 'mastodon/utils/filters';
|
||||
|
||||
|
|
|
@ -1,20 +1,34 @@
|
|||
import type { AnyAction, Middleware } from 'redux';
|
||||
import { isAction } from '@reduxjs/toolkit';
|
||||
import type { Action, Middleware } from '@reduxjs/toolkit';
|
||||
|
||||
import type { RootState } from '..';
|
||||
import { showAlertForError } from '../../actions/alerts';
|
||||
|
||||
const defaultFailSuffix = 'FAIL';
|
||||
const isFailedAction = new RegExp(`${defaultFailSuffix}$`, 'g');
|
||||
|
||||
export const errorsMiddleware: Middleware<unknown, RootState> =
|
||||
interface ActionWithMaybeAlertParams extends Action {
|
||||
skipAlert?: boolean;
|
||||
skipNotFound?: boolean;
|
||||
error?: unknown;
|
||||
}
|
||||
|
||||
function isActionWithmaybeAlertParams(
|
||||
action: unknown,
|
||||
): action is ActionWithMaybeAlertParams {
|
||||
return isAction(action);
|
||||
}
|
||||
|
||||
export const errorsMiddleware: Middleware<Record<string, never>, RootState> =
|
||||
({ dispatch }) =>
|
||||
(next) =>
|
||||
(action: AnyAction & { skipAlert?: boolean; skipNotFound?: boolean }) => {
|
||||
if (action.type && !action.skipAlert) {
|
||||
const isFail = new RegExp(`${defaultFailSuffix}$`, 'g');
|
||||
|
||||
if (typeof action.type === 'string' && action.type.match(isFail)) {
|
||||
dispatch(showAlertForError(action.error, action.skipNotFound));
|
||||
}
|
||||
(action) => {
|
||||
if (
|
||||
isActionWithmaybeAlertParams(action) &&
|
||||
!action.skipAlert &&
|
||||
action.type.match(isFailedAction)
|
||||
) {
|
||||
dispatch(showAlertForError(action.error, action.skipNotFound));
|
||||
}
|
||||
|
||||
return next(action);
|
||||
|
|
|
@ -3,9 +3,11 @@ import {
|
|||
isPending as isThunkActionPending,
|
||||
isFulfilled as isThunkActionFulfilled,
|
||||
isRejected as isThunkActionRejected,
|
||||
isAction,
|
||||
} from '@reduxjs/toolkit';
|
||||
import type { Middleware, UnknownAction } from '@reduxjs/toolkit';
|
||||
|
||||
import { showLoading, hideLoading } from 'react-redux-loading-bar';
|
||||
import type { AnyAction, Middleware } from 'redux';
|
||||
|
||||
import type { RootState } from '..';
|
||||
|
||||
|
@ -19,14 +21,28 @@ const defaultTypeSuffixes: Config['promiseTypeSuffixes'] = [
|
|||
'REJECTED',
|
||||
];
|
||||
|
||||
interface ActionWithSkipLoading extends UnknownAction {
|
||||
skipLoading: boolean;
|
||||
}
|
||||
|
||||
function isActionWithSkipLoading(
|
||||
action: unknown,
|
||||
): action is ActionWithSkipLoading {
|
||||
return (
|
||||
isAction(action) &&
|
||||
'skipLoading' in action &&
|
||||
typeof action.skipLoading === 'boolean'
|
||||
);
|
||||
}
|
||||
|
||||
export const loadingBarMiddleware = (
|
||||
config: Config = {},
|
||||
): Middleware<unknown, RootState> => {
|
||||
): Middleware<{ skipLoading?: boolean }, RootState> => {
|
||||
const promiseTypeSuffixes = config.promiseTypeSuffixes ?? defaultTypeSuffixes;
|
||||
|
||||
return ({ dispatch }) =>
|
||||
(next) =>
|
||||
(action: AnyAction) => {
|
||||
(action) => {
|
||||
let isPending = false;
|
||||
let isFulfilled = false;
|
||||
let isRejected = false;
|
||||
|
@ -39,7 +55,7 @@ export const loadingBarMiddleware = (
|
|||
else if (isThunkActionFulfilled(action)) isFulfilled = true;
|
||||
else if (isThunkActionRejected(action)) isRejected = true;
|
||||
} else if (
|
||||
action.type &&
|
||||
isActionWithSkipLoading(action) &&
|
||||
!action.skipLoading &&
|
||||
typeof action.type === 'string'
|
||||
) {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import type { Middleware, AnyAction } from 'redux';
|
||||
import { isAction } from '@reduxjs/toolkit';
|
||||
import type { Middleware, UnknownAction } from '@reduxjs/toolkit';
|
||||
|
||||
import ready from 'mastodon/ready';
|
||||
import { assetHost } from 'mastodon/utils/config';
|
||||
|
@ -10,6 +11,21 @@ interface AudioSource {
|
|||
type: string;
|
||||
}
|
||||
|
||||
interface ActionWithMetaSound extends UnknownAction {
|
||||
meta: { sound: string };
|
||||
}
|
||||
|
||||
function isActionWithMetaSound(action: unknown): action is ActionWithMetaSound {
|
||||
return (
|
||||
isAction(action) &&
|
||||
'meta' in action &&
|
||||
typeof action.meta === 'object' &&
|
||||
!!action.meta &&
|
||||
'sound' in action.meta &&
|
||||
typeof action.meta.sound === 'string'
|
||||
);
|
||||
}
|
||||
|
||||
const createAudio = (sources: AudioSource[]) => {
|
||||
const audio = new Audio();
|
||||
sources.forEach(({ type, src }) => {
|
||||
|
@ -34,7 +50,10 @@ const play = (audio: HTMLAudioElement) => {
|
|||
void audio.play();
|
||||
};
|
||||
|
||||
export const soundsMiddleware = (): Middleware<unknown, RootState> => {
|
||||
export const soundsMiddleware = (): Middleware<
|
||||
Record<string, never>,
|
||||
RootState
|
||||
> => {
|
||||
const soundCache: Record<string, HTMLAudioElement> = {};
|
||||
|
||||
void ready(() => {
|
||||
|
@ -50,15 +69,15 @@ export const soundsMiddleware = (): Middleware<unknown, RootState> => {
|
|||
]);
|
||||
});
|
||||
|
||||
return () =>
|
||||
(next) =>
|
||||
(action: AnyAction & { meta?: { sound?: string } }) => {
|
||||
const sound = action.meta?.sound;
|
||||
return () => (next) => (action) => {
|
||||
if (isActionWithMetaSound(action)) {
|
||||
const sound = action.meta.sound;
|
||||
|
||||
if (sound && Object.hasOwn(soundCache, sound)) {
|
||||
play(soundCache[sound]);
|
||||
}
|
||||
}
|
||||
|
||||
return next(action);
|
||||
};
|
||||
return next(action);
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import type { TypedUseSelectorHook } from 'react-redux';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
|
||||
import { createAsyncThunk } from '@reduxjs/toolkit';
|
||||
import type { TypedUseSelectorHook } from 'react-redux';
|
||||
// eslint-disable-next-line @typescript-eslint/no-restricted-imports
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
|
||||
import type { AppDispatch, RootState } from './store';
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ class ContentSecurityPolicy
|
|||
end
|
||||
|
||||
def media_hosts
|
||||
[assets_host, cdn_host_value].compact
|
||||
[assets_host, cdn_host_value, paperclip_root_url].compact
|
||||
end
|
||||
|
||||
private
|
||||
|
@ -23,6 +23,15 @@ class ContentSecurityPolicy
|
|||
s3_alias_host || s3_cloudfront_host || azure_alias_host || s3_hostname_host
|
||||
end
|
||||
|
||||
def paperclip_root_url
|
||||
root_url = ENV.fetch('PAPERCLIP_ROOT_URL', nil)
|
||||
return if root_url.blank?
|
||||
|
||||
(Addressable::URI.parse(assets_host) + root_url).tap do |uri|
|
||||
uri.path += '/' unless uri.path.blank? || uri.path.end_with?('/')
|
||||
end.to_s
|
||||
end
|
||||
|
||||
def url_from_base_host
|
||||
host_to_url(base_host)
|
||||
end
|
||||
|
|
|
@ -69,16 +69,6 @@ class EmojiFormatter
|
|||
@emoji_map ||= custom_emojis.each_with_object({}) { |e, h| h[e.shortcode] = [full_asset_url(e.image.url), full_asset_url(e.image.url(:static))] }
|
||||
end
|
||||
|
||||
def count_tag_nesting(tag)
|
||||
if tag[1] == '/'
|
||||
-1
|
||||
elsif tag[-2] == '/'
|
||||
0
|
||||
else
|
||||
1
|
||||
end
|
||||
end
|
||||
|
||||
def tag_for_emoji(shortcode, emoji)
|
||||
return content_tag(:span, ":#{shortcode}:", translate: 'no') if raw_shortcode?
|
||||
|
||||
|
|
|
@ -409,7 +409,7 @@ class FeedManager
|
|||
# @param [Integer] receiver_id
|
||||
# @param [Hash] crutches
|
||||
# @return [Boolean]
|
||||
def filter_from_home?(status, receiver_id, crutches, timeline_type = :home, stl_home: false) # rubocop:disable Metrics/PerceivedComplexity
|
||||
def filter_from_home?(status, receiver_id, crutches, timeline_type = :home, stl_home: false) # rubocop:disable Metrics/PerceivedComplexity, Metrics/AbcSize
|
||||
return false if receiver_id == status.account_id
|
||||
return true if status.reply? && (status.in_reply_to_id.nil? || status.in_reply_to_account_id.nil?) && !(timeline_type == :home && status.limited_visibility?)
|
||||
return true if (timeline_type != :list || stl_home) && (crutches[:exclusive_list_users][status.account_id].present? || crutches[:exclusive_antenna_users][status.account_id].present?)
|
||||
|
@ -588,7 +588,7 @@ class FeedManager
|
|||
# @param [Integer] receiver_id
|
||||
# @param [Array<Status>] statuses
|
||||
# @return [Hash]
|
||||
def build_crutches(receiver_id, statuses)
|
||||
def build_crutches(receiver_id, statuses) # rubocop:disable Metrics/AbcSize
|
||||
crutches = {}
|
||||
|
||||
crutches[:active_mentions] = crutches_active_mentions(statuses)
|
||||
|
|
|
@ -1,79 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Settings
|
||||
class ScopedSettings
|
||||
DEFAULTING_TO_UNSCOPED = %w(
|
||||
theme
|
||||
noindex
|
||||
).freeze
|
||||
|
||||
def initialize(object)
|
||||
@object = object
|
||||
end
|
||||
|
||||
def method_missing(method, *args)
|
||||
method_name = method.to_s
|
||||
# set a value for a variable
|
||||
if method_name[-1] == '='
|
||||
var_name = method_name.sub('=', '')
|
||||
value = args.first
|
||||
self[var_name] = value
|
||||
else
|
||||
# retrieve a value
|
||||
self[method_name]
|
||||
end
|
||||
end
|
||||
|
||||
def respond_to_missing?(*)
|
||||
true
|
||||
end
|
||||
|
||||
def all_as_records
|
||||
vars = thing_scoped
|
||||
records = vars.index_by(&:var)
|
||||
|
||||
Setting.default_settings.each do |key, default_value|
|
||||
next if records.key?(key) || default_value.is_a?(Hash)
|
||||
|
||||
records[key] = Setting.new(var: key, value: default_value)
|
||||
end
|
||||
|
||||
records
|
||||
end
|
||||
|
||||
def []=(key, value)
|
||||
key = key.to_s
|
||||
record = thing_scoped.find_or_initialize_by(var: key)
|
||||
record.update!(value: value)
|
||||
|
||||
Rails.cache.write(Setting.cache_key(key, @object), value)
|
||||
end
|
||||
|
||||
def [](key)
|
||||
Rails.cache.fetch(Setting.cache_key(key, @object)) do
|
||||
db_val = thing_scoped.find_by(var: key.to_s)
|
||||
if db_val
|
||||
default_value = ScopedSettings.default_settings[key]
|
||||
return default_value.with_indifferent_access.merge!(db_val.value) if default_value.is_a?(Hash)
|
||||
|
||||
db_val.value
|
||||
else
|
||||
ScopedSettings.default_settings[key]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class << self
|
||||
def default_settings
|
||||
defaulting = DEFAULTING_TO_UNSCOPED.index_with { |k| Setting[k] }
|
||||
Setting.default_settings.merge!(defaulting)
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def thing_scoped
|
||||
Setting.unscoped.where(thing_type: @object.class.base_class.to_s, thing_id: @object.id)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -43,7 +43,7 @@ class StatusCacheHydrator
|
|||
end
|
||||
end
|
||||
|
||||
def hydrate_reblog_payload(empty_payload, account_id, account)
|
||||
def hydrate_reblog_payload(empty_payload, account_id, account) # rubocop:disable Metrics/AbcSize
|
||||
empty_payload.tap do |payload|
|
||||
payload[:muted] = false
|
||||
payload[:bookmarked] = false
|
||||
|
|
|
@ -115,6 +115,8 @@ class Account < ApplicationRecord
|
|||
validates :shared_inbox_url, absence: true, if: :local?, on: :create
|
||||
validates :followers_url, absence: true, if: :local?, on: :create
|
||||
|
||||
normalizes :username, with: ->(username) { username.squish }
|
||||
|
||||
scope :remote, -> { where.not(domain: nil) }
|
||||
scope :local, -> { where(domain: nil) }
|
||||
scope :partitioned, -> { order(Arel.sql('row_number() over (partition by domain)')) }
|
||||
|
@ -136,7 +138,7 @@ class Account < ApplicationRecord
|
|||
scope :discoverable, -> { searchable.without_silenced.where(discoverable: true).joins(:account_stat) }
|
||||
scope :followable_by, ->(account) { joins(arel_table.join(Follow.arel_table, Arel::Nodes::OuterJoin).on(arel_table[:id].eq(Follow.arel_table[:target_account_id]).and(Follow.arel_table[:account_id].eq(account.id))).join_sources).where(Follow.arel_table[:id].eq(nil)).joins(arel_table.join(FollowRequest.arel_table, Arel::Nodes::OuterJoin).on(arel_table[:id].eq(FollowRequest.arel_table[:target_account_id]).and(FollowRequest.arel_table[:account_id].eq(account.id))).join_sources).where(FollowRequest.arel_table[:id].eq(nil)) }
|
||||
scope :by_recent_status, -> { includes(:account_stat).merge(AccountStat.order('last_status_at DESC NULLS LAST')).references(:account_stat) }
|
||||
scope :by_recent_sign_in, -> { order(Arel.sql('users.current_sign_in_at DESC NULLS LAST')) }
|
||||
scope :by_recent_activity, -> { left_joins(:user, :account_stat).order(coalesced_activity_timestamps.desc).order(id: :desc) }
|
||||
scope :popular, -> { order('account_stats.followers_count desc') }
|
||||
scope :by_domain_and_subdomains, ->(domain) { where(domain: Instance.by_domain_and_subdomains(domain).select(:domain)) }
|
||||
scope :not_excluded_by_account, ->(account) { where.not(id: account.excluded_from_timeline_account_ids) }
|
||||
|
@ -481,6 +483,14 @@ class Account < ApplicationRecord
|
|||
DeliveryFailureTracker.without_unavailable(urls)
|
||||
end
|
||||
|
||||
def coalesced_activity_timestamps
|
||||
Arel.sql(
|
||||
<<~SQL.squish
|
||||
COALESCE(users.current_sign_in_at, account_stats.last_status_at, to_timestamp(0))
|
||||
SQL
|
||||
)
|
||||
end
|
||||
|
||||
def from_text(text)
|
||||
return [] if text.blank?
|
||||
|
||||
|
@ -514,7 +524,6 @@ class Account < ApplicationRecord
|
|||
end
|
||||
|
||||
before_validation :prepare_contents, if: :local?
|
||||
before_validation :prepare_username, on: :create
|
||||
before_create :generate_keys
|
||||
before_destroy :clean_feed_manager
|
||||
|
||||
|
@ -536,10 +545,6 @@ class Account < ApplicationRecord
|
|||
note&.strip!
|
||||
end
|
||||
|
||||
def prepare_username
|
||||
username&.squish!
|
||||
end
|
||||
|
||||
def generate_keys
|
||||
return unless local? && private_key.blank? && public_key.blank?
|
||||
|
||||
|
|
|
@ -104,15 +104,7 @@ class AccountFilter
|
|||
def order_scope(value)
|
||||
case value.to_s
|
||||
when 'active'
|
||||
accounts_with_users
|
||||
.left_joins(:account_stat)
|
||||
.order(
|
||||
Arel.sql(
|
||||
<<~SQL.squish
|
||||
COALESCE(users.current_sign_in_at, account_stats.last_status_at, to_timestamp(0)) DESC, accounts.id DESC
|
||||
SQL
|
||||
)
|
||||
)
|
||||
Account.by_recent_activity
|
||||
when 'recent'
|
||||
Account.recent
|
||||
else
|
||||
|
|
|
@ -20,9 +20,8 @@
|
|||
class Announcement < ApplicationRecord
|
||||
scope :unpublished, -> { where(published: false) }
|
||||
scope :published, -> { where(published: true) }
|
||||
scope :without_muted, ->(account) { joins("LEFT OUTER JOIN announcement_mutes ON announcement_mutes.announcement_id = announcements.id AND announcement_mutes.account_id = #{account.id}").where(announcement_mutes: { id: nil }) }
|
||||
scope :chronological, -> { order(Arel.sql('COALESCE(announcements.starts_at, announcements.scheduled_at, announcements.published_at, announcements.created_at) ASC')) }
|
||||
scope :reverse_chronological, -> { order(Arel.sql('COALESCE(announcements.starts_at, announcements.scheduled_at, announcements.published_at, announcements.created_at) DESC')) }
|
||||
scope :chronological, -> { order(coalesced_chronology_timestamps.asc) }
|
||||
scope :reverse_chronological, -> { order(coalesced_chronology_timestamps.desc) }
|
||||
|
||||
has_many :announcement_mutes, dependent: :destroy
|
||||
has_many :announcement_reactions, dependent: :destroy
|
||||
|
@ -33,6 +32,16 @@ class Announcement < ApplicationRecord
|
|||
|
||||
before_validation :set_published, on: :create
|
||||
|
||||
class << self
|
||||
def coalesced_chronology_timestamps
|
||||
Arel.sql(
|
||||
<<~SQL.squish
|
||||
COALESCE(announcements.starts_at, announcements.scheduled_at, announcements.published_at, announcements.created_at)
|
||||
SQL
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def to_log_human_identifier
|
||||
text
|
||||
end
|
||||
|
@ -45,10 +54,6 @@ class Announcement < ApplicationRecord
|
|||
update!(published: false, scheduled_at: nil)
|
||||
end
|
||||
|
||||
def time_range?
|
||||
starts_at? && ends_at?
|
||||
end
|
||||
|
||||
def mentions
|
||||
@mentions ||= Account.from_text(text)
|
||||
end
|
||||
|
|
|
@ -44,7 +44,7 @@ class CustomEmoji < ApplicationRecord
|
|||
|
||||
has_attached_file :image, styles: { static: { format: 'png', convert_options: '-coalesce +profile "!icc,*" +set date:modify +set date:create +set date:timestamp' } }, validate_media_type: false
|
||||
|
||||
before_validation :downcase_domain
|
||||
normalizes :domain, with: ->(domain) { domain.downcase }
|
||||
|
||||
validates_attachment :image, content_type: { content_type: IMAGE_MIME_TYPES }, presence: true, size: { less_than: LIMIT }
|
||||
validates :shortcode, uniqueness: { scope: :domain }, format: { with: SHORTCODE_ONLY_RE }, length: { minimum: 2 }
|
||||
|
@ -112,7 +112,7 @@ class CustomEmoji < ApplicationRecord
|
|||
end
|
||||
|
||||
def search(shortcode)
|
||||
where('"custom_emojis"."shortcode" ILIKE ?', "%#{shortcode}%")
|
||||
where(arel_table[:shortcode].matches("%#{sanitize_sql_like(shortcode)}%"))
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -122,10 +122,6 @@ class CustomEmoji < ApplicationRecord
|
|||
Rails.cache.delete(EntityCache.instance.to_key(:emoji, shortcode, domain))
|
||||
end
|
||||
|
||||
def downcase_domain
|
||||
self.domain = domain.downcase unless domain.nil?
|
||||
end
|
||||
|
||||
def set_post_size
|
||||
image.queued_for_write.each do |style, file|
|
||||
size(file.path) if style == :original
|
||||
|
|
|
@ -31,7 +31,7 @@ class CustomEmojiFilter
|
|||
def scope_for(key, value)
|
||||
case key.to_s
|
||||
when 'local'
|
||||
CustomEmoji.local.left_joins(:category).reorder(Arel.sql('custom_emoji_categories.name ASC NULLS FIRST, custom_emojis.shortcode ASC'))
|
||||
CustomEmoji.local.left_joins(:category).reorder(CustomEmojiCategory.arel_table[:name].asc.nulls_first).order(shortcode: :asc)
|
||||
when 'remote'
|
||||
CustomEmoji.remote
|
||||
when 'by_domain'
|
||||
|
|
|
@ -20,23 +20,8 @@
|
|||
class CustomFilter < ApplicationRecord
|
||||
self.ignored_columns += %w(whole_word irreversible)
|
||||
|
||||
# NOTE: We previously used `alias_attribute` but this does not play nicely
|
||||
# with cache
|
||||
def title
|
||||
phrase
|
||||
end
|
||||
|
||||
def title=(value)
|
||||
self.phrase = value
|
||||
end
|
||||
|
||||
def filter_action
|
||||
action
|
||||
end
|
||||
|
||||
def filter_action=(value)
|
||||
self.action = value
|
||||
end
|
||||
alias_attribute :title, :phrase
|
||||
alias_attribute :filter_action, :action
|
||||
|
||||
VALID_CONTEXTS = %w(
|
||||
home
|
||||
|
@ -161,6 +146,10 @@ class CustomFilter < ApplicationRecord
|
|||
end
|
||||
|
||||
def context_must_be_valid
|
||||
errors.add(:context, I18n.t('filters.errors.invalid_context')) if context.empty? || context.any? { |c| !VALID_CONTEXTS.include?(c) }
|
||||
errors.add(:context, I18n.t('filters.errors.invalid_context')) if invalid_context_value?
|
||||
end
|
||||
|
||||
def invalid_context_value?
|
||||
context.blank? || context.difference(VALID_CONTEXTS).any?
|
||||
end
|
||||
end
|
||||
|
|
|
@ -17,15 +17,7 @@ class CustomFilterKeyword < ApplicationRecord
|
|||
|
||||
validates :keyword, presence: true
|
||||
|
||||
# NOTE: We previously used `alias_attribute` but this does not play nicely
|
||||
# with cache
|
||||
def phrase
|
||||
keyword
|
||||
end
|
||||
|
||||
def phrase=(value)
|
||||
self.keyword = value
|
||||
end
|
||||
alias_attribute :phrase, :keyword
|
||||
|
||||
before_save :prepare_cache_invalidation!
|
||||
before_destroy :prepare_cache_invalidation!
|
||||
|
|
|
@ -54,7 +54,7 @@ class DomainBlock < ApplicationRecord
|
|||
.or(where(reject_straight_follow: true))
|
||||
.or(where(reject_friend: true))
|
||||
}
|
||||
scope :by_severity, -> { order(Arel.sql('(CASE severity WHEN 0 THEN 1 WHEN 1 THEN 2 WHEN 2 THEN 0 END), domain')) }
|
||||
scope :by_severity, -> { in_order_of(:severity, %w(noop silence suspend)).order(:domain) }
|
||||
|
||||
def to_log_human_identifier
|
||||
domain
|
||||
|
@ -151,11 +151,6 @@ class DomainBlock < ApplicationRecord
|
|||
(reject_media || !other_block.reject_media) && (reject_favourite || !other_block.reject_favourite) && (reject_reply || !other_block.reject_reply) && (reject_reply_exclude_followers || !other_block.reject_reply_exclude_followers) && (reject_reports || !other_block.reject_reports)
|
||||
end
|
||||
|
||||
def affected_accounts_count
|
||||
scope = suspend? ? accounts.where(suspended_at: created_at) : accounts.where(silenced_at: created_at)
|
||||
scope.count
|
||||
end
|
||||
|
||||
def public_domain
|
||||
return domain unless obfuscate?
|
||||
|
||||
|
|
|
@ -13,49 +13,114 @@
|
|||
# thing_id :bigint(8)
|
||||
#
|
||||
|
||||
class Setting < RailsSettings::Base
|
||||
source Rails.root.join('config', 'settings.yml')
|
||||
# This file is derived from a fork of the `rails-settings-cached` gem available at
|
||||
# https://github.com/mastodon/rails-settings-cached/tree/v0.6.6-aliases-true, with
|
||||
# the original available at:
|
||||
# https://github.com/huacnlee/rails-settings-cached/tree/0.x
|
||||
|
||||
# It is licensed as follows:
|
||||
|
||||
# Copyright (c) 2006 Alex Wayne
|
||||
# Some additional features added 2009 by Georg Ledermann
|
||||
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
# "Software"), to deal in the Software without restriction, including
|
||||
# without limitation the rights to use, copy, modify, merge, publish,
|
||||
# distribute, sublicense, and/or sell copies of the Software, and to
|
||||
# permit persons to whom the Software is furnished to do so, subject to
|
||||
# the following conditions:
|
||||
|
||||
# The above copyright notice and this permission notice shall be
|
||||
# included in all copies or substantial portions of the Software.
|
||||
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOa AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SaALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
class Setting < ApplicationRecord
|
||||
after_commit :rewrite_cache, on: %i(create update)
|
||||
after_commit :expire_cache, on: %i(destroy)
|
||||
|
||||
# Settings are server-wide settings only, but they were previously
|
||||
# used for users too. This can be dropped later with a database
|
||||
# migration dropping any scoped setting.
|
||||
default_scope { where(thing_type: nil, thing_id: nil) }
|
||||
|
||||
class << self
|
||||
# get or set a variable with the variable as the called method
|
||||
# rubocop:disable Style/MissingRespondToMissing
|
||||
def method_missing(method, *args)
|
||||
# set a value for a variable
|
||||
if method.end_with?('=')
|
||||
var_name = method.to_s.chomp('=')
|
||||
value = args.first
|
||||
self[var_name] = value
|
||||
else
|
||||
# retrieve a value
|
||||
self[method.to_s]
|
||||
end
|
||||
end
|
||||
# rubocop:enable Style/MissingRespondToMissing
|
||||
|
||||
def cache_prefix_by_startup
|
||||
@cache_prefix_by_startup ||= Digest::MD5.hexdigest(default_settings.to_s)
|
||||
end
|
||||
|
||||
def cache_key(var_name)
|
||||
"rails_settings_cached/#{cache_prefix_by_startup}/#{var_name}"
|
||||
end
|
||||
|
||||
def [](key)
|
||||
Rails.cache.fetch(cache_key(key)) do
|
||||
db_val = find_by(var: key)
|
||||
db_val ? db_val.value : default_settings[key]
|
||||
end
|
||||
end
|
||||
|
||||
# set a setting value by [] notation
|
||||
def []=(var_name, value)
|
||||
record = find_or_initialize_by(var: var_name.to_s)
|
||||
record.value = value
|
||||
record.save!
|
||||
end
|
||||
|
||||
def default_settings
|
||||
return @default_settings if defined?(@default_settings)
|
||||
|
||||
content = Rails.root.join('config', 'settings.yml').read
|
||||
hash = content.empty? ? {} : YAML.safe_load(ERB.new(content).result, aliases: true).to_hash
|
||||
@default_settings = (hash[Rails.env] || {}).freeze
|
||||
end
|
||||
end
|
||||
|
||||
# get the value field, YAML decoded
|
||||
def value
|
||||
YAML.safe_load(self[:value], permitted_classes: [ActiveSupport::HashWithIndifferentAccess, Symbol]) if self[:value].present?
|
||||
end
|
||||
|
||||
# set the value field, YAML encoded
|
||||
def value=(new_value)
|
||||
self[:value] = new_value.to_yaml
|
||||
end
|
||||
|
||||
def rewrite_cache
|
||||
Rails.cache.write(cache_key, value)
|
||||
end
|
||||
|
||||
def expire_cache
|
||||
Rails.cache.delete(cache_key)
|
||||
end
|
||||
|
||||
def cache_key
|
||||
self.class.cache_key(var)
|
||||
end
|
||||
|
||||
def to_param
|
||||
var
|
||||
end
|
||||
|
||||
class << self
|
||||
def [](key)
|
||||
return super(key) unless rails_initialized?
|
||||
|
||||
Rails.cache.fetch(cache_key(key, nil)) do
|
||||
db_val = object(key)
|
||||
|
||||
if db_val
|
||||
default_value = default_settings[key]
|
||||
|
||||
return default_value.with_indifferent_access.merge!(db_val.value) if default_value.is_a?(Hash)
|
||||
|
||||
db_val.value
|
||||
else
|
||||
default_settings[key]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def all_as_records
|
||||
vars = thing_scoped
|
||||
records = vars.index_by(&:var)
|
||||
|
||||
default_settings.each do |key, default_value|
|
||||
next if records.key?(key) || default_value.is_a?(Hash)
|
||||
|
||||
records[key] = Setting.new(var: key, value: default_value)
|
||||
end
|
||||
|
||||
records
|
||||
end
|
||||
|
||||
def default_settings
|
||||
return {} unless RailsSettings::Default.enabled?
|
||||
|
||||
RailsSettings::Default.instance
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -138,8 +138,6 @@ class Status < ApplicationRecord
|
|||
scope :with_public_visibility, -> { where(visibility: [:public, :public_unlisted, :login]) }
|
||||
scope :with_public_search_visibility, -> { merge(where(visibility: [:public, :public_unlisted, :login]).or(Status.where(searchability: [:public, :public_unlisted]))) }
|
||||
scope :tagged_with, ->(tag_ids) { joins(:statuses_tags).where(statuses_tags: { tag_id: tag_ids }) }
|
||||
scope :excluding_silenced_accounts, -> { left_outer_joins(:account).where(accounts: { silenced_at: nil }) }
|
||||
scope :including_silenced_accounts, -> { left_outer_joins(:account).where.not(accounts: { silenced_at: nil }) }
|
||||
scope :not_excluded_by_account, ->(account) { where.not(account_id: account.excluded_from_timeline_account_ids) }
|
||||
scope :not_domain_blocked_by_account, ->(account) { account.excluded_from_timeline_domains.blank? ? left_outer_joins(:account) : left_outer_joins(:account).where('accounts.domain IS NULL OR accounts.domain NOT IN (?)', account.excluded_from_timeline_domains) }
|
||||
scope :tagged_with_all, lambda { |tag_ids|
|
||||
|
|
|
@ -119,16 +119,16 @@ class User < ApplicationRecord
|
|||
scope :active, -> { confirmed.where(arel_table[:current_sign_in_at].gteq(ACTIVE_DURATION.ago)).joins(:account).where(accounts: { suspended_at: nil }) }
|
||||
scope :matches_email, ->(value) { where(arel_table[:email].matches("#{value}%")) }
|
||||
scope :matches_ip, ->(value) { left_joins(:ips).where('user_ips.ip <<= ?', value).group('users.id') }
|
||||
scope :emailable, -> { confirmed.enabled.joins(:account).merge(Account.searchable) }
|
||||
|
||||
before_validation :sanitize_languages
|
||||
before_validation :sanitize_role
|
||||
before_validation :sanitize_time_zone
|
||||
before_validation :sanitize_locale
|
||||
before_create :set_approved
|
||||
after_commit :send_pending_devise_notifications
|
||||
after_create_commit :trigger_webhooks
|
||||
|
||||
normalizes :locale, with: ->(locale) { I18n.available_locales.exclude?(locale.to_sym) ? nil : locale }
|
||||
normalizes :time_zone, with: ->(time_zone) { ActiveSupport::TimeZone[time_zone].nil? ? nil : time_zone }
|
||||
normalizes :chosen_languages, with: ->(chosen_languages) { chosen_languages.compact_blank.presence }
|
||||
|
||||
# This avoids a deprecation warning from Rails 5.1
|
||||
# It seems possible that a future release of devise-two-factor will
|
||||
# handle this itself, and this can be removed from our User class.
|
||||
|
@ -450,25 +450,10 @@ class User < ApplicationRecord
|
|||
@bypass_invite_request_check
|
||||
end
|
||||
|
||||
def sanitize_languages
|
||||
return if chosen_languages.nil?
|
||||
|
||||
chosen_languages.compact_blank!
|
||||
self.chosen_languages = nil if chosen_languages.empty?
|
||||
end
|
||||
|
||||
def sanitize_role
|
||||
self.role = nil if role.present? && role.everyone?
|
||||
end
|
||||
|
||||
def sanitize_time_zone
|
||||
self.time_zone = nil if time_zone.present? && ActiveSupport::TimeZone[time_zone].nil?
|
||||
end
|
||||
|
||||
def sanitize_locale
|
||||
self.locale = nil if locale.present? && I18n.available_locales.exclude?(locale.to_sym)
|
||||
end
|
||||
|
||||
def prepare_new_user!
|
||||
BootstrapTimelineWorker.perform_async(account_id)
|
||||
ActivityTracker.increment('activity:accounts:local')
|
||||
|
|
|
@ -47,6 +47,7 @@ class EmailMxValidator < ActiveModel::Validator
|
|||
dns.timeouts = 5
|
||||
|
||||
records = dns.getresources(domain, Resolv::DNS::Resource::IN::MX).to_a.map { |e| e.exchange.to_s }
|
||||
next if records == [''] # This domain explicitly rejects emails
|
||||
|
||||
([domain] + records).uniq.each do |hostname|
|
||||
ips.concat(dns.getresources(hostname, Resolv::DNS::Resource::IN::A).to_a.map { |e| e.address.to_s })
|
||||
|
|
|
@ -5,7 +5,10 @@
|
|||
= fa_icon 'warning'
|
||||
.log-entry__content
|
||||
.log-entry__title
|
||||
= t(account_warning.action, scope: 'admin.strikes.actions', name: content_tag(:span, account_warning.account ? account_warning.account.username : I18n.t('admin.action_logs.deleted_account'), class: 'username'), target: content_tag(:span, account_warning.target_account.pretty_acct, class: 'target')).html_safe
|
||||
= t(account_warning.action,
|
||||
scope: 'admin.strikes.actions',
|
||||
name: content_tag(:span, account_warning.account ? account_warning.account.username : I18n.t('admin.action_logs.deleted_account'), class: 'username'),
|
||||
target: content_tag(:span, account_warning.target_account.pretty_acct, class: 'target')).html_safe
|
||||
.log-entry__timestamp
|
||||
%time.formatted{ datetime: account_warning.created_at.iso8601 }
|
||||
= l(account_warning.created_at)
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
= image_tag action_log.account.avatar.url(:original), alt: '', width: 40, height: 40, class: 'avatar'
|
||||
.log-entry__content
|
||||
.log-entry__title
|
||||
= t("admin.action_logs.actions.#{action_log.action}_#{action_log.target_type.underscore}_html", name: content_tag(:span, action_log.account.username, class: 'username'), target: content_tag(:span, log_target(action_log), class: 'target'))
|
||||
= t "admin.action_logs.actions.#{action_log.action}_#{action_log.target_type.underscore}_html",
|
||||
name: content_tag(:span, action_log.account.username, class: 'username'),
|
||||
target: content_tag(:span, log_target(action_log), class: 'target')
|
||||
.log-entry__timestamp
|
||||
%time.formatted{ datetime: action_log.created_at.iso8601 }
|
||||
|
|
|
@ -2,6 +2,16 @@
|
|||
= render_video_component(status, visible: false)
|
||||
- elsif status.ordered_media_attachments.first.audio?
|
||||
- audio = status.ordered_media_attachments.first
|
||||
= react_component :audio, src: audio.file.url(:original), height: 110, alt: audio.description, lang: status.language, duration: audio.file.meta.dig(:original, :duration)
|
||||
= react_component :audio,
|
||||
alt: audio.description,
|
||||
duration: audio.file.meta.dig(:original, :duration),
|
||||
height: 110,
|
||||
lang: status.language,
|
||||
src: audio.file.url(:original)
|
||||
- else
|
||||
= react_component :media_gallery, height: 343, sensitive: status.sensitive?, visible: false, lang: status.language, media: status.ordered_media_attachments.map { |a| ActiveModelSerializers::SerializableResource.new(a, serializer: REST::MediaAttachmentSerializer).as_json }
|
||||
= react_component :media_gallery,
|
||||
height: 343,
|
||||
lang: status.language,
|
||||
media: status.ordered_media_attachments.map { |a| ActiveModelSerializers::SerializableResource.new(a, serializer: REST::MediaAttachmentSerializer).as_json },
|
||||
sensitive: status.sensitive?,
|
||||
visible: false
|
||||
|
|
|
@ -5,7 +5,11 @@
|
|||
= f.input :return_to, as: :hidden
|
||||
|
||||
.field-group
|
||||
= f.input :current_password, wrapper: :with_block_label, input_html: { autocomplete: 'current-password', autofocus: true }, label: t('challenge.prompt'), required: true
|
||||
= f.input :current_password,
|
||||
input_html: { autocomplete: 'current-password', autofocus: true },
|
||||
label: t('challenge.prompt'),
|
||||
required: true,
|
||||
wrapper: :with_block_label
|
||||
|
||||
.actions
|
||||
= f.button :button, t('challenge.confirm'), type: :submit
|
||||
|
|
|
@ -21,7 +21,13 @@
|
|||
= render 'shared/error_messages', object: resource
|
||||
|
||||
.fields-group
|
||||
= f.input :email, autofocus: true, wrapper: :with_label, label: t('simple_form.labels.defaults.email'), input_html: { 'aria-label': t('simple_form.labels.defaults.email') }, readonly: current_user.present?, hint: current_user.present? && t('auth.confirmations.wrong_email_hint')
|
||||
= f.input :email,
|
||||
autofocus: true,
|
||||
hint: current_user.present? && t('auth.confirmations.wrong_email_hint'),
|
||||
input_html: { 'aria-label': t('simple_form.labels.defaults.email') },
|
||||
label: t('simple_form.labels.defaults.email'),
|
||||
readonly: current_user.present?,
|
||||
wrapper: :with_label
|
||||
|
||||
.actions
|
||||
= f.button :button, t('auth.resend_confirmation'), type: :submit
|
||||
|
|
|
@ -8,9 +8,18 @@
|
|||
= f.input :reset_password_token, as: :hidden
|
||||
|
||||
.fields-group
|
||||
= f.input :password, wrapper: :with_label, autofocus: true, label: t('simple_form.labels.defaults.new_password'), input_html: { 'aria-label': t('simple_form.labels.defaults.new_password'), autocomplete: 'new-password', minlength: User.password_length.first, maxlength: User.password_length.last }, required: true
|
||||
= f.input :password,
|
||||
autofocus: true,
|
||||
input_html: { 'aria-label': t('simple_form.labels.defaults.new_password'), autocomplete: 'new-password', minlength: User.password_length.first, maxlength: User.password_length.last },
|
||||
label: t('simple_form.labels.defaults.new_password'),
|
||||
required: true,
|
||||
wrapper: :with_label
|
||||
.fields-group
|
||||
= f.input :password_confirmation, wrapper: :with_label, label: t('simple_form.labels.defaults.confirm_new_password'), input_html: { 'aria-label': t('simple_form.labels.defaults.confirm_new_password'), autocomplete: 'new-password' }, required: true
|
||||
= f.input :password_confirmation,
|
||||
input_html: { 'aria-label': t('simple_form.labels.defaults.confirm_new_password'), autocomplete: 'new-password' },
|
||||
label: t('simple_form.labels.defaults.confirm_new_password'),
|
||||
required: true,
|
||||
wrapper: :with_label
|
||||
|
||||
.actions
|
||||
= f.button :button, t('auth.set_new_password'), type: :submit
|
||||
|
|
|
@ -5,7 +5,12 @@
|
|||
= render 'shared/error_messages', object: resource
|
||||
|
||||
.fields-group
|
||||
= f.input :email, autofocus: true, wrapper: :with_label, label: t('simple_form.labels.defaults.email'), input_html: { 'aria-label': t('simple_form.labels.defaults.email') }, hint: false
|
||||
= f.input :email,
|
||||
autofocus: true,
|
||||
hint: false,
|
||||
input_html: { 'aria-label': t('simple_form.labels.defaults.email') },
|
||||
label: t('simple_form.labels.defaults.email'),
|
||||
wrapper: :with_label
|
||||
|
||||
.actions
|
||||
= f.button :button, t('auth.reset_password'), type: :submit
|
||||
|
|
|
@ -5,7 +5,9 @@
|
|||
= fa_icon 'warning'
|
||||
.log-entry__content
|
||||
.log-entry__title
|
||||
= t('disputes.strikes.title', action: t(account_warning.action, scope: 'disputes.strikes.title_actions'), date: l(account_warning.created_at.to_date))
|
||||
= t 'disputes.strikes.title',
|
||||
action: t(account_warning.action, scope: 'disputes.strikes.title_actions'),
|
||||
date: l(account_warning.created_at.to_date)
|
||||
.log-entry__timestamp
|
||||
%time.formatted{ datetime: account_warning.created_at.iso8601 }= l(account_warning.created_at)
|
||||
|
||||
|
|
|
@ -3,7 +3,9 @@
|
|||
%span{ title: session.user_agent }<
|
||||
= fa_icon "#{session_device_icon(session)} fw", 'aria-label': session_device_icon(session)
|
||||
|
||||
= t 'sessions.description', browser: t("sessions.browsers.#{session.browser}", default: session.browser.to_s), platform: t("sessions.platforms.#{session.platform}", default: session.platform.to_s)
|
||||
= t 'sessions.description',
|
||||
browser: t("sessions.browsers.#{session.browser}", default: session.browser.to_s),
|
||||
platform: t("sessions.platforms.#{session.platform}", default: session.platform.to_s)
|
||||
%td
|
||||
%samp= session.ip
|
||||
%td
|
||||
|
|
|
@ -15,15 +15,33 @@
|
|||
- if (!use_seamless_external_login? || resource.encrypted_password.present?) && !omniauth_only?
|
||||
.fields-row
|
||||
.fields-row__column.fields-group.fields-row__column-6
|
||||
= f.input :email, wrapper: :with_label, input_html: { 'aria-label': t('simple_form.labels.defaults.email') }, required: true, disabled: current_account.suspended?
|
||||
= f.input :email,
|
||||
disabled: current_account.suspended?,
|
||||
input_html: { 'aria-label': t('simple_form.labels.defaults.email') },
|
||||
required: true,
|
||||
wrapper: :with_label
|
||||
.fields-row__column.fields-group.fields-row__column-6
|
||||
= f.input :current_password, wrapper: :with_label, input_html: { 'aria-label': t('simple_form.labels.defaults.current_password'), autocomplete: 'current-password' }, required: true, disabled: current_account.suspended?, hint: false
|
||||
= f.input :current_password,
|
||||
disabled: current_account.suspended?,
|
||||
hint: false,
|
||||
input_html: { 'aria-label': t('simple_form.labels.defaults.current_password'), autocomplete: 'current-password' },
|
||||
required: true,
|
||||
wrapper: :with_label
|
||||
|
||||
.fields-row
|
||||
.fields-row__column.fields-group.fields-row__column-6
|
||||
= f.input :password, wrapper: :with_label, label: t('simple_form.labels.defaults.new_password'), input_html: { 'aria-label': t('simple_form.labels.defaults.new_password'), autocomplete: 'new-password', minlength: User.password_length.first, maxlength: User.password_length.last }, hint: t('simple_form.hints.defaults.password'), disabled: current_account.suspended?
|
||||
= f.input :password,
|
||||
disabled: current_account.suspended?,
|
||||
hint: t('simple_form.hints.defaults.password'),
|
||||
input_html: { 'aria-label': t('simple_form.labels.defaults.new_password'), autocomplete: 'new-password', minlength: User.password_length.first, maxlength: User.password_length.last },
|
||||
label: t('simple_form.labels.defaults.new_password'),
|
||||
wrapper: :with_label
|
||||
.fields-row__column.fields-group.fields-row__column-6
|
||||
= f.input :password_confirmation, wrapper: :with_label, label: t('simple_form.labels.defaults.confirm_new_password'), input_html: { 'aria-label': t('simple_form.labels.defaults.confirm_new_password'), autocomplete: 'new-password' }, disabled: current_account.suspended?
|
||||
= f.input :password_confirmation,
|
||||
disabled: current_account.suspended?,
|
||||
input_html: { 'aria-label': t('simple_form.labels.defaults.confirm_new_password'), autocomplete: 'new-password' },
|
||||
label: t('simple_form.labels.defaults.confirm_new_password'),
|
||||
wrapper: :with_label
|
||||
|
||||
.actions
|
||||
= f.button :button, t('generic.save_changes'), type: :submit, class: 'button', disabled: current_account.suspended?
|
||||
|
|
|
@ -19,25 +19,61 @@
|
|||
|
||||
.fields-group
|
||||
= f.simple_fields_for :account do |ff|
|
||||
= ff.input :username, wrapper: :with_label, label: false, required: true, input_html: { 'aria-label': t('simple_form.labels.defaults.username'), autocomplete: 'off', placeholder: t('simple_form.labels.defaults.username'), pattern: '[a-zA-Z0-9_]+', maxlength: 30 }, append: "@#{site_hostname}"
|
||||
= f.input :email, placeholder: t('simple_form.labels.defaults.email'), required: true, input_html: { 'aria-label': t('simple_form.labels.defaults.email'), autocomplete: 'username' }, hint: false
|
||||
= f.input :password, placeholder: t('simple_form.labels.defaults.password'), required: true, input_html: { 'aria-label': t('simple_form.labels.defaults.password'), autocomplete: 'new-password', minlength: User.password_length.first, maxlength: User.password_length.last }, hint: false
|
||||
= f.input :password_confirmation, placeholder: t('simple_form.labels.defaults.confirm_password'), required: true, input_html: { 'aria-label': t('simple_form.labels.defaults.confirm_password'), autocomplete: 'new-password' }, hint: false
|
||||
= f.input :confirm_password, as: :string, placeholder: t('simple_form.labels.defaults.honeypot', label: t('simple_form.labels.defaults.password')), required: false, input_html: { 'aria-label': t('simple_form.labels.defaults.honeypot', label: t('simple_form.labels.defaults.password')), autocomplete: 'off' }, hint: false
|
||||
= f.input :website, as: :url, wrapper: :with_label, label: t('simple_form.labels.defaults.honeypot', label: 'Website'), required: false, input_html: { 'aria-label': t('simple_form.labels.defaults.honeypot', label: 'Website'), autocomplete: 'off' }
|
||||
= ff.input :username,
|
||||
append: "@#{site_hostname}",
|
||||
input_html: { 'aria-label': t('simple_form.labels.defaults.username'), autocomplete: 'off', placeholder: t('simple_form.labels.defaults.username'), pattern: '[a-zA-Z0-9_]+', maxlength: 30 },
|
||||
label: false,
|
||||
required: true,
|
||||
wrapper: :with_label
|
||||
= f.input :email,
|
||||
hint: false,
|
||||
input_html: { 'aria-label': t('simple_form.labels.defaults.email'), autocomplete: 'username' },
|
||||
placeholder: t('simple_form.labels.defaults.email'),
|
||||
required: true
|
||||
= f.input :password,
|
||||
hint: false,
|
||||
input_html: { 'aria-label': t('simple_form.labels.defaults.password'), autocomplete: 'new-password', minlength: User.password_length.first, maxlength: User.password_length.last },
|
||||
placeholder: t('simple_form.labels.defaults.password'),
|
||||
required: true
|
||||
= f.input :password_confirmation,
|
||||
hint: false,
|
||||
input_html: { 'aria-label': t('simple_form.labels.defaults.confirm_password'), autocomplete: 'new-password' },
|
||||
placeholder: t('simple_form.labels.defaults.confirm_password'),
|
||||
required: true
|
||||
= f.input :confirm_password,
|
||||
as: :string,
|
||||
hint: false,
|
||||
input_html: { 'aria-label': t('simple_form.labels.defaults.honeypot', label: t('simple_form.labels.defaults.password')), autocomplete: 'off' },
|
||||
placeholder: t('simple_form.labels.defaults.honeypot', label: t('simple_form.labels.defaults.password')),
|
||||
required: false
|
||||
= f.input :website,
|
||||
as: :url,
|
||||
input_html: { 'aria-label': t('simple_form.labels.defaults.honeypot', label: 'Website'), autocomplete: 'off' },
|
||||
label: t('simple_form.labels.defaults.honeypot', label: 'Website'),
|
||||
required: false,
|
||||
wrapper: :with_label
|
||||
|
||||
- if approved_registrations? && @invite.blank?
|
||||
%p.lead= t('auth.sign_up.manual_review', domain: site_hostname)
|
||||
|
||||
.fields-group
|
||||
= f.simple_fields_for :invite_request, resource.invite_request || resource.build_invite_request do |invite_request_fields|
|
||||
= invite_request_fields.input :text, as: :text, wrapper: :with_block_label, required: Setting.require_invite_text, label: false, hint: false
|
||||
= invite_request_fields.input :text,
|
||||
as: :text,
|
||||
hint: false,
|
||||
label: false,
|
||||
required: Setting.require_invite_text,
|
||||
wrapper: :with_block_label
|
||||
|
||||
= hidden_field_tag :accept, params[:accept]
|
||||
= f.input :invite_code, as: :hidden
|
||||
|
||||
.fields-group
|
||||
= f.input :agreement, as: :boolean, wrapper: :with_label, label: t('auth.privacy_policy_agreement_html', rules_path: about_more_path, privacy_policy_path: privacy_policy_path), required: true
|
||||
= f.input :agreement,
|
||||
as: :boolean,
|
||||
label: t('auth.privacy_policy_agreement_html', rules_path: about_more_path, privacy_policy_path: privacy_policy_path),
|
||||
required: true,
|
||||
wrapper: :with_label
|
||||
|
||||
- if Setting.registration_button_message.present?
|
||||
%div
|
||||
|
|
|
@ -10,11 +10,25 @@
|
|||
%p.lead= t('auth.sign_in.preamble_html', domain: site_hostname)
|
||||
.fields-group
|
||||
- if use_seamless_external_login?
|
||||
= f.input :email, autofocus: true, wrapper: :with_label, label: t('simple_form.labels.defaults.username_or_email'), input_html: { 'aria-label': t('simple_form.labels.defaults.username_or_email') }, hint: false
|
||||
= f.input :email,
|
||||
autofocus: true,
|
||||
hint: false,
|
||||
input_html: { 'aria-label': t('simple_form.labels.defaults.username_or_email') },
|
||||
label: t('simple_form.labels.defaults.username_or_email'),
|
||||
wrapper: :with_label
|
||||
- else
|
||||
= f.input :email, autofocus: true, wrapper: :with_label, label: t('simple_form.labels.defaults.email'), input_html: { 'aria-label': t('simple_form.labels.defaults.email') }, hint: false
|
||||
= f.input :email,
|
||||
autofocus: true,
|
||||
hint: false,
|
||||
input_html: { 'aria-label': t('simple_form.labels.defaults.email') },
|
||||
label: t('simple_form.labels.defaults.email'),
|
||||
wrapper: :with_label
|
||||
.fields-group
|
||||
= f.input :password, wrapper: :with_label, label: t('simple_form.labels.defaults.password'), input_html: { 'aria-label': t('simple_form.labels.defaults.password'), autocomplete: 'current-password' }, hint: false
|
||||
= f.input :password,
|
||||
hint: false,
|
||||
input_html: { 'aria-label': t('simple_form.labels.defaults.password'), autocomplete: 'current-password' },
|
||||
label: t('simple_form.labels.defaults.password'),
|
||||
wrapper: :with_label
|
||||
|
||||
.actions
|
||||
= f.button :button, t('auth.login'), type: :submit
|
||||
|
|
|
@ -5,7 +5,12 @@
|
|||
%p.hint.authentication-hint= t('simple_form.hints.sessions.otp')
|
||||
|
||||
.fields-group
|
||||
= f.input :otp_attempt, type: :number, wrapper: :with_label, label: t('simple_form.labels.defaults.otp_attempt'), input_html: { 'aria-label': t('simple_form.labels.defaults.otp_attempt'), autocomplete: 'one-time-code' }, autofocus: true
|
||||
= f.input :otp_attempt,
|
||||
autofocus: true,
|
||||
input_html: { 'aria-label': t('simple_form.labels.defaults.otp_attempt'), autocomplete: 'one-time-code' },
|
||||
label: t('simple_form.labels.defaults.otp_attempt'),
|
||||
type: :number,
|
||||
wrapper: :with_label
|
||||
|
||||
.actions
|
||||
= f.button :button, t('auth.login'), type: :submit
|
||||
|
|
|
@ -16,7 +16,10 @@
|
|||
%p.lead= t('auth.setup.email_below_hint_html')
|
||||
|
||||
.fields-group
|
||||
= f.input :email, required: true, hint: false, input_html: { 'aria-label': t('simple_form.labels.defaults.email'), autocomplete: 'off' }
|
||||
= f.input :email,
|
||||
hint: false,
|
||||
input_html: { 'aria-label': t('simple_form.labels.defaults.email'), autocomplete: 'off' },
|
||||
required: true
|
||||
|
||||
.actions
|
||||
= f.button :button, t('auth.resend_confirmation'), type: :submit, class: 'button timer-button', disabled: true
|
||||
|
|
|
@ -4,7 +4,11 @@
|
|||
.simple_form
|
||||
%h1.title= t('mail_subscriptions.unsubscribe.title')
|
||||
%p.lead
|
||||
= t('mail_subscriptions.unsubscribe.confirmation_html', domain: content_tag(:strong, site_hostname), type: content_tag(:strong, I18n.t(@type, scope: 'mail_subscriptions.unsubscribe.emails')), email: content_tag(:strong, @user.email), settings_path: settings_preferences_notifications_path)
|
||||
= t 'mail_subscriptions.unsubscribe.confirmation_html',
|
||||
domain: content_tag(:strong, site_hostname),
|
||||
type: content_tag(:strong, I18n.t(@type, scope: 'mail_subscriptions.unsubscribe.emails')),
|
||||
email: content_tag(:strong, @user.email),
|
||||
settings_path: settings_preferences_notifications_path
|
||||
|
||||
= form_tag unsubscribe_path, method: :post do
|
||||
= hidden_field_tag :token, params[:token]
|
||||
|
|
|
@ -6,14 +6,39 @@
|
|||
meta = @media_attachment.file.meta || {}
|
||||
|
||||
- if @media_attachment.video?
|
||||
= react_component :video, src: @media_attachment.file.url(:original), preview: @media_attachment.thumbnail.present? ? @media_attachment.thumbnail.url : @media_attachment.file.url(:small), frameRate: meta.dig('original', 'frame_rate'), blurhash: @media_attachment.blurhash, width: 670, height: 380, editable: true, detailed: true, inline: true, alt: @media_attachment.description, media: [ActiveModelSerializers::SerializableResource.new(@media_attachment, serializer: REST::MediaAttachmentSerializer)].as_json do
|
||||
= react_component :video,
|
||||
alt: @media_attachment.description,
|
||||
blurhash: @media_attachment.blurhash,
|
||||
detailed: true,
|
||||
editable: true,
|
||||
frameRate: meta.dig('original', 'frame_rate'),
|
||||
height: 380,
|
||||
inline: true,
|
||||
media: [ActiveModelSerializers::SerializableResource.new(@media_attachment, serializer: REST::MediaAttachmentSerializer)].as_json,
|
||||
preview: @media_attachment.thumbnail.present? ? @media_attachment.thumbnail.url : @media_attachment.file.url(:small),
|
||||
src: @media_attachment.file.url(:original),
|
||||
width: 670 do
|
||||
%video{ controls: 'controls' }
|
||||
%source{ src: @media_attachment.file.url(:original) }
|
||||
- elsif @media_attachment.gifv?
|
||||
= react_component :media_gallery, height: 380, standalone: true, autoplay: true, media: [ActiveModelSerializers::SerializableResource.new(@media_attachment, serializer: REST::MediaAttachmentSerializer).as_json] do
|
||||
= react_component :media_gallery,
|
||||
autoplay: true,
|
||||
height: 380,
|
||||
media: [ActiveModelSerializers::SerializableResource.new(@media_attachment, serializer: REST::MediaAttachmentSerializer).as_json],
|
||||
standalone: true do
|
||||
%video{ autoplay: 'autoplay', muted: 'muted', loop: 'loop' }
|
||||
%source{ src: @media_attachment.file.url(:original) }
|
||||
- elsif @media_attachment.audio?
|
||||
= react_component :audio, src: @media_attachment.file.url(:original), poster: @media_attachment.thumbnail.present? ? @media_attachment.thumbnail.url : @media_attachment.account.avatar_static_url, backgroundColor: meta.dig('colors', 'background'), foregroundColor: meta.dig('colors', 'foreground'), accentColor: meta.dig('colors', 'accent'), width: 670, height: 380, fullscreen: true, alt: @media_attachment.description, duration: meta.dig(:original, :duration) do
|
||||
= react_component :audio,
|
||||
accentColor: meta.dig('colors', 'accent'),
|
||||
alt: @media_attachment.description,
|
||||
backgroundColor: meta.dig('colors', 'background'),
|
||||
duration: meta.dig(:original, :duration),
|
||||
foregroundColor: meta.dig('colors', 'foreground'),
|
||||
fullscreen: true,
|
||||
height: 380,
|
||||
poster: @media_attachment.thumbnail.present? ? @media_attachment.thumbnail.url : @media_attachment.account.avatar_static_url,
|
||||
src: @media_attachment.file.url(:original),
|
||||
width: 670 do
|
||||
%audio{ controls: 'controls' }
|
||||
%source{ src: @media_attachment.file.url(:original) }
|
||||
|
|
|
@ -1,11 +1,17 @@
|
|||
.fields-group
|
||||
= f.input :name, wrapper: :with_label, label: t('activerecord.attributes.doorkeeper/application.name')
|
||||
= f.input :name,
|
||||
label: t('activerecord.attributes.doorkeeper/application.name'),
|
||||
wrapper: :with_label
|
||||
|
||||
.fields-group
|
||||
= f.input :website, wrapper: :with_label, label: t('activerecord.attributes.doorkeeper/application.website')
|
||||
= f.input :website,
|
||||
label: t('activerecord.attributes.doorkeeper/application.website'),
|
||||
wrapper: :with_label
|
||||
|
||||
.fields-group
|
||||
= f.input :redirect_uri, wrapper: :with_block_label, label: t('activerecord.attributes.doorkeeper/application.redirect_uri'), hint: t('doorkeeper.applications.help.redirect_uri')
|
||||
= f.input :redirect_uri,
|
||||
label: t('activerecord.attributes.doorkeeper/application.redirect_uri'), hint: t('doorkeeper.applications.help.redirect_uri'),
|
||||
wrapper: :with_block_label
|
||||
|
||||
%p.hint= t('doorkeeper.applications.help.native_redirect_uri', native_redirect_uri: content_tag(:code, Doorkeeper.configuration.native_redirect_uri)).html_safe
|
||||
|
||||
|
@ -15,4 +21,15 @@
|
|||
%span.hint= t('simple_form.hints.defaults.scopes')
|
||||
|
||||
- Doorkeeper.configuration.scopes.group_by { |s| s.split(':').first }.each_value do |value|
|
||||
= f.input :scopes, label: false, hint: false, collection: value.sort, wrapper: :with_block_label, include_blank: false, label_method: ->(scope) { safe_join([content_tag(:samp, scope, class: class_for_scope(scope)), content_tag(:span, t("doorkeeper.scopes.#{scope}"), class: 'hint')]) }, selected: f.object.scopes.all, required: false, as: :check_boxes, collection_wrapper_tag: 'ul', item_wrapper_tag: 'li'
|
||||
= f.input :scopes,
|
||||
as: :check_boxes,
|
||||
collection_wrapper_tag: 'ul',
|
||||
collection: value.sort,
|
||||
hint: false,
|
||||
include_blank: false,
|
||||
item_wrapper_tag: 'li',
|
||||
label_method: ->(scope) { safe_join([content_tag(:samp, scope, class: class_for_scope(scope)), content_tag(:span, t("doorkeeper.scopes.#{scope}"), class: 'hint')]) },
|
||||
label: false,
|
||||
required: false,
|
||||
selected: f.object.scopes.all,
|
||||
wrapper: :with_block_label
|
||||
|
|
|
@ -11,7 +11,9 @@
|
|||
%p.lead= t('featured_tags.hint_html')
|
||||
|
||||
.fields-group
|
||||
= f.input :name, wrapper: :with_block_label, hint: safe_join([t('simple_form.hints.featured_tag.name'), safe_join(@recently_used_tags.map { |tag| link_to("##{tag.display_name}", settings_featured_tags_path(featured_tag: { name: tag.name }), method: :post) }, ', ')], ' ')
|
||||
= f.input :name,
|
||||
hint: featured_tags_hint(@recently_used_tags),
|
||||
wrapper: :with_block_label
|
||||
|
||||
.actions
|
||||
= f.button :button, t('featured_tags.add_new'), type: :submit
|
||||
|
|
|
@ -3,13 +3,29 @@
|
|||
|
||||
= simple_form_for @import, url: settings_imports_path do |f|
|
||||
.field-group
|
||||
= f.input :type, as: :grouped_select, collection: { constructive: %i(following bookmarks lists), destructive: %i(muting blocking domain_blocking) }, wrapper: :with_block_label, include_blank: false, label_method: ->(type) { I18n.t("imports.types.#{type}") }, group_label_method: ->(group) { I18n.t("imports.type_groups.#{group.first}") }, group_method: :last, hint: t('imports.preface')
|
||||
= f.input :type,
|
||||
as: :grouped_select,
|
||||
collection: { constructive: %i(following bookmarks lists), destructive: %i(muting blocking domain_blocking) },
|
||||
group_label_method: ->(group) { I18n.t("imports.type_groups.#{group.first}") },
|
||||
group_method: :last,
|
||||
hint: t('imports.preface'),
|
||||
include_blank: false,
|
||||
label_method: ->(type) { I18n.t("imports.types.#{type}") },
|
||||
wrapper: :with_block_label
|
||||
|
||||
.fields-row
|
||||
.fields-group.fields-row__column.fields-row__column-6
|
||||
= f.input :data, as: :file, wrapper: :with_block_label, hint: t('simple_form.hints.imports.data')
|
||||
= f.input :data,
|
||||
as: :file,
|
||||
hint: t('simple_form.hints.imports.data'),
|
||||
wrapper: :with_block_label
|
||||
.fields-group.fields-row__column.fields-row__column-6
|
||||
= f.input :mode, as: :radio_buttons, collection: Import::MODES, label_method: ->(mode) { safe_join([I18n.t("imports.modes.#{mode}"), content_tag(:span, I18n.t("imports.modes.#{mode}_long"), class: 'hint')]) }, collection_wrapper_tag: 'ul', item_wrapper_tag: 'li'
|
||||
= f.input :mode,
|
||||
as: :radio_buttons,
|
||||
collection_wrapper_tag: 'ul',
|
||||
collection: Import::MODES,
|
||||
item_wrapper_tag: 'li',
|
||||
label_method: ->(mode) { safe_join([I18n.t("imports.modes.#{mode}"), content_tag(:span, I18n.t("imports.modes.#{mode}_long"), class: 'hint')]) }
|
||||
|
||||
.actions
|
||||
= f.button :button, t('imports.upload'), type: :submit
|
||||
|
|
|
@ -1,8 +1,3 @@
|
|||
:ruby
|
||||
method_str = content_tag(:span, login_activity.omniauth? ? t(login_activity.provider, scope: 'auth.providers') : t(login_activity.authentication_method, scope: 'login_activities.authentication_methods'), class: 'target')
|
||||
ip_str = content_tag(:span, login_activity.ip, class: 'target')
|
||||
browser_str = content_tag(:span, t('sessions.description', browser: t("sessions.browsers.#{login_activity.browser}", default: login_activity.browser.to_s), platform: t("sessions.platforms.#{login_activity.platform}", default: login_activity.platform.to_s)), class: 'target', title: login_activity.user_agent)
|
||||
|
||||
.log-entry
|
||||
.log-entry__header
|
||||
.log-entry__avatar
|
||||
|
@ -10,9 +5,6 @@
|
|||
= fa_icon login_activity.success? ? 'check' : 'times'
|
||||
.log-entry__content
|
||||
.log-entry__title
|
||||
- if login_activity.success?
|
||||
= t('login_activities.successful_sign_in_html', method: method_str, ip: ip_str, browser: browser_str)
|
||||
- else
|
||||
= t('login_activities.failed_sign_in_html', method: method_str, ip: ip_str, browser: browser_str)
|
||||
= login_activity_title(login_activity)
|
||||
.log-entry__timestamp
|
||||
%time.formatted{ datetime: login_activity.created_at.iso8601 }= l(login_activity.created_at)
|
||||
|
|
|
@ -15,7 +15,11 @@
|
|||
|
||||
.fields-row
|
||||
.fields-row__column.fields-group.fields-row__column-6
|
||||
= f.input :acct, wrapper: :with_block_label, input_html: { autocapitalize: 'none', autocorrect: 'off' }, label: t('simple_form.labels.account_migration.acct'), hint: t('simple_form.hints.account_migration.acct')
|
||||
= f.input :acct,
|
||||
hint: t('simple_form.hints.account_migration.acct'),
|
||||
input_html: { autocapitalize: 'none', autocorrect: 'off' },
|
||||
label: t('simple_form.labels.account_migration.acct'),
|
||||
wrapper: :with_block_label
|
||||
|
||||
.fields-row__column.fields-group.fields-row__column-6
|
||||
- if current_user.encrypted_password.present?
|
||||
|
|
|
@ -7,13 +7,28 @@
|
|||
= simple_form_for current_user, url: settings_preferences_appearance_path, html: { method: :put, id: 'edit_user' } do |f|
|
||||
.fields-row
|
||||
.fields-group.fields-row__column.fields-row__column-6
|
||||
= f.input :locale, collection: ui_languages, wrapper: :with_label, include_blank: false, label_method: ->(locale) { native_locale_name(locale) }, selected: I18n.locale, hint: false
|
||||
= f.input :locale,
|
||||
collection: ui_languages,
|
||||
hint: false,
|
||||
include_blank: false,
|
||||
label_method: ->(locale) { native_locale_name(locale) },
|
||||
selected: I18n.locale,
|
||||
wrapper: :with_label
|
||||
.fields-group.fields-row__column.fields-row__column-6
|
||||
= f.input :time_zone, wrapper: :with_label, collection: ActiveSupport::TimeZone.all.map { |tz| ["(GMT#{tz.formatted_offset}) #{tz.name}", tz.tzinfo.name] }, hint: false
|
||||
= f.input :time_zone,
|
||||
collection: ActiveSupport::TimeZone.all.map { |tz| ["(GMT#{tz.formatted_offset}) #{tz.name}", tz.tzinfo.name] },
|
||||
hint: false,
|
||||
wrapper: :with_label
|
||||
|
||||
.fields-group
|
||||
= f.simple_fields_for :settings, current_user.settings do |ff|
|
||||
= ff.input :theme, collection: Themes.instance.names, label_method: ->(theme) { I18n.t("themes.#{theme}", default: theme) }, wrapper: :with_label, label: I18n.t('simple_form.labels.defaults.setting_theme'), include_blank: false, hint: false
|
||||
= ff.input :theme,
|
||||
collection: Themes.instance.names,
|
||||
hint: false,
|
||||
include_blank: false,
|
||||
label_method: ->(theme) { I18n.t("themes.#{theme}", default: theme) },
|
||||
label: I18n.t('simple_form.labels.defaults.setting_theme'),
|
||||
wrapper: :with_label
|
||||
|
||||
- unless I18n.locale == :en
|
||||
.flash-message.translation-prompt
|
||||
|
@ -25,12 +40,18 @@
|
|||
%p.hint= t 'appearance.advanced_web_interface_hint'
|
||||
|
||||
.fields-group
|
||||
= ff.input :'web.advanced_layout', wrapper: :with_label, hint: false, label: I18n.t('simple_form.labels.defaults.setting_advanced_layout')
|
||||
= ff.input :'web.advanced_layout',
|
||||
hint: false,
|
||||
label: I18n.t('simple_form.labels.defaults.setting_advanced_layout'),
|
||||
wrapper: :with_label
|
||||
|
||||
%h4= t 'appearance.animations_and_accessibility'
|
||||
|
||||
.fields-group
|
||||
= ff.input :'web.use_pending_items', wrapper: :with_label, label: I18n.t('simple_form.labels.defaults.setting_use_pending_items'), hint: I18n.t('simple_form.hints.defaults.setting_use_pending_items')
|
||||
= ff.input :'web.use_pending_items',
|
||||
hint: I18n.t('simple_form.hints.defaults.setting_use_pending_items'),
|
||||
label: I18n.t('simple_form.labels.defaults.setting_use_pending_items'),
|
||||
wrapper: :with_label
|
||||
|
||||
.fields-group
|
||||
= ff.input :'web.auto_play', wrapper: :with_label, recommended: true, label: I18n.t('simple_form.labels.defaults.setting_auto_play_gif')
|
||||
|
@ -83,13 +104,28 @@
|
|||
%h4= t 'appearance.sensitive_content'
|
||||
|
||||
.fields-group
|
||||
= ff.input :'web.display_media', collection: %w(default show_all hide_all), label_method: ->(item) { t("simple_form.hints.defaults.setting_display_media_#{item}") }, hint: false, as: :radio_buttons, collection_wrapper_tag: 'ul', item_wrapper_tag: 'li', wrapper: :with_floating_label, label: I18n.t('simple_form.labels.defaults.setting_display_media')
|
||||
= ff.input :'web.display_media',
|
||||
as: :radio_buttons,
|
||||
collection_wrapper_tag: 'ul',
|
||||
collection: %w(default show_all hide_all),
|
||||
hint: false,
|
||||
item_wrapper_tag: 'li',
|
||||
label_method: ->(item) { t("simple_form.hints.defaults.setting_display_media_#{item}") },
|
||||
label: I18n.t('simple_form.labels.defaults.setting_display_media'),
|
||||
wrapper: :with_floating_label
|
||||
|
||||
.fields-group
|
||||
= ff.input :'web.display_media_expand', wrapper: :with_label, kmyblue: true, label: I18n.t('simple_form.labels.defaults.setting_display_media_expand'), hint: I18n.t('simple_form.hints.defaults.setting_display_media_expand')
|
||||
= ff.input :'web.display_media_expand',
|
||||
kmyblue: true,
|
||||
hint: I18n.t('simple_form.hints.defaults.setting_display_media_expand'),
|
||||
label: I18n.t('simple_form.labels.defaults.setting_display_media_expand'),
|
||||
wrapper: :with_label
|
||||
|
||||
.fields-group
|
||||
= ff.input :'web.use_blurhash', wrapper: :with_label, label: I18n.t('simple_form.labels.defaults.setting_use_blurhash'), hint: I18n.t('simple_form.hints.defaults.setting_use_blurhash')
|
||||
= ff.input :'web.use_blurhash',
|
||||
hint: I18n.t('simple_form.hints.defaults.setting_use_blurhash'),
|
||||
label: I18n.t('simple_form.labels.defaults.setting_use_blurhash'),
|
||||
wrapper: :with_label
|
||||
|
||||
.fields-group
|
||||
= ff.input :'web.expand_content_warnings', wrapper: :with_label, label: I18n.t('simple_form.labels.defaults.setting_expand_spoilers')
|
||||
|
|
|
@ -34,7 +34,13 @@
|
|||
|
||||
- if SoftwareUpdate.check_enabled? && current_user.can?(:view_devops)
|
||||
.fields-group
|
||||
= ff.input :'notification_emails.software_updates', wrapper: :with_label, label: I18n.t('simple_form.labels.notification_emails.software_updates.label'), collection: %w(none critical patch all), label_method: ->(setting) { I18n.t("simple_form.labels.notification_emails.software_updates.#{setting}") }, include_blank: false, hint: false
|
||||
= ff.input :'notification_emails.software_updates',
|
||||
collection: %w(none critical patch all),
|
||||
hint: false,
|
||||
include_blank: false,
|
||||
label_method: ->(setting) { I18n.t("simple_form.labels.notification_emails.software_updates.#{setting}") },
|
||||
label: I18n.t('simple_form.labels.notification_emails.software_updates.label'),
|
||||
wrapper: :with_label
|
||||
|
||||
%h4= t 'notifications.other_settings'
|
||||
|
||||
|
|
|
@ -9,7 +9,11 @@
|
|||
|
||||
= f.simple_fields_for :settings, current_user.settings do |ff|
|
||||
.fields-group
|
||||
= ff.input :aggregate_reblogs, wrapper: :with_label, recommended: true, label: I18n.t('simple_form.labels.defaults.setting_aggregate_reblogs'), hint: I18n.t('simple_form.hints.defaults.setting_aggregate_reblogs')
|
||||
= ff.input :aggregate_reblogs,
|
||||
hint: I18n.t('simple_form.hints.defaults.setting_aggregate_reblogs'),
|
||||
label: I18n.t('simple_form.labels.defaults.setting_aggregate_reblogs'),
|
||||
recommended: true,
|
||||
wrapper: :with_label
|
||||
|
||||
.fields-group
|
||||
= ff.input :lock_follow_from_bot, wrapper: :with_label, kmyblue: true, label: I18n.t('simple_form.labels.defaults.setting_lock_follow_from_bot')
|
||||
|
@ -18,17 +22,37 @@
|
|||
|
||||
.fields-row
|
||||
.fields-group.fields-row__column.fields-row__column-12
|
||||
= ff.input :default_language, collection: [nil] + filterable_languages, wrapper: :with_label, label_method: ->(locale) { locale.nil? ? I18n.t('statuses.default_language') : native_locale_name(locale) }, required: false, include_blank: false, hint: false, label: I18n.t('simple_form.labels.defaults.setting_default_language')
|
||||
= ff.input :default_language,
|
||||
collection: [nil] + filterable_languages,
|
||||
hint: false,
|
||||
include_blank: false,
|
||||
label_method: ->(locale) { locale.nil? ? I18n.t('statuses.default_language') : native_locale_name(locale) },
|
||||
label: I18n.t('simple_form.labels.defaults.setting_default_language'),
|
||||
required: false,
|
||||
wrapper: :with_label
|
||||
|
||||
.fields-group
|
||||
= ff.input :default_sensitive, wrapper: :with_label, label: I18n.t('simple_form.labels.defaults.setting_default_sensitive'), hint: I18n.t('simple_form.hints.defaults.setting_default_sensitive')
|
||||
= ff.input :default_sensitive,
|
||||
hint: I18n.t('simple_form.hints.defaults.setting_default_sensitive'),
|
||||
label: I18n.t('simple_form.labels.defaults.setting_default_sensitive'),
|
||||
wrapper: :with_label
|
||||
|
||||
- if Setting.enable_emoji_reaction
|
||||
%h4= t 'preferences.emoji_reaction_permitting'
|
||||
|
||||
.fields-row
|
||||
.fields-group.fields-row__column.fields-row__column-12
|
||||
= ff.input :emoji_reaction_policy, kmyblue: true, collection: %w(allow outside_only followers_only following_only mutuals_only block), label_method: ->(item) { safe_join([t("simple_form.labels.defaults.setting_emoji_reaction_policy_items.#{item}")]) }, collection_wrapper_tag: 'ul', item_wrapper_tag: 'li', include_blank: false, wrapper: :with_label, label: I18n.t('simple_form.labels.defaults.setting_emoji_reaction_policy'), hint: false, warning_hint: I18n.t('simple_form.hints.defaults.setting_emoji_reaction_policy')
|
||||
= ff.input :emoji_reaction_policy,
|
||||
collection: %w(allow outside_only followers_only following_only mutuals_only block),
|
||||
collection_wrapper_tag: 'ul',
|
||||
hint: false,
|
||||
include_blank: false,
|
||||
item_wrapper_tag: 'li',
|
||||
kmyblue: true,
|
||||
label: I18n.t('simple_form.labels.defaults.setting_emoji_reaction_policy'),
|
||||
label_method: ->(item) { safe_join([t("simple_form.labels.defaults.setting_emoji_reaction_policy_items.#{item}")]) },
|
||||
warning_hint: I18n.t('simple_form.hints.defaults.setting_emoji_reaction_policy'),
|
||||
wrapper: :with_label
|
||||
|
||||
.fields-group
|
||||
= ff.input :slip_local_emoji_reaction, wrapper: :with_label, kmyblue: true, label: I18n.t('simple_form.labels.defaults.setting_slip_local_emoji_reaction')
|
||||
|
@ -43,10 +67,28 @@
|
|||
= ff.input :'web.enable_dtl_menu', wrapper: :with_label, kmyblue: true, label: I18n.t('simple_form.labels.defaults.setting_dtl_menu')
|
||||
|
||||
.fields-group
|
||||
= ff.input :dtl_force_visibility, kmyblue: true, collection: %w(unchange public public_unlisted unlisted), label_method: ->(item) { safe_join([t("simple_form.labels.dtl_force_visibility.#{item}")]) }, as: :radio_buttons, collection_wrapper_tag: 'ul', item_wrapper_tag: 'li', wrapper: :with_floating_label, label: I18n.t('simple_form.labels.defaults.setting_dtl_force_visibility'), hint: I18n.t('simple_form.hints.defaults.setting_dtl_force_visibility', tag: @dtl_tag)
|
||||
= ff.input :dtl_force_visibility,
|
||||
as: :radio_buttons,
|
||||
collection: %w(unchange public public_unlisted unlisted),
|
||||
collection_wrapper_tag: 'ul',
|
||||
hint: I18n.t('simple_form.hints.defaults.setting_dtl_force_visibility', tag: @dtl_tag),
|
||||
item_wrapper_tag: 'li',
|
||||
kmyblue: true,
|
||||
label: I18n.t('simple_form.labels.defaults.setting_dtl_force_visibility'),
|
||||
label_method: ->(item) { safe_join([t("simple_form.labels.dtl_force_visibility.#{item}")]) },
|
||||
wrapper: :with_floating_label
|
||||
|
||||
.fields-group
|
||||
= ff.input :dtl_force_searchability, kmyblue: true, collection: %w(unchange public public_unlisted), label_method: ->(item) { safe_join([t("simple_form.labels.dtl_force_searchability.#{item}")]) }, as: :radio_buttons, collection_wrapper_tag: 'ul', item_wrapper_tag: 'li', wrapper: :with_floating_label, label: I18n.t('simple_form.labels.defaults.setting_dtl_force_searchability'), hint: I18n.t('simple_form.hints.defaults.setting_dtl_force_searchability', tag: @dtl_tag)
|
||||
= ff.input :dtl_force_searchability,
|
||||
as: :radio_buttons,
|
||||
collection: %w(unchange public public_unlisted),
|
||||
collection_wrapper_tag: 'ul',
|
||||
hint: I18n.t('simple_form.hints.defaults.setting_dtl_force_searchability', tag: @dtl_tag),
|
||||
item_wrapper_tag: 'li',
|
||||
kmyblue: true,
|
||||
label: I18n.t('simple_form.labels.defaults.setting_dtl_force_searchability'),
|
||||
label_method: ->(item) { safe_join([t("simple_form.labels.dtl_force_searchability.#{item}")]) },
|
||||
wrapper: :with_floating_label
|
||||
|
||||
.fields-group
|
||||
= ff.input :dtl_force_subscribable, wrapper: :with_label, kmyblue: true, label: I18n.t('simple_form.labels.defaults.setting_dtl_force_subscribable'), hint: I18n.t('simple_form.hints.defaults.setting_dtl_force_subscribable')
|
||||
|
@ -54,7 +96,15 @@
|
|||
%h4= t 'preferences.public_timelines'
|
||||
|
||||
.fields-group
|
||||
= f.input :chosen_languages, collection: filterable_languages, wrapper: :with_block_label, include_blank: false, label_method: ->(locale) { native_locale_name(locale) }, required: false, as: :check_boxes, collection_wrapper_tag: 'ul', item_wrapper_tag: 'li'
|
||||
= f.input :chosen_languages,
|
||||
as: :check_boxes,
|
||||
collection_wrapper_tag: 'ul',
|
||||
collection: filterable_languages,
|
||||
include_blank: false,
|
||||
item_wrapper_tag: 'li',
|
||||
label_method: ->(locale) { native_locale_name(locale) },
|
||||
required: false,
|
||||
wrapper: :with_block_label
|
||||
|
||||
.actions
|
||||
= f.button :button, t('generic.save_changes'), type: :submit
|
||||
|
|
|
@ -12,10 +12,25 @@
|
|||
|
||||
.fields-row
|
||||
.fields-group.fields-row__column.fields-row__column-6
|
||||
= ff.input :default_privacy, collection: Status.selectable_visibilities, wrapper: :with_label, include_blank: false, label_method: ->(visibility) { safe_join([I18n.t("statuses.visibilities.#{visibility}"), I18n.t("statuses.visibilities.#{visibility}_long")], ' - ') }, required: false, hint: false, label: I18n.t('simple_form.labels.defaults.setting_default_privacy')
|
||||
= ff.input :default_privacy,
|
||||
collection: Status.selectable_visibilities,
|
||||
hint: false,
|
||||
include_blank: false,
|
||||
label: I18n.t('simple_form.labels.defaults.setting_default_privacy'),
|
||||
label_method: ->(visibility) { safe_join([I18n.t("statuses.visibilities.#{visibility}"), I18n.t("statuses.visibilities.#{visibility}_long")], ' - ') },
|
||||
required: false,
|
||||
wrapper: :with_label
|
||||
|
||||
.fields-group.fields-row__column.fields-row__column-6
|
||||
= ff.input :default_reblog_privacy, collection: Status.selectable_reblog_visibilities, wrapper: :with_label, kmyblue: true, include_blank: false, label_method: ->(visibility) { safe_join([I18n.t("statuses.visibilities.#{visibility}"), I18n.t("statuses.visibilities.#{visibility}_long")], ' - ') }, required: false, hint: false, label: I18n.t('simple_form.labels.defaults.setting_default_reblog_privacy')
|
||||
= ff.input :default_reblog_privacy,
|
||||
collection: Status.selectable_reblog_visibilities,
|
||||
hint: false,
|
||||
include_blank: false,
|
||||
kmyblue: true,
|
||||
label: I18n.t('simple_form.labels.defaults.setting_default_reblog_privacy'),
|
||||
label_method: ->(visibility) { safe_join([I18n.t("statuses.visibilities.#{visibility}"), I18n.t("statuses.visibilities.#{visibility}_long")], ' - ') },
|
||||
required: false,
|
||||
wrapper: :with_label
|
||||
|
||||
.fields-group
|
||||
= ff.input :stay_privacy, wrapper: :with_label, kmyblue: true, label: I18n.t('simple_form.labels.defaults.setting_stay_privacy')
|
||||
|
@ -31,7 +46,15 @@
|
|||
|
||||
.fields-row
|
||||
.fields-group.fields-row__column.fields-row__column-12
|
||||
= ff.input :default_searchability, collection: Status.selectable_searchabilities, wrapper: :with_label, kmyblue: true, include_blank: false, label_method: ->(searchability) { safe_join([I18n.t("statuses.searchabilities.#{searchability}"), I18n.t("statuses.searchabilities.#{searchability}_long")], ' - ') }, required: false, label: I18n.t('simple_form.labels.defaults.setting_default_searchability'), hint: I18n.t('simple_form.hints.defaults.setting_default_searchability')
|
||||
= ff.input :default_searchability,
|
||||
collection: Status.selectable_searchabilities,
|
||||
hint: I18n.t('simple_form.hints.defaults.setting_default_searchability'),
|
||||
include_blank: false,
|
||||
kmyblue: true,
|
||||
label: I18n.t('simple_form.labels.defaults.setting_default_searchability'),
|
||||
label_method: ->(searchability) { safe_join([I18n.t("statuses.searchabilities.#{searchability}"), I18n.t("statuses.searchabilities.#{searchability}_long")], ' - ') },
|
||||
required: false,
|
||||
wrapper: :with_label
|
||||
|
||||
.fields-group
|
||||
= ff.input :disallow_unlisted_public_searchability, wrapper: :with_label, kmyblue: true, label: I18n.t('simple_form.labels.defaults.setting_disallow_unlisted_public_searchability'), hint: I18n.t('simple_form.hints.defaults.setting_disallow_unlisted_public_searchability')
|
||||
|
@ -40,7 +63,15 @@
|
|||
|
||||
.fields-row
|
||||
.fields-group.fields-row__column.fields-row__column-12
|
||||
= ff.input :default_searchability_of_search, collection: Status.selectable_searchabilities_for_search, wrapper: :with_label, kmyblue: true, include_blank: false, label_method: ->(searchability) { safe_join([I18n.t("statuses.searchabilities.#{searchability}"), I18n.t("statuses.searchabilities.#{searchability}_search_long")], ' - ') }, required: false, hint: false, label: I18n.t('simple_form.labels.defaults.setting_default_searchability_of_search')
|
||||
= ff.input :default_searchability_of_search,
|
||||
collection: Status.selectable_searchabilities_for_search,
|
||||
hint: false,
|
||||
include_blank: false,
|
||||
kmyblue: true,
|
||||
label: I18n.t('simple_form.labels.defaults.setting_default_searchability_of_search'),
|
||||
label_method: ->(searchability) { safe_join([I18n.t("statuses.searchabilities.#{searchability}"), I18n.t("statuses.searchabilities.#{searchability}_search_long")], ' - ') },
|
||||
required: false,
|
||||
wrapper: :with_label
|
||||
|
||||
.fields-group
|
||||
= ff.input :use_public_index, wrapper: :with_label, kmyblue: true, label: I18n.t('simple_form.labels.defaults.setting_use_public_index')
|
||||
|
|
|
@ -40,7 +40,14 @@
|
|||
= f.simple_fields_for :settings, current_user.settings do |ff|
|
||||
.fields-row
|
||||
.fields-group.fields-row__column.fields-row__column-12
|
||||
= ff.input :default_searchability, collection: Status.selectable_searchabilities, wrapper: :with_label, kmyblue: true, include_blank: false, label_method: ->(searchability) { safe_join([I18n.t("statuses.searchabilities.#{searchability}"), I18n.t("statuses.searchabilities.#{searchability}_long")], ' - ') }, required: false, label: I18n.t('simple_form.labels.account.searchability_kmyblue')
|
||||
= ff.input :default_searchability,
|
||||
collection: Status.selectable_searchabilities,
|
||||
include_blank: false,
|
||||
kmyblue: true,
|
||||
label: I18n.t('simple_form.labels.account.searchability_kmyblue'),
|
||||
label_method: ->(searchability) { safe_join([I18n.t("statuses.searchabilities.#{searchability}"), I18n.t("statuses.searchabilities.#{searchability}_long")], ' - ') },
|
||||
required: false,
|
||||
wrapper: :with_label
|
||||
|
||||
%h4= t('privacy.privacy')
|
||||
|
||||
|
|
|
@ -22,7 +22,16 @@
|
|||
= ff.input :link_preview, wrapper: :with_label, kmyblue: true, label: I18n.t('simple_form.labels.defaults.setting_link_preview'), hint: I18n.t('simple_form.hints.defaults.setting_link_preview')
|
||||
|
||||
.fields-group
|
||||
= f.input :subscription_policy, kmyblue: true, collection: %w(allow followers_only block), label_method: ->(item) { safe_join([t("simple_form.labels.subscription_policy.#{item}")]) }, as: :radio_buttons, collection_wrapper_tag: 'ul', item_wrapper_tag: 'li', wrapper: :with_floating_label, label: t('simple_form.labels.defaults.subscription_policy'), hint: t('simple_form.hints.defaults.subscription_policy')
|
||||
= f.input :subscription_policy,
|
||||
as: :radio_buttons,
|
||||
collection: %w(allow followers_only block),
|
||||
collection_wrapper_tag: 'ul',
|
||||
hint: t('simple_form.hints.defaults.subscription_policy'),
|
||||
item_wrapper_tag: 'li',
|
||||
kmyblue: true,
|
||||
label: t('simple_form.labels.defaults.subscription_policy'),
|
||||
label_method: ->(item) { safe_join([t("simple_form.labels.subscription_policy.#{item}")]) },
|
||||
wrapper: :with_floating_label
|
||||
|
||||
.fields-group
|
||||
= ff.input :allow_quote, wrapper: :with_label, kmyblue: true, label: I18n.t('simple_form.labels.defaults.setting_allow_quote'), hint: false
|
||||
|
|
|
@ -36,7 +36,10 @@
|
|||
.fields-row
|
||||
.fields-row__column.fields-row__column-6
|
||||
.fields-group
|
||||
= f.input :avatar, wrapper: :with_block_label, input_html: { accept: Account::Avatar::IMAGE_MIME_TYPES.join(',') }, hint: t('simple_form.hints.defaults.avatar', dimensions: '400x400', size: number_to_human_size(Account::Avatar::LIMIT))
|
||||
= f.input :avatar,
|
||||
hint: t('simple_form.hints.defaults.avatar', dimensions: '400x400', size: number_to_human_size(Account::Avatar::LIMIT)),
|
||||
input_html: { accept: Account::Avatar::IMAGE_MIME_TYPES.join(',') },
|
||||
wrapper: :with_block_label
|
||||
|
||||
.fields-row__column.fields-row__column-6
|
||||
.fields-group
|
||||
|
@ -49,7 +52,10 @@
|
|||
.fields-row
|
||||
.fields-row__column.fields-row__column-6
|
||||
.fields-group
|
||||
= f.input :header, wrapper: :with_block_label, input_html: { accept: Account::Header::IMAGE_MIME_TYPES.join(',') }, hint: t('simple_form.hints.defaults.header', dimensions: '1500x500', size: number_to_human_size(Account::Header::LIMIT))
|
||||
= f.input :header,
|
||||
hint: t('simple_form.hints.defaults.header', dimensions: '1500x500', size: number_to_human_size(Account::Header::LIMIT)),
|
||||
input_html: { accept: Account::Header::IMAGE_MIME_TYPES.join(',') },
|
||||
wrapper: :with_block_label
|
||||
|
||||
.fields-row__column.fields-row__column-6
|
||||
.fields-group
|
||||
|
@ -62,7 +68,13 @@
|
|||
%h4= t('edit_profile.other')
|
||||
|
||||
.fields-group
|
||||
= f.input :my_actor_type, collection: %w(person bot), label_method: ->(item) { safe_join([t("simple_form.labels.defaults.#{item}"), content_tag(:span, I18n.t("simple_form.hints.defaults.#{item}"), class: 'hint')]) }, as: :radio_buttons, collection_wrapper_tag: 'ul', item_wrapper_tag: 'li', wrapper: :with_floating_label
|
||||
= f.input :my_actor_type,
|
||||
as: :radio_buttons,
|
||||
collection: %w(person bot),
|
||||
collection_wrapper_tag: 'ul',
|
||||
item_wrapper_tag: 'li',
|
||||
label_method: ->(item) { safe_join([t("simple_form.labels.defaults.#{item}"), content_tag(:span, I18n.t("simple_form.hints.defaults.#{item}"), class: 'hint')]) },
|
||||
wrapper: :with_floating_label
|
||||
|
||||
.actions
|
||||
= f.button :button, t('generic.save_changes'), type: :submit
|
||||
|
|
|
@ -12,7 +12,12 @@
|
|||
%samp.qr-alternative__code= @new_otp_secret.scan(/.{4}/).join(' ')
|
||||
|
||||
.fields-group
|
||||
= f.input :otp_attempt, wrapper: :with_label, hint: t('otp_authentication.code_hint'), label: t('simple_form.labels.defaults.otp_attempt'), input_html: { autocomplete: 'off' }, required: true
|
||||
= f.input :otp_attempt,
|
||||
hint: t('otp_authentication.code_hint'),
|
||||
input_html: { autocomplete: 'off' },
|
||||
label: t('simple_form.labels.defaults.otp_attempt'),
|
||||
required: true,
|
||||
wrapper: :with_label
|
||||
|
||||
.actions
|
||||
= f.button :button, t('otp_authentication.enable'), type: :submit
|
||||
|
|
|
@ -36,7 +36,9 @@
|
|||
%tbody
|
||||
%tr
|
||||
%td.column-cell.text-center
|
||||
%p= t 'user_mailer.appeal_approved.explanation', appeal_date: l(@appeal.created_at.in_time_zone(@resource.time_zone.presence), format: :with_time_zone), strike_date: l(@appeal.strike.created_at.in_time_zone(@resource.time_zone.presence), format: :with_time_zone)
|
||||
%p= t 'user_mailer.appeal_approved.explanation',
|
||||
appeal_date: l(@appeal.created_at.in_time_zone(@resource.time_zone.presence), format: :with_time_zone),
|
||||
strike_date: l(@appeal.strike.created_at.in_time_zone(@resource.time_zone.presence), format: :with_time_zone)
|
||||
|
||||
%table.email-table{ cellspacing: 0, cellpadding: 0 }
|
||||
%tbody
|
||||
|
|
|
@ -36,7 +36,9 @@
|
|||
%tbody
|
||||
%tr
|
||||
%td.column-cell.text-center
|
||||
%p= t 'user_mailer.appeal_rejected.explanation', appeal_date: l(@appeal.created_at.in_time_zone(@resource.time_zone.presence), format: :with_time_zone), strike_date: l(@appeal.strike.created_at.in_time_zone(@resource.time_zone.presence), format: :with_time_zone)
|
||||
%p= t 'user_mailer.appeal_rejected.explanation',
|
||||
appeal_date: l(@appeal.created_at.in_time_zone(@resource.time_zone.presence), format: :with_time_zone),
|
||||
strike_date: l(@appeal.strike.created_at.in_time_zone(@resource.time_zone.presence), format: :with_time_zone)
|
||||
|
||||
%table.email-table{ cellspacing: 0, cellpadding: 0 }
|
||||
%tbody
|
||||
|
|
|
@ -45,7 +45,10 @@
|
|||
= @remote_ip
|
||||
%br/
|
||||
%strong #{t('sessions.browser')}:
|
||||
%span{ title: @user_agent }= t 'sessions.description', browser: t("sessions.browsers.#{@detection.id}", default: @detection.id.to_s), platform: t("sessions.platforms.#{@detection.platform.id}", default: @detection.platform.id.to_s)
|
||||
%span{ title: @user_agent }
|
||||
= t 'sessions.description',
|
||||
browser: t("sessions.browsers.#{@detection.id}", default: @detection.id.to_s),
|
||||
platform: t("sessions.platforms.#{@detection.platform.id}", default: @detection.platform.id.to_s)
|
||||
%br/
|
||||
= l(@timestamp.in_time_zone(@resource.time_zone.presence), format: :with_time_zone)
|
||||
|
||||
|
@ -64,4 +67,5 @@
|
|||
%tbody
|
||||
%tr
|
||||
%td.column-cell.text-center
|
||||
%p= t 'user_mailer.suspicious_sign_in.further_actions_html', action: link_to(t('user_mailer.suspicious_sign_in.change_password'), edit_user_registration_url)
|
||||
%p= t 'user_mailer.suspicious_sign_in.further_actions_html',
|
||||
action: link_to(t('user_mailer.suspicious_sign_in.change_password'), edit_user_registration_url)
|
||||
|
|
|
@ -63,6 +63,8 @@ module Mastodon
|
|||
# Initialize configuration defaults for originally generated Rails version.
|
||||
config.load_defaults 7.0
|
||||
|
||||
config.active_record.marshalling_format_version = 7.1
|
||||
|
||||
# Please, add to the `ignore` list any other `lib` subdirectories that do
|
||||
# not contain `.rb` files, or that should not be reloaded or eager loaded.
|
||||
# Common ones are `templates`, `generators`, or `middleware`, for example.
|
||||
|
|
|
@ -31,7 +31,7 @@ Rails.application.configure do
|
|||
:fi,
|
||||
:fo,
|
||||
:fr,
|
||||
:'fr-QC',
|
||||
:'fr-CA',
|
||||
:fy,
|
||||
:ga,
|
||||
:gd,
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue