mirror of
https://git.kescher.at/CatCatNya/catstodon.git
synced 2024-11-23 14:38:07 +01:00
Merge branch 'upstream-main' into develop
Some checks failed
Bundler Audit / security (push) Has been cancelled
Check i18n / check-i18n (push) Has been cancelled
CodeQL / Analyze (push) Has been cancelled
Check formatting / lint (push) Has been cancelled
CSS Linting / lint (push) Has been cancelled
Haml Linting / lint (push) Has been cancelled
JavaScript Linting / lint (push) Has been cancelled
Ruby Linting / lint (push) Has been cancelled
JavaScript Testing / test (push) Has been cancelled
Historical data migration test / test (14-alpine) (push) Has been cancelled
Historical data migration test / test (15-alpine) (push) Has been cancelled
Historical data migration test / test (16-alpine) (push) Has been cancelled
Historical data migration test / test (17-alpine) (push) Has been cancelled
Ruby Testing / build (production) (push) Has been cancelled
Ruby Testing / build (test) (push) Has been cancelled
Ruby Testing / test (.ruby-version) (push) Has been cancelled
Ruby Testing / test (3.2) (push) Has been cancelled
Ruby Testing / Libvips tests (push) Has been cancelled
Ruby Testing / End to End testing (push) Has been cancelled
Ruby Testing / Elastic Search integration testing (push) Has been cancelled
Some checks failed
Bundler Audit / security (push) Has been cancelled
Check i18n / check-i18n (push) Has been cancelled
CodeQL / Analyze (push) Has been cancelled
Check formatting / lint (push) Has been cancelled
CSS Linting / lint (push) Has been cancelled
Haml Linting / lint (push) Has been cancelled
JavaScript Linting / lint (push) Has been cancelled
Ruby Linting / lint (push) Has been cancelled
JavaScript Testing / test (push) Has been cancelled
Historical data migration test / test (14-alpine) (push) Has been cancelled
Historical data migration test / test (15-alpine) (push) Has been cancelled
Historical data migration test / test (16-alpine) (push) Has been cancelled
Historical data migration test / test (17-alpine) (push) Has been cancelled
Ruby Testing / build (production) (push) Has been cancelled
Ruby Testing / build (test) (push) Has been cancelled
Ruby Testing / test (.ruby-version) (push) Has been cancelled
Ruby Testing / test (3.2) (push) Has been cancelled
Ruby Testing / Libvips tests (push) Has been cancelled
Ruby Testing / End to End testing (push) Has been cancelled
Ruby Testing / Elastic Search integration testing (push) Has been cancelled
This commit is contained in:
commit
a38cc7ec83
395 changed files with 5839 additions and 1618 deletions
|
@ -1 +1 @@
|
||||||
3.3.5
|
3.3.6
|
||||||
|
|
|
@ -2,6 +2,48 @@
|
||||||
|
|
||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
## [4.3.1] - 2024-10-21
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Add more explicit explanations about author attribution and `fediverse:creator` (#32383 by @ClearlyClaire)
|
||||||
|
- Add ability to group follow notifications in WebUI, can be disabled in the column settings (#32520 by @renchap)
|
||||||
|
- Add back a 6 hours mute duration option (#32522 by @renchap)
|
||||||
|
- Add note about not changing ActiveRecord encryption secrets once they are set (#32413, #32476, #32512, and #32537 by @ClearlyClaire and @mjankowski)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Change translation feature to translate to selected regional variant (e.g. pt-BR) if available (#32428 by @c960657)
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
|
||||||
|
- Remove ability to get embed code for remote posts (#32578 by @ClearlyClaire)\
|
||||||
|
Getting the embed code is only reliable for local posts.\
|
||||||
|
It never worked for non-Mastodon servers, and stopped working correctly with the changes made in 4.3.0.\
|
||||||
|
We have therefore decided to remove the menu entry while we investigate solutions.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Fix follow recommendation moderation page default language when using regional variant (#32580 by @ClearlyClaire)
|
||||||
|
- Fix column-settings spacing in local timeline in advanced view (#32567 by @lindwurm)
|
||||||
|
- Fix broken i18n in text welcome mailer tags area (#32571 by @mjankowski)
|
||||||
|
- Fix missing or incorrect cache-control headers for Streaming server (#32551 by @ThisIsMissEm)
|
||||||
|
- Fix only the first paragraph being displayed in some notifications (#32348 by @ClearlyClaire)
|
||||||
|
- Fix reblog icons on account media view (#32506 by @tribela)
|
||||||
|
- Fix Content-Security-Policy not allowing OpenStack SWIFT object storage URI (#32439 by @kenkiku1021)
|
||||||
|
- Fix back arrow pointing to the incorrect direction in RTL languages (#32485 by @renchap)
|
||||||
|
- Fix streaming server using `REDIS_USERNAME` instead of `REDIS_USER` (#32493 by @ThisIsMissEm)
|
||||||
|
- Fix follow recommendation carrousel scrolling on RTL layouts (#32462 and #32505 by @ClearlyClaire)
|
||||||
|
- Fix follow recommendation suppressions not applying immediately (#32392 by @ClearlyClaire)
|
||||||
|
- Fix language of push notifications (#32415 by @ClearlyClaire)
|
||||||
|
- Fix mute duration not being shown in list of muted accounts in web UI (#32388 by @ClearlyClaire)
|
||||||
|
- Fix “Mark every notification as read” not updating the read marker if scrolled down (#32385 by @ClearlyClaire)
|
||||||
|
- Fix “Mention” appearing for otherwise filtered posts (#32356 by @ClearlyClaire)
|
||||||
|
- Fix notification requests from suspended accounts still being listed (#32354 by @ClearlyClaire)
|
||||||
|
- Fix list edition modal styling (#32358 and #32367 by @ClearlyClaire and @vmstan)
|
||||||
|
- Fix 4 columns barely not fitting on 1920px screen (#32361 by @ClearlyClaire)
|
||||||
|
- Fix icon alignment in applications list (#32293 by @mjankowski)
|
||||||
|
|
||||||
## [4.3.0] - 2024-10-08
|
## [4.3.0] - 2024-10-08
|
||||||
|
|
||||||
The following changelog entries focus on changes visible to users, administrators, client developers or federated software developers, but there has also been a lot of code modernization, refactoring, and tooling work, in particular by @mjankowski.
|
The following changelog entries focus on changes visible to users, administrators, client developers or federated software developers, but there has also been a lot of code modernization, refactoring, and tooling work, in particular by @mjankowski.
|
||||||
|
|
|
@ -12,7 +12,7 @@ ARG BUILDPLATFORM=${BUILDPLATFORM}
|
||||||
|
|
||||||
# Ruby image to use for base image, change with [--build-arg RUBY_VERSION="3.3.x"]
|
# Ruby image to use for base image, change with [--build-arg RUBY_VERSION="3.3.x"]
|
||||||
# renovate: datasource=docker depName=docker.io/ruby
|
# renovate: datasource=docker depName=docker.io/ruby
|
||||||
ARG RUBY_VERSION="3.3.5"
|
ARG RUBY_VERSION="3.3.6"
|
||||||
# # Node version to use in base image, change with [--build-arg NODE_MAJOR_VERSION="20"]
|
# # Node version to use in base image, change with [--build-arg NODE_MAJOR_VERSION="20"]
|
||||||
# renovate: datasource=node-version depName=node
|
# renovate: datasource=node-version depName=node
|
||||||
ARG NODE_MAJOR_VERSION="22"
|
ARG NODE_MAJOR_VERSION="22"
|
||||||
|
|
10
Gemfile
10
Gemfile
|
@ -6,7 +6,7 @@ ruby '>= 3.2.0'
|
||||||
gem 'propshaft'
|
gem 'propshaft'
|
||||||
gem 'puma', '~> 6.3'
|
gem 'puma', '~> 6.3'
|
||||||
gem 'rack', '~> 2.2.7'
|
gem 'rack', '~> 2.2.7'
|
||||||
gem 'rails', '~> 7.1.1'
|
gem 'rails', '~> 7.2.0'
|
||||||
gem 'thor', '~> 1.2'
|
gem 'thor', '~> 1.2'
|
||||||
|
|
||||||
gem 'dotenv'
|
gem 'dotenv'
|
||||||
|
@ -25,7 +25,7 @@ gem 'ruby-vips', '~> 2.2', require: false
|
||||||
gem 'active_model_serializers', '~> 0.10'
|
gem 'active_model_serializers', '~> 0.10'
|
||||||
gem 'addressable', '~> 2.8'
|
gem 'addressable', '~> 2.8'
|
||||||
gem 'bootsnap', '~> 1.18.0', require: false
|
gem 'bootsnap', '~> 1.18.0', require: false
|
||||||
gem 'browser', '< 6' # https://github.com/fnando/browser/issues/543
|
gem 'browser'
|
||||||
gem 'charlock_holmes', '~> 0.7.7'
|
gem 'charlock_holmes', '~> 0.7.7'
|
||||||
gem 'chewy', '~> 7.3'
|
gem 'chewy', '~> 7.3'
|
||||||
gem 'devise', '~> 4.9'
|
gem 'devise', '~> 4.9'
|
||||||
|
@ -47,13 +47,14 @@ gem 'color_diff', '~> 0.1'
|
||||||
gem 'csv', '~> 3.2'
|
gem 'csv', '~> 3.2'
|
||||||
gem 'discard', '~> 1.2'
|
gem 'discard', '~> 1.2'
|
||||||
gem 'doorkeeper', '~> 5.6'
|
gem 'doorkeeper', '~> 5.6'
|
||||||
|
gem 'faraday-httpclient'
|
||||||
gem 'fast_blank', '~> 1.0'
|
gem 'fast_blank', '~> 1.0'
|
||||||
gem 'fastimage'
|
gem 'fastimage'
|
||||||
gem 'hiredis', '~> 0.6'
|
gem 'hiredis', '~> 0.6'
|
||||||
gem 'htmlentities', '~> 4.3'
|
gem 'htmlentities', '~> 4.3'
|
||||||
gem 'http', '~> 5.2.0'
|
gem 'http', '~> 5.2.0'
|
||||||
gem 'http_accept_language', '~> 2.1'
|
gem 'http_accept_language', '~> 2.1'
|
||||||
gem 'httplog', '~> 1.7.0'
|
gem 'httplog', '~> 1.7.0', require: false
|
||||||
gem 'i18n'
|
gem 'i18n'
|
||||||
gem 'idn-ruby', require: 'idn'
|
gem 'idn-ruby', require: 'idn'
|
||||||
gem 'inline_svg'
|
gem 'inline_svg'
|
||||||
|
@ -62,6 +63,7 @@ gem 'kaminari', '~> 1.2'
|
||||||
gem 'link_header', '~> 0.0'
|
gem 'link_header', '~> 0.0'
|
||||||
gem 'mario-redis-lock', '~> 1.2', require: 'redis_lock'
|
gem 'mario-redis-lock', '~> 1.2', require: 'redis_lock'
|
||||||
gem 'mime-types', '~> 3.6.0', require: 'mime/types/columnar'
|
gem 'mime-types', '~> 3.6.0', require: 'mime/types/columnar'
|
||||||
|
gem 'mutex_m'
|
||||||
gem 'nokogiri', '~> 1.15'
|
gem 'nokogiri', '~> 1.15'
|
||||||
gem 'oj', '~> 3.14'
|
gem 'oj', '~> 3.14'
|
||||||
gem 'ox', '~> 2.14'
|
gem 'ox', '~> 2.14'
|
||||||
|
@ -220,7 +222,7 @@ gem 'concurrent-ruby', require: false
|
||||||
gem 'connection_pool', require: false
|
gem 'connection_pool', require: false
|
||||||
gem 'xorcist', '~> 1.1'
|
gem 'xorcist', '~> 1.1'
|
||||||
|
|
||||||
gem 'net-http', '~> 0.4.0'
|
gem 'net-http', '~> 0.5.0'
|
||||||
gem 'rubyzip', '~> 2.3'
|
gem 'rubyzip', '~> 2.3'
|
||||||
|
|
||||||
gem 'hcaptcha', '~> 7.1'
|
gem 'hcaptcha', '~> 7.1'
|
||||||
|
|
229
Gemfile.lock
229
Gemfile.lock
|
@ -10,51 +10,46 @@ GIT
|
||||||
GEM
|
GEM
|
||||||
remote: https://rubygems.org/
|
remote: https://rubygems.org/
|
||||||
specs:
|
specs:
|
||||||
actioncable (7.1.4.2)
|
actioncable (7.2.2)
|
||||||
actionpack (= 7.1.4.2)
|
actionpack (= 7.2.2)
|
||||||
activesupport (= 7.1.4.2)
|
activesupport (= 7.2.2)
|
||||||
nio4r (~> 2.0)
|
nio4r (~> 2.0)
|
||||||
websocket-driver (>= 0.6.1)
|
websocket-driver (>= 0.6.1)
|
||||||
zeitwerk (~> 2.6)
|
zeitwerk (~> 2.6)
|
||||||
actionmailbox (7.1.4.2)
|
actionmailbox (7.2.2)
|
||||||
actionpack (= 7.1.4.2)
|
actionpack (= 7.2.2)
|
||||||
activejob (= 7.1.4.2)
|
activejob (= 7.2.2)
|
||||||
activerecord (= 7.1.4.2)
|
activerecord (= 7.2.2)
|
||||||
activestorage (= 7.1.4.2)
|
activestorage (= 7.2.2)
|
||||||
activesupport (= 7.1.4.2)
|
activesupport (= 7.2.2)
|
||||||
mail (>= 2.7.1)
|
mail (>= 2.8.0)
|
||||||
net-imap
|
actionmailer (7.2.2)
|
||||||
net-pop
|
actionpack (= 7.2.2)
|
||||||
net-smtp
|
actionview (= 7.2.2)
|
||||||
actionmailer (7.1.4.2)
|
activejob (= 7.2.2)
|
||||||
actionpack (= 7.1.4.2)
|
activesupport (= 7.2.2)
|
||||||
actionview (= 7.1.4.2)
|
mail (>= 2.8.0)
|
||||||
activejob (= 7.1.4.2)
|
|
||||||
activesupport (= 7.1.4.2)
|
|
||||||
mail (~> 2.5, >= 2.5.4)
|
|
||||||
net-imap
|
|
||||||
net-pop
|
|
||||||
net-smtp
|
|
||||||
rails-dom-testing (~> 2.2)
|
rails-dom-testing (~> 2.2)
|
||||||
actionpack (7.1.4.2)
|
actionpack (7.2.2)
|
||||||
actionview (= 7.1.4.2)
|
actionview (= 7.2.2)
|
||||||
activesupport (= 7.1.4.2)
|
activesupport (= 7.2.2)
|
||||||
nokogiri (>= 1.8.5)
|
nokogiri (>= 1.8.5)
|
||||||
racc
|
racc
|
||||||
rack (>= 2.2.4)
|
rack (>= 2.2.4, < 3.2)
|
||||||
rack-session (>= 1.0.1)
|
rack-session (>= 1.0.1)
|
||||||
rack-test (>= 0.6.3)
|
rack-test (>= 0.6.3)
|
||||||
rails-dom-testing (~> 2.2)
|
rails-dom-testing (~> 2.2)
|
||||||
rails-html-sanitizer (~> 1.6)
|
rails-html-sanitizer (~> 1.6)
|
||||||
actiontext (7.1.4.2)
|
useragent (~> 0.16)
|
||||||
actionpack (= 7.1.4.2)
|
actiontext (7.2.2)
|
||||||
activerecord (= 7.1.4.2)
|
actionpack (= 7.2.2)
|
||||||
activestorage (= 7.1.4.2)
|
activerecord (= 7.2.2)
|
||||||
activesupport (= 7.1.4.2)
|
activestorage (= 7.2.2)
|
||||||
|
activesupport (= 7.2.2)
|
||||||
globalid (>= 0.6.0)
|
globalid (>= 0.6.0)
|
||||||
nokogiri (>= 1.8.5)
|
nokogiri (>= 1.8.5)
|
||||||
actionview (7.1.4.2)
|
actionview (7.2.2)
|
||||||
activesupport (= 7.1.4.2)
|
activesupport (= 7.2.2)
|
||||||
builder (~> 3.1)
|
builder (~> 3.1)
|
||||||
erubi (~> 1.11)
|
erubi (~> 1.11)
|
||||||
rails-dom-testing (~> 2.2)
|
rails-dom-testing (~> 2.2)
|
||||||
|
@ -64,31 +59,33 @@ GEM
|
||||||
activemodel (>= 4.1)
|
activemodel (>= 4.1)
|
||||||
case_transform (>= 0.2)
|
case_transform (>= 0.2)
|
||||||
jsonapi-renderer (>= 0.1.1.beta1, < 0.3)
|
jsonapi-renderer (>= 0.1.1.beta1, < 0.3)
|
||||||
activejob (7.1.4.2)
|
activejob (7.2.2)
|
||||||
activesupport (= 7.1.4.2)
|
activesupport (= 7.2.2)
|
||||||
globalid (>= 0.3.6)
|
globalid (>= 0.3.6)
|
||||||
activemodel (7.1.4.2)
|
activemodel (7.2.2)
|
||||||
activesupport (= 7.1.4.2)
|
activesupport (= 7.2.2)
|
||||||
activerecord (7.1.4.2)
|
activerecord (7.2.2)
|
||||||
activemodel (= 7.1.4.2)
|
activemodel (= 7.2.2)
|
||||||
activesupport (= 7.1.4.2)
|
activesupport (= 7.2.2)
|
||||||
timeout (>= 0.4.0)
|
timeout (>= 0.4.0)
|
||||||
activestorage (7.1.4.2)
|
activestorage (7.2.2)
|
||||||
actionpack (= 7.1.4.2)
|
actionpack (= 7.2.2)
|
||||||
activejob (= 7.1.4.2)
|
activejob (= 7.2.2)
|
||||||
activerecord (= 7.1.4.2)
|
activerecord (= 7.2.2)
|
||||||
activesupport (= 7.1.4.2)
|
activesupport (= 7.2.2)
|
||||||
marcel (~> 1.0)
|
marcel (~> 1.0)
|
||||||
activesupport (7.1.4.2)
|
activesupport (7.2.2)
|
||||||
base64
|
base64
|
||||||
|
benchmark (>= 0.3)
|
||||||
bigdecimal
|
bigdecimal
|
||||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
concurrent-ruby (~> 1.0, >= 1.3.1)
|
||||||
connection_pool (>= 2.2.5)
|
connection_pool (>= 2.2.5)
|
||||||
drb
|
drb
|
||||||
i18n (>= 1.6, < 2)
|
i18n (>= 1.6, < 2)
|
||||||
|
logger (>= 1.4.2)
|
||||||
minitest (>= 5.1)
|
minitest (>= 5.1)
|
||||||
mutex_m
|
securerandom (>= 0.3)
|
||||||
tzinfo (~> 2.0)
|
tzinfo (~> 2.0, >= 2.0.5)
|
||||||
addressable (2.8.7)
|
addressable (2.8.7)
|
||||||
public_suffix (>= 2.0.2, < 7.0)
|
public_suffix (>= 2.0.2, < 7.0)
|
||||||
aes_key_wrap (1.1.0)
|
aes_key_wrap (1.1.0)
|
||||||
|
@ -100,8 +97,8 @@ GEM
|
||||||
attr_required (1.0.2)
|
attr_required (1.0.2)
|
||||||
awrence (1.2.1)
|
awrence (1.2.1)
|
||||||
aws-eventstream (1.3.0)
|
aws-eventstream (1.3.0)
|
||||||
aws-partitions (1.997.0)
|
aws-partitions (1.1004.0)
|
||||||
aws-sdk-core (3.211.0)
|
aws-sdk-core (3.212.0)
|
||||||
aws-eventstream (~> 1, >= 1.3.0)
|
aws-eventstream (~> 1, >= 1.3.0)
|
||||||
aws-partitions (~> 1, >= 1.992.0)
|
aws-partitions (~> 1, >= 1.992.0)
|
||||||
aws-sigv4 (~> 1.9)
|
aws-sigv4 (~> 1.9)
|
||||||
|
@ -109,17 +106,18 @@ GEM
|
||||||
aws-sdk-kms (1.95.0)
|
aws-sdk-kms (1.95.0)
|
||||||
aws-sdk-core (~> 3, >= 3.210.0)
|
aws-sdk-core (~> 3, >= 3.210.0)
|
||||||
aws-sigv4 (~> 1.5)
|
aws-sigv4 (~> 1.5)
|
||||||
aws-sdk-s3 (1.169.0)
|
aws-sdk-s3 (1.170.1)
|
||||||
aws-sdk-core (~> 3, >= 3.210.0)
|
aws-sdk-core (~> 3, >= 3.210.0)
|
||||||
aws-sdk-kms (~> 1)
|
aws-sdk-kms (~> 1)
|
||||||
aws-sigv4 (~> 1.5)
|
aws-sigv4 (~> 1.5)
|
||||||
aws-sigv4 (1.10.1)
|
aws-sigv4 (1.10.1)
|
||||||
aws-eventstream (~> 1, >= 1.0.2)
|
aws-eventstream (~> 1, >= 1.0.2)
|
||||||
azure-blob (0.5.2)
|
azure-blob (0.5.3)
|
||||||
rexml
|
rexml
|
||||||
base64 (0.2.0)
|
base64 (0.2.0)
|
||||||
bcp47_spec (0.2.1)
|
bcp47_spec (0.2.1)
|
||||||
bcrypt (3.1.20)
|
bcrypt (3.1.20)
|
||||||
|
benchmark (0.4.0)
|
||||||
better_errors (2.10.1)
|
better_errors (2.10.1)
|
||||||
erubi (>= 1.0.0)
|
erubi (>= 1.0.0)
|
||||||
rack (>= 0.9.0)
|
rack (>= 0.9.0)
|
||||||
|
@ -133,7 +131,7 @@ GEM
|
||||||
msgpack (~> 1.2)
|
msgpack (~> 1.2)
|
||||||
brakeman (6.2.2)
|
brakeman (6.2.2)
|
||||||
racc
|
racc
|
||||||
browser (5.3.1)
|
browser (6.1.0)
|
||||||
brpoplpush-redis_script (0.1.3)
|
brpoplpush-redis_script (0.1.3)
|
||||||
concurrent-ruby (~> 1.0, >= 1.0.5)
|
concurrent-ruby (~> 1.0, >= 1.0.5)
|
||||||
redis (>= 1.0, < 6)
|
redis (>= 1.0, < 6)
|
||||||
|
@ -180,7 +178,7 @@ GEM
|
||||||
activerecord (>= 5.a)
|
activerecord (>= 5.a)
|
||||||
database_cleaner-core (~> 2.0.0)
|
database_cleaner-core (~> 2.0.0)
|
||||||
database_cleaner-core (2.0.1)
|
database_cleaner-core (2.0.1)
|
||||||
date (3.3.4)
|
date (3.4.0)
|
||||||
debug (1.9.2)
|
debug (1.9.2)
|
||||||
irb (~> 1.10)
|
irb (~> 1.10)
|
||||||
reline (>= 0.3.8)
|
reline (>= 0.3.8)
|
||||||
|
@ -191,17 +189,17 @@ GEM
|
||||||
railties (>= 4.1.0)
|
railties (>= 4.1.0)
|
||||||
responders
|
responders
|
||||||
warden (~> 1.2.3)
|
warden (~> 1.2.3)
|
||||||
devise-two-factor (6.0.0)
|
devise-two-factor (6.1.0)
|
||||||
activesupport (~> 7.0)
|
activesupport (>= 7.0, < 8.1)
|
||||||
devise (~> 4.0)
|
devise (~> 4.0)
|
||||||
railties (~> 7.0)
|
railties (>= 7.0, < 8.1)
|
||||||
rotp (~> 6.0)
|
rotp (~> 6.0)
|
||||||
devise_pam_authenticatable2 (9.2.0)
|
devise_pam_authenticatable2 (9.2.0)
|
||||||
devise (>= 4.0.0)
|
devise (>= 4.0.0)
|
||||||
rpam2 (~> 4.0)
|
rpam2 (~> 4.0)
|
||||||
diff-lcs (1.5.1)
|
diff-lcs (1.5.1)
|
||||||
discard (1.3.0)
|
discard (1.4.0)
|
||||||
activerecord (>= 4.2, < 8)
|
activerecord (>= 4.2, < 9.0)
|
||||||
docile (1.4.1)
|
docile (1.4.1)
|
||||||
domain_name (0.6.20240107)
|
domain_name (0.6.20240107)
|
||||||
doorkeeper (5.7.1)
|
doorkeeper (5.7.1)
|
||||||
|
@ -229,29 +227,14 @@ GEM
|
||||||
fabrication (2.31.0)
|
fabrication (2.31.0)
|
||||||
faker (3.5.1)
|
faker (3.5.1)
|
||||||
i18n (>= 1.8.11, < 2)
|
i18n (>= 1.8.11, < 2)
|
||||||
faraday (1.10.3)
|
faraday (2.12.0)
|
||||||
faraday-em_http (~> 1.0)
|
faraday-net_http (>= 2.0, < 3.4)
|
||||||
faraday-em_synchrony (~> 1.0)
|
json
|
||||||
faraday-excon (~> 1.1)
|
logger
|
||||||
faraday-httpclient (~> 1.0)
|
faraday-httpclient (2.0.1)
|
||||||
faraday-multipart (~> 1.0)
|
httpclient (>= 2.2)
|
||||||
faraday-net_http (~> 1.0)
|
faraday-net_http (3.3.0)
|
||||||
faraday-net_http_persistent (~> 1.0)
|
net-http
|
||||||
faraday-patron (~> 1.0)
|
|
||||||
faraday-rack (~> 1.0)
|
|
||||||
faraday-retry (~> 1.0)
|
|
||||||
ruby2_keywords (>= 0.0.4)
|
|
||||||
faraday-em_http (1.0.0)
|
|
||||||
faraday-em_synchrony (1.0.0)
|
|
||||||
faraday-excon (1.1.0)
|
|
||||||
faraday-httpclient (1.0.1)
|
|
||||||
faraday-multipart (1.0.4)
|
|
||||||
multipart-post (~> 2)
|
|
||||||
faraday-net_http (1.0.2)
|
|
||||||
faraday-net_http_persistent (1.2.0)
|
|
||||||
faraday-patron (1.0.0)
|
|
||||||
faraday-rack (1.0.0)
|
|
||||||
faraday-retry (1.0.3)
|
|
||||||
fast_blank (1.0.1)
|
fast_blank (1.0.1)
|
||||||
fastimage (2.3.1)
|
fastimage (2.3.1)
|
||||||
ffi (1.17.0)
|
ffi (1.17.0)
|
||||||
|
@ -347,7 +330,7 @@ GEM
|
||||||
azure-blob (~> 0.5.2)
|
azure-blob (~> 0.5.2)
|
||||||
hashie (~> 5.0)
|
hashie (~> 5.0)
|
||||||
jmespath (1.6.2)
|
jmespath (1.6.2)
|
||||||
json (2.7.4)
|
json (2.8.1)
|
||||||
json-canonicalization (1.0.0)
|
json-canonicalization (1.0.0)
|
||||||
json-jwt (1.15.3.1)
|
json-jwt (1.15.3.1)
|
||||||
activesupport (>= 4.2)
|
activesupport (>= 4.2)
|
||||||
|
@ -362,7 +345,7 @@ GEM
|
||||||
rack (>= 2.2, < 4)
|
rack (>= 2.2, < 4)
|
||||||
rdf (~> 3.3)
|
rdf (~> 3.3)
|
||||||
rexml (~> 3.2)
|
rexml (~> 3.2)
|
||||||
json-ld-preloaded (3.3.0)
|
json-ld-preloaded (3.3.1)
|
||||||
json-ld (~> 3.3)
|
json-ld (~> 3.3)
|
||||||
rdf (~> 3.3)
|
rdf (~> 3.3)
|
||||||
json-schema (5.0.1)
|
json-schema (5.0.1)
|
||||||
|
@ -424,17 +407,16 @@ GEM
|
||||||
mime-types (3.6.0)
|
mime-types (3.6.0)
|
||||||
logger
|
logger
|
||||||
mime-types-data (~> 3.2015)
|
mime-types-data (~> 3.2015)
|
||||||
mime-types-data (3.2024.1001)
|
mime-types-data (3.2024.1105)
|
||||||
mini_mime (1.1.5)
|
mini_mime (1.1.5)
|
||||||
mini_portile2 (2.8.7)
|
mini_portile2 (2.8.7)
|
||||||
minitest (5.25.1)
|
minitest (5.25.1)
|
||||||
msgpack (1.7.3)
|
msgpack (1.7.5)
|
||||||
multi_json (1.15.0)
|
multi_json (1.15.0)
|
||||||
multipart-post (2.4.1)
|
|
||||||
mutex_m (0.2.0)
|
mutex_m (0.2.0)
|
||||||
net-http (0.4.1)
|
net-http (0.5.0)
|
||||||
uri
|
uri
|
||||||
net-imap (0.5.0)
|
net-imap (0.5.1)
|
||||||
date
|
date
|
||||||
net-protocol
|
net-protocol
|
||||||
net-ldap (0.19.0)
|
net-ldap (0.19.0)
|
||||||
|
@ -448,7 +430,7 @@ GEM
|
||||||
nokogiri (1.16.7)
|
nokogiri (1.16.7)
|
||||||
mini_portile2 (~> 2.8.2)
|
mini_portile2 (~> 2.8.2)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
oj (3.16.6)
|
oj (3.16.7)
|
||||||
bigdecimal (>= 3.0)
|
bigdecimal (>= 3.0)
|
||||||
ostruct (>= 0.2)
|
ostruct (>= 0.2)
|
||||||
omniauth (2.1.2)
|
omniauth (2.1.2)
|
||||||
|
@ -572,10 +554,10 @@ GEM
|
||||||
opentelemetry-semantic_conventions (1.10.1)
|
opentelemetry-semantic_conventions (1.10.1)
|
||||||
opentelemetry-api (~> 1.0)
|
opentelemetry-api (~> 1.0)
|
||||||
orm_adapter (0.5.0)
|
orm_adapter (0.5.0)
|
||||||
ostruct (0.6.0)
|
ostruct (0.6.1)
|
||||||
ox (2.14.18)
|
ox (2.14.18)
|
||||||
parallel (1.26.3)
|
parallel (1.26.3)
|
||||||
parser (3.3.5.0)
|
parser (3.3.6.0)
|
||||||
ast (~> 2.4.1)
|
ast (~> 2.4.1)
|
||||||
racc
|
racc
|
||||||
parslet (2.0.0)
|
parslet (2.0.0)
|
||||||
|
@ -597,7 +579,7 @@ GEM
|
||||||
activesupport (>= 7.0.0)
|
activesupport (>= 7.0.0)
|
||||||
rack
|
rack
|
||||||
railties (>= 7.0.0)
|
railties (>= 7.0.0)
|
||||||
psych (5.1.2)
|
psych (5.2.0)
|
||||||
stringio
|
stringio
|
||||||
public_suffix (6.0.1)
|
public_suffix (6.0.1)
|
||||||
puma (6.4.3)
|
puma (6.4.3)
|
||||||
|
@ -629,20 +611,20 @@ GEM
|
||||||
rackup (1.0.0)
|
rackup (1.0.0)
|
||||||
rack (< 3)
|
rack (< 3)
|
||||||
webrick
|
webrick
|
||||||
rails (7.1.4.2)
|
rails (7.2.2)
|
||||||
actioncable (= 7.1.4.2)
|
actioncable (= 7.2.2)
|
||||||
actionmailbox (= 7.1.4.2)
|
actionmailbox (= 7.2.2)
|
||||||
actionmailer (= 7.1.4.2)
|
actionmailer (= 7.2.2)
|
||||||
actionpack (= 7.1.4.2)
|
actionpack (= 7.2.2)
|
||||||
actiontext (= 7.1.4.2)
|
actiontext (= 7.2.2)
|
||||||
actionview (= 7.1.4.2)
|
actionview (= 7.2.2)
|
||||||
activejob (= 7.1.4.2)
|
activejob (= 7.2.2)
|
||||||
activemodel (= 7.1.4.2)
|
activemodel (= 7.2.2)
|
||||||
activerecord (= 7.1.4.2)
|
activerecord (= 7.2.2)
|
||||||
activestorage (= 7.1.4.2)
|
activestorage (= 7.2.2)
|
||||||
activesupport (= 7.1.4.2)
|
activesupport (= 7.2.2)
|
||||||
bundler (>= 1.15.0)
|
bundler (>= 1.15.0)
|
||||||
railties (= 7.1.4.2)
|
railties (= 7.2.2)
|
||||||
rails-controller-testing (1.0.5)
|
rails-controller-testing (1.0.5)
|
||||||
actionpack (>= 5.0.1.rc1)
|
actionpack (>= 5.0.1.rc1)
|
||||||
actionview (>= 5.0.1.rc1)
|
actionview (>= 5.0.1.rc1)
|
||||||
|
@ -657,10 +639,10 @@ GEM
|
||||||
rails-i18n (7.0.10)
|
rails-i18n (7.0.10)
|
||||||
i18n (>= 0.7, < 2)
|
i18n (>= 0.7, < 2)
|
||||||
railties (>= 6.0.0, < 8)
|
railties (>= 6.0.0, < 8)
|
||||||
railties (7.1.4.2)
|
railties (7.2.2)
|
||||||
actionpack (= 7.1.4.2)
|
actionpack (= 7.2.2)
|
||||||
activesupport (= 7.1.4.2)
|
activesupport (= 7.2.2)
|
||||||
irb
|
irb (~> 1.13)
|
||||||
rackup (>= 1.0.0)
|
rackup (>= 1.0.0)
|
||||||
rake (>= 12.2)
|
rake (>= 12.2)
|
||||||
thor (~> 1.0, >= 1.2.2)
|
thor (~> 1.0, >= 1.2.2)
|
||||||
|
@ -682,7 +664,7 @@ GEM
|
||||||
redlock (1.3.2)
|
redlock (1.3.2)
|
||||||
redis (>= 3.0.0, < 6.0)
|
redis (>= 3.0.0, < 6.0)
|
||||||
regexp_parser (2.9.2)
|
regexp_parser (2.9.2)
|
||||||
reline (0.5.10)
|
reline (0.5.11)
|
||||||
io-console (~> 0.5)
|
io-console (~> 0.5)
|
||||||
request_store (1.6.0)
|
request_store (1.6.0)
|
||||||
rack (>= 1.4)
|
rack (>= 1.4)
|
||||||
|
@ -691,7 +673,7 @@ GEM
|
||||||
railties (>= 5.2)
|
railties (>= 5.2)
|
||||||
rexml (3.3.9)
|
rexml (3.3.9)
|
||||||
rotp (6.3.0)
|
rotp (6.3.0)
|
||||||
rouge (4.4.0)
|
rouge (4.5.1)
|
||||||
rpam2 (4.0.2)
|
rpam2 (4.0.2)
|
||||||
rqrcode (2.2.0)
|
rqrcode (2.2.0)
|
||||||
chunky_png (~> 1.0)
|
chunky_png (~> 1.0)
|
||||||
|
@ -711,7 +693,7 @@ GEM
|
||||||
rspec-mocks (3.13.2)
|
rspec-mocks (3.13.2)
|
||||||
diff-lcs (>= 1.2.0, < 2.0)
|
diff-lcs (>= 1.2.0, < 2.0)
|
||||||
rspec-support (~> 3.13.0)
|
rspec-support (~> 3.13.0)
|
||||||
rspec-rails (7.0.1)
|
rspec-rails (7.1.0)
|
||||||
actionpack (>= 7.0)
|
actionpack (>= 7.0)
|
||||||
activesupport (>= 7.0)
|
activesupport (>= 7.0)
|
||||||
railties (>= 7.0)
|
railties (>= 7.0)
|
||||||
|
@ -760,7 +742,6 @@ GEM
|
||||||
ruby-vips (2.2.2)
|
ruby-vips (2.2.2)
|
||||||
ffi (~> 1.12)
|
ffi (~> 1.12)
|
||||||
logger
|
logger
|
||||||
ruby2_keywords (0.0.5)
|
|
||||||
rubyzip (2.3.2)
|
rubyzip (2.3.2)
|
||||||
rufus-scheduler (3.9.1)
|
rufus-scheduler (3.9.1)
|
||||||
fugit (~> 1.1, >= 1.1.6)
|
fugit (~> 1.1, >= 1.1.6)
|
||||||
|
@ -772,6 +753,7 @@ GEM
|
||||||
scenic (1.8.0)
|
scenic (1.8.0)
|
||||||
activerecord (>= 4.0.0)
|
activerecord (>= 4.0.0)
|
||||||
railties (>= 4.0.0)
|
railties (>= 4.0.0)
|
||||||
|
securerandom (0.3.2)
|
||||||
selenium-webdriver (4.26.0)
|
selenium-webdriver (4.26.0)
|
||||||
base64 (~> 0.2)
|
base64 (~> 0.2)
|
||||||
logger (~> 1.4)
|
logger (~> 1.4)
|
||||||
|
@ -812,8 +794,8 @@ GEM
|
||||||
stackprof (0.2.26)
|
stackprof (0.2.26)
|
||||||
stoplight (4.1.0)
|
stoplight (4.1.0)
|
||||||
redlock (~> 1.0)
|
redlock (~> 1.0)
|
||||||
stringio (3.1.1)
|
stringio (3.1.2)
|
||||||
strong_migrations (2.0.2)
|
strong_migrations (2.1.0)
|
||||||
activerecord (>= 6.1)
|
activerecord (>= 6.1)
|
||||||
swd (1.3.0)
|
swd (1.3.0)
|
||||||
activesupport (>= 3)
|
activesupport (>= 3)
|
||||||
|
@ -828,7 +810,7 @@ GEM
|
||||||
test-prof (1.4.2)
|
test-prof (1.4.2)
|
||||||
thor (1.3.2)
|
thor (1.3.2)
|
||||||
tilt (2.4.0)
|
tilt (2.4.0)
|
||||||
timeout (0.4.1)
|
timeout (0.4.2)
|
||||||
tpm-key_attestation (0.12.1)
|
tpm-key_attestation (0.12.1)
|
||||||
bindata (~> 2.4)
|
bindata (~> 2.4)
|
||||||
openssl (> 2.0)
|
openssl (> 2.0)
|
||||||
|
@ -855,6 +837,7 @@ GEM
|
||||||
unf_ext (0.0.9.1)
|
unf_ext (0.0.9.1)
|
||||||
unicode-display_width (2.6.0)
|
unicode-display_width (2.6.0)
|
||||||
uri (0.13.1)
|
uri (0.13.1)
|
||||||
|
useragent (0.16.10)
|
||||||
validate_email (0.1.6)
|
validate_email (0.1.6)
|
||||||
activemodel (>= 3.0)
|
activemodel (>= 3.0)
|
||||||
mail (>= 2.2.5)
|
mail (>= 2.2.5)
|
||||||
|
@ -884,7 +867,7 @@ GEM
|
||||||
rack-proxy (>= 0.6.1)
|
rack-proxy (>= 0.6.1)
|
||||||
railties (>= 5.2)
|
railties (>= 5.2)
|
||||||
semantic_range (>= 2.3.0)
|
semantic_range (>= 2.3.0)
|
||||||
webrick (1.8.2)
|
webrick (1.9.0)
|
||||||
websocket (1.2.11)
|
websocket (1.2.11)
|
||||||
websocket-driver (0.7.6)
|
websocket-driver (0.7.6)
|
||||||
websocket-extensions (>= 0.1.0)
|
websocket-extensions (>= 0.1.0)
|
||||||
|
@ -908,7 +891,7 @@ DEPENDENCIES
|
||||||
blurhash (~> 0.1)
|
blurhash (~> 0.1)
|
||||||
bootsnap (~> 1.18.0)
|
bootsnap (~> 1.18.0)
|
||||||
brakeman (~> 6.0)
|
brakeman (~> 6.0)
|
||||||
browser (< 6)
|
browser
|
||||||
bundler-audit (~> 0.9)
|
bundler-audit (~> 0.9)
|
||||||
capybara (~> 3.39)
|
capybara (~> 3.39)
|
||||||
charlock_holmes (~> 0.7.7)
|
charlock_holmes (~> 0.7.7)
|
||||||
|
@ -930,6 +913,7 @@ DEPENDENCIES
|
||||||
email_spec
|
email_spec
|
||||||
fabrication (~> 2.30)
|
fabrication (~> 2.30)
|
||||||
faker (~> 3.2)
|
faker (~> 3.2)
|
||||||
|
faraday-httpclient
|
||||||
fast_blank (~> 1.0)
|
fast_blank (~> 1.0)
|
||||||
fastimage
|
fastimage
|
||||||
flatware-rspec
|
flatware-rspec
|
||||||
|
@ -962,7 +946,8 @@ DEPENDENCIES
|
||||||
mario-redis-lock (~> 1.2)
|
mario-redis-lock (~> 1.2)
|
||||||
memory_profiler
|
memory_profiler
|
||||||
mime-types (~> 3.6.0)
|
mime-types (~> 3.6.0)
|
||||||
net-http (~> 0.4.0)
|
mutex_m
|
||||||
|
net-http (~> 0.5.0)
|
||||||
net-ldap (~> 0.18)
|
net-ldap (~> 0.18)
|
||||||
nokogiri (~> 1.15)
|
nokogiri (~> 1.15)
|
||||||
oj (~> 3.14)
|
oj (~> 3.14)
|
||||||
|
@ -1000,7 +985,7 @@ DEPENDENCIES
|
||||||
rack-attack (~> 6.6)
|
rack-attack (~> 6.6)
|
||||||
rack-cors (~> 2.0)
|
rack-cors (~> 2.0)
|
||||||
rack-test (~> 2.1)
|
rack-test (~> 2.1)
|
||||||
rails (~> 7.1.1)
|
rails (~> 7.2.0)
|
||||||
rails-controller-testing (~> 1.0)
|
rails-controller-testing (~> 1.0)
|
||||||
rails-i18n (~> 7.0)
|
rails-i18n (~> 7.0)
|
||||||
rdf-normalize (~> 0.5)
|
rdf-normalize (~> 0.5)
|
||||||
|
|
2
Rakefile
2
Rakefile
|
@ -3,6 +3,6 @@
|
||||||
# Add your own tasks in files placed in lib/tasks ending in .rake,
|
# Add your own tasks in files placed in lib/tasks ending in .rake,
|
||||||
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
|
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
|
||||||
|
|
||||||
require File.expand_path('config/application', __dir__)
|
require_relative 'config/application'
|
||||||
|
|
||||||
Rails.application.load_tasks
|
Rails.application.load_tasks
|
||||||
|
|
|
@ -5,7 +5,7 @@ module Admin
|
||||||
def index
|
def index
|
||||||
authorize :email_domain_block, :index?
|
authorize :email_domain_block, :index?
|
||||||
|
|
||||||
@email_domain_blocks = EmailDomainBlock.where(parent_id: nil).includes(:children).order(id: :desc).page(params[:page])
|
@email_domain_blocks = EmailDomainBlock.parents.includes(:children).order(id: :desc).page(params[:page])
|
||||||
@form = Form::EmailDomainBlockBatch.new
|
@form = Form::EmailDomainBlockBatch.new
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -58,10 +58,7 @@ module Admin
|
||||||
private
|
private
|
||||||
|
|
||||||
def set_resolved_records
|
def set_resolved_records
|
||||||
Resolv::DNS.open do |dns|
|
@resolved_records = DomainResource.new(@email_domain_block.domain).mx
|
||||||
dns.timeouts = 5
|
|
||||||
@resolved_records = dns.getresources(@email_domain_block.domain, Resolv::DNS::Resource::IN::MX).to_a
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def resource_params
|
def resource_params
|
||||||
|
|
|
@ -32,7 +32,7 @@ module Admin
|
||||||
|
|
||||||
def deactivate_all
|
def deactivate_all
|
||||||
authorize :invite, :deactivate_all?
|
authorize :invite, :deactivate_all?
|
||||||
Invite.available.in_batches.update_all(expires_at: Time.now.utc)
|
Invite.available.in_batches.touch_all(:expires_at)
|
||||||
redirect_to admin_invites_path
|
redirect_to admin_invites_path
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ module Admin
|
||||||
@relay = Relay.new(resource_params)
|
@relay = Relay.new(resource_params)
|
||||||
|
|
||||||
if @relay.save
|
if @relay.save
|
||||||
|
log_action :create, @relay
|
||||||
@relay.enable!
|
@relay.enable!
|
||||||
redirect_to admin_relays_path
|
redirect_to admin_relays_path
|
||||||
else
|
else
|
||||||
|
@ -31,18 +32,21 @@ module Admin
|
||||||
def destroy
|
def destroy
|
||||||
authorize :relay, :update?
|
authorize :relay, :update?
|
||||||
@relay.destroy
|
@relay.destroy
|
||||||
|
log_action :destroy, @relay
|
||||||
redirect_to admin_relays_path
|
redirect_to admin_relays_path
|
||||||
end
|
end
|
||||||
|
|
||||||
def enable
|
def enable
|
||||||
authorize :relay, :update?
|
authorize :relay, :update?
|
||||||
@relay.enable!
|
@relay.enable!
|
||||||
|
log_action :enable, @relay
|
||||||
redirect_to admin_relays_path
|
redirect_to admin_relays_path
|
||||||
end
|
end
|
||||||
|
|
||||||
def disable
|
def disable
|
||||||
authorize :relay, :update?
|
authorize :relay, :update?
|
||||||
@relay.disable!
|
@relay.disable!
|
||||||
|
log_action :disable, @relay
|
||||||
redirect_to admin_relays_path
|
redirect_to admin_relays_path
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,8 @@ module Admin
|
||||||
|
|
||||||
def show
|
def show
|
||||||
authorize [:admin, @status], :show?
|
authorize [:admin, @status], :show?
|
||||||
|
|
||||||
|
@status_batch_action = Admin::StatusBatchAction.new
|
||||||
end
|
end
|
||||||
|
|
||||||
def batch
|
def batch
|
||||||
|
|
|
@ -17,6 +17,17 @@ class Api::V1::AnnualReportsController < Api::BaseController
|
||||||
relationships: @relationships
|
relationships: @relationships
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def show
|
||||||
|
with_read_replica do
|
||||||
|
@presenter = AnnualReportsPresenter.new([@annual_report])
|
||||||
|
@relationships = StatusRelationshipsPresenter.new(@presenter.statuses, current_account.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
render json: @presenter,
|
||||||
|
serializer: REST::AnnualReportsSerializer,
|
||||||
|
relationships: @relationships
|
||||||
|
end
|
||||||
|
|
||||||
def read
|
def read
|
||||||
@annual_report.view!
|
@annual_report.view!
|
||||||
render_empty
|
render_empty
|
||||||
|
|
|
@ -7,7 +7,6 @@ module WebAppControllerConcern
|
||||||
vary_by 'Accept, Accept-Language, Cookie'
|
vary_by 'Accept, Accept-Language, Cookie'
|
||||||
|
|
||||||
before_action :redirect_unauthenticated_to_permalinks!
|
before_action :redirect_unauthenticated_to_permalinks!
|
||||||
before_action :set_app_body_class
|
|
||||||
|
|
||||||
content_security_policy do |p|
|
content_security_policy do |p|
|
||||||
policy = ContentSecurityPolicy.new
|
policy = ContentSecurityPolicy.new
|
||||||
|
@ -24,10 +23,6 @@ module WebAppControllerConcern
|
||||||
!(ENV['ONE_CLICK_SSO_LOGIN'] == 'true' && ENV['OMNIAUTH_ONLY'] == 'true' && Devise.omniauth_providers.length == 1) && current_user.nil?
|
!(ENV['ONE_CLICK_SSO_LOGIN'] == 'true' && ENV['OMNIAUTH_ONLY'] == 'true' && Devise.omniauth_providers.length == 1) && current_user.nil?
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_app_body_class
|
|
||||||
@body_classes = 'app-body'
|
|
||||||
end
|
|
||||||
|
|
||||||
def redirect_unauthenticated_to_permalinks!
|
def redirect_unauthenticated_to_permalinks!
|
||||||
return if user_signed_in? # NOTE: Different from upstream because we allow moved users to log in
|
return if user_signed_in? # NOTE: Different from upstream because we allow moved users to log in
|
||||||
|
|
||||||
|
|
|
@ -35,12 +35,6 @@ class Oauth::AuthorizedApplicationsController < Doorkeeper::AuthorizedApplicatio
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_last_used_at_by_app
|
def set_last_used_at_by_app
|
||||||
@last_used_at_by_app = Doorkeeper::AccessToken
|
@last_used_at_by_app = current_resource_owner.applications_last_used
|
||||||
.select('DISTINCT ON (application_id) application_id, last_used_at')
|
|
||||||
.where(resource_owner_id: current_resource_owner.id)
|
|
||||||
.where.not(last_used_at: nil)
|
|
||||||
.order(application_id: :desc, last_used_at: :desc)
|
|
||||||
.pluck(:application_id, :last_used_at)
|
|
||||||
.to_h
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -12,12 +12,12 @@ module Admin::AccountModerationNotesHelper
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def admin_account_inline_link_to(account)
|
def admin_account_inline_link_to(account, path: nil)
|
||||||
return if account.nil?
|
return if account.nil?
|
||||||
|
|
||||||
link_to(
|
link_to(
|
||||||
account_inline_text(account),
|
account_inline_text(account),
|
||||||
admin_account_path(account.id),
|
path || admin_account_path(account.id),
|
||||||
class: class_names('inline-name-tag', suspended: suspended_account?(account)),
|
class: class_names('inline-name-tag', suspended: suspended_account?(account)),
|
||||||
title: account.acct
|
title: account.acct
|
||||||
)
|
)
|
||||||
|
|
|
@ -33,6 +33,8 @@ module Admin::ActionLogsHelper
|
||||||
else
|
else
|
||||||
I18n.t('admin.action_logs.deleted_account')
|
I18n.t('admin.action_logs.deleted_account')
|
||||||
end
|
end
|
||||||
|
when 'Relay'
|
||||||
|
link_to log.human_identifier, admin_relays_path
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -79,7 +79,7 @@ module ApplicationHelper
|
||||||
|
|
||||||
def html_title
|
def html_title
|
||||||
safe_join(
|
safe_join(
|
||||||
[content_for(:page_title).to_s.chomp, title]
|
[content_for(:page_title), title]
|
||||||
.compact_blank,
|
.compact_blank,
|
||||||
' - '
|
' - '
|
||||||
)
|
)
|
||||||
|
|
|
@ -16,6 +16,6 @@ module RegistrationHelper
|
||||||
end
|
end
|
||||||
|
|
||||||
def ip_blocked?(remote_ip)
|
def ip_blocked?(remote_ip)
|
||||||
IpBlock.where(severity: :sign_up_block).exists?(['ip >>= ?', remote_ip.to_s])
|
IpBlock.severity_sign_up_block.containing(remote_ip.to_s).exists?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -21,6 +21,7 @@ export const allNotificationTypes = [
|
||||||
'admin.report',
|
'admin.report',
|
||||||
'moderation_warning',
|
'moderation_warning',
|
||||||
'severed_relationships',
|
'severed_relationships',
|
||||||
|
'annual_report',
|
||||||
];
|
];
|
||||||
|
|
||||||
export type NotificationWithStatusType =
|
export type NotificationWithStatusType =
|
||||||
|
@ -39,7 +40,8 @@ export type NotificationType =
|
||||||
| 'moderation_warning'
|
| 'moderation_warning'
|
||||||
| 'severed_relationships'
|
| 'severed_relationships'
|
||||||
| 'admin.sign_up'
|
| 'admin.sign_up'
|
||||||
| 'admin.report';
|
| 'admin.report'
|
||||||
|
| 'annual_report';
|
||||||
|
|
||||||
export interface BaseNotificationJSON {
|
export interface BaseNotificationJSON {
|
||||||
id: string;
|
id: string;
|
||||||
|
@ -132,6 +134,15 @@ interface AccountRelationshipSeveranceNotificationJSON
|
||||||
event: ApiAccountRelationshipSeveranceEventJSON;
|
event: ApiAccountRelationshipSeveranceEventJSON;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ApiAnnualReportEventJSON {
|
||||||
|
year: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AnnualReportNotificationGroupJSON extends BaseNotificationGroupJSON {
|
||||||
|
type: 'annual_report';
|
||||||
|
annual_report: ApiAnnualReportEventJSON;
|
||||||
|
}
|
||||||
|
|
||||||
export type ApiNotificationJSON =
|
export type ApiNotificationJSON =
|
||||||
| SimpleNotificationJSON
|
| SimpleNotificationJSON
|
||||||
| ReportNotificationJSON
|
| ReportNotificationJSON
|
||||||
|
@ -144,7 +155,8 @@ export type ApiNotificationGroupJSON =
|
||||||
| ReportNotificationGroupJSON
|
| ReportNotificationGroupJSON
|
||||||
| AccountRelationshipSeveranceNotificationGroupJSON
|
| AccountRelationshipSeveranceNotificationGroupJSON
|
||||||
| NotificationGroupWithStatusJSON
|
| NotificationGroupWithStatusJSON
|
||||||
| ModerationWarningNotificationGroupJSON;
|
| ModerationWarningNotificationGroupJSON
|
||||||
|
| AnnualReportNotificationGroupJSON;
|
||||||
|
|
||||||
export interface ApiNotificationGroupsResultJSON {
|
export interface ApiNotificationGroupsResultJSON {
|
||||||
accounts: ApiAccountJSON[];
|
accounts: ApiAccountJSON[];
|
||||||
|
|
|
@ -19,6 +19,7 @@ export const CollapseButton = ({ collapsed, setCollapsed }) => {
|
||||||
if (e.button === 0) {
|
if (e.button === 0) {
|
||||||
setCollapsed(!collapsed);
|
setCollapsed(!collapsed);
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
}
|
}
|
||||||
}, [collapsed, setCollapsed]);
|
}, [collapsed, setCollapsed]);
|
||||||
|
|
||||||
|
|
|
@ -98,12 +98,12 @@ class Item extends PureComponent {
|
||||||
height = 50;
|
height = 50;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attachment.get('description')?.length > 0) {
|
|
||||||
badges.push(<AltTextBadge key='alt' description={attachment.get('description')} />);
|
|
||||||
}
|
|
||||||
|
|
||||||
const description = attachment.getIn(['translation', 'description']) || attachment.get('description');
|
const description = attachment.getIn(['translation', 'description']) || attachment.get('description');
|
||||||
|
|
||||||
|
if (description?.length > 0) {
|
||||||
|
badges.push(<AltTextBadge key='alt' description={description} />);
|
||||||
|
}
|
||||||
|
|
||||||
if (attachment.get('type') === 'unknown') {
|
if (attachment.get('type') === 'unknown') {
|
||||||
return (
|
return (
|
||||||
<div className={classNames('media-gallery__item', { standalone, 'media-gallery__item--tall': height === 100, 'media-gallery__item--wide': width === 100 })} key={attachment.get('id')}>
|
<div className={classNames('media-gallery__item', { standalone, 'media-gallery__item--tall': height === 100, 'media-gallery__item--wide': width === 100 })} key={attachment.get('id')}>
|
||||||
|
|
|
@ -13,11 +13,14 @@ class ModalRoot extends PureComponent {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
children: PropTypes.node,
|
children: PropTypes.node,
|
||||||
onClose: PropTypes.func.isRequired,
|
onClose: PropTypes.func.isRequired,
|
||||||
backgroundColor: PropTypes.shape({
|
backgroundColor: PropTypes.oneOfType([
|
||||||
r: PropTypes.number,
|
PropTypes.string,
|
||||||
g: PropTypes.number,
|
PropTypes.shape({
|
||||||
b: PropTypes.number,
|
r: PropTypes.number,
|
||||||
}),
|
g: PropTypes.number,
|
||||||
|
b: PropTypes.number,
|
||||||
|
}),
|
||||||
|
]),
|
||||||
noEsc: PropTypes.bool,
|
noEsc: PropTypes.bool,
|
||||||
ignoreFocus: PropTypes.bool,
|
ignoreFocus: PropTypes.bool,
|
||||||
...WithOptionalRouterPropTypes,
|
...WithOptionalRouterPropTypes,
|
||||||
|
@ -146,14 +149,17 @@ class ModalRoot extends PureComponent {
|
||||||
|
|
||||||
let backgroundColor = null;
|
let backgroundColor = null;
|
||||||
|
|
||||||
if (this.props.backgroundColor) {
|
if (this.props.backgroundColor && typeof this.props.backgroundColor === 'string') {
|
||||||
backgroundColor = multiply({ ...this.props.backgroundColor, a: 1 }, { r: 0, g: 0, b: 0, a: 0.7 });
|
backgroundColor = this.props.backgroundColor;
|
||||||
|
} else if (this.props.backgroundColor) {
|
||||||
|
const darkenedColor = multiply({ ...this.props.backgroundColor, a: 1 }, { r: 0, g: 0, b: 0, a: 0.7 });
|
||||||
|
backgroundColor = `rgb(${darkenedColor.r}, ${darkenedColor.g}, ${darkenedColor.b})`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='modal-root' ref={this.setRef}>
|
<div className='modal-root' ref={this.setRef}>
|
||||||
<div style={{ pointerEvents: visible ? 'auto' : 'none' }}>
|
<div style={{ pointerEvents: visible ? 'auto' : 'none' }}>
|
||||||
<div role='presentation' className='modal-root__overlay' onClick={onClose} style={{ backgroundColor: backgroundColor ? `rgba(${backgroundColor.r}, ${backgroundColor.g}, ${backgroundColor.b}, 0.9)` : null }} />
|
<div role='presentation' className='modal-root__overlay' onClick={onClose} style={{ backgroundColor }} />
|
||||||
<div role='dialog' className='modal-root__container'>{children}</div>
|
<div role='dialog' className='modal-root__container'>{children}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -377,26 +377,29 @@ class Status extends ImmutablePureComponent {
|
||||||
const { isCollapsed } = this.state;
|
const { isCollapsed } = this.state;
|
||||||
if (!history) return;
|
if (!history) return;
|
||||||
|
|
||||||
if (e.button === 0 && !(e.ctrlKey || e.altKey || e.metaKey)) {
|
if (e.button !== 0 || e.ctrlKey || e.altKey || e.metaKey) {
|
||||||
if (isCollapsed) this.setCollapsed(false);
|
return;
|
||||||
else if (e.shiftKey) {
|
|
||||||
this.setCollapsed(true);
|
|
||||||
document.getSelection().removeAllRanges();
|
|
||||||
} else if (this.props.onClick) {
|
|
||||||
this.props.onClick();
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
if (destination === undefined) {
|
|
||||||
destination = `/@${
|
|
||||||
status.getIn(['reblog', 'account', 'acct'], status.getIn(['account', 'acct']))
|
|
||||||
}/${
|
|
||||||
status.getIn(['reblog', 'id'], status.get('id'))
|
|
||||||
}`;
|
|
||||||
}
|
|
||||||
history.push(destination);
|
|
||||||
}
|
|
||||||
e.preventDefault();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isCollapsed) this.setCollapsed(false);
|
||||||
|
else if (e.shiftKey) {
|
||||||
|
this.setCollapsed(true);
|
||||||
|
document.getSelection().removeAllRanges();
|
||||||
|
} else if (this.props.onClick) {
|
||||||
|
this.props.onClick();
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
if (destination === undefined) {
|
||||||
|
destination = `/@${
|
||||||
|
status.getIn(['reblog', 'account', 'acct'], status.getIn(['account', 'acct']))
|
||||||
|
}/${
|
||||||
|
status.getIn(['reblog', 'id'], status.get('id'))
|
||||||
|
}`;
|
||||||
|
}
|
||||||
|
history.push(destination);
|
||||||
|
}
|
||||||
|
|
||||||
|
e.preventDefault();
|
||||||
};
|
};
|
||||||
|
|
||||||
handleToggleMediaVisibility = () => {
|
handleToggleMediaVisibility = () => {
|
||||||
|
@ -589,22 +592,23 @@ class Status extends ImmutablePureComponent {
|
||||||
|
|
||||||
let prepend, rebloggedByText;
|
let prepend, rebloggedByText;
|
||||||
|
|
||||||
|
const connectUp = previousId && previousId === status.get('in_reply_to_id');
|
||||||
|
const connectToRoot = rootId && rootId === status.get('in_reply_to_id');
|
||||||
|
const connectReply = nextInReplyToId && nextInReplyToId === status.get('id');
|
||||||
|
const matchedFilters = status.get('matched_filters');
|
||||||
|
|
||||||
if (hidden) {
|
if (hidden) {
|
||||||
return (
|
return (
|
||||||
<HotKeys handlers={handlers} tabIndex={unfocusable ? null : -1}>
|
<HotKeys handlers={handlers} tabIndex={unfocusable ? null : -1}>
|
||||||
<div ref={this.handleRef} className='status focusable' tabIndex={unfocusable ? null : 0}>
|
<div ref={this.handleRef} className='status focusable' tabIndex={unfocusable ? null : 0}>
|
||||||
<span>{status.getIn(['account', 'display_name']) || status.getIn(['account', 'username'])}</span>
|
<span>{status.getIn(['account', 'display_name']) || status.getIn(['account', 'username'])}</span>
|
||||||
<span>{status.get('content')}</span>
|
{status.get('spoiler_text').length > 0 && (<span>{status.get('spoiler_text')}</span>)}
|
||||||
|
{isExpanded && <span>{status.get('content')}</span>}
|
||||||
</div>
|
</div>
|
||||||
</HotKeys>
|
</HotKeys>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const connectUp = previousId && previousId === status.get('in_reply_to_id');
|
|
||||||
const connectToRoot = rootId && rootId === status.get('in_reply_to_id');
|
|
||||||
const connectReply = nextInReplyToId && nextInReplyToId === status.get('id');
|
|
||||||
const matchedFilters = status.get('matched_filters');
|
|
||||||
|
|
||||||
if (this.state.forceFilter === undefined ? matchedFilters : this.state.forceFilter) {
|
if (this.state.forceFilter === undefined ? matchedFilters : this.state.forceFilter) {
|
||||||
const minHandlers = this.props.muted ? {} : {
|
const minHandlers = this.props.muted ? {} : {
|
||||||
moveUp: this.handleHotkeyMoveUp,
|
moveUp: this.handleHotkeyMoveUp,
|
||||||
|
@ -813,7 +817,8 @@ class Status extends ImmutablePureComponent {
|
||||||
{(connectReply || connectUp || connectToRoot) && <div className={classNames('status__line', { 'status__line--full': connectReply, 'status__line--first': !status.get('in_reply_to_id') && !connectToRoot })} />}
|
{(connectReply || connectUp || connectToRoot) && <div className={classNames('status__line', { 'status__line--full': connectReply, 'status__line--first': !status.get('in_reply_to_id') && !connectToRoot })} />}
|
||||||
|
|
||||||
{(!muted || !isCollapsed) && (
|
{(!muted || !isCollapsed) && (
|
||||||
<header className='status__info'>
|
/* eslint-disable-next-line jsx-a11y/no-static-element-interactions */
|
||||||
|
<header onClick={this.parseClick} className='status__info'>
|
||||||
<StatusHeader
|
<StatusHeader
|
||||||
status={status}
|
status={status}
|
||||||
friend={account}
|
friend={account}
|
||||||
|
|
|
@ -18,15 +18,10 @@ export default class StatusHeader extends PureComponent {
|
||||||
parseClick: PropTypes.func.isRequired,
|
parseClick: PropTypes.func.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Handles clicks on account name/image
|
|
||||||
handleClick = (acct, e) => {
|
|
||||||
const { parseClick } = this.props;
|
|
||||||
parseClick(e, `/@${acct}`);
|
|
||||||
};
|
|
||||||
|
|
||||||
handleAccountClick = (e) => {
|
handleAccountClick = (e) => {
|
||||||
const { status } = this.props;
|
const { status, parseClick } = this.props;
|
||||||
this.handleClick(status.getIn(['account', 'acct']), e);
|
parseClick(e, `/@${status.getIn(['account', 'acct'])}`);
|
||||||
|
e.stopPropagation();
|
||||||
};
|
};
|
||||||
|
|
||||||
// Rendering.
|
// Rendering.
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
|
import booster from '@/images/archetypes/booster.png';
|
||||||
|
import lurker from '@/images/archetypes/lurker.png';
|
||||||
|
import oracle from '@/images/archetypes/oracle.png';
|
||||||
|
import pollster from '@/images/archetypes/pollster.png';
|
||||||
|
import replier from '@/images/archetypes/replier.png';
|
||||||
|
import type { Archetype as ArchetypeData } from 'flavours/glitch/models/annual_report';
|
||||||
|
|
||||||
|
export const Archetype: React.FC<{
|
||||||
|
data: ArchetypeData;
|
||||||
|
}> = ({ data }) => {
|
||||||
|
let illustration, label;
|
||||||
|
|
||||||
|
switch (data) {
|
||||||
|
case 'booster':
|
||||||
|
illustration = booster;
|
||||||
|
label = (
|
||||||
|
<FormattedMessage
|
||||||
|
id='annual_report.summary.archetype.booster'
|
||||||
|
defaultMessage='The cool-hunter'
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case 'replier':
|
||||||
|
illustration = replier;
|
||||||
|
label = (
|
||||||
|
<FormattedMessage
|
||||||
|
id='annual_report.summary.archetype.replier'
|
||||||
|
defaultMessage='The social butterfly'
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case 'pollster':
|
||||||
|
illustration = pollster;
|
||||||
|
label = (
|
||||||
|
<FormattedMessage
|
||||||
|
id='annual_report.summary.archetype.pollster'
|
||||||
|
defaultMessage='The pollster'
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case 'lurker':
|
||||||
|
illustration = lurker;
|
||||||
|
label = (
|
||||||
|
<FormattedMessage
|
||||||
|
id='annual_report.summary.archetype.lurker'
|
||||||
|
defaultMessage='The lurker'
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case 'oracle':
|
||||||
|
illustration = oracle;
|
||||||
|
label = (
|
||||||
|
<FormattedMessage
|
||||||
|
id='annual_report.summary.archetype.oracle'
|
||||||
|
defaultMessage='The oracle'
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='annual-report__bento__box annual-report__summary__archetype'>
|
||||||
|
<div className='annual-report__summary__archetype__label'>{label}</div>
|
||||||
|
<img src={illustration} alt='' />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
|
@ -0,0 +1,69 @@
|
||||||
|
import { FormattedMessage, FormattedNumber } from 'react-intl';
|
||||||
|
|
||||||
|
import { Sparklines, SparklinesCurve } from 'react-sparklines';
|
||||||
|
|
||||||
|
import { ShortNumber } from 'flavours/glitch/components/short_number';
|
||||||
|
import type { TimeSeriesMonth } from 'flavours/glitch/models/annual_report';
|
||||||
|
|
||||||
|
export const Followers: React.FC<{
|
||||||
|
data: TimeSeriesMonth[];
|
||||||
|
total?: number;
|
||||||
|
}> = ({ data, total }) => {
|
||||||
|
const change = data.reduce((sum, item) => sum + item.followers, 0);
|
||||||
|
|
||||||
|
const cumulativeGraph = data.reduce(
|
||||||
|
(newData, item) => [
|
||||||
|
...newData,
|
||||||
|
item.followers + (newData[newData.length - 1] ?? 0),
|
||||||
|
],
|
||||||
|
[0],
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='annual-report__bento__box annual-report__summary__followers'>
|
||||||
|
<Sparklines data={cumulativeGraph} margin={0}>
|
||||||
|
<svg>
|
||||||
|
<defs>
|
||||||
|
<linearGradient id='gradient' x1='0%' y1='0%' x2='0%' y2='100%'>
|
||||||
|
<stop
|
||||||
|
offset='0%'
|
||||||
|
stopColor='var(--sparkline-gradient-top)'
|
||||||
|
stopOpacity='1'
|
||||||
|
/>
|
||||||
|
<stop
|
||||||
|
offset='100%'
|
||||||
|
stopColor='var(--sparkline-gradient-bottom)'
|
||||||
|
stopOpacity='0'
|
||||||
|
/>
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
<SparklinesCurve style={{ fill: 'none' }} />
|
||||||
|
</Sparklines>
|
||||||
|
|
||||||
|
<div className='annual-report__summary__followers__foreground'>
|
||||||
|
<div className='annual-report__summary__followers__number'>
|
||||||
|
{change > -1 ? '+' : '-'}
|
||||||
|
<FormattedNumber value={change} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='annual-report__summary__followers__label'>
|
||||||
|
<span>
|
||||||
|
<FormattedMessage
|
||||||
|
id='annual_report.summary.followers.followers'
|
||||||
|
defaultMessage='followers'
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
<div className='annual-report__summary__followers__footnote'>
|
||||||
|
<FormattedMessage
|
||||||
|
id='annual_report.summary.followers.total'
|
||||||
|
defaultMessage='{count} total'
|
||||||
|
values={{ count: <ShortNumber value={total ?? 0} /> }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
|
@ -0,0 +1,109 @@
|
||||||
|
/* eslint-disable @typescript-eslint/no-unsafe-return,
|
||||||
|
@typescript-eslint/no-explicit-any,
|
||||||
|
@typescript-eslint/no-unsafe-assignment */
|
||||||
|
|
||||||
|
import { useCallback } from 'react';
|
||||||
|
|
||||||
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
|
import { toggleStatusSpoilers } from 'flavours/glitch/actions/statuses';
|
||||||
|
import { DetailedStatus } from 'flavours/glitch/features/status/components/detailed_status';
|
||||||
|
import { me } from 'flavours/glitch/initial_state';
|
||||||
|
import type { TopStatuses } from 'flavours/glitch/models/annual_report';
|
||||||
|
import {
|
||||||
|
makeGetStatus,
|
||||||
|
makeGetPictureInPicture,
|
||||||
|
} from 'flavours/glitch/selectors';
|
||||||
|
import { useAppSelector, useAppDispatch } from 'flavours/glitch/store';
|
||||||
|
|
||||||
|
const getStatus = makeGetStatus() as unknown as (arg0: any, arg1: any) => any;
|
||||||
|
const getPictureInPicture = makeGetPictureInPicture() as unknown as (
|
||||||
|
arg0: any,
|
||||||
|
arg1: any,
|
||||||
|
) => any;
|
||||||
|
|
||||||
|
export const HighlightedPost: React.FC<{
|
||||||
|
data: TopStatuses;
|
||||||
|
}> = ({ data }) => {
|
||||||
|
let statusId, label;
|
||||||
|
|
||||||
|
if (data.by_reblogs) {
|
||||||
|
statusId = data.by_reblogs;
|
||||||
|
label = (
|
||||||
|
<FormattedMessage
|
||||||
|
id='annual_report.summary.highlighted_post.by_reblogs'
|
||||||
|
defaultMessage='most boosted post'
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
} else if (data.by_favourites) {
|
||||||
|
statusId = data.by_favourites;
|
||||||
|
label = (
|
||||||
|
<FormattedMessage
|
||||||
|
id='annual_report.summary.highlighted_post.by_favourites'
|
||||||
|
defaultMessage='most favourited post'
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
statusId = data.by_replies;
|
||||||
|
label = (
|
||||||
|
<FormattedMessage
|
||||||
|
id='annual_report.summary.highlighted_post.by_replies'
|
||||||
|
defaultMessage='post with the most replies'
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
|
const domain = useAppSelector((state) => state.meta.get('domain'));
|
||||||
|
const status = useAppSelector((state) =>
|
||||||
|
statusId ? getStatus(state, { id: statusId }) : undefined,
|
||||||
|
);
|
||||||
|
const pictureInPicture = useAppSelector((state) =>
|
||||||
|
statusId ? getPictureInPicture(state, { id: statusId }) : undefined,
|
||||||
|
);
|
||||||
|
const account = useAppSelector((state) =>
|
||||||
|
me ? state.accounts.get(me) : undefined,
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleToggleHidden = useCallback(() => {
|
||||||
|
dispatch(toggleStatusSpoilers(statusId));
|
||||||
|
}, [dispatch, statusId]);
|
||||||
|
|
||||||
|
if (!status) {
|
||||||
|
return (
|
||||||
|
<div className='annual-report__bento__box annual-report__summary__most-boosted-post' />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const displayName = (
|
||||||
|
<span className='display-name'>
|
||||||
|
<strong className='display-name__html'>
|
||||||
|
<FormattedMessage
|
||||||
|
id='annual_report.summary.highlighted_post.possessive'
|
||||||
|
defaultMessage="{name}'s"
|
||||||
|
values={{
|
||||||
|
name: account && (
|
||||||
|
<bdi
|
||||||
|
dangerouslySetInnerHTML={{ __html: account.display_name_html }}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</strong>
|
||||||
|
<span className='display-name__account'>{label}</span>
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='annual-report__bento__box annual-report__summary__most-boosted-post'>
|
||||||
|
<DetailedStatus
|
||||||
|
status={status}
|
||||||
|
pictureInPicture={pictureInPicture}
|
||||||
|
domain={domain}
|
||||||
|
onToggleHidden={handleToggleHidden}
|
||||||
|
overrideDisplayName={displayName}
|
||||||
|
expanded={false}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
|
@ -0,0 +1,99 @@
|
||||||
|
import { useState, useEffect } from 'react';
|
||||||
|
|
||||||
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
|
import {
|
||||||
|
importFetchedStatuses,
|
||||||
|
importFetchedAccounts,
|
||||||
|
} from 'flavours/glitch/actions/importer';
|
||||||
|
import { apiRequestGet, apiRequestPost } from 'flavours/glitch/api';
|
||||||
|
import { LoadingIndicator } from 'flavours/glitch/components/loading_indicator';
|
||||||
|
import { me } from 'flavours/glitch/initial_state';
|
||||||
|
import type { Account } from 'flavours/glitch/models/account';
|
||||||
|
import type { AnnualReport as AnnualReportData } from 'flavours/glitch/models/annual_report';
|
||||||
|
import type { Status } from 'flavours/glitch/models/status';
|
||||||
|
import { useAppSelector, useAppDispatch } from 'flavours/glitch/store';
|
||||||
|
|
||||||
|
import { Archetype } from './archetype';
|
||||||
|
import { Followers } from './followers';
|
||||||
|
import { HighlightedPost } from './highlighted_post';
|
||||||
|
import { MostUsedHashtag } from './most_used_hashtag';
|
||||||
|
import { NewPosts } from './new_posts';
|
||||||
|
import { Percentile } from './percentile';
|
||||||
|
|
||||||
|
interface AnnualReportResponse {
|
||||||
|
annual_reports: AnnualReportData[];
|
||||||
|
accounts: Account[];
|
||||||
|
statuses: Status[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export const AnnualReport: React.FC<{
|
||||||
|
year: string;
|
||||||
|
}> = ({ year }) => {
|
||||||
|
const [response, setResponse] = useState<AnnualReportResponse | null>(null);
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
const currentAccount = useAppSelector((state) =>
|
||||||
|
me ? state.accounts.get(me) : undefined,
|
||||||
|
);
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setLoading(true);
|
||||||
|
|
||||||
|
apiRequestGet<AnnualReportResponse>(`v1/annual_reports/${year}`)
|
||||||
|
.then((data) => {
|
||||||
|
dispatch(importFetchedStatuses(data.statuses));
|
||||||
|
dispatch(importFetchedAccounts(data.accounts));
|
||||||
|
|
||||||
|
setResponse(data);
|
||||||
|
setLoading(false);
|
||||||
|
|
||||||
|
return apiRequestPost(`v1/annual_reports/${year}/read`);
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
setLoading(false);
|
||||||
|
});
|
||||||
|
}, [dispatch, year, setResponse, setLoading]);
|
||||||
|
|
||||||
|
if (loading) {
|
||||||
|
return <LoadingIndicator />;
|
||||||
|
}
|
||||||
|
|
||||||
|
const report = response?.annual_reports[0];
|
||||||
|
|
||||||
|
if (!report) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='annual-report'>
|
||||||
|
<div className='annual-report__header'>
|
||||||
|
<h1>
|
||||||
|
<FormattedMessage
|
||||||
|
id='annual_report.summary.thanks'
|
||||||
|
defaultMessage='Thanks for being part of Mastodon!'
|
||||||
|
/>
|
||||||
|
</h1>
|
||||||
|
<p>
|
||||||
|
<FormattedMessage
|
||||||
|
id='annual_report.summary.here_it_is'
|
||||||
|
defaultMessage='Here is your {year} in review:'
|
||||||
|
values={{ year: report.year }}
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='annual-report__bento annual-report__summary'>
|
||||||
|
<Archetype data={report.data.archetype} />
|
||||||
|
<HighlightedPost data={report.data.top_statuses} />
|
||||||
|
<Followers
|
||||||
|
data={report.data.time_series}
|
||||||
|
total={currentAccount?.followers_count}
|
||||||
|
/>
|
||||||
|
<MostUsedHashtag data={report.data.top_hashtags} />
|
||||||
|
<Percentile data={report.data.percentiles} />
|
||||||
|
<NewPosts data={report.data.time_series} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
|
@ -0,0 +1,29 @@
|
||||||
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
|
import type { NameAndCount } from 'flavours/glitch/models/annual_report';
|
||||||
|
|
||||||
|
export const MostUsedApp: React.FC<{
|
||||||
|
data: NameAndCount[];
|
||||||
|
}> = ({ data }) => {
|
||||||
|
const app = data[0];
|
||||||
|
|
||||||
|
if (!app) {
|
||||||
|
return (
|
||||||
|
<div className='annual-report__bento__box annual-report__summary__most-used-app' />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='annual-report__bento__box annual-report__summary__most-used-app'>
|
||||||
|
<div className='annual-report__summary__most-used-app__icon'>
|
||||||
|
{app.name}
|
||||||
|
</div>
|
||||||
|
<div className='annual-report__summary__most-used-app__label'>
|
||||||
|
<FormattedMessage
|
||||||
|
id='annual_report.summary.most_used_app.most_used_app'
|
||||||
|
defaultMessage='most used app'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
|
@ -0,0 +1,30 @@
|
||||||
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
|
import type { NameAndCount } from 'flavours/glitch/models/annual_report';
|
||||||
|
|
||||||
|
export const MostUsedHashtag: React.FC<{
|
||||||
|
data: NameAndCount[];
|
||||||
|
}> = ({ data }) => {
|
||||||
|
const hashtag = data[0];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='annual-report__bento__box annual-report__summary__most-used-hashtag'>
|
||||||
|
<div className='annual-report__summary__most-used-hashtag__hashtag'>
|
||||||
|
{hashtag ? (
|
||||||
|
<>#{hashtag.name}</>
|
||||||
|
) : (
|
||||||
|
<FormattedMessage
|
||||||
|
id='annual_report.summary.most_used_hashtag.none'
|
||||||
|
defaultMessage='None'
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className='annual-report__summary__most-used-hashtag__label'>
|
||||||
|
<FormattedMessage
|
||||||
|
id='annual_report.summary.most_used_hashtag.most_used_hashtag'
|
||||||
|
defaultMessage='most used hashtag'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
|
@ -0,0 +1,53 @@
|
||||||
|
import { FormattedNumber, FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
|
import ChatBubbleIcon from '@/material-icons/400-24px/chat_bubble.svg?react';
|
||||||
|
import type { TimeSeriesMonth } from 'flavours/glitch/models/annual_report';
|
||||||
|
|
||||||
|
export const NewPosts: React.FC<{
|
||||||
|
data: TimeSeriesMonth[];
|
||||||
|
}> = ({ data }) => {
|
||||||
|
const posts = data.reduce((sum, item) => sum + item.statuses, 0);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='annual-report__bento__box annual-report__summary__new-posts'>
|
||||||
|
<svg width={500} height={500}>
|
||||||
|
<defs>
|
||||||
|
<pattern
|
||||||
|
id='posts'
|
||||||
|
x='0'
|
||||||
|
y='0'
|
||||||
|
width='32'
|
||||||
|
height='35'
|
||||||
|
patternUnits='userSpaceOnUse'
|
||||||
|
>
|
||||||
|
<circle cx='12' cy='12' r='12' fill='var(--lime)' />
|
||||||
|
<ChatBubbleIcon
|
||||||
|
fill='var(--indigo-1)'
|
||||||
|
x='4'
|
||||||
|
y='4'
|
||||||
|
width='16'
|
||||||
|
height='16'
|
||||||
|
/>
|
||||||
|
</pattern>
|
||||||
|
</defs>
|
||||||
|
|
||||||
|
<rect
|
||||||
|
width={500}
|
||||||
|
height={500}
|
||||||
|
fill='url(#posts)'
|
||||||
|
style={{ opacity: 0.2 }}
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
<div className='annual-report__summary__new-posts__number'>
|
||||||
|
<FormattedNumber value={posts} />
|
||||||
|
</div>
|
||||||
|
<div className='annual-report__summary__new-posts__label'>
|
||||||
|
<FormattedMessage
|
||||||
|
id='annual_report.summary.new_posts.new_posts'
|
||||||
|
defaultMessage='new posts'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
|
@ -0,0 +1,53 @@
|
||||||
|
/* eslint-disable react/jsx-no-useless-fragment */
|
||||||
|
import { FormattedMessage, FormattedNumber } from 'react-intl';
|
||||||
|
|
||||||
|
import type { Percentiles } from 'flavours/glitch/models/annual_report';
|
||||||
|
|
||||||
|
export const Percentile: React.FC<{
|
||||||
|
data: Percentiles;
|
||||||
|
}> = ({ data }) => {
|
||||||
|
const percentile = data.statuses;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='annual-report__bento__box annual-report__summary__percentile'>
|
||||||
|
<FormattedMessage
|
||||||
|
id='annual_report.summary.percentile.text'
|
||||||
|
defaultMessage='<topLabel>That puts you in the top</topLabel><percentage></percentage><bottomLabel>of Mastodon users.</bottomLabel>'
|
||||||
|
values={{
|
||||||
|
topLabel: (str) => (
|
||||||
|
<div className='annual-report__summary__percentile__label'>
|
||||||
|
{str}
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
percentage: () => (
|
||||||
|
<div className='annual-report__summary__percentile__number'>
|
||||||
|
<FormattedNumber
|
||||||
|
value={Math.min(percentile, 99) / 100}
|
||||||
|
style='percent'
|
||||||
|
maximumFractionDigits={percentile < 1 ? 1 : 0}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
bottomLabel: (str) => (
|
||||||
|
<div>
|
||||||
|
<div className='annual-report__summary__percentile__label'>
|
||||||
|
{str}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{percentile < 6 && (
|
||||||
|
<div className='annual-report__summary__percentile__footnote'>
|
||||||
|
<FormattedMessage
|
||||||
|
id='annual_report.summary.percentile.we_wont_tell_bernie'
|
||||||
|
defaultMessage="We won't tell Bernie."
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{(message) => <>{message}</>}
|
||||||
|
</FormattedMessage>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
|
@ -68,7 +68,7 @@ class FollowRequests extends ImmutablePureComponent {
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Column bindToDocument={!multiColumn} icon='user-plus' iconComponent={PersonAddIcon} heading={intl.formatMessage(messages.heading)}>
|
<Column bindToDocument={!multiColumn} icon='user-plus' iconComponent={PersonAddIcon} heading={intl.formatMessage(messages.heading)} alwaysShowBackButton>
|
||||||
<ScrollableList
|
<ScrollableList
|
||||||
scrollKey='follow_requests'
|
scrollKey='follow_requests'
|
||||||
onLoadMore={this.handleLoadMore}
|
onLoadMore={this.handleLoadMore}
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
import { useCallback } from 'react';
|
||||||
|
|
||||||
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
|
import classNames from 'classnames';
|
||||||
|
|
||||||
|
import CelebrationIcon from '@/material-icons/400-24px/celebration.svg?react';
|
||||||
|
import { openModal } from 'flavours/glitch/actions/modal';
|
||||||
|
import { Icon } from 'flavours/glitch/components/icon';
|
||||||
|
import type { NotificationGroupAnnualReport } from 'flavours/glitch/models/notification_group';
|
||||||
|
import { useAppDispatch } from 'flavours/glitch/store';
|
||||||
|
|
||||||
|
export const NotificationAnnualReport: React.FC<{
|
||||||
|
notification: NotificationGroupAnnualReport;
|
||||||
|
unread: boolean;
|
||||||
|
}> = ({ notification: { annualReport }, unread }) => {
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
|
const year = annualReport.year;
|
||||||
|
|
||||||
|
const handleClick = useCallback(() => {
|
||||||
|
dispatch(
|
||||||
|
openModal({
|
||||||
|
modalType: 'ANNUAL_REPORT',
|
||||||
|
modalProps: { year },
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}, [dispatch, year]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
role='button'
|
||||||
|
className={classNames(
|
||||||
|
'notification-group notification-group--link notification-group--annual-report focusable',
|
||||||
|
{ 'notification-group--unread': unread },
|
||||||
|
)}
|
||||||
|
tabIndex={0}
|
||||||
|
>
|
||||||
|
<div className='notification-group__icon'>
|
||||||
|
<Icon id='celebration' icon={CelebrationIcon} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='notification-group__main'>
|
||||||
|
<p>
|
||||||
|
<FormattedMessage
|
||||||
|
id='notification.annual_report.message'
|
||||||
|
defaultMessage="Your {year} #Wrapstodon awaits! Unveil your year's highlights and memorable moments on Mastodon!"
|
||||||
|
values={{ year }}
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
<button onClick={handleClick} className='link-button'>
|
||||||
|
<FormattedMessage
|
||||||
|
id='notification.annual_report.view'
|
||||||
|
defaultMessage='View #Wrapstodon'
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
|
@ -9,6 +9,7 @@ import { useAppSelector, useAppDispatch } from 'flavours/glitch/store';
|
||||||
|
|
||||||
import { NotificationAdminReport } from './notification_admin_report';
|
import { NotificationAdminReport } from './notification_admin_report';
|
||||||
import { NotificationAdminSignUp } from './notification_admin_sign_up';
|
import { NotificationAdminSignUp } from './notification_admin_sign_up';
|
||||||
|
import { NotificationAnnualReport } from './notification_annual_report';
|
||||||
import { NotificationFavourite } from './notification_favourite';
|
import { NotificationFavourite } from './notification_favourite';
|
||||||
import { NotificationFollow } from './notification_follow';
|
import { NotificationFollow } from './notification_follow';
|
||||||
import { NotificationFollowRequest } from './notification_follow_request';
|
import { NotificationFollowRequest } from './notification_follow_request';
|
||||||
|
@ -152,6 +153,14 @@ export const NotificationGroup: React.FC<{
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
|
case 'annual_report':
|
||||||
|
content = (
|
||||||
|
<NotificationAnnualReport
|
||||||
|
unread={unread}
|
||||||
|
notification={notificationGroup}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,6 +54,7 @@ export const DetailedStatus: React.FC<{
|
||||||
domain: string;
|
domain: string;
|
||||||
showMedia?: boolean;
|
showMedia?: boolean;
|
||||||
withLogo?: boolean;
|
withLogo?: boolean;
|
||||||
|
overrideDisplayName?: React.ReactNode;
|
||||||
pictureInPicture: any;
|
pictureInPicture: any;
|
||||||
onToggleHidden?: (status: any) => void;
|
onToggleHidden?: (status: any) => void;
|
||||||
onToggleMediaVisibility?: () => void;
|
onToggleMediaVisibility?: () => void;
|
||||||
|
@ -70,6 +71,7 @@ export const DetailedStatus: React.FC<{
|
||||||
domain,
|
domain,
|
||||||
showMedia,
|
showMedia,
|
||||||
withLogo,
|
withLogo,
|
||||||
|
overrideDisplayName,
|
||||||
pictureInPicture,
|
pictureInPicture,
|
||||||
onToggleMediaVisibility,
|
onToggleMediaVisibility,
|
||||||
onToggleHidden,
|
onToggleHidden,
|
||||||
|
@ -386,7 +388,11 @@ export const DetailedStatus: React.FC<{
|
||||||
<div className='detailed-status__display-avatar'>
|
<div className='detailed-status__display-avatar'>
|
||||||
<Avatar account={status.get('account')} size={46} />
|
<Avatar account={status.get('account')} size={46} />
|
||||||
</div>
|
</div>
|
||||||
<DisplayName account={status.get('account')} localDomain={domain} />
|
|
||||||
|
{overrideDisplayName ?? (
|
||||||
|
<DisplayName account={status.get('account')} localDomain={domain} />
|
||||||
|
)}
|
||||||
|
|
||||||
{withLogo && (
|
{withLogo && (
|
||||||
<>
|
<>
|
||||||
<div className='spacer' />
|
<div className='spacer' />
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
|
import { AnnualReport } from 'flavours/glitch/features/annual_report';
|
||||||
|
|
||||||
|
const AnnualReportModal: React.FC<{
|
||||||
|
year: string;
|
||||||
|
onChangeBackgroundColor: (arg0: string) => void;
|
||||||
|
}> = ({ year, onChangeBackgroundColor }) => {
|
||||||
|
useEffect(() => {
|
||||||
|
onChangeBackgroundColor('var(--indigo-1)');
|
||||||
|
}, [onChangeBackgroundColor]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='modal-root__modal annual-report-modal'>
|
||||||
|
<AnnualReport year={year} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// eslint-disable-next-line import/no-default-export
|
||||||
|
export default AnnualReportModal;
|
|
@ -20,6 +20,7 @@ import {
|
||||||
SubscribedLanguagesModal,
|
SubscribedLanguagesModal,
|
||||||
ClosedRegistrationsModal,
|
ClosedRegistrationsModal,
|
||||||
IgnoreNotificationsModal,
|
IgnoreNotificationsModal,
|
||||||
|
AnnualReportModal,
|
||||||
} from 'flavours/glitch/features/ui/util/async-components';
|
} from 'flavours/glitch/features/ui/util/async-components';
|
||||||
import { getScrollbarWidth } from 'flavours/glitch/utils/scrollbar';
|
import { getScrollbarWidth } from 'flavours/glitch/utils/scrollbar';
|
||||||
|
|
||||||
|
@ -82,6 +83,7 @@ export const MODAL_COMPONENTS = {
|
||||||
'INTERACTION': InteractionModal,
|
'INTERACTION': InteractionModal,
|
||||||
'CLOSED_REGISTRATIONS': ClosedRegistrationsModal,
|
'CLOSED_REGISTRATIONS': ClosedRegistrationsModal,
|
||||||
'IGNORE_NOTIFICATIONS': IgnoreNotificationsModal,
|
'IGNORE_NOTIFICATIONS': IgnoreNotificationsModal,
|
||||||
|
'ANNUAL_REPORT': AnnualReportModal,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class ModalRoot extends PureComponent {
|
export default class ModalRoot extends PureComponent {
|
||||||
|
|
|
@ -532,7 +532,9 @@ class UI extends PureComponent {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
handleHotkeyBack = () => {
|
handleHotkeyBack = e => {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
const { history } = this.props;
|
const { history } = this.props;
|
||||||
|
|
||||||
if (history.location?.state?.fromMastodon) {
|
if (history.location?.state?.fromMastodon) {
|
||||||
|
|
|
@ -229,3 +229,7 @@ export function NotificationRequest () {
|
||||||
export function LinkTimeline () {
|
export function LinkTimeline () {
|
||||||
return import(/*webpackChunkName: "features/glitch/link_timeline" */'../../link_timeline');
|
return import(/*webpackChunkName: "features/glitch/link_timeline" */'../../link_timeline');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function AnnualReportModal () {
|
||||||
|
return import(/*webpackChunkName: "flavours/glitch/async/modals/annual_report_modal" */'../components/annual_report_modal');
|
||||||
|
}
|
||||||
|
|
|
@ -154,7 +154,5 @@
|
||||||
"status.is_poll": "Dieser Toot ist eine Umfrage",
|
"status.is_poll": "Dieser Toot ist eine Umfrage",
|
||||||
"status.local_only": "Nur auf deiner Instanz sichtbar",
|
"status.local_only": "Nur auf deiner Instanz sichtbar",
|
||||||
"status.show_filter_reason": "Trotzdem anzeigen",
|
"status.show_filter_reason": "Trotzdem anzeigen",
|
||||||
"status.show_less": "Weniger anzeigen",
|
|
||||||
"status.show_more": "Mehr anzeigen",
|
|
||||||
"status.uncollapse": "Ausklappen"
|
"status.uncollapse": "Ausklappen"
|
||||||
}
|
}
|
||||||
|
|
|
@ -154,7 +154,5 @@
|
||||||
"status.is_poll": "Esta publicación es una encuesta",
|
"status.is_poll": "Esta publicación es una encuesta",
|
||||||
"status.local_only": "Sólo visible para tu instancia",
|
"status.local_only": "Sólo visible para tu instancia",
|
||||||
"status.show_filter_reason": "Mostrar de todos modos",
|
"status.show_filter_reason": "Mostrar de todos modos",
|
||||||
"status.show_less": "Mostrar menos",
|
|
||||||
"status.show_more": "Mostrar más",
|
|
||||||
"status.uncollapse": "Descolapsar"
|
"status.uncollapse": "Descolapsar"
|
||||||
}
|
}
|
||||||
|
|
|
@ -154,7 +154,5 @@
|
||||||
"status.is_poll": "이 글은 설문입니다",
|
"status.is_poll": "이 글은 설문입니다",
|
||||||
"status.local_only": "당신의 서버에서만 보입니다",
|
"status.local_only": "당신의 서버에서만 보입니다",
|
||||||
"status.show_filter_reason": "그냥 표시하기",
|
"status.show_filter_reason": "그냥 표시하기",
|
||||||
"status.show_less": "접기",
|
|
||||||
"status.show_more": "더보기",
|
|
||||||
"status.uncollapse": "펼치기"
|
"status.uncollapse": "펼치기"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,88 @@
|
||||||
{
|
{
|
||||||
"about.fork_disclaimer": "Glitch-soc - это бесплатное программное обеспечение с открытым исходным кодом, обращенное от Mastodon.",
|
"about.fork_disclaimer": "Glitch-soc — это свободное программное обеспечение с открытым исходным кодом, ответвлённое от Mastodon.",
|
||||||
|
"account.follows": "Подписки",
|
||||||
|
"account.follows_you": "Подписан(а) на вас",
|
||||||
|
"account.suspended_disclaimer_full": "Этот пользователь был заблокирован модератором.",
|
||||||
|
"boost_modal.missing_description": "Этот пост содержит медиафайлы без описания",
|
||||||
|
"column.favourited_by": "Добавили в избранное",
|
||||||
|
"column.reblogged_by": "Продвинули",
|
||||||
|
"column_header.profile": "Профиль",
|
||||||
|
"column_subheading.lists": "Списки",
|
||||||
|
"column_subheading.navigation": "Навигация",
|
||||||
|
"compose.attach.doodle": "Нарисовать что-нибудь",
|
||||||
|
"compose.change_federation": "Изменить настройки федерации",
|
||||||
|
"compose.content-type.html": "HTML",
|
||||||
|
"compose.content-type.markdown": "Markdown",
|
||||||
|
"compose.content-type.plain": "Простой текст",
|
||||||
|
"compose.disable_threaded_mode": "Отключить режим треда",
|
||||||
|
"compose.enable_threaded_mode": "Включить режим треда",
|
||||||
|
"confirmation_modal.do_not_ask_again": "Больше не спрашивать подтверждение",
|
||||||
|
"confirmations.deprecated_settings.confirm": "Использовать настройки Mastodon",
|
||||||
|
"confirmations.missing_media_description.confirm": "Всё равно опубликовать",
|
||||||
|
"direct.group_by_conversations": "Группировать по перепискам",
|
||||||
|
"endorsed_accounts_editor.endorsed_accounts": "Рекомендованные аккаунты",
|
||||||
|
"favourite_modal.favourite": "Добавить пост в избранное?",
|
||||||
|
"federation.federated.long": "Разрешить делиться этим постом с другими серверами",
|
||||||
|
"federation.local_only.long": "Запретить делиться этим постом с другими серверами",
|
||||||
|
"home.column_settings.advanced": "Продвинутые настройки",
|
||||||
|
"home.column_settings.filter_regex": "Фильтр по регулярным выражениям",
|
||||||
|
"keyboard_shortcuts.bookmark": "добавить закладку",
|
||||||
|
"keyboard_shortcuts.toggle_collapse": "свернуть/развернуть пост",
|
||||||
|
"moved_to_warning": "Этот аккаунт переехал на {moved_to_link}, и скорее всего не принимает новых подписчиков.",
|
||||||
|
"navigation_bar.app_settings": "Настройки приложения",
|
||||||
|
"navigation_bar.keyboard_shortcuts": "Сочетания клавиш",
|
||||||
|
"notification.markForDeletion": "Отметить для удаления",
|
||||||
|
"notification_purge.btn_all": "Выбрать все",
|
||||||
|
"notification_purge.btn_apply": "Удалить выбранное",
|
||||||
|
"notification_purge.btn_invert": "Инвертировать выбор",
|
||||||
|
"notification_purge.btn_none": "Отменить выбор",
|
||||||
|
"notification_purge.start": "Войти в режим очистки уведомлений",
|
||||||
|
"notifications.column_settings.filter_bar.show_bar": "Показать панель фильтров",
|
||||||
|
"notifications.marked_clear": "Удалить выбранные уведомления",
|
||||||
|
"notifications.marked_clear_confirmation": "Вы уверены, что хотите безвозвратно удалить все выбранные уведомления?",
|
||||||
|
"settings.auto_collapse": "Сворачивать автоматически",
|
||||||
|
"settings.auto_collapse_all": "Всё",
|
||||||
|
"settings.auto_collapse_height": "Высота (в пикселях) для того, чтобы пост считался длинным",
|
||||||
|
"settings.auto_collapse_lengthy": "Длинные посты",
|
||||||
|
"settings.auto_collapse_media": "Посты с медиафайлами",
|
||||||
|
"settings.auto_collapse_notifications": "Уведомления",
|
||||||
|
"settings.auto_collapse_reblogs": "Продвижения",
|
||||||
|
"settings.auto_collapse_replies": "Ответы",
|
||||||
|
"settings.close": "Закрыть",
|
||||||
|
"settings.collapsed_statuses": "Сворачивание постов",
|
||||||
|
"settings.compose_box_opts": "Форма постинга",
|
||||||
"settings.content_warnings": "Content warnings",
|
"settings.content_warnings": "Content warnings",
|
||||||
"settings.preferences": "Preferences"
|
"settings.content_warnings.regexp": "Регулярное выражение",
|
||||||
|
"settings.content_warnings_unfold_opts": "Автоматическое раскрытие",
|
||||||
|
"settings.deprecated_setting": "Эта опция теперь может быть включена в {settings_page_link} Mastodon",
|
||||||
|
"settings.enable_collapsed": "Включить сворачивание постов",
|
||||||
|
"settings.general": "Общие",
|
||||||
|
"settings.hicolor_privacy_icons": "Цветные значки публичности поста",
|
||||||
|
"settings.hicolor_privacy_icons.hint": "Отображать значки публичности поста в ярких и различимых цветах",
|
||||||
|
"settings.media": "Медиафайлы",
|
||||||
|
"settings.notifications.favicon_badge": "Индикатор уведомлений на иконке сайта",
|
||||||
|
"settings.notifications_opts": "Опции уведомлений",
|
||||||
|
"settings.pop_in_left": "Слева",
|
||||||
|
"settings.pop_in_player": "Включить плавающий плеер",
|
||||||
|
"settings.pop_in_position": "Расположение плавающего плеера:",
|
||||||
|
"settings.pop_in_right": "Справа",
|
||||||
|
"settings.preferences": "Preferences",
|
||||||
|
"settings.shared_settings_link": "настройках пользователя",
|
||||||
|
"settings.show_reply_counter": "Показывать приблизительное число ответов",
|
||||||
|
"settings.side_arm": "Дополнительная кнопка постинга:",
|
||||||
|
"settings.side_arm.none": "Нет",
|
||||||
|
"settings.side_arm_reply_mode": "При ответе на пост дополнительная кнопка постинга должна:",
|
||||||
|
"settings.status_icons": "Значки постов",
|
||||||
|
"settings.status_icons_language": "Индикатор языка",
|
||||||
|
"settings.status_icons_local_only": "Индикатор нефедерируемого поста",
|
||||||
|
"settings.status_icons_media": "Индикаторы медиафайлов и опросов",
|
||||||
|
"settings.status_icons_reply": "Индикатор ответа",
|
||||||
|
"settings.status_icons_visibility": "Индикатор публичности поста",
|
||||||
|
"settings.tag_misleading_links": "Помечать обманчивые ссылки",
|
||||||
|
"status.collapse": "Свернуть",
|
||||||
|
"status.hide": "Скрыть пост",
|
||||||
|
"status.in_reply_to": "Этот пост является ответом",
|
||||||
|
"status.is_poll": "Этот пост содержит опрос",
|
||||||
|
"status.show_filter_reason": "Всё равно показать",
|
||||||
|
"status.uncollapse": "Развернуть"
|
||||||
}
|
}
|
||||||
|
|
|
@ -153,7 +153,5 @@
|
||||||
"status.is_poll": "此嘟文是投票",
|
"status.is_poll": "此嘟文是投票",
|
||||||
"status.local_only": "此嘟文仅本站可见",
|
"status.local_only": "此嘟文仅本站可见",
|
||||||
"status.show_filter_reason": "仍然显示",
|
"status.show_filter_reason": "仍然显示",
|
||||||
"status.show_less": "部分显示",
|
|
||||||
"status.show_more": "完全显示",
|
|
||||||
"status.uncollapse": "展开"
|
"status.uncollapse": "展开"
|
||||||
}
|
}
|
||||||
|
|
44
app/javascript/flavours/glitch/models/annual_report.ts
Normal file
44
app/javascript/flavours/glitch/models/annual_report.ts
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
export interface Percentiles {
|
||||||
|
followers: number;
|
||||||
|
statuses: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NameAndCount {
|
||||||
|
name: string;
|
||||||
|
count: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TimeSeriesMonth {
|
||||||
|
month: number;
|
||||||
|
statuses: number;
|
||||||
|
following: number;
|
||||||
|
followers: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TopStatuses {
|
||||||
|
by_reblogs: number;
|
||||||
|
by_favourites: number;
|
||||||
|
by_replies: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Archetype =
|
||||||
|
| 'lurker'
|
||||||
|
| 'booster'
|
||||||
|
| 'pollster'
|
||||||
|
| 'replier'
|
||||||
|
| 'oracle';
|
||||||
|
|
||||||
|
interface AnnualReportV1 {
|
||||||
|
most_used_apps: NameAndCount[];
|
||||||
|
percentiles: Percentiles;
|
||||||
|
top_hashtags: NameAndCount[];
|
||||||
|
top_statuses: TopStatuses;
|
||||||
|
time_series: TimeSeriesMonth[];
|
||||||
|
archetype: Archetype;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AnnualReport {
|
||||||
|
year: number;
|
||||||
|
schema_version: number;
|
||||||
|
data: AnnualReportV1;
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
import type {
|
import type {
|
||||||
ApiAccountRelationshipSeveranceEventJSON,
|
ApiAccountRelationshipSeveranceEventJSON,
|
||||||
ApiAccountWarningJSON,
|
ApiAccountWarningJSON,
|
||||||
|
ApiAnnualReportEventJSON,
|
||||||
BaseNotificationGroupJSON,
|
BaseNotificationGroupJSON,
|
||||||
ApiNotificationGroupJSON,
|
ApiNotificationGroupJSON,
|
||||||
ApiNotificationJSON,
|
ApiNotificationJSON,
|
||||||
|
@ -66,6 +67,12 @@ export interface NotificationGroupSeveredRelationships
|
||||||
event: AccountRelationshipSeveranceEvent;
|
event: AccountRelationshipSeveranceEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type AnnualReportEvent = ApiAnnualReportEventJSON;
|
||||||
|
export interface NotificationGroupAnnualReport
|
||||||
|
extends BaseNotification<'annual_report'> {
|
||||||
|
annualReport: AnnualReportEvent;
|
||||||
|
}
|
||||||
|
|
||||||
interface Report extends Omit<ApiReportJSON, 'target_account'> {
|
interface Report extends Omit<ApiReportJSON, 'target_account'> {
|
||||||
targetAccountId: string;
|
targetAccountId: string;
|
||||||
}
|
}
|
||||||
|
@ -88,7 +95,8 @@ export type NotificationGroup =
|
||||||
| NotificationGroupModerationWarning
|
| NotificationGroupModerationWarning
|
||||||
| NotificationGroupSeveredRelationships
|
| NotificationGroupSeveredRelationships
|
||||||
| NotificationGroupAdminSignUp
|
| NotificationGroupAdminSignUp
|
||||||
| NotificationGroupAdminReport;
|
| NotificationGroupAdminReport
|
||||||
|
| NotificationGroupAnnualReport;
|
||||||
|
|
||||||
function createReportFromJSON(reportJSON: ApiReportJSON): Report {
|
function createReportFromJSON(reportJSON: ApiReportJSON): Report {
|
||||||
const { target_account, ...report } = reportJSON;
|
const { target_account, ...report } = reportJSON;
|
||||||
|
@ -114,6 +122,12 @@ function createAccountRelationshipSeveranceEventFromJSON(
|
||||||
return eventJson;
|
return eventJson;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createAnnualReportEventFromJSON(
|
||||||
|
eventJson: ApiAnnualReportEventJSON,
|
||||||
|
): AnnualReportEvent {
|
||||||
|
return eventJson;
|
||||||
|
}
|
||||||
|
|
||||||
export function createNotificationGroupFromJSON(
|
export function createNotificationGroupFromJSON(
|
||||||
groupJson: ApiNotificationGroupJSON,
|
groupJson: ApiNotificationGroupJSON,
|
||||||
): NotificationGroup {
|
): NotificationGroup {
|
||||||
|
@ -148,7 +162,6 @@ export function createNotificationGroupFromJSON(
|
||||||
event: createAccountRelationshipSeveranceEventFromJSON(group.event),
|
event: createAccountRelationshipSeveranceEventFromJSON(group.event),
|
||||||
sampleAccountIds,
|
sampleAccountIds,
|
||||||
};
|
};
|
||||||
|
|
||||||
case 'moderation_warning': {
|
case 'moderation_warning': {
|
||||||
const { moderation_warning, ...groupWithoutModerationWarning } = group;
|
const { moderation_warning, ...groupWithoutModerationWarning } = group;
|
||||||
return {
|
return {
|
||||||
|
@ -157,6 +170,14 @@ export function createNotificationGroupFromJSON(
|
||||||
sampleAccountIds,
|
sampleAccountIds,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
case 'annual_report': {
|
||||||
|
const { annual_report, ...groupWithoutAnnualReport } = group;
|
||||||
|
return {
|
||||||
|
...groupWithoutAnnualReport,
|
||||||
|
annualReport: createAnnualReportEventFromJSON(annual_report),
|
||||||
|
sampleAccountIds,
|
||||||
|
};
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return {
|
return {
|
||||||
sampleAccountIds,
|
sampleAccountIds,
|
||||||
|
|
|
@ -1943,3 +1943,31 @@ a.sparkline {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.status__card {
|
||||||
|
padding: 15px;
|
||||||
|
border-radius: 4px;
|
||||||
|
background: $ui-base-color;
|
||||||
|
font-size: 15px;
|
||||||
|
line-height: 20px;
|
||||||
|
word-wrap: break-word;
|
||||||
|
font-weight: 400;
|
||||||
|
border: 1px solid lighten($ui-base-color, 4%);
|
||||||
|
color: $primary-text-color;
|
||||||
|
box-sizing: border-box;
|
||||||
|
min-height: 100%;
|
||||||
|
|
||||||
|
.status__prepend {
|
||||||
|
padding: 0 0 15px;
|
||||||
|
gap: 4px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status__content {
|
||||||
|
padding-top: 0;
|
||||||
|
|
||||||
|
summary {
|
||||||
|
display: list-item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
340
app/javascript/flavours/glitch/styles/annual_reports.scss
Normal file
340
app/javascript/flavours/glitch/styles/annual_reports.scss
Normal file
|
@ -0,0 +1,340 @@
|
||||||
|
:root {
|
||||||
|
--indigo-1: #17063b;
|
||||||
|
--indigo-2: #2f0c7a;
|
||||||
|
--indigo-3: #562cfc;
|
||||||
|
--indigo-5: #858afa;
|
||||||
|
--indigo-6: #cccfff;
|
||||||
|
--lime: #baff3b;
|
||||||
|
--goldenrod-2: #ffc954;
|
||||||
|
}
|
||||||
|
|
||||||
|
.annual-report {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
background: var(--indigo-1);
|
||||||
|
padding: 24px;
|
||||||
|
|
||||||
|
&__header {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 25px;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 30px;
|
||||||
|
color: var(--lime);
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 20px;
|
||||||
|
color: var(--indigo-6);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__bento {
|
||||||
|
display: grid;
|
||||||
|
gap: 8px;
|
||||||
|
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1fr);
|
||||||
|
grid-template-rows: minmax(0, auto) minmax(0, 1fr) minmax(0, auto) minmax(
|
||||||
|
0,
|
||||||
|
auto
|
||||||
|
);
|
||||||
|
|
||||||
|
&__box {
|
||||||
|
padding: 16px;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: var(--indigo-2);
|
||||||
|
color: var(--indigo-5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__summary {
|
||||||
|
&__most-boosted-post {
|
||||||
|
grid-column: span 2;
|
||||||
|
grid-row: span 2;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
.status__content,
|
||||||
|
.content-warning {
|
||||||
|
color: var(--indigo-6);
|
||||||
|
}
|
||||||
|
|
||||||
|
.detailed-status {
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-warning {
|
||||||
|
border: 0;
|
||||||
|
background: var(--indigo-1);
|
||||||
|
|
||||||
|
.link-button {
|
||||||
|
color: var(--indigo-5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.detailed-status__meta__line {
|
||||||
|
border-bottom-color: var(--indigo-3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.detailed-status__meta {
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detailed-status__meta,
|
||||||
|
.poll__footer,
|
||||||
|
.poll__link,
|
||||||
|
.detailed-status .logo,
|
||||||
|
.detailed-status__display-name {
|
||||||
|
color: var(--indigo-5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.detailed-status__meta .animated-number,
|
||||||
|
.detailed-status__display-name strong {
|
||||||
|
color: var(--indigo-6);
|
||||||
|
}
|
||||||
|
|
||||||
|
.poll__chart {
|
||||||
|
background-color: var(--indigo-3);
|
||||||
|
|
||||||
|
&.leading {
|
||||||
|
background-color: var(--goldenrod-2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-card,
|
||||||
|
.hashtag-bar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__followers {
|
||||||
|
grid-column: span 1;
|
||||||
|
text-align: center;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
padding-block-start: 24px;
|
||||||
|
padding-block-end: 24px;
|
||||||
|
|
||||||
|
--sparkline-gradient-top: rgba(86, 44, 252, 50%);
|
||||||
|
--sparkline-gradient-bottom: rgba(86, 44, 252, 0%);
|
||||||
|
|
||||||
|
&__foreground {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 8px;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__number {
|
||||||
|
font-size: 31px;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 37px;
|
||||||
|
color: var(--lime);
|
||||||
|
}
|
||||||
|
|
||||||
|
&__label {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 17px;
|
||||||
|
color: var(--indigo-6);
|
||||||
|
}
|
||||||
|
|
||||||
|
&__footnote {
|
||||||
|
display: block;
|
||||||
|
font-weight: 400;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
svg {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
inset-inline-end: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 0;
|
||||||
|
height: 70%;
|
||||||
|
width: auto;
|
||||||
|
|
||||||
|
path:first-child {
|
||||||
|
fill: url('#gradient') !important;
|
||||||
|
fill-opacity: 1 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
path:last-child {
|
||||||
|
stroke: var(--indigo-3) !important;
|
||||||
|
fill: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__archetype {
|
||||||
|
grid-column: span 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
text-align: center;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
img {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__label {
|
||||||
|
padding: 16px;
|
||||||
|
padding-bottom: 8px;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 17px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--lime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__most-used-app {
|
||||||
|
grid-column: span 1;
|
||||||
|
text-align: center;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 8px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
&__label {
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 17px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--indigo-6);
|
||||||
|
}
|
||||||
|
|
||||||
|
&__icon {
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 17px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--goldenrod-2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__percentile {
|
||||||
|
grid-row: span 2;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
text-align: center;
|
||||||
|
text-wrap: balance;
|
||||||
|
padding: 16px 8px;
|
||||||
|
|
||||||
|
&__label {
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 17px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__number {
|
||||||
|
font-size: 54px;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 73px;
|
||||||
|
color: var(--goldenrod-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
&__footnote {
|
||||||
|
font-size: 11px;
|
||||||
|
line-height: 14px;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__new-posts {
|
||||||
|
grid-column: span 2;
|
||||||
|
text-align: center;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
&__label {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 24px;
|
||||||
|
color: var(--indigo-6);
|
||||||
|
z-index: 1;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__number {
|
||||||
|
font-size: 76px;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 91px;
|
||||||
|
color: var(--goldenrod-2);
|
||||||
|
z-index: 1;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
svg {
|
||||||
|
position: absolute;
|
||||||
|
inset-inline-start: -7px;
|
||||||
|
top: -4px;
|
||||||
|
z-index: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__most-used-hashtag {
|
||||||
|
grid-column: span 2;
|
||||||
|
text-align: center;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
&__hashtag {
|
||||||
|
font-size: 42px;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 58px;
|
||||||
|
color: var(--indigo-6);
|
||||||
|
margin-inline-start: -100%;
|
||||||
|
margin-inline-end: -100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__label {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 17px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.annual-report-modal {
|
||||||
|
max-width: 600px;
|
||||||
|
background: var(--indigo-1);
|
||||||
|
border-radius: 16px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow-y: auto;
|
||||||
|
|
||||||
|
.loading-indicator .circular-progress {
|
||||||
|
color: var(--lime);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: $no-columns-breakpoint) {
|
||||||
|
border-bottom: 0;
|
||||||
|
border-radius: 16px 16px 0 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification-group--annual-report {
|
||||||
|
.notification-group__icon {
|
||||||
|
color: var(--lime);
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification-group__main .link-button {
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--lime);
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,6 +15,7 @@
|
||||||
@import 'polls';
|
@import 'polls';
|
||||||
@import 'modal';
|
@import 'modal';
|
||||||
@import 'emoji_picker';
|
@import 'emoji_picker';
|
||||||
|
@import 'annual_reports';
|
||||||
@import 'about';
|
@import 'about';
|
||||||
@import 'tables';
|
@import 'tables';
|
||||||
@import 'admin';
|
@import 'admin';
|
||||||
|
|
|
@ -1861,7 +1861,8 @@ body > [data-popper-placement] {
|
||||||
|
|
||||||
.status__wrapper-direct,
|
.status__wrapper-direct,
|
||||||
.notification-ungrouped--direct,
|
.notification-ungrouped--direct,
|
||||||
.notification-group--direct {
|
.notification-group--direct,
|
||||||
|
.notification-group--annual-report {
|
||||||
background: rgba($ui-highlight-color, 0.05);
|
background: rgba($ui-highlight-color, 0.05);
|
||||||
|
|
||||||
&:focus {
|
&:focus {
|
||||||
|
@ -6258,7 +6259,8 @@ a.status-card {
|
||||||
inset-inline-start: 0;
|
inset-inline-start: 0;
|
||||||
inset-inline-end: 0;
|
inset-inline-end: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
background: rgba($base-overlay-background, 0.7);
|
opacity: 0.9;
|
||||||
|
background: $base-overlay-background;
|
||||||
transition: background 0.5s;
|
transition: background 0.5s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -598,3 +598,10 @@ a.sparkline {
|
||||||
::-webkit-scrollbar-thumb {
|
::-webkit-scrollbar-thumb {
|
||||||
opacity: 0.25;
|
opacity: 0.25;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.notification-group--annual-report {
|
||||||
|
.notification-group__icon,
|
||||||
|
.notification-group__main .link-button {
|
||||||
|
color: var(--indigo-3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -339,12 +339,12 @@ a.table-action-link {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.status__content {
|
// Reset the status card to not have borders, background or padding when
|
||||||
padding-top: 0;
|
// inline in the table of statuses
|
||||||
|
.status__card {
|
||||||
strong {
|
border: none;
|
||||||
font-weight: 700;
|
background: none;
|
||||||
}
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nothing-here {
|
.nothing-here {
|
||||||
|
|
BIN
app/javascript/images/archetypes/booster.png
Executable file
BIN
app/javascript/images/archetypes/booster.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 620 KiB |
BIN
app/javascript/images/archetypes/lurker.png
Executable file
BIN
app/javascript/images/archetypes/lurker.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 1 MiB |
BIN
app/javascript/images/archetypes/oracle.png
Executable file
BIN
app/javascript/images/archetypes/oracle.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 1.2 MiB |
BIN
app/javascript/images/archetypes/pollster.png
Executable file
BIN
app/javascript/images/archetypes/pollster.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 710 KiB |
BIN
app/javascript/images/archetypes/replier.png
Executable file
BIN
app/javascript/images/archetypes/replier.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 786 KiB |
|
@ -20,6 +20,7 @@ export const allNotificationTypes = [
|
||||||
'admin.report',
|
'admin.report',
|
||||||
'moderation_warning',
|
'moderation_warning',
|
||||||
'severed_relationships',
|
'severed_relationships',
|
||||||
|
'annual_report',
|
||||||
];
|
];
|
||||||
|
|
||||||
export type NotificationWithStatusType =
|
export type NotificationWithStatusType =
|
||||||
|
@ -37,7 +38,8 @@ export type NotificationType =
|
||||||
| 'moderation_warning'
|
| 'moderation_warning'
|
||||||
| 'severed_relationships'
|
| 'severed_relationships'
|
||||||
| 'admin.sign_up'
|
| 'admin.sign_up'
|
||||||
| 'admin.report';
|
| 'admin.report'
|
||||||
|
| 'annual_report';
|
||||||
|
|
||||||
export interface BaseNotificationJSON {
|
export interface BaseNotificationJSON {
|
||||||
id: string;
|
id: string;
|
||||||
|
@ -130,6 +132,15 @@ interface AccountRelationshipSeveranceNotificationJSON
|
||||||
event: ApiAccountRelationshipSeveranceEventJSON;
|
event: ApiAccountRelationshipSeveranceEventJSON;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ApiAnnualReportEventJSON {
|
||||||
|
year: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AnnualReportNotificationGroupJSON extends BaseNotificationGroupJSON {
|
||||||
|
type: 'annual_report';
|
||||||
|
annual_report: ApiAnnualReportEventJSON;
|
||||||
|
}
|
||||||
|
|
||||||
export type ApiNotificationJSON =
|
export type ApiNotificationJSON =
|
||||||
| SimpleNotificationJSON
|
| SimpleNotificationJSON
|
||||||
| ReportNotificationJSON
|
| ReportNotificationJSON
|
||||||
|
@ -142,7 +153,8 @@ export type ApiNotificationGroupJSON =
|
||||||
| ReportNotificationGroupJSON
|
| ReportNotificationGroupJSON
|
||||||
| AccountRelationshipSeveranceNotificationGroupJSON
|
| AccountRelationshipSeveranceNotificationGroupJSON
|
||||||
| NotificationGroupWithStatusJSON
|
| NotificationGroupWithStatusJSON
|
||||||
| ModerationWarningNotificationGroupJSON;
|
| ModerationWarningNotificationGroupJSON
|
||||||
|
| AnnualReportNotificationGroupJSON;
|
||||||
|
|
||||||
export interface ApiNotificationGroupsResultJSON {
|
export interface ApiNotificationGroupsResultJSON {
|
||||||
accounts: ApiAccountJSON[];
|
accounts: ApiAccountJSON[];
|
||||||
|
|
|
@ -97,12 +97,12 @@ class Item extends PureComponent {
|
||||||
height = 50;
|
height = 50;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attachment.get('description')?.length > 0) {
|
|
||||||
badges.push(<AltTextBadge key='alt' description={attachment.get('description')} />);
|
|
||||||
}
|
|
||||||
|
|
||||||
const description = attachment.getIn(['translation', 'description']) || attachment.get('description');
|
const description = attachment.getIn(['translation', 'description']) || attachment.get('description');
|
||||||
|
|
||||||
|
if (description?.length > 0) {
|
||||||
|
badges.push(<AltTextBadge key='alt' description={description} />);
|
||||||
|
}
|
||||||
|
|
||||||
if (attachment.get('type') === 'unknown') {
|
if (attachment.get('type') === 'unknown') {
|
||||||
return (
|
return (
|
||||||
<div className={classNames('media-gallery__item', { standalone, 'media-gallery__item--tall': height === 100, 'media-gallery__item--wide': width === 100 })} key={attachment.get('id')}>
|
<div className={classNames('media-gallery__item', { standalone, 'media-gallery__item--tall': height === 100, 'media-gallery__item--wide': width === 100 })} key={attachment.get('id')}>
|
||||||
|
|
|
@ -13,11 +13,14 @@ class ModalRoot extends PureComponent {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
children: PropTypes.node,
|
children: PropTypes.node,
|
||||||
onClose: PropTypes.func.isRequired,
|
onClose: PropTypes.func.isRequired,
|
||||||
backgroundColor: PropTypes.shape({
|
backgroundColor: PropTypes.oneOfType([
|
||||||
r: PropTypes.number,
|
PropTypes.string,
|
||||||
g: PropTypes.number,
|
PropTypes.shape({
|
||||||
b: PropTypes.number,
|
r: PropTypes.number,
|
||||||
}),
|
g: PropTypes.number,
|
||||||
|
b: PropTypes.number,
|
||||||
|
}),
|
||||||
|
]),
|
||||||
ignoreFocus: PropTypes.bool,
|
ignoreFocus: PropTypes.bool,
|
||||||
...WithOptionalRouterPropTypes,
|
...WithOptionalRouterPropTypes,
|
||||||
};
|
};
|
||||||
|
@ -141,14 +144,17 @@ class ModalRoot extends PureComponent {
|
||||||
|
|
||||||
let backgroundColor = null;
|
let backgroundColor = null;
|
||||||
|
|
||||||
if (this.props.backgroundColor) {
|
if (this.props.backgroundColor && typeof this.props.backgroundColor === 'string') {
|
||||||
backgroundColor = multiply({ ...this.props.backgroundColor, a: 1 }, { r: 0, g: 0, b: 0, a: 0.7 });
|
backgroundColor = this.props.backgroundColor;
|
||||||
|
} else if (this.props.backgroundColor) {
|
||||||
|
const darkenedColor = multiply({ ...this.props.backgroundColor, a: 1 }, { r: 0, g: 0, b: 0, a: 0.7 });
|
||||||
|
backgroundColor = `rgb(${darkenedColor.r}, ${darkenedColor.g}, ${darkenedColor.b})`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='modal-root' ref={this.setRef}>
|
<div className='modal-root' ref={this.setRef}>
|
||||||
<div style={{ pointerEvents: visible ? 'auto' : 'none' }}>
|
<div style={{ pointerEvents: visible ? 'auto' : 'none' }}>
|
||||||
<div role='presentation' className='modal-root__overlay' onClick={onClose} style={{ backgroundColor: backgroundColor ? `rgba(${backgroundColor.r}, ${backgroundColor.g}, ${backgroundColor.b}, 0.9)` : null }} />
|
<div role='presentation' className='modal-root__overlay' onClick={onClose} style={{ backgroundColor }} />
|
||||||
<div role='dialog' className='modal-root__container'>{children}</div>
|
<div role='dialog' className='modal-root__container'>{children}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -394,17 +394,6 @@ class Status extends ImmutablePureComponent {
|
||||||
|
|
||||||
let media, statusAvatar, prepend, rebloggedByText;
|
let media, statusAvatar, prepend, rebloggedByText;
|
||||||
|
|
||||||
if (hidden) {
|
|
||||||
return (
|
|
||||||
<HotKeys handlers={handlers} tabIndex={unfocusable ? null : -1}>
|
|
||||||
<div ref={this.handleRef} className={classNames('status__wrapper', { focusable: !this.props.muted })} tabIndex={unfocusable ? null : 0}>
|
|
||||||
<span>{status.getIn(['account', 'display_name']) || status.getIn(['account', 'username'])}</span>
|
|
||||||
<span>{status.get('content')}</span>
|
|
||||||
</div>
|
|
||||||
</HotKeys>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const connectUp = previousId && previousId === status.get('in_reply_to_id');
|
const connectUp = previousId && previousId === status.get('in_reply_to_id');
|
||||||
const connectToRoot = rootId && rootId === status.get('in_reply_to_id');
|
const connectToRoot = rootId && rootId === status.get('in_reply_to_id');
|
||||||
const connectReply = nextInReplyToId && nextInReplyToId === status.get('id');
|
const connectReply = nextInReplyToId && nextInReplyToId === status.get('id');
|
||||||
|
@ -444,6 +433,20 @@ class Status extends ImmutablePureComponent {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const expanded = (!matchedFilters || this.state.showDespiteFilter) && (!status.get('hidden') || status.get('spoiler_text').length === 0);
|
||||||
|
|
||||||
|
if (hidden) {
|
||||||
|
return (
|
||||||
|
<HotKeys handlers={handlers} tabIndex={unfocusable ? null : -1}>
|
||||||
|
<div ref={this.handleRef} className={classNames('status__wrapper', { focusable: !this.props.muted })} tabIndex={unfocusable ? null : 0}>
|
||||||
|
<span>{status.getIn(['account', 'display_name']) || status.getIn(['account', 'username'])}</span>
|
||||||
|
{status.get('spoiler_text').length > 0 && (<span>{status.get('spoiler_text')}</span>)}
|
||||||
|
{expanded && <span>{status.get('content')}</span>}
|
||||||
|
</div>
|
||||||
|
</HotKeys>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (pictureInPicture.get('inUse')) {
|
if (pictureInPicture.get('inUse')) {
|
||||||
media = <PictureInPicturePlaceholder aspectRatio={this.getAttachmentAspectRatio()} />;
|
media = <PictureInPicturePlaceholder aspectRatio={this.getAttachmentAspectRatio()} />;
|
||||||
} else if (status.get('media_attachments').size > 0) {
|
} else if (status.get('media_attachments').size > 0) {
|
||||||
|
@ -538,7 +541,6 @@ class Status extends ImmutablePureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
const {statusContentProps, hashtagBar} = getHashtagBarForStatus(status);
|
const {statusContentProps, hashtagBar} = getHashtagBarForStatus(status);
|
||||||
const expanded = (!matchedFilters || this.state.showDespiteFilter) && (!status.get('hidden') || status.get('spoiler_text').length === 0);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<HotKeys handlers={handlers} tabIndex={unfocusable ? null : -1}>
|
<HotKeys handlers={handlers} tabIndex={unfocusable ? null : -1}>
|
||||||
|
|
69
app/javascript/mastodon/features/annual_report/archetype.tsx
Normal file
69
app/javascript/mastodon/features/annual_report/archetype.tsx
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
|
import booster from '@/images/archetypes/booster.png';
|
||||||
|
import lurker from '@/images/archetypes/lurker.png';
|
||||||
|
import oracle from '@/images/archetypes/oracle.png';
|
||||||
|
import pollster from '@/images/archetypes/pollster.png';
|
||||||
|
import replier from '@/images/archetypes/replier.png';
|
||||||
|
import type { Archetype as ArchetypeData } from 'mastodon/models/annual_report';
|
||||||
|
|
||||||
|
export const Archetype: React.FC<{
|
||||||
|
data: ArchetypeData;
|
||||||
|
}> = ({ data }) => {
|
||||||
|
let illustration, label;
|
||||||
|
|
||||||
|
switch (data) {
|
||||||
|
case 'booster':
|
||||||
|
illustration = booster;
|
||||||
|
label = (
|
||||||
|
<FormattedMessage
|
||||||
|
id='annual_report.summary.archetype.booster'
|
||||||
|
defaultMessage='The cool-hunter'
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case 'replier':
|
||||||
|
illustration = replier;
|
||||||
|
label = (
|
||||||
|
<FormattedMessage
|
||||||
|
id='annual_report.summary.archetype.replier'
|
||||||
|
defaultMessage='The social butterfly'
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case 'pollster':
|
||||||
|
illustration = pollster;
|
||||||
|
label = (
|
||||||
|
<FormattedMessage
|
||||||
|
id='annual_report.summary.archetype.pollster'
|
||||||
|
defaultMessage='The pollster'
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case 'lurker':
|
||||||
|
illustration = lurker;
|
||||||
|
label = (
|
||||||
|
<FormattedMessage
|
||||||
|
id='annual_report.summary.archetype.lurker'
|
||||||
|
defaultMessage='The lurker'
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case 'oracle':
|
||||||
|
illustration = oracle;
|
||||||
|
label = (
|
||||||
|
<FormattedMessage
|
||||||
|
id='annual_report.summary.archetype.oracle'
|
||||||
|
defaultMessage='The oracle'
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='annual-report__bento__box annual-report__summary__archetype'>
|
||||||
|
<div className='annual-report__summary__archetype__label'>{label}</div>
|
||||||
|
<img src={illustration} alt='' />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
69
app/javascript/mastodon/features/annual_report/followers.tsx
Normal file
69
app/javascript/mastodon/features/annual_report/followers.tsx
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
import { FormattedMessage, FormattedNumber } from 'react-intl';
|
||||||
|
|
||||||
|
import { Sparklines, SparklinesCurve } from 'react-sparklines';
|
||||||
|
|
||||||
|
import { ShortNumber } from 'mastodon/components/short_number';
|
||||||
|
import type { TimeSeriesMonth } from 'mastodon/models/annual_report';
|
||||||
|
|
||||||
|
export const Followers: React.FC<{
|
||||||
|
data: TimeSeriesMonth[];
|
||||||
|
total?: number;
|
||||||
|
}> = ({ data, total }) => {
|
||||||
|
const change = data.reduce((sum, item) => sum + item.followers, 0);
|
||||||
|
|
||||||
|
const cumulativeGraph = data.reduce(
|
||||||
|
(newData, item) => [
|
||||||
|
...newData,
|
||||||
|
item.followers + (newData[newData.length - 1] ?? 0),
|
||||||
|
],
|
||||||
|
[0],
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='annual-report__bento__box annual-report__summary__followers'>
|
||||||
|
<Sparklines data={cumulativeGraph} margin={0}>
|
||||||
|
<svg>
|
||||||
|
<defs>
|
||||||
|
<linearGradient id='gradient' x1='0%' y1='0%' x2='0%' y2='100%'>
|
||||||
|
<stop
|
||||||
|
offset='0%'
|
||||||
|
stopColor='var(--sparkline-gradient-top)'
|
||||||
|
stopOpacity='1'
|
||||||
|
/>
|
||||||
|
<stop
|
||||||
|
offset='100%'
|
||||||
|
stopColor='var(--sparkline-gradient-bottom)'
|
||||||
|
stopOpacity='0'
|
||||||
|
/>
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
<SparklinesCurve style={{ fill: 'none' }} />
|
||||||
|
</Sparklines>
|
||||||
|
|
||||||
|
<div className='annual-report__summary__followers__foreground'>
|
||||||
|
<div className='annual-report__summary__followers__number'>
|
||||||
|
{change > -1 ? '+' : '-'}
|
||||||
|
<FormattedNumber value={change} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='annual-report__summary__followers__label'>
|
||||||
|
<span>
|
||||||
|
<FormattedMessage
|
||||||
|
id='annual_report.summary.followers.followers'
|
||||||
|
defaultMessage='followers'
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
<div className='annual-report__summary__followers__footnote'>
|
||||||
|
<FormattedMessage
|
||||||
|
id='annual_report.summary.followers.total'
|
||||||
|
defaultMessage='{count} total'
|
||||||
|
values={{ count: <ShortNumber value={total ?? 0} /> }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
|
@ -0,0 +1,105 @@
|
||||||
|
/* eslint-disable @typescript-eslint/no-unsafe-return,
|
||||||
|
@typescript-eslint/no-explicit-any,
|
||||||
|
@typescript-eslint/no-unsafe-assignment */
|
||||||
|
|
||||||
|
import { useCallback } from 'react';
|
||||||
|
|
||||||
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
|
import { toggleStatusSpoilers } from 'mastodon/actions/statuses';
|
||||||
|
import { DetailedStatus } from 'mastodon/features/status/components/detailed_status';
|
||||||
|
import { me } from 'mastodon/initial_state';
|
||||||
|
import type { TopStatuses } from 'mastodon/models/annual_report';
|
||||||
|
import { makeGetStatus, makeGetPictureInPicture } from 'mastodon/selectors';
|
||||||
|
import { useAppSelector, useAppDispatch } from 'mastodon/store';
|
||||||
|
|
||||||
|
const getStatus = makeGetStatus() as unknown as (arg0: any, arg1: any) => any;
|
||||||
|
const getPictureInPicture = makeGetPictureInPicture() as unknown as (
|
||||||
|
arg0: any,
|
||||||
|
arg1: any,
|
||||||
|
) => any;
|
||||||
|
|
||||||
|
export const HighlightedPost: React.FC<{
|
||||||
|
data: TopStatuses;
|
||||||
|
}> = ({ data }) => {
|
||||||
|
let statusId, label;
|
||||||
|
|
||||||
|
if (data.by_reblogs) {
|
||||||
|
statusId = data.by_reblogs;
|
||||||
|
label = (
|
||||||
|
<FormattedMessage
|
||||||
|
id='annual_report.summary.highlighted_post.by_reblogs'
|
||||||
|
defaultMessage='most boosted post'
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
} else if (data.by_favourites) {
|
||||||
|
statusId = data.by_favourites;
|
||||||
|
label = (
|
||||||
|
<FormattedMessage
|
||||||
|
id='annual_report.summary.highlighted_post.by_favourites'
|
||||||
|
defaultMessage='most favourited post'
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
statusId = data.by_replies;
|
||||||
|
label = (
|
||||||
|
<FormattedMessage
|
||||||
|
id='annual_report.summary.highlighted_post.by_replies'
|
||||||
|
defaultMessage='post with the most replies'
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
|
const domain = useAppSelector((state) => state.meta.get('domain'));
|
||||||
|
const status = useAppSelector((state) =>
|
||||||
|
statusId ? getStatus(state, { id: statusId }) : undefined,
|
||||||
|
);
|
||||||
|
const pictureInPicture = useAppSelector((state) =>
|
||||||
|
statusId ? getPictureInPicture(state, { id: statusId }) : undefined,
|
||||||
|
);
|
||||||
|
const account = useAppSelector((state) =>
|
||||||
|
me ? state.accounts.get(me) : undefined,
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleToggleHidden = useCallback(() => {
|
||||||
|
dispatch(toggleStatusSpoilers(statusId));
|
||||||
|
}, [dispatch, statusId]);
|
||||||
|
|
||||||
|
if (!status) {
|
||||||
|
return (
|
||||||
|
<div className='annual-report__bento__box annual-report__summary__most-boosted-post' />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const displayName = (
|
||||||
|
<span className='display-name'>
|
||||||
|
<strong className='display-name__html'>
|
||||||
|
<FormattedMessage
|
||||||
|
id='annual_report.summary.highlighted_post.possessive'
|
||||||
|
defaultMessage="{name}'s"
|
||||||
|
values={{
|
||||||
|
name: account && (
|
||||||
|
<bdi
|
||||||
|
dangerouslySetInnerHTML={{ __html: account.display_name_html }}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</strong>
|
||||||
|
<span className='display-name__account'>{label}</span>
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='annual-report__bento__box annual-report__summary__most-boosted-post'>
|
||||||
|
<DetailedStatus
|
||||||
|
status={status}
|
||||||
|
pictureInPicture={pictureInPicture}
|
||||||
|
domain={domain}
|
||||||
|
onToggleHidden={handleToggleHidden}
|
||||||
|
overrideDisplayName={displayName}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
99
app/javascript/mastodon/features/annual_report/index.tsx
Normal file
99
app/javascript/mastodon/features/annual_report/index.tsx
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
import { useState, useEffect } from 'react';
|
||||||
|
|
||||||
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
|
import {
|
||||||
|
importFetchedStatuses,
|
||||||
|
importFetchedAccounts,
|
||||||
|
} from 'mastodon/actions/importer';
|
||||||
|
import { apiRequestGet, apiRequestPost } from 'mastodon/api';
|
||||||
|
import { LoadingIndicator } from 'mastodon/components/loading_indicator';
|
||||||
|
import { me } from 'mastodon/initial_state';
|
||||||
|
import type { Account } from 'mastodon/models/account';
|
||||||
|
import type { AnnualReport as AnnualReportData } from 'mastodon/models/annual_report';
|
||||||
|
import type { Status } from 'mastodon/models/status';
|
||||||
|
import { useAppSelector, useAppDispatch } from 'mastodon/store';
|
||||||
|
|
||||||
|
import { Archetype } from './archetype';
|
||||||
|
import { Followers } from './followers';
|
||||||
|
import { HighlightedPost } from './highlighted_post';
|
||||||
|
import { MostUsedHashtag } from './most_used_hashtag';
|
||||||
|
import { NewPosts } from './new_posts';
|
||||||
|
import { Percentile } from './percentile';
|
||||||
|
|
||||||
|
interface AnnualReportResponse {
|
||||||
|
annual_reports: AnnualReportData[];
|
||||||
|
accounts: Account[];
|
||||||
|
statuses: Status[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export const AnnualReport: React.FC<{
|
||||||
|
year: string;
|
||||||
|
}> = ({ year }) => {
|
||||||
|
const [response, setResponse] = useState<AnnualReportResponse | null>(null);
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
const currentAccount = useAppSelector((state) =>
|
||||||
|
me ? state.accounts.get(me) : undefined,
|
||||||
|
);
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setLoading(true);
|
||||||
|
|
||||||
|
apiRequestGet<AnnualReportResponse>(`v1/annual_reports/${year}`)
|
||||||
|
.then((data) => {
|
||||||
|
dispatch(importFetchedStatuses(data.statuses));
|
||||||
|
dispatch(importFetchedAccounts(data.accounts));
|
||||||
|
|
||||||
|
setResponse(data);
|
||||||
|
setLoading(false);
|
||||||
|
|
||||||
|
return apiRequestPost(`v1/annual_reports/${year}/read`);
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
setLoading(false);
|
||||||
|
});
|
||||||
|
}, [dispatch, year, setResponse, setLoading]);
|
||||||
|
|
||||||
|
if (loading) {
|
||||||
|
return <LoadingIndicator />;
|
||||||
|
}
|
||||||
|
|
||||||
|
const report = response?.annual_reports[0];
|
||||||
|
|
||||||
|
if (!report) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='annual-report'>
|
||||||
|
<div className='annual-report__header'>
|
||||||
|
<h1>
|
||||||
|
<FormattedMessage
|
||||||
|
id='annual_report.summary.thanks'
|
||||||
|
defaultMessage='Thanks for being part of Mastodon!'
|
||||||
|
/>
|
||||||
|
</h1>
|
||||||
|
<p>
|
||||||
|
<FormattedMessage
|
||||||
|
id='annual_report.summary.here_it_is'
|
||||||
|
defaultMessage='Here is your {year} in review:'
|
||||||
|
values={{ year: report.year }}
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='annual-report__bento annual-report__summary'>
|
||||||
|
<Archetype data={report.data.archetype} />
|
||||||
|
<HighlightedPost data={report.data.top_statuses} />
|
||||||
|
<Followers
|
||||||
|
data={report.data.time_series}
|
||||||
|
total={currentAccount?.followers_count}
|
||||||
|
/>
|
||||||
|
<MostUsedHashtag data={report.data.top_hashtags} />
|
||||||
|
<Percentile data={report.data.percentiles} />
|
||||||
|
<NewPosts data={report.data.time_series} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
|
@ -0,0 +1,29 @@
|
||||||
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
|
import type { NameAndCount } from 'mastodon/models/annual_report';
|
||||||
|
|
||||||
|
export const MostUsedApp: React.FC<{
|
||||||
|
data: NameAndCount[];
|
||||||
|
}> = ({ data }) => {
|
||||||
|
const app = data[0];
|
||||||
|
|
||||||
|
if (!app) {
|
||||||
|
return (
|
||||||
|
<div className='annual-report__bento__box annual-report__summary__most-used-app' />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='annual-report__bento__box annual-report__summary__most-used-app'>
|
||||||
|
<div className='annual-report__summary__most-used-app__icon'>
|
||||||
|
{app.name}
|
||||||
|
</div>
|
||||||
|
<div className='annual-report__summary__most-used-app__label'>
|
||||||
|
<FormattedMessage
|
||||||
|
id='annual_report.summary.most_used_app.most_used_app'
|
||||||
|
defaultMessage='most used app'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
|
@ -0,0 +1,30 @@
|
||||||
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
|
import type { NameAndCount } from 'mastodon/models/annual_report';
|
||||||
|
|
||||||
|
export const MostUsedHashtag: React.FC<{
|
||||||
|
data: NameAndCount[];
|
||||||
|
}> = ({ data }) => {
|
||||||
|
const hashtag = data[0];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='annual-report__bento__box annual-report__summary__most-used-hashtag'>
|
||||||
|
<div className='annual-report__summary__most-used-hashtag__hashtag'>
|
||||||
|
{hashtag ? (
|
||||||
|
<>#{hashtag.name}</>
|
||||||
|
) : (
|
||||||
|
<FormattedMessage
|
||||||
|
id='annual_report.summary.most_used_hashtag.none'
|
||||||
|
defaultMessage='None'
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className='annual-report__summary__most-used-hashtag__label'>
|
||||||
|
<FormattedMessage
|
||||||
|
id='annual_report.summary.most_used_hashtag.most_used_hashtag'
|
||||||
|
defaultMessage='most used hashtag'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
53
app/javascript/mastodon/features/annual_report/new_posts.tsx
Normal file
53
app/javascript/mastodon/features/annual_report/new_posts.tsx
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
import { FormattedNumber, FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
|
import ChatBubbleIcon from '@/material-icons/400-24px/chat_bubble.svg?react';
|
||||||
|
import type { TimeSeriesMonth } from 'mastodon/models/annual_report';
|
||||||
|
|
||||||
|
export const NewPosts: React.FC<{
|
||||||
|
data: TimeSeriesMonth[];
|
||||||
|
}> = ({ data }) => {
|
||||||
|
const posts = data.reduce((sum, item) => sum + item.statuses, 0);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='annual-report__bento__box annual-report__summary__new-posts'>
|
||||||
|
<svg width={500} height={500}>
|
||||||
|
<defs>
|
||||||
|
<pattern
|
||||||
|
id='posts'
|
||||||
|
x='0'
|
||||||
|
y='0'
|
||||||
|
width='32'
|
||||||
|
height='35'
|
||||||
|
patternUnits='userSpaceOnUse'
|
||||||
|
>
|
||||||
|
<circle cx='12' cy='12' r='12' fill='var(--lime)' />
|
||||||
|
<ChatBubbleIcon
|
||||||
|
fill='var(--indigo-1)'
|
||||||
|
x='4'
|
||||||
|
y='4'
|
||||||
|
width='16'
|
||||||
|
height='16'
|
||||||
|
/>
|
||||||
|
</pattern>
|
||||||
|
</defs>
|
||||||
|
|
||||||
|
<rect
|
||||||
|
width={500}
|
||||||
|
height={500}
|
||||||
|
fill='url(#posts)'
|
||||||
|
style={{ opacity: 0.2 }}
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
<div className='annual-report__summary__new-posts__number'>
|
||||||
|
<FormattedNumber value={posts} />
|
||||||
|
</div>
|
||||||
|
<div className='annual-report__summary__new-posts__label'>
|
||||||
|
<FormattedMessage
|
||||||
|
id='annual_report.summary.new_posts.new_posts'
|
||||||
|
defaultMessage='new posts'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
|
@ -0,0 +1,53 @@
|
||||||
|
/* eslint-disable react/jsx-no-useless-fragment */
|
||||||
|
import { FormattedMessage, FormattedNumber } from 'react-intl';
|
||||||
|
|
||||||
|
import type { Percentiles } from 'mastodon/models/annual_report';
|
||||||
|
|
||||||
|
export const Percentile: React.FC<{
|
||||||
|
data: Percentiles;
|
||||||
|
}> = ({ data }) => {
|
||||||
|
const percentile = data.statuses;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='annual-report__bento__box annual-report__summary__percentile'>
|
||||||
|
<FormattedMessage
|
||||||
|
id='annual_report.summary.percentile.text'
|
||||||
|
defaultMessage='<topLabel>That puts you in the top</topLabel><percentage></percentage><bottomLabel>of Mastodon users.</bottomLabel>'
|
||||||
|
values={{
|
||||||
|
topLabel: (str) => (
|
||||||
|
<div className='annual-report__summary__percentile__label'>
|
||||||
|
{str}
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
percentage: () => (
|
||||||
|
<div className='annual-report__summary__percentile__number'>
|
||||||
|
<FormattedNumber
|
||||||
|
value={Math.min(percentile, 99) / 100}
|
||||||
|
style='percent'
|
||||||
|
maximumFractionDigits={percentile < 1 ? 1 : 0}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
bottomLabel: (str) => (
|
||||||
|
<div>
|
||||||
|
<div className='annual-report__summary__percentile__label'>
|
||||||
|
{str}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{percentile < 6 && (
|
||||||
|
<div className='annual-report__summary__percentile__footnote'>
|
||||||
|
<FormattedMessage
|
||||||
|
id='annual_report.summary.percentile.we_wont_tell_bernie'
|
||||||
|
defaultMessage="We won't tell Bernie."
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{(message) => <>{message}</>}
|
||||||
|
</FormattedMessage>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
|
@ -68,7 +68,7 @@ class FollowRequests extends ImmutablePureComponent {
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Column bindToDocument={!multiColumn} icon='user-plus' iconComponent={PersonAddIcon} heading={intl.formatMessage(messages.heading)}>
|
<Column bindToDocument={!multiColumn} icon='user-plus' iconComponent={PersonAddIcon} heading={intl.formatMessage(messages.heading)} alwaysShowBackButton>
|
||||||
<ScrollableList
|
<ScrollableList
|
||||||
scrollKey='follow_requests'
|
scrollKey='follow_requests'
|
||||||
onLoadMore={this.handleLoadMore}
|
onLoadMore={this.handleLoadMore}
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
import { useCallback } from 'react';
|
||||||
|
|
||||||
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
|
import classNames from 'classnames';
|
||||||
|
|
||||||
|
import CelebrationIcon from '@/material-icons/400-24px/celebration.svg?react';
|
||||||
|
import { openModal } from 'mastodon/actions/modal';
|
||||||
|
import { Icon } from 'mastodon/components/icon';
|
||||||
|
import type { NotificationGroupAnnualReport } from 'mastodon/models/notification_group';
|
||||||
|
import { useAppDispatch } from 'mastodon/store';
|
||||||
|
|
||||||
|
export const NotificationAnnualReport: React.FC<{
|
||||||
|
notification: NotificationGroupAnnualReport;
|
||||||
|
unread: boolean;
|
||||||
|
}> = ({ notification: { annualReport }, unread }) => {
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
|
const year = annualReport.year;
|
||||||
|
|
||||||
|
const handleClick = useCallback(() => {
|
||||||
|
dispatch(
|
||||||
|
openModal({
|
||||||
|
modalType: 'ANNUAL_REPORT',
|
||||||
|
modalProps: { year },
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}, [dispatch, year]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
role='button'
|
||||||
|
className={classNames(
|
||||||
|
'notification-group notification-group--link notification-group--annual-report focusable',
|
||||||
|
{ 'notification-group--unread': unread },
|
||||||
|
)}
|
||||||
|
tabIndex={0}
|
||||||
|
>
|
||||||
|
<div className='notification-group__icon'>
|
||||||
|
<Icon id='celebration' icon={CelebrationIcon} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='notification-group__main'>
|
||||||
|
<p>
|
||||||
|
<FormattedMessage
|
||||||
|
id='notification.annual_report.message'
|
||||||
|
defaultMessage="Your {year} #Wrapstodon awaits! Unveil your year's highlights and memorable moments on Mastodon!"
|
||||||
|
values={{ year }}
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
<button onClick={handleClick} className='link-button'>
|
||||||
|
<FormattedMessage
|
||||||
|
id='notification.annual_report.view'
|
||||||
|
defaultMessage='View #Wrapstodon'
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
|
@ -9,6 +9,7 @@ import { useAppSelector, useAppDispatch } from 'mastodon/store';
|
||||||
|
|
||||||
import { NotificationAdminReport } from './notification_admin_report';
|
import { NotificationAdminReport } from './notification_admin_report';
|
||||||
import { NotificationAdminSignUp } from './notification_admin_sign_up';
|
import { NotificationAdminSignUp } from './notification_admin_sign_up';
|
||||||
|
import { NotificationAnnualReport } from './notification_annual_report';
|
||||||
import { NotificationFavourite } from './notification_favourite';
|
import { NotificationFavourite } from './notification_favourite';
|
||||||
import { NotificationFollow } from './notification_follow';
|
import { NotificationFollow } from './notification_follow';
|
||||||
import { NotificationFollowRequest } from './notification_follow_request';
|
import { NotificationFollowRequest } from './notification_follow_request';
|
||||||
|
@ -143,6 +144,14 @@ export const NotificationGroup: React.FC<{
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
|
case 'annual_report':
|
||||||
|
content = (
|
||||||
|
<NotificationAnnualReport
|
||||||
|
unread={unread}
|
||||||
|
notification={notificationGroup}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,6 +49,7 @@ export const DetailedStatus: React.FC<{
|
||||||
domain: string;
|
domain: string;
|
||||||
showMedia?: boolean;
|
showMedia?: boolean;
|
||||||
withLogo?: boolean;
|
withLogo?: boolean;
|
||||||
|
overrideDisplayName?: React.ReactNode;
|
||||||
pictureInPicture: any;
|
pictureInPicture: any;
|
||||||
onToggleHidden?: (status: any) => void;
|
onToggleHidden?: (status: any) => void;
|
||||||
onToggleMediaVisibility?: () => void;
|
onToggleMediaVisibility?: () => void;
|
||||||
|
@ -62,6 +63,7 @@ export const DetailedStatus: React.FC<{
|
||||||
domain,
|
domain,
|
||||||
showMedia,
|
showMedia,
|
||||||
withLogo,
|
withLogo,
|
||||||
|
overrideDisplayName,
|
||||||
pictureInPicture,
|
pictureInPicture,
|
||||||
onToggleMediaVisibility,
|
onToggleMediaVisibility,
|
||||||
onToggleHidden,
|
onToggleHidden,
|
||||||
|
@ -319,7 +321,11 @@ export const DetailedStatus: React.FC<{
|
||||||
<div className='detailed-status__display-avatar'>
|
<div className='detailed-status__display-avatar'>
|
||||||
<Avatar account={status.get('account')} size={46} />
|
<Avatar account={status.get('account')} size={46} />
|
||||||
</div>
|
</div>
|
||||||
<DisplayName account={status.get('account')} localDomain={domain} />
|
|
||||||
|
{overrideDisplayName ?? (
|
||||||
|
<DisplayName account={status.get('account')} localDomain={domain} />
|
||||||
|
)}
|
||||||
|
|
||||||
{withLogo && (
|
{withLogo && (
|
||||||
<>
|
<>
|
||||||
<div className='spacer' />
|
<div className='spacer' />
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
|
import { AnnualReport } from 'mastodon/features/annual_report';
|
||||||
|
|
||||||
|
const AnnualReportModal: React.FC<{
|
||||||
|
year: string;
|
||||||
|
onChangeBackgroundColor: (arg0: string) => void;
|
||||||
|
}> = ({ year, onChangeBackgroundColor }) => {
|
||||||
|
useEffect(() => {
|
||||||
|
onChangeBackgroundColor('var(--indigo-1)');
|
||||||
|
}, [onChangeBackgroundColor]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='modal-root__modal annual-report-modal'>
|
||||||
|
<AnnualReport year={year} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// eslint-disable-next-line import/no-default-export
|
||||||
|
export default AnnualReportModal;
|
|
@ -18,6 +18,7 @@ import {
|
||||||
SubscribedLanguagesModal,
|
SubscribedLanguagesModal,
|
||||||
ClosedRegistrationsModal,
|
ClosedRegistrationsModal,
|
||||||
IgnoreNotificationsModal,
|
IgnoreNotificationsModal,
|
||||||
|
AnnualReportModal,
|
||||||
} from 'mastodon/features/ui/util/async-components';
|
} from 'mastodon/features/ui/util/async-components';
|
||||||
import { getScrollbarWidth } from 'mastodon/utils/scrollbar';
|
import { getScrollbarWidth } from 'mastodon/utils/scrollbar';
|
||||||
|
|
||||||
|
@ -72,6 +73,7 @@ export const MODAL_COMPONENTS = {
|
||||||
'INTERACTION': InteractionModal,
|
'INTERACTION': InteractionModal,
|
||||||
'CLOSED_REGISTRATIONS': ClosedRegistrationsModal,
|
'CLOSED_REGISTRATIONS': ClosedRegistrationsModal,
|
||||||
'IGNORE_NOTIFICATIONS': IgnoreNotificationsModal,
|
'IGNORE_NOTIFICATIONS': IgnoreNotificationsModal,
|
||||||
|
'ANNUAL_REPORT': AnnualReportModal,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class ModalRoot extends PureComponent {
|
export default class ModalRoot extends PureComponent {
|
||||||
|
|
|
@ -482,7 +482,9 @@ class UI extends PureComponent {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
handleHotkeyBack = () => {
|
handleHotkeyBack = e => {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
const { history } = this.props;
|
const { history } = this.props;
|
||||||
|
|
||||||
if (history.location?.state?.fromMastodon) {
|
if (history.location?.state?.fromMastodon) {
|
||||||
|
|
|
@ -217,3 +217,7 @@ export function NotificationRequest () {
|
||||||
export function LinkTimeline () {
|
export function LinkTimeline () {
|
||||||
return import(/*webpackChunkName: "features/link_timeline" */'../../link_timeline');
|
return import(/*webpackChunkName: "features/link_timeline" */'../../link_timeline');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function AnnualReportModal () {
|
||||||
|
return import(/*webpackChunkName: "modals/annual_report_modal" */'../components/annual_report_modal');
|
||||||
|
}
|
||||||
|
|
|
@ -86,6 +86,7 @@
|
||||||
"alert.unexpected.title": "المعذرة!",
|
"alert.unexpected.title": "المعذرة!",
|
||||||
"alt_text_badge.title": "نص بديل",
|
"alt_text_badge.title": "نص بديل",
|
||||||
"announcement.announcement": "إعلان",
|
"announcement.announcement": "إعلان",
|
||||||
|
"annual_report.summary.archetype.booster": "The cool-hunter",
|
||||||
"attachments_list.unprocessed": "(غير معالَج)",
|
"attachments_list.unprocessed": "(غير معالَج)",
|
||||||
"audio.hide": "إخفاء المقطع الصوتي",
|
"audio.hide": "إخفاء المقطع الصوتي",
|
||||||
"block_modal.remote_users_caveat": "سوف نطلب من الخادم {domain} أن يحترم قرارك، لكن الالتزام غير مضمون لأن بعض الخواديم قد تتعامل مع نصوص الكتل بشكل مختلف. قد تظل المنشورات العامة مرئية للمستخدمين غير المسجلين الدخول.",
|
"block_modal.remote_users_caveat": "سوف نطلب من الخادم {domain} أن يحترم قرارك، لكن الالتزام غير مضمون لأن بعض الخواديم قد تتعامل مع نصوص الكتل بشكل مختلف. قد تظل المنشورات العامة مرئية للمستخدمين غير المسجلين الدخول.",
|
||||||
|
|
|
@ -154,7 +154,7 @@
|
||||||
"compose_form.hashtag_warning": "Гэты допіс не будзе паказаны пад аніякім хэштэгам, бо ён не публічны. Толькі публічныя допісы можна знайсці па хэштэгу.",
|
"compose_form.hashtag_warning": "Гэты допіс не будзе паказаны пад аніякім хэштэгам, бо ён не публічны. Толькі публічныя допісы можна знайсці па хэштэгу.",
|
||||||
"compose_form.lock_disclaimer": "Ваш уліковы запіс не {locked}. Усе могуць падпісацца на вас, каб бачыць допісы толькі для падпісчыкаў.",
|
"compose_form.lock_disclaimer": "Ваш уліковы запіс не {locked}. Усе могуць падпісацца на вас, каб бачыць допісы толькі для падпісчыкаў.",
|
||||||
"compose_form.lock_disclaimer.lock": "закрыты",
|
"compose_form.lock_disclaimer.lock": "закрыты",
|
||||||
"compose_form.placeholder": "Што здарылася?",
|
"compose_form.placeholder": "Што ў вас новага?",
|
||||||
"compose_form.poll.duration": "Працягласць апытання",
|
"compose_form.poll.duration": "Працягласць апытання",
|
||||||
"compose_form.poll.multiple": "Множны выбар",
|
"compose_form.poll.multiple": "Множны выбар",
|
||||||
"compose_form.poll.option_placeholder": "Варыянт {number}",
|
"compose_form.poll.option_placeholder": "Варыянт {number}",
|
||||||
|
|
|
@ -87,6 +87,17 @@
|
||||||
"alert.unexpected.title": "Опаа!",
|
"alert.unexpected.title": "Опаа!",
|
||||||
"alt_text_badge.title": "Алтернативен текст",
|
"alt_text_badge.title": "Алтернативен текст",
|
||||||
"announcement.announcement": "Оповестяване",
|
"announcement.announcement": "Оповестяване",
|
||||||
|
"annual_report.summary.archetype.lurker": "Дебнещото",
|
||||||
|
"annual_report.summary.archetype.oracle": "Оракул",
|
||||||
|
"annual_report.summary.archetype.pollster": "Анкетьорче",
|
||||||
|
"annual_report.summary.archetype.replier": "Социална пеперуда",
|
||||||
|
"annual_report.summary.followers.followers": "последователи",
|
||||||
|
"annual_report.summary.followers.total": "{count} общо",
|
||||||
|
"annual_report.summary.highlighted_post.by_favourites": "най-правено като любима публикация",
|
||||||
|
"annual_report.summary.most_used_app.most_used_app": "най-употребявано приложение",
|
||||||
|
"annual_report.summary.most_used_hashtag.most_used_hashtag": "най-употребяван хаштаг",
|
||||||
|
"annual_report.summary.new_posts.new_posts": "нови публикации",
|
||||||
|
"annual_report.summary.thanks": "Благодарим, че сте част от Mastodon!",
|
||||||
"attachments_list.unprocessed": "(необработено)",
|
"attachments_list.unprocessed": "(необработено)",
|
||||||
"audio.hide": "Скриване на звука",
|
"audio.hide": "Скриване на звука",
|
||||||
"block_modal.remote_users_caveat": "Ще поискаме сървърът {domain} да почита решението ви. Съгласието обаче не се гарантира откак някои сървъри могат да боравят с блоковете по различен начин. Обществените публикации още може да се виждат от невлезли в системата потребители.",
|
"block_modal.remote_users_caveat": "Ще поискаме сървърът {domain} да почита решението ви. Съгласието обаче не се гарантира откак някои сървъри могат да боравят с блоковете по различен начин. Обществените публикации още може да се виждат от невлезли в системата потребители.",
|
||||||
|
@ -158,6 +169,7 @@
|
||||||
"compose_form.poll.duration": "Времетраене на анкетата",
|
"compose_form.poll.duration": "Времетраене на анкетата",
|
||||||
"compose_form.poll.multiple": "Множествен избор",
|
"compose_form.poll.multiple": "Множествен избор",
|
||||||
"compose_form.poll.option_placeholder": "Избор {number}",
|
"compose_form.poll.option_placeholder": "Избор {number}",
|
||||||
|
"compose_form.poll.single": "Единичен избор",
|
||||||
"compose_form.poll.switch_to_multiple": "Промяна на анкетата, за да се позволят множество възможни избора",
|
"compose_form.poll.switch_to_multiple": "Промяна на анкетата, за да се позволят множество възможни избора",
|
||||||
"compose_form.poll.switch_to_single": "Промяна на анкетата, за да се позволи един възможен избор",
|
"compose_form.poll.switch_to_single": "Промяна на анкетата, за да се позволи един възможен избор",
|
||||||
"compose_form.poll.type": "Стил",
|
"compose_form.poll.type": "Стил",
|
||||||
|
@ -195,6 +207,8 @@
|
||||||
"confirmations.unfollow.message": "Наистина ли искате да не следвате {name}?",
|
"confirmations.unfollow.message": "Наистина ли искате да не следвате {name}?",
|
||||||
"confirmations.unfollow.title": "Спирате ли да следвате потребителя?",
|
"confirmations.unfollow.title": "Спирате ли да следвате потребителя?",
|
||||||
"content_warning.hide": "Скриване на публ.",
|
"content_warning.hide": "Скриване на публ.",
|
||||||
|
"content_warning.show": "Нека се покаже",
|
||||||
|
"content_warning.show_more": "Показване на още",
|
||||||
"conversation.delete": "Изтриване на разговора",
|
"conversation.delete": "Изтриване на разговора",
|
||||||
"conversation.mark_as_read": "Маркиране като прочетено",
|
"conversation.mark_as_read": "Маркиране като прочетено",
|
||||||
"conversation.open": "Преглед на разговора",
|
"conversation.open": "Преглед на разговора",
|
||||||
|
@ -365,6 +379,9 @@
|
||||||
"home.pending_critical_update.link": "Преглед на обновяванията",
|
"home.pending_critical_update.link": "Преглед на обновяванията",
|
||||||
"home.pending_critical_update.title": "Налично критично обновяване на сигурността!",
|
"home.pending_critical_update.title": "Налично критично обновяване на сигурността!",
|
||||||
"home.show_announcements": "Показване на оповестяванията",
|
"home.show_announcements": "Показване на оповестяванията",
|
||||||
|
"ignore_notifications_modal.disclaimer": "Mastodon не може да осведоми потребители, че сте пренебрегнали известията им. Пренебрегването на известията няма да спре самите съобщения да не бъдат изпращани.",
|
||||||
|
"ignore_notifications_modal.filter_to_act_users": "Вие все още ще може да приемате, отхвърляте или докладвате потребители",
|
||||||
|
"ignore_notifications_modal.filter_to_avoid_confusion": "Прецеждането помага за избягване на възможно объркване",
|
||||||
"interaction_modal.description.favourite": "Имайки акаунт в Mastodon, може да сложите тази публикации в любими, за да позволите на автора да узнае, че я цените и да я запазите за по-късно.",
|
"interaction_modal.description.favourite": "Имайки акаунт в Mastodon, може да сложите тази публикации в любими, за да позволите на автора да узнае, че я цените и да я запазите за по-късно.",
|
||||||
"interaction_modal.description.follow": "С акаунт в Mastodon може да последвате {name}, за да получавате публикациите от този акаунт в началния си инфоканал.",
|
"interaction_modal.description.follow": "С акаунт в Mastodon може да последвате {name}, за да получавате публикациите от този акаунт в началния си инфоканал.",
|
||||||
"interaction_modal.description.reblog": "С акаунт в Mastodon може да подсилите тази публикация, за да я споделите с последователите си.",
|
"interaction_modal.description.reblog": "С акаунт в Mastodon може да подсилите тази публикация, за да я споделите с последователите си.",
|
||||||
|
@ -380,6 +397,7 @@
|
||||||
"interaction_modal.title.follow": "Последване на {name}",
|
"interaction_modal.title.follow": "Последване на {name}",
|
||||||
"interaction_modal.title.reblog": "Подсилване на публикацията на {name}",
|
"interaction_modal.title.reblog": "Подсилване на публикацията на {name}",
|
||||||
"interaction_modal.title.reply": "Отговаряне на публикацията на {name}",
|
"interaction_modal.title.reply": "Отговаряне на публикацията на {name}",
|
||||||
|
"interaction_modal.title.vote": "Гласувайте в анкетата на {name}",
|
||||||
"intervals.full.days": "{number, plural, one {# ден} other {# дни}}",
|
"intervals.full.days": "{number, plural, one {# ден} other {# дни}}",
|
||||||
"intervals.full.hours": "{number, plural, one {# час} other {# часа}}",
|
"intervals.full.hours": "{number, plural, one {# час} other {# часа}}",
|
||||||
"intervals.full.minutes": "{number, plural, one {# минута} other {# минути}}",
|
"intervals.full.minutes": "{number, plural, one {# минута} other {# минути}}",
|
||||||
|
@ -420,6 +438,8 @@
|
||||||
"lightbox.close": "Затваряне",
|
"lightbox.close": "Затваряне",
|
||||||
"lightbox.next": "Напред",
|
"lightbox.next": "Напред",
|
||||||
"lightbox.previous": "Назад",
|
"lightbox.previous": "Назад",
|
||||||
|
"lightbox.zoom_in": "Увеличение до действителната големина",
|
||||||
|
"lightbox.zoom_out": "Увеличение до побиране",
|
||||||
"limited_account_hint.action": "Показване на профила въпреки това",
|
"limited_account_hint.action": "Показване на профила въпреки това",
|
||||||
"limited_account_hint.title": "Този профил е бил скрит от модераторите на {domain}.",
|
"limited_account_hint.title": "Този профил е бил скрит от модераторите на {domain}.",
|
||||||
"link_preview.author": "От {name}",
|
"link_preview.author": "От {name}",
|
||||||
|
@ -441,6 +461,7 @@
|
||||||
"lists.subheading": "Вашите списъци",
|
"lists.subheading": "Вашите списъци",
|
||||||
"load_pending": "{count, plural, one {# нов елемент} other {# нови елемента}}",
|
"load_pending": "{count, plural, one {# нов елемент} other {# нови елемента}}",
|
||||||
"loading_indicator.label": "Зареждане…",
|
"loading_indicator.label": "Зареждане…",
|
||||||
|
"media_gallery.hide": "Скриване",
|
||||||
"moved_to_account_banner.text": "Вашият акаунт {disabledAccount} сега е изключен, защото се преместихте в {movedToAccount}.",
|
"moved_to_account_banner.text": "Вашият акаунт {disabledAccount} сега е изключен, защото се преместихте в {movedToAccount}.",
|
||||||
"mute_modal.hide_from_notifications": "Скриване от известията",
|
"mute_modal.hide_from_notifications": "Скриване от известията",
|
||||||
"mute_modal.hide_options": "Скриване на възможностите",
|
"mute_modal.hide_options": "Скриване на възможностите",
|
||||||
|
@ -489,6 +510,7 @@
|
||||||
"notification.favourite": "{name} направи любима публикацията ви",
|
"notification.favourite": "{name} направи любима публикацията ви",
|
||||||
"notification.favourite.name_and_others_with_link": "{name} и <a>{count, plural, one {# друг} other {# други}}</a> направиха любима ваша публикация",
|
"notification.favourite.name_and_others_with_link": "{name} и <a>{count, plural, one {# друг} other {# други}}</a> направиха любима ваша публикация",
|
||||||
"notification.follow": "{name} ви последва",
|
"notification.follow": "{name} ви последва",
|
||||||
|
"notification.follow.name_and_others": "{name} и <a>{count, plural, one {# друг} other {# други}}</a> ви последваха",
|
||||||
"notification.follow_request": "{name} поиска да ви последва",
|
"notification.follow_request": "{name} поиска да ви последва",
|
||||||
"notification.follow_request.name_and_others": "{name} и {count, plural, one {# друг} other {# други}} поискаха да ви последват",
|
"notification.follow_request.name_and_others": "{name} и {count, plural, one {# друг} other {# други}} поискаха да ви последват",
|
||||||
"notification.label.mention": "Споменаване",
|
"notification.label.mention": "Споменаване",
|
||||||
|
@ -496,6 +518,7 @@
|
||||||
"notification.label.private_reply": "Личен отговор",
|
"notification.label.private_reply": "Личен отговор",
|
||||||
"notification.label.reply": "Отговор",
|
"notification.label.reply": "Отговор",
|
||||||
"notification.mention": "Споменаване",
|
"notification.mention": "Споменаване",
|
||||||
|
"notification.mentioned_you": "{name} ви спомена",
|
||||||
"notification.moderation-warning.learn_more": "Научете повече",
|
"notification.moderation-warning.learn_more": "Научете повече",
|
||||||
"notification.moderation_warning": "Получихте предупреждение за модериране",
|
"notification.moderation_warning": "Получихте предупреждение за модериране",
|
||||||
"notification.moderation_warning.action_delete_statuses": "Някои от публикациите ви са премахнати.",
|
"notification.moderation_warning.action_delete_statuses": "Някои от публикациите ви са премахнати.",
|
||||||
|
@ -752,6 +775,7 @@
|
||||||
"status.bookmark": "Отмятане",
|
"status.bookmark": "Отмятане",
|
||||||
"status.cancel_reblog_private": "Край на подсилването",
|
"status.cancel_reblog_private": "Край на подсилването",
|
||||||
"status.cannot_reblog": "Публикацията не може да се подсилва",
|
"status.cannot_reblog": "Публикацията не може да се подсилва",
|
||||||
|
"status.continued_thread": "Продължена нишка",
|
||||||
"status.copy": "Копиране на връзката към публикация",
|
"status.copy": "Копиране на връзката към публикация",
|
||||||
"status.delete": "Изтриване",
|
"status.delete": "Изтриване",
|
||||||
"status.detailed_status": "Подробен изглед на разговора",
|
"status.detailed_status": "Подробен изглед на разговора",
|
||||||
|
@ -760,6 +784,7 @@
|
||||||
"status.edit": "Редактиране",
|
"status.edit": "Редактиране",
|
||||||
"status.edited": "Последно редактирано на {date}",
|
"status.edited": "Последно редактирано на {date}",
|
||||||
"status.edited_x_times": "Редактирано {count, plural,one {{count} път} other {{count} пъти}}",
|
"status.edited_x_times": "Редактирано {count, plural,one {{count} път} other {{count} пъти}}",
|
||||||
|
"status.embed": "Вземане на кода за вграждане",
|
||||||
"status.favourite": "Любимо",
|
"status.favourite": "Любимо",
|
||||||
"status.favourites": "{count, plural, one {любимо} other {любими}}",
|
"status.favourites": "{count, plural, one {любимо} other {любими}}",
|
||||||
"status.filter": "Филтриране на публ.",
|
"status.filter": "Филтриране на публ.",
|
||||||
|
@ -784,6 +809,7 @@
|
||||||
"status.reblogs.empty": "Още никого не е подсилвал публикацията. Подсилващият ще се покаже тук.",
|
"status.reblogs.empty": "Още никого не е подсилвал публикацията. Подсилващият ще се покаже тук.",
|
||||||
"status.redraft": "Изтриване и преработване",
|
"status.redraft": "Изтриване и преработване",
|
||||||
"status.remove_bookmark": "Премахване на отметката",
|
"status.remove_bookmark": "Премахване на отметката",
|
||||||
|
"status.replied_in_thread": "Отговорено в нишката",
|
||||||
"status.replied_to": "В отговор до {name}",
|
"status.replied_to": "В отговор до {name}",
|
||||||
"status.reply": "Отговор",
|
"status.reply": "Отговор",
|
||||||
"status.replyAll": "Отговор на нишка",
|
"status.replyAll": "Отговор на нишка",
|
||||||
|
@ -821,6 +847,7 @@
|
||||||
"upload_error.poll": "Качването на файлове не е позволено с анкети.",
|
"upload_error.poll": "Качването на файлове не е позволено с анкети.",
|
||||||
"upload_form.audio_description": "Опишете за хора, които са глухи или трудно чуват",
|
"upload_form.audio_description": "Опишете за хора, които са глухи или трудно чуват",
|
||||||
"upload_form.description": "Опишете за хора, които са слепи или имат слабо зрение",
|
"upload_form.description": "Опишете за хора, които са слепи или имат слабо зрение",
|
||||||
|
"upload_form.drag_and_drop.instructions": "Натиснете интервал или enter, за да подберете мултимедийно прикачване. Провлачвайки, ползвайте клавишите със стрелки, за да премествате мултимедията във всяка дадена посока. Натиснете пак интервал или enter, за да се стовари мултимедийното прикачване в новото си положение или натиснете Esc за отмяна.",
|
||||||
"upload_form.edit": "Редактиране",
|
"upload_form.edit": "Редактиране",
|
||||||
"upload_form.thumbnail": "Промяна на миниобраза",
|
"upload_form.thumbnail": "Промяна на миниобраза",
|
||||||
"upload_form.video_description": "Опишете за хора, които са глухи или трудно чуват, слепи или имат слабо зрение",
|
"upload_form.video_description": "Опишете за хора, които са глухи или трудно чуват, слепи или имат слабо зрение",
|
||||||
|
|
|
@ -82,6 +82,8 @@
|
||||||
"alert.unexpected.message": "Ur fazi dic'hortozet zo degouezhet.",
|
"alert.unexpected.message": "Ur fazi dic'hortozet zo degouezhet.",
|
||||||
"alert.unexpected.title": "Hopala !",
|
"alert.unexpected.title": "Hopala !",
|
||||||
"announcement.announcement": "Kemennad",
|
"announcement.announcement": "Kemennad",
|
||||||
|
"annual_report.summary.followers.followers": "heulier",
|
||||||
|
"annual_report.summary.highlighted_post.possessive": "{name}",
|
||||||
"attachments_list.unprocessed": "(ket meret)",
|
"attachments_list.unprocessed": "(ket meret)",
|
||||||
"audio.hide": "Kuzhat ar c'hleved",
|
"audio.hide": "Kuzhat ar c'hleved",
|
||||||
"block_modal.show_less": "Diskouez nebeutoc'h",
|
"block_modal.show_less": "Diskouez nebeutoc'h",
|
||||||
|
|
|
@ -87,6 +87,19 @@
|
||||||
"alert.unexpected.title": "Vaja!",
|
"alert.unexpected.title": "Vaja!",
|
||||||
"alt_text_badge.title": "Text alternatiu",
|
"alt_text_badge.title": "Text alternatiu",
|
||||||
"announcement.announcement": "Anunci",
|
"announcement.announcement": "Anunci",
|
||||||
|
"annual_report.summary.archetype.oracle": "L'Oracle",
|
||||||
|
"annual_report.summary.followers.followers": "seguidors",
|
||||||
|
"annual_report.summary.followers.total": "{count} en total",
|
||||||
|
"annual_report.summary.here_it_is": "El repàs del vostre {year}:",
|
||||||
|
"annual_report.summary.highlighted_post.by_favourites": "la publicació més afavorida",
|
||||||
|
"annual_report.summary.highlighted_post.by_reblogs": "la publicació més impulsada",
|
||||||
|
"annual_report.summary.highlighted_post.by_replies": "la publicació amb més respostes",
|
||||||
|
"annual_report.summary.highlighted_post.possessive": "de {name}",
|
||||||
|
"annual_report.summary.most_used_app.most_used_app": "l'aplicació més utilitzada",
|
||||||
|
"annual_report.summary.most_used_hashtag.most_used_hashtag": "l'etiqueta més utilitzada",
|
||||||
|
"annual_report.summary.most_used_hashtag.none": "Cap",
|
||||||
|
"annual_report.summary.new_posts.new_posts": "publicacions noves",
|
||||||
|
"annual_report.summary.thanks": "Gràcies per formar part de Mastodon!",
|
||||||
"attachments_list.unprocessed": "(sense processar)",
|
"attachments_list.unprocessed": "(sense processar)",
|
||||||
"audio.hide": "Amaga l'àudio",
|
"audio.hide": "Amaga l'àudio",
|
||||||
"block_modal.remote_users_caveat": "Li demanarem al servidor {domain} que respecti la vostra decisió, tot i que no podem garantir-ho, ja que alguns servidors gestionen de forma diferent els blocatges. És possible que els usuaris no autenticats puguin veure les publicacions públiques.",
|
"block_modal.remote_users_caveat": "Li demanarem al servidor {domain} que respecti la vostra decisió, tot i que no podem garantir-ho, ja que alguns servidors gestionen de forma diferent els blocatges. És possible que els usuaris no autenticats puguin veure les publicacions públiques.",
|
||||||
|
|
|
@ -87,11 +87,30 @@
|
||||||
"alert.unexpected.title": "Wps!",
|
"alert.unexpected.title": "Wps!",
|
||||||
"alt_text_badge.title": "Testun Amgen",
|
"alt_text_badge.title": "Testun Amgen",
|
||||||
"announcement.announcement": "Cyhoeddiad",
|
"announcement.announcement": "Cyhoeddiad",
|
||||||
|
"annual_report.summary.archetype.booster": "Y hyrwyddwr",
|
||||||
|
"annual_report.summary.archetype.lurker": "Yr arsylwr",
|
||||||
|
"annual_report.summary.archetype.oracle": "Yr oracl",
|
||||||
|
"annual_report.summary.archetype.pollster": "Yr arholwr",
|
||||||
|
"annual_report.summary.archetype.replier": "Y sbardunwr",
|
||||||
|
"annual_report.summary.followers.followers": "dilynwyr",
|
||||||
|
"annual_report.summary.followers.total": "{count} cyfanswm",
|
||||||
|
"annual_report.summary.here_it_is": "Dyma eich {year} yn gryno:",
|
||||||
|
"annual_report.summary.highlighted_post.by_favourites": "postiad wedi'i ffefrynu fwyaf",
|
||||||
|
"annual_report.summary.highlighted_post.by_reblogs": "postiad wedi'i hybu fwyaf",
|
||||||
|
"annual_report.summary.highlighted_post.by_replies": "postiad gyda'r ymatebion mwyaf",
|
||||||
|
"annual_report.summary.highlighted_post.possessive": "{name}",
|
||||||
|
"annual_report.summary.most_used_app.most_used_app": "ap a ddefnyddiwyd fwyaf",
|
||||||
|
"annual_report.summary.most_used_hashtag.most_used_hashtag": "hashnod a ddefnyddiwyd fwyaf",
|
||||||
|
"annual_report.summary.most_used_hashtag.none": "Dim",
|
||||||
|
"annual_report.summary.new_posts.new_posts": "postiadau newydd",
|
||||||
|
"annual_report.summary.percentile.text": "<topLabel>Rydych chi yn y </topLabel><percentage></percentage><bottomLabel>mwyaf o ddefnyddwyr Mastodon.</bottomLabel>",
|
||||||
|
"annual_report.summary.percentile.we_wont_tell_bernie": "Ni fyddwn yn dweud wrth Bernie.",
|
||||||
|
"annual_report.summary.thanks": "Diolch am fod yn rhan o Mastodon!",
|
||||||
"attachments_list.unprocessed": "(heb eu prosesu)",
|
"attachments_list.unprocessed": "(heb eu prosesu)",
|
||||||
"audio.hide": "Cuddio sain",
|
"audio.hide": "Cuddio sain",
|
||||||
"block_modal.remote_users_caveat": "Byddwn yn gofyn i'r gweinydd {domain} barchu eich penderfyniad. Fodd bynnag, nid yw cydymffurfiad wedi'i warantu gan y gall rhai gweinyddwyr drin rhwystro mewn ffyrdd gwahanol. Mae'n bosibl y bydd postiadau cyhoeddus yn dal i fod yn weladwy i ddefnyddwyr nad ydynt wedi mewngofnodi.",
|
"block_modal.remote_users_caveat": "Byddwn yn gofyn i'r gweinydd {domain} barchu eich penderfyniad. Fodd bynnag, nid yw cydymffurfiad wedi'i warantu gan y gall rhai gweinyddwyr drin rhwystro mewn ffyrdd gwahanol. Mae'n bosibl y bydd postiadau cyhoeddus yn dal i fod yn weladwy i ddefnyddwyr nad ydynt wedi mewngofnodi.",
|
||||||
"block_modal.show_less": "Dangos llai",
|
"block_modal.show_less": "Dangos llai",
|
||||||
"block_modal.show_more": "Dangos mwy",
|
"block_modal.show_more": "Dangos rhagor",
|
||||||
"block_modal.they_cant_mention": "Nid ydynt yn gallu eich crybwyll na'ch dilyn.",
|
"block_modal.they_cant_mention": "Nid ydynt yn gallu eich crybwyll na'ch dilyn.",
|
||||||
"block_modal.they_cant_see_posts": "Nid ydynt yn gallu gweld eich postiadau ac ni fyddwch yn gweld eu rhai hwy.",
|
"block_modal.they_cant_see_posts": "Nid ydynt yn gallu gweld eich postiadau ac ni fyddwch yn gweld eu rhai hwy.",
|
||||||
"block_modal.they_will_know": "Gallant weld eu bod wedi'u rhwystro.",
|
"block_modal.they_will_know": "Gallant weld eu bod wedi'u rhwystro.",
|
||||||
|
@ -163,9 +182,9 @@
|
||||||
"compose_form.poll.switch_to_single": "Newid pleidlais i gyfyngu i un dewis",
|
"compose_form.poll.switch_to_single": "Newid pleidlais i gyfyngu i un dewis",
|
||||||
"compose_form.poll.type": "Arddull",
|
"compose_form.poll.type": "Arddull",
|
||||||
"compose_form.publish": "Postiad",
|
"compose_form.publish": "Postiad",
|
||||||
"compose_form.publish_form": "Cyhoeddi",
|
"compose_form.publish_form": "Postiad newydd",
|
||||||
"compose_form.reply": "Ateb",
|
"compose_form.reply": "Ateb",
|
||||||
"compose_form.save_changes": "Diweddariad",
|
"compose_form.save_changes": "Diweddaru",
|
||||||
"compose_form.spoiler.marked": "Dileu rhybudd cynnwys",
|
"compose_form.spoiler.marked": "Dileu rhybudd cynnwys",
|
||||||
"compose_form.spoiler.unmarked": "Ychwanegu rhybudd cynnwys",
|
"compose_form.spoiler.unmarked": "Ychwanegu rhybudd cynnwys",
|
||||||
"compose_form.spoiler_placeholder": "Rhybudd cynnwys (dewisol)",
|
"compose_form.spoiler_placeholder": "Rhybudd cynnwys (dewisol)",
|
||||||
|
@ -508,6 +527,8 @@
|
||||||
"notification.admin.report_statuses_other": "Adroddodd {name} {target}",
|
"notification.admin.report_statuses_other": "Adroddodd {name} {target}",
|
||||||
"notification.admin.sign_up": "Cofrestrodd {name}",
|
"notification.admin.sign_up": "Cofrestrodd {name}",
|
||||||
"notification.admin.sign_up.name_and_others": "Cofrestrodd {name} {count, plural, one {ac # arall} other {a # arall}}",
|
"notification.admin.sign_up.name_and_others": "Cofrestrodd {name} {count, plural, one {ac # arall} other {a # arall}}",
|
||||||
|
"notification.annual_report.message": "Mae eich #Wrapstodon {year} yn aros i chi! Gwelwch eich uchafbwyntiau ac amseroedd i'w cofio o'r flwyddyn hon ar Mastodon!",
|
||||||
|
"notification.annual_report.view": "Gweld #Wrapstodon",
|
||||||
"notification.favourite": "Ffafriodd {name} eich postiad",
|
"notification.favourite": "Ffafriodd {name} eich postiad",
|
||||||
"notification.favourite.name_and_others_with_link": "Ffafriodd {name} a <a>{count, plural, one {# arall} other {# arall}}</a> eich postiad",
|
"notification.favourite.name_and_others_with_link": "Ffafriodd {name} a <a>{count, plural, one {# arall} other {# arall}}</a> eich postiad",
|
||||||
"notification.follow": "Dilynodd {name} chi",
|
"notification.follow": "Dilynodd {name} chi",
|
||||||
|
|
|
@ -87,6 +87,25 @@
|
||||||
"alert.unexpected.title": "Ups!",
|
"alert.unexpected.title": "Ups!",
|
||||||
"alt_text_badge.title": "Alt text",
|
"alt_text_badge.title": "Alt text",
|
||||||
"announcement.announcement": "Bekendtgørelse",
|
"announcement.announcement": "Bekendtgørelse",
|
||||||
|
"annual_report.summary.archetype.booster": "Cool-hunter",
|
||||||
|
"annual_report.summary.archetype.lurker": "Lurker",
|
||||||
|
"annual_report.summary.archetype.oracle": "Oracle",
|
||||||
|
"annual_report.summary.archetype.pollster": "Pollster",
|
||||||
|
"annual_report.summary.archetype.replier": "Social butterfly",
|
||||||
|
"annual_report.summary.followers.followers": "følgere",
|
||||||
|
"annual_report.summary.followers.total": "{count} i alt",
|
||||||
|
"annual_report.summary.here_it_is": "Her er {year} i sammendrag:",
|
||||||
|
"annual_report.summary.highlighted_post.by_favourites": "mest favoritmarkerede indlæg",
|
||||||
|
"annual_report.summary.highlighted_post.by_reblogs": "mest boostede indlæg",
|
||||||
|
"annual_report.summary.highlighted_post.by_replies": "indlæg med flest svar",
|
||||||
|
"annual_report.summary.highlighted_post.possessive": "{name}s",
|
||||||
|
"annual_report.summary.most_used_app.most_used_app": "mest benyttede app",
|
||||||
|
"annual_report.summary.most_used_hashtag.most_used_hashtag": "mest benyttede hashtag",
|
||||||
|
"annual_report.summary.most_used_hashtag.none": "Intet",
|
||||||
|
"annual_report.summary.new_posts.new_posts": "nye indlæg",
|
||||||
|
"annual_report.summary.percentile.text": "<topLabel>Det betyder, at man er i top</topLabel><percentage></percentage><bottomLabel>af Mastodon-brugere.</bottomLabel>",
|
||||||
|
"annual_report.summary.percentile.we_wont_tell_bernie": "Vi fortæller det ikke til Bernie.",
|
||||||
|
"annual_report.summary.thanks": "Tak for at være en del af Mastodon!",
|
||||||
"attachments_list.unprocessed": "(ubehandlet)",
|
"attachments_list.unprocessed": "(ubehandlet)",
|
||||||
"audio.hide": "Skjul lyd",
|
"audio.hide": "Skjul lyd",
|
||||||
"block_modal.remote_users_caveat": "Serveren {domain} vil blive bedt om at respektere din beslutning. Overholdelse er dog ikke garanteret, da nogle servere kan håndtere blokke forskelligt. Offentlige indlæg kan stadig være synlige for ikke-indloggede brugere.",
|
"block_modal.remote_users_caveat": "Serveren {domain} vil blive bedt om at respektere din beslutning. Overholdelse er dog ikke garanteret, da nogle servere kan håndtere blokke forskelligt. Offentlige indlæg kan stadig være synlige for ikke-indloggede brugere.",
|
||||||
|
@ -158,6 +177,7 @@
|
||||||
"compose_form.poll.duration": "Afstemningens varighed",
|
"compose_form.poll.duration": "Afstemningens varighed",
|
||||||
"compose_form.poll.multiple": "Multivalg",
|
"compose_form.poll.multiple": "Multivalg",
|
||||||
"compose_form.poll.option_placeholder": "Valgmulighed {number}",
|
"compose_form.poll.option_placeholder": "Valgmulighed {number}",
|
||||||
|
"compose_form.poll.single": "Enkeltvalg",
|
||||||
"compose_form.poll.switch_to_multiple": "Ændr afstemning til flervalgstype",
|
"compose_form.poll.switch_to_multiple": "Ændr afstemning til flervalgstype",
|
||||||
"compose_form.poll.switch_to_single": "Ændr afstemning til enkeltvalgstype",
|
"compose_form.poll.switch_to_single": "Ændr afstemning til enkeltvalgstype",
|
||||||
"compose_form.poll.type": "Stil",
|
"compose_form.poll.type": "Stil",
|
||||||
|
@ -507,6 +527,8 @@
|
||||||
"notification.admin.report_statuses_other": "{name} anmeldte {target}",
|
"notification.admin.report_statuses_other": "{name} anmeldte {target}",
|
||||||
"notification.admin.sign_up": "{name} tilmeldte sig",
|
"notification.admin.sign_up": "{name} tilmeldte sig",
|
||||||
"notification.admin.sign_up.name_and_others": "{name} og {count, plural, one {# anden} other {# andre}} tilmeldte sig",
|
"notification.admin.sign_up.name_and_others": "{name} og {count, plural, one {# anden} other {# andre}} tilmeldte sig",
|
||||||
|
"notification.annual_report.message": "{year} #Wrapstodon venter! Afslør årets højdepunkter og mindeværdige øjeblikke på Mastodon!",
|
||||||
|
"notification.annual_report.view": "Vis #Wrapstodon",
|
||||||
"notification.favourite": "{name} favoritmarkerede dit indlæg",
|
"notification.favourite": "{name} favoritmarkerede dit indlæg",
|
||||||
"notification.favourite.name_and_others_with_link": "{name} og <a>{count, plural, one {# anden} other {# andre}}</a> gjorde dit indlæg til favorit",
|
"notification.favourite.name_and_others_with_link": "{name} og <a>{count, plural, one {# anden} other {# andre}}</a> gjorde dit indlæg til favorit",
|
||||||
"notification.follow": "{name} begyndte at følge dig",
|
"notification.follow": "{name} begyndte at følge dig",
|
||||||
|
|
|
@ -87,6 +87,25 @@
|
||||||
"alert.unexpected.title": "Oha!",
|
"alert.unexpected.title": "Oha!",
|
||||||
"alt_text_badge.title": "Bildbeschreibung",
|
"alt_text_badge.title": "Bildbeschreibung",
|
||||||
"announcement.announcement": "Ankündigung",
|
"announcement.announcement": "Ankündigung",
|
||||||
|
"annual_report.summary.archetype.booster": "Trendjäger*in",
|
||||||
|
"annual_report.summary.archetype.lurker": "Beobachter*in",
|
||||||
|
"annual_report.summary.archetype.oracle": "Orakel",
|
||||||
|
"annual_report.summary.archetype.pollster": "Meinungsforscher*in",
|
||||||
|
"annual_report.summary.archetype.replier": "Geselliger Schmetterling",
|
||||||
|
"annual_report.summary.followers.followers": "Follower",
|
||||||
|
"annual_report.summary.followers.total": "{count} insgesamt",
|
||||||
|
"annual_report.summary.here_it_is": "Dein Jahresrückblick für {year}:",
|
||||||
|
"annual_report.summary.highlighted_post.by_favourites": "am häufigsten favorisierter Beitrag",
|
||||||
|
"annual_report.summary.highlighted_post.by_reblogs": "am häufigsten geteilter Beitrag",
|
||||||
|
"annual_report.summary.highlighted_post.by_replies": "Beitrag mit den meisten Antworten",
|
||||||
|
"annual_report.summary.highlighted_post.possessive": "{name}",
|
||||||
|
"annual_report.summary.most_used_app.most_used_app": "am häufigsten verwendete App",
|
||||||
|
"annual_report.summary.most_used_hashtag.most_used_hashtag": "am häufigsten verwendeter Hashtag",
|
||||||
|
"annual_report.summary.most_used_hashtag.none": "Kein",
|
||||||
|
"annual_report.summary.new_posts.new_posts": "neue Beiträge",
|
||||||
|
"annual_report.summary.percentile.text": "<topLabel>Damit gehörst du zu den obersten</topLabel><percentage></percentage><bottomLabel>der Mastodon-Nutzer*innen.</bottomLabel>",
|
||||||
|
"annual_report.summary.percentile.we_wont_tell_bernie": "Wir werden Bernie nichts verraten.",
|
||||||
|
"annual_report.summary.thanks": "Danke, dass du Teil von Mastodon bist!",
|
||||||
"attachments_list.unprocessed": "(ausstehend)",
|
"attachments_list.unprocessed": "(ausstehend)",
|
||||||
"audio.hide": "Audio ausblenden",
|
"audio.hide": "Audio ausblenden",
|
||||||
"block_modal.remote_users_caveat": "Wir werden den Server {domain} bitten, deine Entscheidung zu respektieren. Allerdings kann nicht garantiert werden, dass sie eingehalten wird, weil einige Server Blockierungen unterschiedlich handhaben können. Öffentliche Beiträge können für nicht angemeldete Nutzer*innen weiterhin sichtbar sein.",
|
"block_modal.remote_users_caveat": "Wir werden den Server {domain} bitten, deine Entscheidung zu respektieren. Allerdings kann nicht garantiert werden, dass sie eingehalten wird, weil einige Server Blockierungen unterschiedlich handhaben können. Öffentliche Beiträge können für nicht angemeldete Nutzer*innen weiterhin sichtbar sein.",
|
||||||
|
@ -507,13 +526,15 @@
|
||||||
"notification.admin.report_statuses": "{name} meldete {target} wegen {category}",
|
"notification.admin.report_statuses": "{name} meldete {target} wegen {category}",
|
||||||
"notification.admin.report_statuses_other": "{name} meldete {target}",
|
"notification.admin.report_statuses_other": "{name} meldete {target}",
|
||||||
"notification.admin.sign_up": "{name} registrierte sich",
|
"notification.admin.sign_up": "{name} registrierte sich",
|
||||||
"notification.admin.sign_up.name_and_others": "{name} und {count, plural, one {# weitere Person} other {# weitere Personen}} registrierten sich",
|
"notification.admin.sign_up.name_and_others": "{name} und {count, plural, one {# weiteres Profil} other {# weitere Profile}} registrierten sich",
|
||||||
|
"notification.annual_report.message": "Dein {year} #Wrapstodon erwartet dich! Lass deine Highlights und unvergesslichen Momente auf Mastodon erneut aufleben!",
|
||||||
|
"notification.annual_report.view": "#Wrapstodon ansehen",
|
||||||
"notification.favourite": "{name} favorisierte deinen Beitrag",
|
"notification.favourite": "{name} favorisierte deinen Beitrag",
|
||||||
"notification.favourite.name_and_others_with_link": "{name} und <a>{count, plural, one {# weitere Person} other {# weitere Personen}}</a> favorisierten deinen Beitrag",
|
"notification.favourite.name_and_others_with_link": "{name} und <a>{count, plural, one {# weiteres Profil} other {# weitere Profile}}</a> favorisierten deinen Beitrag",
|
||||||
"notification.follow": "{name} folgt dir",
|
"notification.follow": "{name} folgt dir",
|
||||||
"notification.follow.name_and_others": "{name} und <a>{count, plural, one {# weitere Person} other {# weitere Personen}}</a> folgen dir",
|
"notification.follow.name_and_others": "{name} und <a>{count, plural, one {# weiteres Profil} other {# weitere Profile}}</a> folgen dir",
|
||||||
"notification.follow_request": "{name} möchte dir folgen",
|
"notification.follow_request": "{name} möchte dir folgen",
|
||||||
"notification.follow_request.name_and_others": "{name} und {count, plural, one {# weitere Person} other {# weitere Personen}} möchten dir folgen",
|
"notification.follow_request.name_and_others": "{name} und {count, plural, one {# weiteres Profil} other {# weitere Profile}} möchten dir folgen",
|
||||||
"notification.label.mention": "Erwähnung",
|
"notification.label.mention": "Erwähnung",
|
||||||
"notification.label.private_mention": "Private Erwähnung",
|
"notification.label.private_mention": "Private Erwähnung",
|
||||||
"notification.label.private_reply": "Private Antwort",
|
"notification.label.private_reply": "Private Antwort",
|
||||||
|
@ -532,7 +553,7 @@
|
||||||
"notification.own_poll": "Deine Umfrage ist beendet",
|
"notification.own_poll": "Deine Umfrage ist beendet",
|
||||||
"notification.poll": "Eine Umfrage, an der du teilgenommen hast, ist beendet",
|
"notification.poll": "Eine Umfrage, an der du teilgenommen hast, ist beendet",
|
||||||
"notification.reblog": "{name} teilte deinen Beitrag",
|
"notification.reblog": "{name} teilte deinen Beitrag",
|
||||||
"notification.reblog.name_and_others_with_link": "{name} und <a>{count, plural, one {# weitere Person} other {# weitere Personen}}</a> teilten deinen Beitrag",
|
"notification.reblog.name_and_others_with_link": "{name} und <a>{count, plural, one {# weiteres Profil} other {# weitere Profile}}</a> teilten deinen Beitrag",
|
||||||
"notification.relationships_severance_event": "Verbindungen mit {name} verloren",
|
"notification.relationships_severance_event": "Verbindungen mit {name} verloren",
|
||||||
"notification.relationships_severance_event.account_suspension": "Ein Admin von {from} hat {target} gesperrt. Du wirst von diesem Profil keine Updates mehr erhalten und auch nicht mit ihm interagieren können.",
|
"notification.relationships_severance_event.account_suspension": "Ein Admin von {from} hat {target} gesperrt. Du wirst von diesem Profil keine Updates mehr erhalten und auch nicht mit ihm interagieren können.",
|
||||||
"notification.relationships_severance_event.domain_block": "Ein Admin von {from} hat {target} blockiert – darunter {followersCount} deiner Follower und {followingCount, plural, one {# Konto, dem} other {# Konten, denen}} du folgst.",
|
"notification.relationships_severance_event.domain_block": "Ein Admin von {from} hat {target} blockiert – darunter {followersCount} deiner Follower und {followingCount, plural, one {# Konto, dem} other {# Konten, denen}} du folgst.",
|
||||||
|
|
|
@ -87,6 +87,24 @@
|
||||||
"alert.unexpected.title": "Ουπς!",
|
"alert.unexpected.title": "Ουπς!",
|
||||||
"alt_text_badge.title": "Εναλλακτικό κείμενο",
|
"alt_text_badge.title": "Εναλλακτικό κείμενο",
|
||||||
"announcement.announcement": "Ανακοίνωση",
|
"announcement.announcement": "Ανακοίνωση",
|
||||||
|
"annual_report.summary.archetype.booster": "Ο κυνηγός των φοβερών",
|
||||||
|
"annual_report.summary.archetype.lurker": "Ο διακριτικός",
|
||||||
|
"annual_report.summary.archetype.oracle": "Η Πυθία",
|
||||||
|
"annual_report.summary.archetype.pollster": "Ο δημοσκόπος",
|
||||||
|
"annual_report.summary.archetype.replier": "Η κοινωνική πεταλούδα",
|
||||||
|
"annual_report.summary.followers.followers": "ακόλουθοι",
|
||||||
|
"annual_report.summary.followers.total": "{count} συνολικά",
|
||||||
|
"annual_report.summary.here_it_is": "Εδώ είναι το {year} σου σε ανασκόπηση:",
|
||||||
|
"annual_report.summary.highlighted_post.by_favourites": "πιο αγαπημένη ανάρτηση",
|
||||||
|
"annual_report.summary.highlighted_post.by_reblogs": "πιο ενισχυμένη ανάρτηση",
|
||||||
|
"annual_report.summary.highlighted_post.by_replies": "ανάρτηση με τις περισσότερες απαντήσεις",
|
||||||
|
"annual_report.summary.highlighted_post.possessive": "του χρήστη {name}",
|
||||||
|
"annual_report.summary.most_used_app.most_used_app": "πιο χρησιμοποιημένη εφαρμογή",
|
||||||
|
"annual_report.summary.most_used_hashtag.most_used_hashtag": "πιο χρησιμοποιημένη ετικέτα",
|
||||||
|
"annual_report.summary.new_posts.new_posts": "νέες αναρτήσεις",
|
||||||
|
"annual_report.summary.percentile.text": "<topLabel>Αυτό σε βάζει στην κορυφή του </topLabel><percentage></percentage><bottomLabel>των χρηστών του Mastodon.</bottomLabel>",
|
||||||
|
"annual_report.summary.percentile.we_wont_tell_bernie": "Δεν θα το πούμε στον Bernie.",
|
||||||
|
"annual_report.summary.thanks": "Ευχαριστούμε που συμμετέχεις στο Mastodon!",
|
||||||
"attachments_list.unprocessed": "(μη επεξεργασμένο)",
|
"attachments_list.unprocessed": "(μη επεξεργασμένο)",
|
||||||
"audio.hide": "Απόκρυψη αρχείου ήχου",
|
"audio.hide": "Απόκρυψη αρχείου ήχου",
|
||||||
"block_modal.remote_users_caveat": "Θα ζητήσουμε από τον διακομιστή {domain} να σεβαστεί την απόφασή σου. Ωστόσο, η συμμόρφωση δεν είναι εγγυημένη δεδομένου ότι ορισμένοι διακομιστές ενδέχεται να χειρίζονται τους αποκλεισμούς διαφορετικά. Οι δημόσιες αναρτήσεις ενδέχεται να είναι ορατές σε μη συνδεδεμένους χρήστες.",
|
"block_modal.remote_users_caveat": "Θα ζητήσουμε από τον διακομιστή {domain} να σεβαστεί την απόφασή σου. Ωστόσο, η συμμόρφωση δεν είναι εγγυημένη δεδομένου ότι ορισμένοι διακομιστές ενδέχεται να χειρίζονται τους αποκλεισμούς διαφορετικά. Οι δημόσιες αναρτήσεις ενδέχεται να είναι ορατές σε μη συνδεδεμένους χρήστες.",
|
||||||
|
@ -158,6 +176,7 @@
|
||||||
"compose_form.poll.duration": "Διάρκεια δημοσκόπησης",
|
"compose_form.poll.duration": "Διάρκεια δημοσκόπησης",
|
||||||
"compose_form.poll.multiple": "Πολλαπλή επιλογή",
|
"compose_form.poll.multiple": "Πολλαπλή επιλογή",
|
||||||
"compose_form.poll.option_placeholder": "Επιλογή {number}",
|
"compose_form.poll.option_placeholder": "Επιλογή {number}",
|
||||||
|
"compose_form.poll.single": "Μονή επιλογή",
|
||||||
"compose_form.poll.switch_to_multiple": "Ενημέρωση δημοσκόπησης με πολλαπλές επιλογές",
|
"compose_form.poll.switch_to_multiple": "Ενημέρωση δημοσκόπησης με πολλαπλές επιλογές",
|
||||||
"compose_form.poll.switch_to_single": "Ενημέρωση δημοσκόπησης με μοναδική επιλογή",
|
"compose_form.poll.switch_to_single": "Ενημέρωση δημοσκόπησης με μοναδική επιλογή",
|
||||||
"compose_form.poll.type": "Στυλ",
|
"compose_form.poll.type": "Στυλ",
|
||||||
|
@ -196,6 +215,7 @@
|
||||||
"confirmations.unfollow.title": "Άρση ακολούθησης;",
|
"confirmations.unfollow.title": "Άρση ακολούθησης;",
|
||||||
"content_warning.hide": "Απόκρυψη ανάρτησης",
|
"content_warning.hide": "Απόκρυψη ανάρτησης",
|
||||||
"content_warning.show": "Εμφάνιση ούτως ή άλλως",
|
"content_warning.show": "Εμφάνιση ούτως ή άλλως",
|
||||||
|
"content_warning.show_more": "Εμφάνιση περισσότερων",
|
||||||
"conversation.delete": "Διαγραφή συζήτησης",
|
"conversation.delete": "Διαγραφή συζήτησης",
|
||||||
"conversation.mark_as_read": "Σήμανση ως αναγνωσμένο",
|
"conversation.mark_as_read": "Σήμανση ως αναγνωσμένο",
|
||||||
"conversation.open": "Προβολή συνομιλίας",
|
"conversation.open": "Προβολή συνομιλίας",
|
||||||
|
@ -304,6 +324,7 @@
|
||||||
"filter_modal.select_filter.subtitle": "Χρησιμοποιήστε μια υπάρχουσα κατηγορία ή δημιουργήστε μια νέα",
|
"filter_modal.select_filter.subtitle": "Χρησιμοποιήστε μια υπάρχουσα κατηγορία ή δημιουργήστε μια νέα",
|
||||||
"filter_modal.select_filter.title": "Φιλτράρισμα αυτής της ανάρτησης",
|
"filter_modal.select_filter.title": "Φιλτράρισμα αυτής της ανάρτησης",
|
||||||
"filter_modal.title.status": "Φιλτράρισμα μιας ανάρτησης",
|
"filter_modal.title.status": "Φιλτράρισμα μιας ανάρτησης",
|
||||||
|
"filter_warning.matches_filter": "Ταιριάζει με το φίλτρο “<span>{title}</span>”",
|
||||||
"filtered_notifications_banner.pending_requests": "Από {count, plural, =0 {κανένα} one {ένα άτομο} other {# άτομα}} που μπορεί να ξέρεις",
|
"filtered_notifications_banner.pending_requests": "Από {count, plural, =0 {κανένα} one {ένα άτομο} other {# άτομα}} που μπορεί να ξέρεις",
|
||||||
"filtered_notifications_banner.title": "Φιλτραρισμένες ειδοποιήσεις",
|
"filtered_notifications_banner.title": "Φιλτραρισμένες ειδοποιήσεις",
|
||||||
"firehose.all": "Όλα",
|
"firehose.all": "Όλα",
|
||||||
|
@ -383,9 +404,10 @@
|
||||||
"interaction_modal.description.follow": "Με έναν λογαριασμό Mastodon, μπορείς να ακολουθήσεις τον/την {name} ώστε να λαμβάνεις τις αναρτήσεις του/της στη δική σου ροή.",
|
"interaction_modal.description.follow": "Με έναν λογαριασμό Mastodon, μπορείς να ακολουθήσεις τον/την {name} ώστε να λαμβάνεις τις αναρτήσεις του/της στη δική σου ροή.",
|
||||||
"interaction_modal.description.reblog": "Με ένα λογαριασμό Mastodon, μπορείς να ενισχύσεις αυτή την ανάρτηση για να τη μοιραστείς με τους δικούς σου ακολούθους.",
|
"interaction_modal.description.reblog": "Με ένα λογαριασμό Mastodon, μπορείς να ενισχύσεις αυτή την ανάρτηση για να τη μοιραστείς με τους δικούς σου ακολούθους.",
|
||||||
"interaction_modal.description.reply": "Με ένα λογαριασμό Mastodon, μπορείς να απαντήσεις σε αυτή την ανάρτηση.",
|
"interaction_modal.description.reply": "Με ένα λογαριασμό Mastodon, μπορείς να απαντήσεις σε αυτή την ανάρτηση.",
|
||||||
"interaction_modal.login.action": "Take me home\nΠήγαινέ με στην αρχική σελίδα",
|
"interaction_modal.description.vote": "Με ένα λογαριασμό Mastodon, μπορείς να απαντήσεις σ' αυτή την ανάρτηση.",
|
||||||
|
"interaction_modal.login.action": "Πήγαινέ με στην αρχική σελίδα",
|
||||||
"interaction_modal.login.prompt": "Τομέας του οικιακού σου διακομιστή, πχ. mastodon.social",
|
"interaction_modal.login.prompt": "Τομέας του οικιακού σου διακομιστή, πχ. mastodon.social",
|
||||||
"interaction_modal.no_account_yet": "Not on Mastodon?\nΔεν είστε στο Mastodon;",
|
"interaction_modal.no_account_yet": "Δεν είστε στο Mastodon;",
|
||||||
"interaction_modal.on_another_server": "Σε διαφορετικό διακομιστή",
|
"interaction_modal.on_another_server": "Σε διαφορετικό διακομιστή",
|
||||||
"interaction_modal.on_this_server": "Σε αυτόν τον διακομιστή",
|
"interaction_modal.on_this_server": "Σε αυτόν τον διακομιστή",
|
||||||
"interaction_modal.sign_in": "Δεν είσαι συνδεδεμένος σε αυτόν το διακομιστή. Πού φιλοξενείται ο λογαριασμός σου;",
|
"interaction_modal.sign_in": "Δεν είσαι συνδεδεμένος σε αυτόν το διακομιστή. Πού φιλοξενείται ο λογαριασμός σου;",
|
||||||
|
@ -394,6 +416,7 @@
|
||||||
"interaction_modal.title.follow": "Ακολούθησε {name}",
|
"interaction_modal.title.follow": "Ακολούθησε {name}",
|
||||||
"interaction_modal.title.reblog": "Ενίσχυσε την ανάρτηση του {name}",
|
"interaction_modal.title.reblog": "Ενίσχυσε την ανάρτηση του {name}",
|
||||||
"interaction_modal.title.reply": "Απάντηση στην ανάρτηση του {name}",
|
"interaction_modal.title.reply": "Απάντηση στην ανάρτηση του {name}",
|
||||||
|
"interaction_modal.title.vote": "Ψήφισε στη δημοσκόπηση του χρήστη {name}",
|
||||||
"intervals.full.days": "{number, plural, one {# μέρα} other {# μέρες}}",
|
"intervals.full.days": "{number, plural, one {# μέρα} other {# μέρες}}",
|
||||||
"intervals.full.hours": "{number, plural, one {# ώρα} other {# ώρες}}",
|
"intervals.full.hours": "{number, plural, one {# ώρα} other {# ώρες}}",
|
||||||
"intervals.full.minutes": "{number, plural, one {# λεπτό} other {# λεπτά}}",
|
"intervals.full.minutes": "{number, plural, one {# λεπτό} other {# λεπτά}}",
|
||||||
|
@ -503,9 +526,12 @@
|
||||||
"notification.admin.report_statuses_other": "Ο χρήστης {name} ανέφερε τον χρήστη {target}",
|
"notification.admin.report_statuses_other": "Ο χρήστης {name} ανέφερε τον χρήστη {target}",
|
||||||
"notification.admin.sign_up": "{name} έχει εγγραφεί",
|
"notification.admin.sign_up": "{name} έχει εγγραφεί",
|
||||||
"notification.admin.sign_up.name_and_others": "{name} και {count, plural, one {# ακόμη} other {# ακόμη}} έχουν εγγραφεί",
|
"notification.admin.sign_up.name_and_others": "{name} και {count, plural, one {# ακόμη} other {# ακόμη}} έχουν εγγραφεί",
|
||||||
|
"notification.annual_report.message": "Το #Wrapstodon {year} σε περιμένει! Αποκάλυψε τα στιγμιότυπα της χρονιάς και αξέχαστες στιγμές σου στο Mastodon!",
|
||||||
|
"notification.annual_report.view": "Προβολή #Wrapstodon",
|
||||||
"notification.favourite": "{name} favorited your post\n{name} προτίμησε την ανάρτηση σου",
|
"notification.favourite": "{name} favorited your post\n{name} προτίμησε την ανάρτηση σου",
|
||||||
"notification.favourite.name_and_others_with_link": "{name} και <a>{count, plural, one {# ακόμη} other {# ακόμη}}</a> αγάπησαν την ανάρτησή σου",
|
"notification.favourite.name_and_others_with_link": "{name} και <a>{count, plural, one {# ακόμη} other {# ακόμη}}</a> αγάπησαν την ανάρτησή σου",
|
||||||
"notification.follow": "Ο/Η {name} σε ακολούθησε",
|
"notification.follow": "Ο/Η {name} σε ακολούθησε",
|
||||||
|
"notification.follow.name_and_others": "Ο χρήστης {name} και <a>{count, plural, one {# ακόμη} other {# ακόμη}}</a> σε ακολούθησαν",
|
||||||
"notification.follow_request": "Ο/H {name} ζήτησε να σε ακολουθήσει",
|
"notification.follow_request": "Ο/H {name} ζήτησε να σε ακολουθήσει",
|
||||||
"notification.follow_request.name_and_others": "{name} και {count, plural, one {# άλλος} other {# άλλοι}} ζήτησαν να σε ακολουθήσουν",
|
"notification.follow_request.name_and_others": "{name} και {count, plural, one {# άλλος} other {# άλλοι}} ζήτησαν να σε ακολουθήσουν",
|
||||||
"notification.label.mention": "Επισήμανση",
|
"notification.label.mention": "Επισήμανση",
|
||||||
|
@ -513,6 +539,7 @@
|
||||||
"notification.label.private_reply": "Ιδιωτική απάντηση",
|
"notification.label.private_reply": "Ιδιωτική απάντηση",
|
||||||
"notification.label.reply": "Απάντηση",
|
"notification.label.reply": "Απάντηση",
|
||||||
"notification.mention": "Επισήμανση",
|
"notification.mention": "Επισήμανση",
|
||||||
|
"notification.mentioned_you": "Ο χρήστης {name} σε επισήμανε",
|
||||||
"notification.moderation-warning.learn_more": "Μάθε περισσότερα",
|
"notification.moderation-warning.learn_more": "Μάθε περισσότερα",
|
||||||
"notification.moderation_warning": "Έχετε λάβει μία προειδοποίηση συντονισμού",
|
"notification.moderation_warning": "Έχετε λάβει μία προειδοποίηση συντονισμού",
|
||||||
"notification.moderation_warning.action_delete_statuses": "Ορισμένες από τις αναρτήσεις σου έχουν αφαιρεθεί.",
|
"notification.moderation_warning.action_delete_statuses": "Ορισμένες από τις αναρτήσεις σου έχουν αφαιρεθεί.",
|
||||||
|
@ -563,6 +590,7 @@
|
||||||
"notifications.column_settings.filter_bar.category": "Μπάρα γρήγορου φίλτρου",
|
"notifications.column_settings.filter_bar.category": "Μπάρα γρήγορου φίλτρου",
|
||||||
"notifications.column_settings.follow": "Νέοι ακόλουθοι:",
|
"notifications.column_settings.follow": "Νέοι ακόλουθοι:",
|
||||||
"notifications.column_settings.follow_request": "Νέο αίτημα ακολούθησης:",
|
"notifications.column_settings.follow_request": "Νέο αίτημα ακολούθησης:",
|
||||||
|
"notifications.column_settings.group": "Ομάδα",
|
||||||
"notifications.column_settings.mention": "Επισημάνσεις:",
|
"notifications.column_settings.mention": "Επισημάνσεις:",
|
||||||
"notifications.column_settings.poll": "Αποτελέσματα δημοσκόπησης:",
|
"notifications.column_settings.poll": "Αποτελέσματα δημοσκόπησης:",
|
||||||
"notifications.column_settings.push": "Ειδοποιήσεις Push",
|
"notifications.column_settings.push": "Ειδοποιήσεις Push",
|
||||||
|
|
|
@ -87,6 +87,25 @@
|
||||||
"alert.unexpected.title": "Oops!",
|
"alert.unexpected.title": "Oops!",
|
||||||
"alt_text_badge.title": "Alt text",
|
"alt_text_badge.title": "Alt text",
|
||||||
"announcement.announcement": "Announcement",
|
"announcement.announcement": "Announcement",
|
||||||
|
"annual_report.summary.archetype.booster": "The cool-hunter",
|
||||||
|
"annual_report.summary.archetype.lurker": "The lurker",
|
||||||
|
"annual_report.summary.archetype.oracle": "The oracle",
|
||||||
|
"annual_report.summary.archetype.pollster": "The pollster",
|
||||||
|
"annual_report.summary.archetype.replier": "The social butterfly",
|
||||||
|
"annual_report.summary.followers.followers": "followers",
|
||||||
|
"annual_report.summary.followers.total": "{count} total",
|
||||||
|
"annual_report.summary.here_it_is": "Here is your {year} in review:",
|
||||||
|
"annual_report.summary.highlighted_post.by_favourites": "most favourited post",
|
||||||
|
"annual_report.summary.highlighted_post.by_reblogs": "most boosted post",
|
||||||
|
"annual_report.summary.highlighted_post.by_replies": "post with the most replies",
|
||||||
|
"annual_report.summary.highlighted_post.possessive": "{name}'s",
|
||||||
|
"annual_report.summary.most_used_app.most_used_app": "most used app",
|
||||||
|
"annual_report.summary.most_used_hashtag.most_used_hashtag": "most used hashtag",
|
||||||
|
"annual_report.summary.most_used_hashtag.none": "None",
|
||||||
|
"annual_report.summary.new_posts.new_posts": "new posts",
|
||||||
|
"annual_report.summary.percentile.text": "<topLabel>That puts you in the top</topLabel><percentage></percentage><bottomLabel>of Mastodon users.</bottomLabel>",
|
||||||
|
"annual_report.summary.percentile.we_wont_tell_bernie": "We won't tell Bernie.",
|
||||||
|
"annual_report.summary.thanks": "Thanks for being part of Mastodon!",
|
||||||
"attachments_list.unprocessed": "(unprocessed)",
|
"attachments_list.unprocessed": "(unprocessed)",
|
||||||
"audio.hide": "Hide audio",
|
"audio.hide": "Hide audio",
|
||||||
"block_modal.remote_users_caveat": "We will ask the server {domain} to respect your decision. However, compliance is not guaranteed since some servers may handle blocks differently. Public posts may still be visible to non-logged-in users.",
|
"block_modal.remote_users_caveat": "We will ask the server {domain} to respect your decision. However, compliance is not guaranteed since some servers may handle blocks differently. Public posts may still be visible to non-logged-in users.",
|
||||||
|
@ -508,6 +527,8 @@
|
||||||
"notification.admin.report_statuses_other": "{name} reported {target}",
|
"notification.admin.report_statuses_other": "{name} reported {target}",
|
||||||
"notification.admin.sign_up": "{name} signed up",
|
"notification.admin.sign_up": "{name} signed up",
|
||||||
"notification.admin.sign_up.name_and_others": "{name} and {count, plural, one {# other} other {# others}} signed up",
|
"notification.admin.sign_up.name_and_others": "{name} and {count, plural, one {# other} other {# others}} signed up",
|
||||||
|
"notification.annual_report.message": "Your {year} #Wrapstodon awaits! Unveil your year's highlights and memorable moments on Mastodon!",
|
||||||
|
"notification.annual_report.view": "View #Wrapstodon",
|
||||||
"notification.favourite": "{name} favorited your post",
|
"notification.favourite": "{name} favorited your post",
|
||||||
"notification.favourite.name_and_others_with_link": "{name} and <a>{count, plural, one {# other} other {# others}}</a> favorited your post",
|
"notification.favourite.name_and_others_with_link": "{name} and <a>{count, plural, one {# other} other {# others}}</a> favorited your post",
|
||||||
"notification.follow": "{name} followed you",
|
"notification.follow": "{name} followed you",
|
||||||
|
|
|
@ -45,7 +45,7 @@
|
||||||
"account.languages": "Ŝanĝi la abonitajn lingvojn",
|
"account.languages": "Ŝanĝi la abonitajn lingvojn",
|
||||||
"account.link_verified_on": "Propreco de tiu ligilo estis konfirmita je {date}",
|
"account.link_verified_on": "Propreco de tiu ligilo estis konfirmita je {date}",
|
||||||
"account.locked_info": "Tiu konto estas privatigita. La posedanto mane akceptas tiun, kiu povas sekvi rin.",
|
"account.locked_info": "Tiu konto estas privatigita. La posedanto mane akceptas tiun, kiu povas sekvi rin.",
|
||||||
"account.media": "Plurmedioj",
|
"account.media": "Plurmedio",
|
||||||
"account.mention": "Mencii @{name}",
|
"account.mention": "Mencii @{name}",
|
||||||
"account.moved_to": "{name} indikis, ke ria nova konto estas nun:",
|
"account.moved_to": "{name} indikis, ke ria nova konto estas nun:",
|
||||||
"account.mute": "Silentigi @{name}",
|
"account.mute": "Silentigi @{name}",
|
||||||
|
@ -87,6 +87,13 @@
|
||||||
"alert.unexpected.title": "Aj!",
|
"alert.unexpected.title": "Aj!",
|
||||||
"alt_text_badge.title": "Alt-teksto",
|
"alt_text_badge.title": "Alt-teksto",
|
||||||
"announcement.announcement": "Anonco",
|
"announcement.announcement": "Anonco",
|
||||||
|
"annual_report.summary.archetype.replier": "La plej societema",
|
||||||
|
"annual_report.summary.followers.followers": "sekvantoj",
|
||||||
|
"annual_report.summary.highlighted_post.by_replies": "afiŝo kun la plej multaj respondoj",
|
||||||
|
"annual_report.summary.most_used_app.most_used_app": "plej uzita apo",
|
||||||
|
"annual_report.summary.most_used_hashtag.none": "Nenio",
|
||||||
|
"annual_report.summary.new_posts.new_posts": "novaj afiŝoj",
|
||||||
|
"annual_report.summary.thanks": "Dankon pro esti parto de Mastodon!",
|
||||||
"attachments_list.unprocessed": "(neprilaborita)",
|
"attachments_list.unprocessed": "(neprilaborita)",
|
||||||
"audio.hide": "Kaŝi aŭdion",
|
"audio.hide": "Kaŝi aŭdion",
|
||||||
"block_modal.remote_users_caveat": "Ni petos al la servilo {domain} respekti vian elekton. Tamen, plenumo ne estas garantiita ĉar iuj serviloj eble manipulas blokojn malsame. Publikaj afiŝoj eble ankoraŭ estas videbla por ne-ensalutintaj uzantoj.",
|
"block_modal.remote_users_caveat": "Ni petos al la servilo {domain} respekti vian elekton. Tamen, plenumo ne estas garantiita ĉar iuj serviloj eble manipulas blokojn malsame. Publikaj afiŝoj eble ankoraŭ estas videbla por ne-ensalutintaj uzantoj.",
|
||||||
|
@ -142,7 +149,7 @@
|
||||||
"column_header.unpin": "Malfiksi",
|
"column_header.unpin": "Malfiksi",
|
||||||
"column_subheading.settings": "Agordoj",
|
"column_subheading.settings": "Agordoj",
|
||||||
"community.column_settings.local_only": "Nur loka",
|
"community.column_settings.local_only": "Nur loka",
|
||||||
"community.column_settings.media_only": "Nur plurmedioj",
|
"community.column_settings.media_only": "Nur plurmedio",
|
||||||
"community.column_settings.remote_only": "Nur fora",
|
"community.column_settings.remote_only": "Nur fora",
|
||||||
"compose.language.change": "Ŝanĝi lingvon",
|
"compose.language.change": "Ŝanĝi lingvon",
|
||||||
"compose.language.search": "Serĉi lingvojn...",
|
"compose.language.search": "Serĉi lingvojn...",
|
||||||
|
@ -214,7 +221,7 @@
|
||||||
"dismissable_banner.community_timeline": "Jen la plej novaj publikaj afiŝoj de uzantoj, kies kontojn gastigas {domain}.",
|
"dismissable_banner.community_timeline": "Jen la plej novaj publikaj afiŝoj de uzantoj, kies kontojn gastigas {domain}.",
|
||||||
"dismissable_banner.dismiss": "Eksigi",
|
"dismissable_banner.dismiss": "Eksigi",
|
||||||
"dismissable_banner.explore_links": "Tiuj novaĵoj estas aktuale priparolataj de uzantoj en tiu ĉi kaj aliaj serviloj, sur la malcentrigita reto.",
|
"dismissable_banner.explore_links": "Tiuj novaĵoj estas aktuale priparolataj de uzantoj en tiu ĉi kaj aliaj serviloj, sur la malcentrigita reto.",
|
||||||
"dismissable_banner.explore_statuses": "Ĉi tiuj estas afiŝoj de la tuta socia reto, kiuj populariĝas hodiaŭ. Pli novaj afiŝoj kun pli da diskonigoj kaj plej ŝatataj estas rangigitaj pli alte.",
|
"dismissable_banner.explore_statuses": "Jen afiŝoj en la socia reto kiuj populariĝis hodiaŭ. Novaj afiŝoj kun pli da diskonigoj kaj stelumoj aperas pli alte.",
|
||||||
"dismissable_banner.explore_tags": "Ĉi tiuj kradvostoj populariĝas en ĉi tiu kaj aliaj serviloj en la malcentraliza reto nun.",
|
"dismissable_banner.explore_tags": "Ĉi tiuj kradvostoj populariĝas en ĉi tiu kaj aliaj serviloj en la malcentraliza reto nun.",
|
||||||
"dismissable_banner.public_timeline": "Ĉi tiuj estas la plej lastatempaj publikaj afiŝoj de homoj en la socia reto, kiujn homoj sur {domain} sekvas.",
|
"dismissable_banner.public_timeline": "Ĉi tiuj estas la plej lastatempaj publikaj afiŝoj de homoj en la socia reto, kiujn homoj sur {domain} sekvas.",
|
||||||
"domain_block_modal.block": "Bloki servilon",
|
"domain_block_modal.block": "Bloki servilon",
|
||||||
|
@ -333,7 +340,7 @@
|
||||||
"followed_tags": "Sekvataj kradvortoj",
|
"followed_tags": "Sekvataj kradvortoj",
|
||||||
"footer.about": "Pri",
|
"footer.about": "Pri",
|
||||||
"footer.directory": "Profilujo",
|
"footer.directory": "Profilujo",
|
||||||
"footer.get_app": "Akiru la Programon",
|
"footer.get_app": "Akiri la apon",
|
||||||
"footer.invite": "Inviti homojn",
|
"footer.invite": "Inviti homojn",
|
||||||
"footer.keyboard_shortcuts": "Fulmoklavoj",
|
"footer.keyboard_shortcuts": "Fulmoklavoj",
|
||||||
"footer.privacy_policy": "Politiko de privateco",
|
"footer.privacy_policy": "Politiko de privateco",
|
||||||
|
@ -382,7 +389,7 @@
|
||||||
"ignore_notifications_modal.not_followers_title": "Ĉu ignori sciigojn de homoj, kiuj ne sekvas vin?",
|
"ignore_notifications_modal.not_followers_title": "Ĉu ignori sciigojn de homoj, kiuj ne sekvas vin?",
|
||||||
"ignore_notifications_modal.not_following_title": "Ĉu ignori sciigojn de homoj, kiujn vi ne sekvas?",
|
"ignore_notifications_modal.not_following_title": "Ĉu ignori sciigojn de homoj, kiujn vi ne sekvas?",
|
||||||
"ignore_notifications_modal.private_mentions_title": "Ĉu ignori sciigojn de nepetitaj privataj mencioj?",
|
"ignore_notifications_modal.private_mentions_title": "Ĉu ignori sciigojn de nepetitaj privataj mencioj?",
|
||||||
"interaction_modal.description.favourite": "Per konto ĉe Mastodon, vi povas stelumiti ĉi tiun afiŝon por sciigi la afiŝanton ke vi aprezigas ŝin kaj konservas por la estonteco.",
|
"interaction_modal.description.favourite": "Per konto ĉe Mastodon, vi povas stelumi ĉi tiun afiŝon por sciigi la afiŝanton ke vi sâtas kaj konservas ĝin por poste.",
|
||||||
"interaction_modal.description.follow": "Kun konto ĉe Mastodon, vi povas sekvi {name} por ricevi iliajn afiŝojn en via hejma fluo.",
|
"interaction_modal.description.follow": "Kun konto ĉe Mastodon, vi povas sekvi {name} por ricevi iliajn afiŝojn en via hejma fluo.",
|
||||||
"interaction_modal.description.reblog": "Kun konto ĉe Mastodon, vi povas diskonigi ĉi tiun afiŝon, por ke viaj propraj sekvantoj vidu ĝin.",
|
"interaction_modal.description.reblog": "Kun konto ĉe Mastodon, vi povas diskonigi ĉi tiun afiŝon, por ke viaj propraj sekvantoj vidu ĝin.",
|
||||||
"interaction_modal.description.reply": "Kun konto ĉe Mastodon, vi povos respondi al ĉi tiu afiŝo.",
|
"interaction_modal.description.reply": "Kun konto ĉe Mastodon, vi povos respondi al ĉi tiu afiŝo.",
|
||||||
|
@ -508,6 +515,7 @@
|
||||||
"notification.admin.report_statuses_other": "{name} raportis {target}",
|
"notification.admin.report_statuses_other": "{name} raportis {target}",
|
||||||
"notification.admin.sign_up": "{name} kreis konton",
|
"notification.admin.sign_up": "{name} kreis konton",
|
||||||
"notification.admin.sign_up.name_and_others": "{name} kaj {count, plural, one {# alia} other {# aliaj}} kreis konton",
|
"notification.admin.sign_up.name_and_others": "{name} kaj {count, plural, one {# alia} other {# aliaj}} kreis konton",
|
||||||
|
"notification.annual_report.view": "Vidu #Wrapstodon",
|
||||||
"notification.favourite": "{name} stelumis vian afiŝon",
|
"notification.favourite": "{name} stelumis vian afiŝon",
|
||||||
"notification.favourite.name_and_others_with_link": "{name} kaj <a>{count, plural, one {# alia} other {# aliaj}}</a> ŝatis vian afiŝon",
|
"notification.favourite.name_and_others_with_link": "{name} kaj <a>{count, plural, one {# alia} other {# aliaj}}</a> ŝatis vian afiŝon",
|
||||||
"notification.follow": "{name} eksekvis vin",
|
"notification.follow": "{name} eksekvis vin",
|
||||||
|
@ -640,7 +648,7 @@
|
||||||
"onboarding.start.lead": "Vi nun estas parto de Mastodon, unika, malcentralizita socia amaskomunikilara platformo, kie vi—ne algoritmo—zorgas vian propran sperton. Ni komencu vin sur ĉi tiu nova socia limo:",
|
"onboarding.start.lead": "Vi nun estas parto de Mastodon, unika, malcentralizita socia amaskomunikilara platformo, kie vi—ne algoritmo—zorgas vian propran sperton. Ni komencu vin sur ĉi tiu nova socia limo:",
|
||||||
"onboarding.start.skip": "Ĉu vi ne bezonas helpon por komenci?",
|
"onboarding.start.skip": "Ĉu vi ne bezonas helpon por komenci?",
|
||||||
"onboarding.start.title": "Vi atingas ĝin!",
|
"onboarding.start.title": "Vi atingas ĝin!",
|
||||||
"onboarding.steps.follow_people.body": "Sekvi interesajn homojn estas pri kio Mastodonto temas.",
|
"onboarding.steps.follow_people.body": "You curate your own feed. Lets fill it with interesting people.",
|
||||||
"onboarding.steps.follow_people.title": "Agordu vian hejman fluon",
|
"onboarding.steps.follow_people.title": "Agordu vian hejman fluon",
|
||||||
"onboarding.steps.publish_status.body": "Salutu la mondon per teksto, fotoj, filmetoj aŭ balotenketoj {emoji}",
|
"onboarding.steps.publish_status.body": "Salutu la mondon per teksto, fotoj, filmetoj aŭ balotenketoj {emoji}",
|
||||||
"onboarding.steps.publish_status.title": "Fari vian unuan afiŝon",
|
"onboarding.steps.publish_status.title": "Fari vian unuan afiŝon",
|
||||||
|
@ -774,9 +782,9 @@
|
||||||
"server_banner.is_one_of_many": "{domain} estas unu el la multaj sendependaj Mastodon-serviloj, kiujn vi povas uzi por partopreni en la fediverso.",
|
"server_banner.is_one_of_many": "{domain} estas unu el la multaj sendependaj Mastodon-serviloj, kiujn vi povas uzi por partopreni en la fediverso.",
|
||||||
"server_banner.server_stats": "Statistikoj de la servilo:",
|
"server_banner.server_stats": "Statistikoj de la servilo:",
|
||||||
"sign_in_banner.create_account": "Krei konton",
|
"sign_in_banner.create_account": "Krei konton",
|
||||||
"sign_in_banner.follow_anyone": "Sekvi iun ajn tra la fediverso kaj vidi ĉion en kronologia ordo. Neniuj algoritmoj, reklamoj aŭ klakbetoj videblas.",
|
"sign_in_banner.follow_anyone": "Sekvu iun ajn tra la fediverso kaj vidu ĉion laŭ templinio. Nul algoritmo, reklamo aŭ kliklogilo ĉeestas.",
|
||||||
"sign_in_banner.mastodon_is": "Mastodonto estas la plej bona maniero por resti flank-al-flanke kun kio okazas.",
|
"sign_in_banner.mastodon_is": "Mastodon estas la plej bona maniero resti ĝisdata pri aktualaĵoj.",
|
||||||
"sign_in_banner.sign_in": "Saluti",
|
"sign_in_banner.sign_in": "Ensaluti",
|
||||||
"sign_in_banner.sso_redirect": "Ensalutu aŭ Registriĝi",
|
"sign_in_banner.sso_redirect": "Ensalutu aŭ Registriĝi",
|
||||||
"status.admin_account": "Malfermi fasadon de moderigado por @{name}",
|
"status.admin_account": "Malfermi fasadon de moderigado por @{name}",
|
||||||
"status.admin_domain": "Malfermu moderigan interfacon por {domain}",
|
"status.admin_domain": "Malfermu moderigan interfacon por {domain}",
|
||||||
|
|
|
@ -87,6 +87,25 @@
|
||||||
"alert.unexpected.title": "¡Epa!",
|
"alert.unexpected.title": "¡Epa!",
|
||||||
"alt_text_badge.title": "Texto alternativo",
|
"alt_text_badge.title": "Texto alternativo",
|
||||||
"announcement.announcement": "Anuncio",
|
"announcement.announcement": "Anuncio",
|
||||||
|
"annual_report.summary.archetype.booster": "Corrió la voz",
|
||||||
|
"annual_report.summary.archetype.lurker": "El acechador",
|
||||||
|
"annual_report.summary.archetype.oracle": "El oráculo",
|
||||||
|
"annual_report.summary.archetype.pollster": "Estuvo consultando",
|
||||||
|
"annual_report.summary.archetype.replier": "Respondió un montón",
|
||||||
|
"annual_report.summary.followers.followers": "seguidores",
|
||||||
|
"annual_report.summary.followers.total": "{count} en total",
|
||||||
|
"annual_report.summary.here_it_is": "Acá está tu resumen de {year}:",
|
||||||
|
"annual_report.summary.highlighted_post.by_favourites": "el mensaje más veces marcado como favorito",
|
||||||
|
"annual_report.summary.highlighted_post.by_reblogs": "el mensaje que más adhesiones recibió",
|
||||||
|
"annual_report.summary.highlighted_post.by_replies": "el mensaje que más respuestas recibió",
|
||||||
|
"annual_report.summary.highlighted_post.possessive": "{name}",
|
||||||
|
"annual_report.summary.most_used_app.most_used_app": "la aplicación más usada",
|
||||||
|
"annual_report.summary.most_used_hashtag.most_used_hashtag": "la etiqueta más usada",
|
||||||
|
"annual_report.summary.most_used_hashtag.none": "Ninguna",
|
||||||
|
"annual_report.summary.new_posts.new_posts": "nuevos mensajes",
|
||||||
|
"annual_report.summary.percentile.text": "<topLabel>Eso te pone en la cima</topLabel><percentage></percentage><bottomLabel>de los usuarios de Mastodon.</bottomLabel>",
|
||||||
|
"annual_report.summary.percentile.we_wont_tell_bernie": "No se lo diremos a Bernie.",
|
||||||
|
"annual_report.summary.thanks": "¡Gracias por ser parte de Mastodon!",
|
||||||
"attachments_list.unprocessed": "[sin procesar]",
|
"attachments_list.unprocessed": "[sin procesar]",
|
||||||
"audio.hide": "Ocultar audio",
|
"audio.hide": "Ocultar audio",
|
||||||
"block_modal.remote_users_caveat": "Le pediremos al servidor {domain} que respete tu decisión. Sin embargo, el cumplimiento no está garantizado, ya que algunos servidores pueden manejar los bloqueos de forma diferente. Los mensajes públicos todavía podrían estar visibles para los usuarios no conectados.",
|
"block_modal.remote_users_caveat": "Le pediremos al servidor {domain} que respete tu decisión. Sin embargo, el cumplimiento no está garantizado, ya que algunos servidores pueden manejar los bloqueos de forma diferente. Los mensajes públicos todavía podrían estar visibles para los usuarios no conectados.",
|
||||||
|
@ -508,6 +527,8 @@
|
||||||
"notification.admin.report_statuses_other": "{name} denunció a {target}",
|
"notification.admin.report_statuses_other": "{name} denunció a {target}",
|
||||||
"notification.admin.sign_up": "Se registró {name}",
|
"notification.admin.sign_up": "Se registró {name}",
|
||||||
"notification.admin.sign_up.name_and_others": "Se registraron {name} y {count, plural, one {# cuenta más} other {# cuentas más}}",
|
"notification.admin.sign_up.name_and_others": "Se registraron {name} y {count, plural, one {# cuenta más} other {# cuentas más}}",
|
||||||
|
"notification.annual_report.message": "¡Tu #Wrapstodon {year} te espera! ¡Desvela los momentos más destacados y memorables de tu año en Mastodon!",
|
||||||
|
"notification.annual_report.view": "Ver #Wrapstodon",
|
||||||
"notification.favourite": "{name} marcó tu mensaje como favorito",
|
"notification.favourite": "{name} marcó tu mensaje como favorito",
|
||||||
"notification.favourite.name_and_others_with_link": "{name} y <a>{count, plural, one {# cuenta más} other {# cuentas más}}</a> marcaron tu mensaje como favorito",
|
"notification.favourite.name_and_others_with_link": "{name} y <a>{count, plural, one {# cuenta más} other {# cuentas más}}</a> marcaron tu mensaje como favorito",
|
||||||
"notification.follow": "{name} te empezó a seguir",
|
"notification.follow": "{name} te empezó a seguir",
|
||||||
|
|
|
@ -87,6 +87,25 @@
|
||||||
"alert.unexpected.title": "¡Ups!",
|
"alert.unexpected.title": "¡Ups!",
|
||||||
"alt_text_badge.title": "Texto alternativo",
|
"alt_text_badge.title": "Texto alternativo",
|
||||||
"announcement.announcement": "Anuncio",
|
"announcement.announcement": "Anuncio",
|
||||||
|
"annual_report.summary.archetype.booster": "El cazador de tendencias",
|
||||||
|
"annual_report.summary.archetype.lurker": "El acechador",
|
||||||
|
"annual_report.summary.archetype.oracle": "El oraculo",
|
||||||
|
"annual_report.summary.archetype.pollster": "El encuestador",
|
||||||
|
"annual_report.summary.archetype.replier": "La mariposa sociable",
|
||||||
|
"annual_report.summary.followers.followers": "seguidores",
|
||||||
|
"annual_report.summary.followers.total": "{count} en total",
|
||||||
|
"annual_report.summary.here_it_is": "Aquí está tu resumen de {year}:",
|
||||||
|
"annual_report.summary.highlighted_post.by_favourites": "publicación con más favoritos",
|
||||||
|
"annual_report.summary.highlighted_post.by_reblogs": "publicación más impulsada",
|
||||||
|
"annual_report.summary.highlighted_post.by_replies": "publicación con más respuestas",
|
||||||
|
"annual_report.summary.highlighted_post.possessive": "de {name}",
|
||||||
|
"annual_report.summary.most_used_app.most_used_app": "aplicación más usada",
|
||||||
|
"annual_report.summary.most_used_hashtag.most_used_hashtag": "etiqueta más usada",
|
||||||
|
"annual_report.summary.most_used_hashtag.none": "Ninguna",
|
||||||
|
"annual_report.summary.new_posts.new_posts": "nuevas publicaciones",
|
||||||
|
"annual_report.summary.percentile.text": "<topLabel>Eso te pone en el top</topLabel><percentage></percentage><bottomLabel>de usuarios de Mastodon.</bottomLabel>",
|
||||||
|
"annual_report.summary.percentile.we_wont_tell_bernie": "No se lo diremos a Bernie.",
|
||||||
|
"annual_report.summary.thanks": "¡Gracias por ser parte de Mastodon!",
|
||||||
"attachments_list.unprocessed": "(sin procesar)",
|
"attachments_list.unprocessed": "(sin procesar)",
|
||||||
"audio.hide": "Ocultar audio",
|
"audio.hide": "Ocultar audio",
|
||||||
"block_modal.remote_users_caveat": "Le pediremos al servidor {domain} que respete tu decisión. Sin embargo, el cumplimiento no está garantizado ya que algunos servidores pueden manejar bloques de forma diferente. Las publicaciones públicas pueden ser todavía visibles para los usuarios no conectados.",
|
"block_modal.remote_users_caveat": "Le pediremos al servidor {domain} que respete tu decisión. Sin embargo, el cumplimiento no está garantizado ya que algunos servidores pueden manejar bloques de forma diferente. Las publicaciones públicas pueden ser todavía visibles para los usuarios no conectados.",
|
||||||
|
@ -508,6 +527,8 @@
|
||||||
"notification.admin.report_statuses_other": "{name} reportó {target}",
|
"notification.admin.report_statuses_other": "{name} reportó {target}",
|
||||||
"notification.admin.sign_up": "{name} se unio",
|
"notification.admin.sign_up": "{name} se unio",
|
||||||
"notification.admin.sign_up.name_and_others": "{name} y {count, plural, one {# otro} other {# otros}} se registraron",
|
"notification.admin.sign_up.name_and_others": "{name} y {count, plural, one {# otro} other {# otros}} se registraron",
|
||||||
|
"notification.annual_report.message": "¡Tu #Wrapstodon {year} te espera! ¡Desvela los momentos más destacados y memorables de tu año en Mastodon!",
|
||||||
|
"notification.annual_report.view": "Ver #Wrapstodon",
|
||||||
"notification.favourite": "{name} marcó como favorita tu publicación",
|
"notification.favourite": "{name} marcó como favorita tu publicación",
|
||||||
"notification.favourite.name_and_others_with_link": "{name} y <a>{count, plural, one {# otro} other {# otros}}</a> marcaron tu publicación como favorita",
|
"notification.favourite.name_and_others_with_link": "{name} y <a>{count, plural, one {# otro} other {# otros}}</a> marcaron tu publicación como favorita",
|
||||||
"notification.follow": "{name} te empezó a seguir",
|
"notification.follow": "{name} te empezó a seguir",
|
||||||
|
|
|
@ -87,6 +87,25 @@
|
||||||
"alert.unexpected.title": "¡Ups!",
|
"alert.unexpected.title": "¡Ups!",
|
||||||
"alt_text_badge.title": "Texto alternativo",
|
"alt_text_badge.title": "Texto alternativo",
|
||||||
"announcement.announcement": "Anuncio",
|
"announcement.announcement": "Anuncio",
|
||||||
|
"annual_report.summary.archetype.booster": "El cazador de tendencias",
|
||||||
|
"annual_report.summary.archetype.lurker": "El acechador",
|
||||||
|
"annual_report.summary.archetype.oracle": "El oráculo",
|
||||||
|
"annual_report.summary.archetype.pollster": "El encuestador",
|
||||||
|
"annual_report.summary.archetype.replier": "El más sociable",
|
||||||
|
"annual_report.summary.followers.followers": "seguidores",
|
||||||
|
"annual_report.summary.followers.total": "{count} en total",
|
||||||
|
"annual_report.summary.here_it_is": "Aquí está tu resumen de {year}:",
|
||||||
|
"annual_report.summary.highlighted_post.by_favourites": "publicación con más favoritos",
|
||||||
|
"annual_report.summary.highlighted_post.by_reblogs": "publicación más impulsada",
|
||||||
|
"annual_report.summary.highlighted_post.by_replies": "publicación con más respuestas",
|
||||||
|
"annual_report.summary.highlighted_post.possessive": "de {name}",
|
||||||
|
"annual_report.summary.most_used_app.most_used_app": "aplicación más usada",
|
||||||
|
"annual_report.summary.most_used_hashtag.most_used_hashtag": "etiqueta más usada",
|
||||||
|
"annual_report.summary.most_used_hashtag.none": "Ninguna",
|
||||||
|
"annual_report.summary.new_posts.new_posts": "nuevas publicaciones",
|
||||||
|
"annual_report.summary.percentile.text": "<topLabel>Eso te pone en el top</topLabel><percentage></percentage><bottomLabel>de usuarios de Mastodon.</bottomLabel>",
|
||||||
|
"annual_report.summary.percentile.we_wont_tell_bernie": "No se lo diremos a Bernie.",
|
||||||
|
"annual_report.summary.thanks": "¡Gracias por ser parte de Mastodon!",
|
||||||
"attachments_list.unprocessed": "(sin procesar)",
|
"attachments_list.unprocessed": "(sin procesar)",
|
||||||
"audio.hide": "Ocultar audio",
|
"audio.hide": "Ocultar audio",
|
||||||
"block_modal.remote_users_caveat": "Le pediremos al servidor {domain} que respete tu decisión. Sin embargo, el cumplimiento no está garantizado, ya que algunos servidores pueden manejar bloqueos de forma distinta. Los mensajes públicos pueden ser todavía visibles para los usuarios que no hayan iniciado sesión.",
|
"block_modal.remote_users_caveat": "Le pediremos al servidor {domain} que respete tu decisión. Sin embargo, el cumplimiento no está garantizado, ya que algunos servidores pueden manejar bloqueos de forma distinta. Los mensajes públicos pueden ser todavía visibles para los usuarios que no hayan iniciado sesión.",
|
||||||
|
@ -508,6 +527,8 @@
|
||||||
"notification.admin.report_statuses_other": "{name} informó de {target}",
|
"notification.admin.report_statuses_other": "{name} informó de {target}",
|
||||||
"notification.admin.sign_up": "{name} se registró",
|
"notification.admin.sign_up": "{name} se registró",
|
||||||
"notification.admin.sign_up.name_and_others": "{name} y {count, plural, one {# más} other {# más}} se registraron",
|
"notification.admin.sign_up.name_and_others": "{name} y {count, plural, one {# más} other {# más}} se registraron",
|
||||||
|
"notification.annual_report.message": "¡Tu #Wrapstodon {year} te espera! ¡Desvela los momentos más destacados y memorables de tu año en Mastodon!",
|
||||||
|
"notification.annual_report.view": "Ver #Wrapstodon",
|
||||||
"notification.favourite": "{name} marcó como favorita tu publicación",
|
"notification.favourite": "{name} marcó como favorita tu publicación",
|
||||||
"notification.favourite.name_and_others_with_link": "{name} y <a>{count, plural, one {# más} other {# más}}</a> marcaron tu publicación como favorita",
|
"notification.favourite.name_and_others_with_link": "{name} y <a>{count, plural, one {# más} other {# más}}</a> marcaron tu publicación como favorita",
|
||||||
"notification.follow": "{name} te empezó a seguir",
|
"notification.follow": "{name} te empezó a seguir",
|
||||||
|
|
|
@ -87,6 +87,23 @@
|
||||||
"alert.unexpected.title": "Hups!",
|
"alert.unexpected.title": "Hups!",
|
||||||
"alt_text_badge.title": "Vaihtoehtoinen teksti",
|
"alt_text_badge.title": "Vaihtoehtoinen teksti",
|
||||||
"announcement.announcement": "Tiedote",
|
"announcement.announcement": "Tiedote",
|
||||||
|
"annual_report.summary.archetype.booster": "Tehostaja",
|
||||||
|
"annual_report.summary.archetype.lurker": "Lymyilijä",
|
||||||
|
"annual_report.summary.archetype.oracle": "Oraakkeli",
|
||||||
|
"annual_report.summary.archetype.pollster": "Mielipidetutkija",
|
||||||
|
"annual_report.summary.archetype.replier": "Sosiaalinen perhonen",
|
||||||
|
"annual_report.summary.followers.followers": "seuraajaa",
|
||||||
|
"annual_report.summary.followers.total": "{count} yhteensä",
|
||||||
|
"annual_report.summary.here_it_is": "Tässä on katsaus vuoteesi {year}:",
|
||||||
|
"annual_report.summary.highlighted_post.by_favourites": "suosikkeihin lisätyin julkaisu",
|
||||||
|
"annual_report.summary.highlighted_post.by_reblogs": "tehostetuin julkaisu",
|
||||||
|
"annual_report.summary.highlighted_post.by_replies": "julkaisu, jolla on eniten vastauksia",
|
||||||
|
"annual_report.summary.highlighted_post.possessive": "Käyttäjän {name}",
|
||||||
|
"annual_report.summary.most_used_app.most_used_app": "käytetyin sovellus",
|
||||||
|
"annual_report.summary.most_used_hashtag.most_used_hashtag": "käytetyin aihetunniste",
|
||||||
|
"annual_report.summary.new_posts.new_posts": "uutta julkaisua",
|
||||||
|
"annual_report.summary.percentile.text": "<topLabel>Olet osa huippujoukkoa, johon kuuluu</topLabel><percentage></percentage><bottomLabel>Mastodon-käyttäjistä.</bottomLabel>",
|
||||||
|
"annual_report.summary.thanks": "Kiitos, että olet osa Mastodonia!",
|
||||||
"attachments_list.unprocessed": "(käsittelemätön)",
|
"attachments_list.unprocessed": "(käsittelemätön)",
|
||||||
"audio.hide": "Piilota ääni",
|
"audio.hide": "Piilota ääni",
|
||||||
"block_modal.remote_users_caveat": "Pyydämme palvelinta {domain} kunnioittamaan päätöstäsi. Myötämielisyyttä ei kuitenkaan taata, koska jotkin palvelimet voivat käsitellä estoja eri tavalla. Julkiset julkaisut voivat silti näkyä kirjautumattomille käyttäjille.",
|
"block_modal.remote_users_caveat": "Pyydämme palvelinta {domain} kunnioittamaan päätöstäsi. Myötämielisyyttä ei kuitenkaan taata, koska jotkin palvelimet voivat käsitellä estoja eri tavalla. Julkiset julkaisut voivat silti näkyä kirjautumattomille käyttäjille.",
|
||||||
|
@ -158,7 +175,7 @@
|
||||||
"compose_form.poll.duration": "Äänestyksen kesto",
|
"compose_form.poll.duration": "Äänestyksen kesto",
|
||||||
"compose_form.poll.multiple": "Monivalinta",
|
"compose_form.poll.multiple": "Monivalinta",
|
||||||
"compose_form.poll.option_placeholder": "Vaihtoehto {number}",
|
"compose_form.poll.option_placeholder": "Vaihtoehto {number}",
|
||||||
"compose_form.poll.single": "Yksi vaihtoehto",
|
"compose_form.poll.single": "Yksittäisvalinta",
|
||||||
"compose_form.poll.switch_to_multiple": "Muuta äänestys monivalinnaksi",
|
"compose_form.poll.switch_to_multiple": "Muuta äänestys monivalinnaksi",
|
||||||
"compose_form.poll.switch_to_single": "Muuta äänestys yksittäisvalinnaksi",
|
"compose_form.poll.switch_to_single": "Muuta äänestys yksittäisvalinnaksi",
|
||||||
"compose_form.poll.type": "Tyyli",
|
"compose_form.poll.type": "Tyyli",
|
||||||
|
@ -386,7 +403,7 @@
|
||||||
"interaction_modal.description.follow": "Mastodon-tilillä voit seurata käyttäjää {name} saadaksesi hänen julkaisunsa kotisyötteeseesi.",
|
"interaction_modal.description.follow": "Mastodon-tilillä voit seurata käyttäjää {name} saadaksesi hänen julkaisunsa kotisyötteeseesi.",
|
||||||
"interaction_modal.description.reblog": "Mastodon-tilillä voit tehostaa tätä julkaisua jakaaksesi sen seuraajiesi kanssa.",
|
"interaction_modal.description.reblog": "Mastodon-tilillä voit tehostaa tätä julkaisua jakaaksesi sen seuraajiesi kanssa.",
|
||||||
"interaction_modal.description.reply": "Mastodon-tilillä voit vastata tähän julkaisuun.",
|
"interaction_modal.description.reply": "Mastodon-tilillä voit vastata tähän julkaisuun.",
|
||||||
"interaction_modal.description.vote": "Osallistuminen äänestykseen onnistuu Mastodon-tilillä.",
|
"interaction_modal.description.vote": "Mastodon-tilillä voit osallistua tähän äänestykseen.",
|
||||||
"interaction_modal.login.action": "Siirry kotiin",
|
"interaction_modal.login.action": "Siirry kotiin",
|
||||||
"interaction_modal.login.prompt": "Kotipalvelimesi verkkotunnus, kuten mastodon.social",
|
"interaction_modal.login.prompt": "Kotipalvelimesi verkkotunnus, kuten mastodon.social",
|
||||||
"interaction_modal.no_account_yet": "Etkö ole vielä Mastodonissa?",
|
"interaction_modal.no_account_yet": "Etkö ole vielä Mastodonissa?",
|
||||||
|
@ -508,6 +525,8 @@
|
||||||
"notification.admin.report_statuses_other": "{name} raportoi käyttäjän {target}",
|
"notification.admin.report_statuses_other": "{name} raportoi käyttäjän {target}",
|
||||||
"notification.admin.sign_up": "{name} rekisteröityi",
|
"notification.admin.sign_up": "{name} rekisteröityi",
|
||||||
"notification.admin.sign_up.name_and_others": "{name} ja {count, plural, one {# muu} other {# muuta}} rekisteröityivät",
|
"notification.admin.sign_up.name_and_others": "{name} ja {count, plural, one {# muu} other {# muuta}} rekisteröityivät",
|
||||||
|
"notification.annual_report.message": "Vuoden {year} #Wrapstodon odottaa! Paljasta vuotesi kohokohdat ikimuistoiset hetket Mastodonissa!",
|
||||||
|
"notification.annual_report.view": "Näytä #Wrapstodon",
|
||||||
"notification.favourite": "{name} lisäsi julkaisusi suosikkeihinsa",
|
"notification.favourite": "{name} lisäsi julkaisusi suosikkeihinsa",
|
||||||
"notification.favourite.name_and_others_with_link": "{name} ja <a>{count, plural, one {# muu} other {# muuta}}</a> lisäsivät julkaisusi suosikkeihinsa",
|
"notification.favourite.name_and_others_with_link": "{name} ja <a>{count, plural, one {# muu} other {# muuta}}</a> lisäsivät julkaisusi suosikkeihinsa",
|
||||||
"notification.follow": "{name} seurasi sinua",
|
"notification.follow": "{name} seurasi sinua",
|
||||||
|
|
|
@ -87,6 +87,25 @@
|
||||||
"alert.unexpected.title": "Ups!",
|
"alert.unexpected.title": "Ups!",
|
||||||
"alt_text_badge.title": "Annar tekstur",
|
"alt_text_badge.title": "Annar tekstur",
|
||||||
"announcement.announcement": "Kunngerð",
|
"announcement.announcement": "Kunngerð",
|
||||||
|
"annual_report.summary.archetype.booster": "Kuli jagarin",
|
||||||
|
"annual_report.summary.archetype.lurker": "Lúrarin",
|
||||||
|
"annual_report.summary.archetype.oracle": "Oraklið",
|
||||||
|
"annual_report.summary.archetype.pollster": "Spyrjarin",
|
||||||
|
"annual_report.summary.archetype.replier": "Sosiali firvaldurin",
|
||||||
|
"annual_report.summary.followers.followers": "fylgjarar",
|
||||||
|
"annual_report.summary.followers.total": "{count} íalt",
|
||||||
|
"annual_report.summary.here_it_is": "Her er ein samandráttur av {year}:",
|
||||||
|
"annual_report.summary.highlighted_post.by_favourites": "mest dámdi postur",
|
||||||
|
"annual_report.summary.highlighted_post.by_reblogs": "oftast lyfti postur",
|
||||||
|
"annual_report.summary.highlighted_post.by_replies": "postur við flestum svarum",
|
||||||
|
"annual_report.summary.highlighted_post.possessive": "hjá {name}",
|
||||||
|
"annual_report.summary.most_used_app.most_used_app": "mest brúkta app",
|
||||||
|
"annual_report.summary.most_used_hashtag.most_used_hashtag": "mest brúkta frámerki",
|
||||||
|
"annual_report.summary.most_used_hashtag.none": "Einki",
|
||||||
|
"annual_report.summary.new_posts.new_posts": "nýggir postar",
|
||||||
|
"annual_report.summary.percentile.text": "<topLabel>Tað fær teg í topp</topLabel><percentage></percentage><bottomLabel>av Mastodon brúkarum.</bottomLabel>",
|
||||||
|
"annual_report.summary.percentile.we_wont_tell_bernie": "Vit fara ikki at fortelja Bernie tað.",
|
||||||
|
"annual_report.summary.thanks": "Takk fyri at tú er partur av Mastodon!",
|
||||||
"attachments_list.unprocessed": "(óviðgjørt)",
|
"attachments_list.unprocessed": "(óviðgjørt)",
|
||||||
"audio.hide": "Fjal ljóð",
|
"audio.hide": "Fjal ljóð",
|
||||||
"block_modal.remote_users_caveat": "Vit biðja ambætaran {domain} virða tína avgerð. Kortini er eingin vissa um samsvar, av tí at fleiri ambætarar handfara blokkar ymiskt. Almennir postar kunnu framvegis vera sjónligir fyri brúkarar, sum ikki eru innritaðir.",
|
"block_modal.remote_users_caveat": "Vit biðja ambætaran {domain} virða tína avgerð. Kortini er eingin vissa um samsvar, av tí at fleiri ambætarar handfara blokkar ymiskt. Almennir postar kunnu framvegis vera sjónligir fyri brúkarar, sum ikki eru innritaðir.",
|
||||||
|
@ -508,6 +527,8 @@
|
||||||
"notification.admin.report_statuses_other": "{name} meldaði {target}",
|
"notification.admin.report_statuses_other": "{name} meldaði {target}",
|
||||||
"notification.admin.sign_up": "{name} meldaði seg til",
|
"notification.admin.sign_up": "{name} meldaði seg til",
|
||||||
"notification.admin.sign_up.name_and_others": "{name} og {count, plural, one {# annar/onnur} other {# onnur}} teknaðu seg",
|
"notification.admin.sign_up.name_and_others": "{name} og {count, plural, one {# annar/onnur} other {# onnur}} teknaðu seg",
|
||||||
|
"notification.annual_report.message": "Títt {year} #Wrapstodon bíðar! Avdúka hæddarpunktini og minniligu løturnar á Mastodon!",
|
||||||
|
"notification.annual_report.view": "Sí #Wrapstodon",
|
||||||
"notification.favourite": "{name} dámdi postin hjá tær",
|
"notification.favourite": "{name} dámdi postin hjá tær",
|
||||||
"notification.favourite.name_and_others_with_link": "{name} og <a>{count, plural, one {# annar/onnur} other {# onnur}}</a> yndisfrámerktu postin hjá tær",
|
"notification.favourite.name_and_others_with_link": "{name} og <a>{count, plural, one {# annar/onnur} other {# onnur}}</a> yndisfrámerktu postin hjá tær",
|
||||||
"notification.follow": "{name} fylgdi tær",
|
"notification.follow": "{name} fylgdi tær",
|
||||||
|
|
|
@ -87,6 +87,9 @@
|
||||||
"alert.unexpected.title": "Oups!",
|
"alert.unexpected.title": "Oups!",
|
||||||
"alt_text_badge.title": "Texte Alt",
|
"alt_text_badge.title": "Texte Alt",
|
||||||
"announcement.announcement": "Annonce",
|
"announcement.announcement": "Annonce",
|
||||||
|
"annual_report.summary.archetype.oracle": "L’oracle",
|
||||||
|
"annual_report.summary.here_it_is": "Voici votre récap de {year} :",
|
||||||
|
"annual_report.summary.most_used_app.most_used_app": "appli la plus utilisée",
|
||||||
"attachments_list.unprocessed": "(non traité)",
|
"attachments_list.unprocessed": "(non traité)",
|
||||||
"audio.hide": "Masquer l'audio",
|
"audio.hide": "Masquer l'audio",
|
||||||
"block_modal.remote_users_caveat": "Nous allons demander au serveur {domain} de respecter votre décision. Cependant, ce respect n'est pas garanti, car certains serveurs peuvent gérer différemment les blocages. Les messages publics peuvent rester visibles par les utilisateur·rice·s non connecté·e·s.",
|
"block_modal.remote_users_caveat": "Nous allons demander au serveur {domain} de respecter votre décision. Cependant, ce respect n'est pas garanti, car certains serveurs peuvent gérer différemment les blocages. Les messages publics peuvent rester visibles par les utilisateur·rice·s non connecté·e·s.",
|
||||||
|
|
|
@ -87,6 +87,9 @@
|
||||||
"alert.unexpected.title": "Oups !",
|
"alert.unexpected.title": "Oups !",
|
||||||
"alt_text_badge.title": "Texte Alt",
|
"alt_text_badge.title": "Texte Alt",
|
||||||
"announcement.announcement": "Annonce",
|
"announcement.announcement": "Annonce",
|
||||||
|
"annual_report.summary.archetype.oracle": "L’oracle",
|
||||||
|
"annual_report.summary.here_it_is": "Voici votre récap de {year} :",
|
||||||
|
"annual_report.summary.most_used_app.most_used_app": "appli la plus utilisée",
|
||||||
"attachments_list.unprocessed": "(non traité)",
|
"attachments_list.unprocessed": "(non traité)",
|
||||||
"audio.hide": "Masquer l'audio",
|
"audio.hide": "Masquer l'audio",
|
||||||
"block_modal.remote_users_caveat": "Nous allons demander au serveur {domain} de respecter votre décision. Cependant, ce respect n'est pas garanti, car certains serveurs peuvent gérer différemment les blocages. Les messages publics peuvent rester visibles par les utilisateur·rice·s non connecté·e·s.",
|
"block_modal.remote_users_caveat": "Nous allons demander au serveur {domain} de respecter votre décision. Cependant, ce respect n'est pas garanti, car certains serveurs peuvent gérer différemment les blocages. Les messages publics peuvent rester visibles par les utilisateur·rice·s non connecté·e·s.",
|
||||||
|
|
|
@ -158,6 +158,7 @@
|
||||||
"compose_form.poll.duration": "Doer fan de enkête",
|
"compose_form.poll.duration": "Doer fan de enkête",
|
||||||
"compose_form.poll.multiple": "Mearkar",
|
"compose_form.poll.multiple": "Mearkar",
|
||||||
"compose_form.poll.option_placeholder": "Opsje {number}",
|
"compose_form.poll.option_placeholder": "Opsje {number}",
|
||||||
|
"compose_form.poll.single": "Inkelde kar",
|
||||||
"compose_form.poll.switch_to_multiple": "Enkête wizigje om meardere karren ta te stean",
|
"compose_form.poll.switch_to_multiple": "Enkête wizigje om meardere karren ta te stean",
|
||||||
"compose_form.poll.switch_to_single": "Enkête wizigje om in inkelde kar ta te stean",
|
"compose_form.poll.switch_to_single": "Enkête wizigje om in inkelde kar ta te stean",
|
||||||
"compose_form.poll.type": "Styl",
|
"compose_form.poll.type": "Styl",
|
||||||
|
@ -196,6 +197,7 @@
|
||||||
"confirmations.unfollow.title": "Brûker net mear folgje?",
|
"confirmations.unfollow.title": "Brûker net mear folgje?",
|
||||||
"content_warning.hide": "Berjocht ferstopje",
|
"content_warning.hide": "Berjocht ferstopje",
|
||||||
"content_warning.show": "Dochs toane",
|
"content_warning.show": "Dochs toane",
|
||||||
|
"content_warning.show_more": "Mear toane",
|
||||||
"conversation.delete": "Petear fuortsmite",
|
"conversation.delete": "Petear fuortsmite",
|
||||||
"conversation.mark_as_read": "As lêzen markearje",
|
"conversation.mark_as_read": "As lêzen markearje",
|
||||||
"conversation.open": "Petear toane",
|
"conversation.open": "Petear toane",
|
||||||
|
@ -304,6 +306,7 @@
|
||||||
"filter_modal.select_filter.subtitle": "In besteande kategory brûke of in nije oanmeitsje",
|
"filter_modal.select_filter.subtitle": "In besteande kategory brûke of in nije oanmeitsje",
|
||||||
"filter_modal.select_filter.title": "Dit berjocht filterje",
|
"filter_modal.select_filter.title": "Dit berjocht filterje",
|
||||||
"filter_modal.title.status": "In berjocht filterje",
|
"filter_modal.title.status": "In berjocht filterje",
|
||||||
|
"filter_warning.matches_filter": "Komt oerien mei filter ‘<span>{title}</span>’",
|
||||||
"filtered_notifications_banner.pending_requests": "Fan {count, plural, =0 {net ien} one {ien persoan} other {# persoanen}} dy’t jo mooglik kinne",
|
"filtered_notifications_banner.pending_requests": "Fan {count, plural, =0 {net ien} one {ien persoan} other {# persoanen}} dy’t jo mooglik kinne",
|
||||||
"filtered_notifications_banner.title": "Filtere meldingen",
|
"filtered_notifications_banner.title": "Filtere meldingen",
|
||||||
"firehose.all": "Alles",
|
"firehose.all": "Alles",
|
||||||
|
@ -383,6 +386,7 @@
|
||||||
"interaction_modal.description.follow": "Jo kinne mei in Mastodon-account {name} folgje, om sa harren berjochten op jo starttiidline te ûntfangen.",
|
"interaction_modal.description.follow": "Jo kinne mei in Mastodon-account {name} folgje, om sa harren berjochten op jo starttiidline te ûntfangen.",
|
||||||
"interaction_modal.description.reblog": "Jo kinne mei in Mastodon-account dit berjocht booste, om it sa mei jo folgers te dielen.",
|
"interaction_modal.description.reblog": "Jo kinne mei in Mastodon-account dit berjocht booste, om it sa mei jo folgers te dielen.",
|
||||||
"interaction_modal.description.reply": "Jo kinne mei in Mastodon-account op dit berjocht reagearje.",
|
"interaction_modal.description.reply": "Jo kinne mei in Mastodon-account op dit berjocht reagearje.",
|
||||||
|
"interaction_modal.description.vote": "Mei in Mastodon-account kinne jo yn dizze enkête stimme.",
|
||||||
"interaction_modal.login.action": "Gean nei start",
|
"interaction_modal.login.action": "Gean nei start",
|
||||||
"interaction_modal.login.prompt": "Domein fan jo server, byg. mastodon.social",
|
"interaction_modal.login.prompt": "Domein fan jo server, byg. mastodon.social",
|
||||||
"interaction_modal.no_account_yet": "Net op Mastodon?",
|
"interaction_modal.no_account_yet": "Net op Mastodon?",
|
||||||
|
@ -394,6 +398,7 @@
|
||||||
"interaction_modal.title.follow": "{name} folgje",
|
"interaction_modal.title.follow": "{name} folgje",
|
||||||
"interaction_modal.title.reblog": "Berjocht fan {name} booste",
|
"interaction_modal.title.reblog": "Berjocht fan {name} booste",
|
||||||
"interaction_modal.title.reply": "Op it berjocht fan {name} reagearje",
|
"interaction_modal.title.reply": "Op it berjocht fan {name} reagearje",
|
||||||
|
"interaction_modal.title.vote": "Stimme yn {name}’s peiling",
|
||||||
"intervals.full.days": "{number, plural, one {# dei} other {# dagen}} lyn",
|
"intervals.full.days": "{number, plural, one {# dei} other {# dagen}} lyn",
|
||||||
"intervals.full.hours": "{number, plural, one {# oere} other {# oeren}} lyn",
|
"intervals.full.hours": "{number, plural, one {# oere} other {# oeren}} lyn",
|
||||||
"intervals.full.minutes": "{number, plural, one {# minút} other {# minuten}} lyn",
|
"intervals.full.minutes": "{number, plural, one {# minút} other {# minuten}} lyn",
|
||||||
|
@ -506,6 +511,7 @@
|
||||||
"notification.favourite": "{name} hat jo berjocht as favoryt markearre",
|
"notification.favourite": "{name} hat jo berjocht as favoryt markearre",
|
||||||
"notification.favourite.name_and_others_with_link": "{name} en <a>{count, plural, one {# oar} other {# oaren}}</a> hawwe jo berjocht as favoryt markearre",
|
"notification.favourite.name_and_others_with_link": "{name} en <a>{count, plural, one {# oar} other {# oaren}}</a> hawwe jo berjocht as favoryt markearre",
|
||||||
"notification.follow": "{name} folget dy",
|
"notification.follow": "{name} folget dy",
|
||||||
|
"notification.follow.name_and_others": "{name} en <a>{count, plural, one {# oar persoan} other {# oare persoanen}}</a> folgje jo no",
|
||||||
"notification.follow_request": "{name} hat dy in folchfersyk stjoerd",
|
"notification.follow_request": "{name} hat dy in folchfersyk stjoerd",
|
||||||
"notification.follow_request.name_and_others": "{name} en {count, plural, one {# oar} other {# oaren}} hawwe frege om jo te folgjen",
|
"notification.follow_request.name_and_others": "{name} en {count, plural, one {# oar} other {# oaren}} hawwe frege om jo te folgjen",
|
||||||
"notification.label.mention": "Fermelding",
|
"notification.label.mention": "Fermelding",
|
||||||
|
@ -564,6 +570,7 @@
|
||||||
"notifications.column_settings.filter_bar.category": "Flugge filterbalke",
|
"notifications.column_settings.filter_bar.category": "Flugge filterbalke",
|
||||||
"notifications.column_settings.follow": "Nije folgers:",
|
"notifications.column_settings.follow": "Nije folgers:",
|
||||||
"notifications.column_settings.follow_request": "Nij folchfersyk:",
|
"notifications.column_settings.follow_request": "Nij folchfersyk:",
|
||||||
|
"notifications.column_settings.group": "Groepearje",
|
||||||
"notifications.column_settings.mention": "Fermeldingen:",
|
"notifications.column_settings.mention": "Fermeldingen:",
|
||||||
"notifications.column_settings.poll": "Enkêteresultaten:",
|
"notifications.column_settings.poll": "Enkêteresultaten:",
|
||||||
"notifications.column_settings.push": "Pushmeldingen",
|
"notifications.column_settings.push": "Pushmeldingen",
|
||||||
|
|
|
@ -87,6 +87,24 @@
|
||||||
"alert.unexpected.title": "Hiúps!",
|
"alert.unexpected.title": "Hiúps!",
|
||||||
"alt_text_badge.title": "Téacs alt",
|
"alt_text_badge.title": "Téacs alt",
|
||||||
"announcement.announcement": "Fógra",
|
"announcement.announcement": "Fógra",
|
||||||
|
"annual_report.summary.archetype.booster": "An sealgair fionnuar",
|
||||||
|
"annual_report.summary.archetype.lurker": "An lurker",
|
||||||
|
"annual_report.summary.archetype.oracle": "An oracal",
|
||||||
|
"annual_report.summary.archetype.pollster": "An pollaire",
|
||||||
|
"annual_report.summary.archetype.replier": "An féileacán sóisialta",
|
||||||
|
"annual_report.summary.followers.followers": "leanúna",
|
||||||
|
"annual_report.summary.followers.total": "{count} san iomlán",
|
||||||
|
"annual_report.summary.here_it_is": "Seo do {year} faoi athbhreithniú:",
|
||||||
|
"annual_report.summary.highlighted_post.by_favourites": "post is fearr leat",
|
||||||
|
"annual_report.summary.highlighted_post.by_reblogs": "post is treisithe",
|
||||||
|
"annual_report.summary.highlighted_post.by_replies": "post leis an líon is mó freagraí",
|
||||||
|
"annual_report.summary.highlighted_post.possessive": "{name}'s",
|
||||||
|
"annual_report.summary.most_used_app.most_used_app": "aip is mó a úsáidtear",
|
||||||
|
"annual_report.summary.most_used_hashtag.most_used_hashtag": "hashtag is mó a úsáidtear",
|
||||||
|
"annual_report.summary.new_posts.new_posts": "postanna nua",
|
||||||
|
"annual_report.summary.percentile.text": "<topLabel>Cuireann sé sin i mbarr</topLabel><percentage></percentage><bottomLabel> úsáideoirí Mastodon.</bottomLabel>",
|
||||||
|
"annual_report.summary.percentile.we_wont_tell_bernie": "Ní inseoidh muid do Bernie.",
|
||||||
|
"annual_report.summary.thanks": "Go raibh maith agat as a bheith mar chuid de Mastodon!",
|
||||||
"attachments_list.unprocessed": "(neamhphróiseáilte)",
|
"attachments_list.unprocessed": "(neamhphróiseáilte)",
|
||||||
"audio.hide": "Cuir fuaim i bhfolach",
|
"audio.hide": "Cuir fuaim i bhfolach",
|
||||||
"block_modal.remote_users_caveat": "Iarrfaimid ar an bhfreastalaí {domain} meas a bheith agat ar do chinneadh. Mar sin féin, ní ráthaítear comhlíonadh toisc go bhféadfadh roinnt freastalaithe bloic a láimhseáil ar bhealach difriúil. Seans go mbeidh postálacha poiblí fós le feiceáil ag úsáideoirí nach bhfuil logáilte isteach.",
|
"block_modal.remote_users_caveat": "Iarrfaimid ar an bhfreastalaí {domain} meas a bheith agat ar do chinneadh. Mar sin féin, ní ráthaítear comhlíonadh toisc go bhféadfadh roinnt freastalaithe bloic a láimhseáil ar bhealach difriúil. Seans go mbeidh postálacha poiblí fós le feiceáil ag úsáideoirí nach bhfuil logáilte isteach.",
|
||||||
|
@ -386,6 +404,7 @@
|
||||||
"interaction_modal.description.follow": "Le cuntas ar Mastodon, is féidir leat {name} a leanúint chun a gcuid postálacha a fháil i do fhotha baile.",
|
"interaction_modal.description.follow": "Le cuntas ar Mastodon, is féidir leat {name} a leanúint chun a gcuid postálacha a fháil i do fhotha baile.",
|
||||||
"interaction_modal.description.reblog": "Le cuntas ar Mastodon, is féidir leat an postáil seo a threisiú chun é a roinnt le do leantóirí féin.",
|
"interaction_modal.description.reblog": "Le cuntas ar Mastodon, is féidir leat an postáil seo a threisiú chun é a roinnt le do leantóirí féin.",
|
||||||
"interaction_modal.description.reply": "Le cuntas ar Mastodon, is féidir leat freagra a thabhairt ar an bpostáil seo.",
|
"interaction_modal.description.reply": "Le cuntas ar Mastodon, is féidir leat freagra a thabhairt ar an bpostáil seo.",
|
||||||
|
"interaction_modal.description.vote": "Le cuntas ar Mastodon, is féidir leat vótáil sa vótaíocht seo.",
|
||||||
"interaction_modal.login.action": "Thabhairt dom abhaile",
|
"interaction_modal.login.action": "Thabhairt dom abhaile",
|
||||||
"interaction_modal.login.prompt": "Fearann do fhreastalaí baile, e.g. mastodon.sóisialta",
|
"interaction_modal.login.prompt": "Fearann do fhreastalaí baile, e.g. mastodon.sóisialta",
|
||||||
"interaction_modal.no_account_yet": "Ní ar Mastodon?",
|
"interaction_modal.no_account_yet": "Ní ar Mastodon?",
|
||||||
|
@ -397,6 +416,7 @@
|
||||||
"interaction_modal.title.follow": "Lean {name}",
|
"interaction_modal.title.follow": "Lean {name}",
|
||||||
"interaction_modal.title.reblog": "Mol postáil de chuid {name}",
|
"interaction_modal.title.reblog": "Mol postáil de chuid {name}",
|
||||||
"interaction_modal.title.reply": "Freagair postáil {name}",
|
"interaction_modal.title.reply": "Freagair postáil {name}",
|
||||||
|
"interaction_modal.title.vote": "Vótáil i vótaíocht {name}",
|
||||||
"intervals.full.days": "{number, plural, one {# lá} other {# lá}}",
|
"intervals.full.days": "{number, plural, one {# lá} other {# lá}}",
|
||||||
"intervals.full.hours": "{number, plural, one {# uair} other {# uair}}",
|
"intervals.full.hours": "{number, plural, one {# uair} other {# uair}}",
|
||||||
"intervals.full.minutes": "{number, plural, one {# nóiméad} other {# nóiméad}}",
|
"intervals.full.minutes": "{number, plural, one {# nóiméad} other {# nóiméad}}",
|
||||||
|
@ -506,6 +526,8 @@
|
||||||
"notification.admin.report_statuses_other": "{name} tuairiscithe {target}",
|
"notification.admin.report_statuses_other": "{name} tuairiscithe {target}",
|
||||||
"notification.admin.sign_up": "Chláraigh {name}",
|
"notification.admin.sign_up": "Chláraigh {name}",
|
||||||
"notification.admin.sign_up.name_and_others": "{name} agus {count, plural, one {# duine eile} two {# daoine eile} few {# daoine eile} many {# daoine eile} other {# daoine eile}} a chláraigh",
|
"notification.admin.sign_up.name_and_others": "{name} agus {count, plural, one {# duine eile} two {# daoine eile} few {# daoine eile} many {# daoine eile} other {# daoine eile}} a chláraigh",
|
||||||
|
"notification.annual_report.message": "Tá do {year} #Wrapstodon ag fanacht! Nocht buaicphointí na bliana agus chuimhneacháin i gcuimhne ar Mastodon!",
|
||||||
|
"notification.annual_report.view": "Amharc #Wrapstodon",
|
||||||
"notification.favourite": "Is fearr le {name} do phostáil",
|
"notification.favourite": "Is fearr le {name} do phostáil",
|
||||||
"notification.favourite.name_and_others_with_link": "{name} agus <a>{count, plural, one {# duine eile} other {# daoine eile}}</a> thaitin le do phost",
|
"notification.favourite.name_and_others_with_link": "{name} agus <a>{count, plural, one {# duine eile} other {# daoine eile}}</a> thaitin le do phost",
|
||||||
"notification.follow": "Lean {name} thú",
|
"notification.follow": "Lean {name} thú",
|
||||||
|
|
|
@ -87,6 +87,24 @@
|
||||||
"alert.unexpected.title": "Vaites!",
|
"alert.unexpected.title": "Vaites!",
|
||||||
"alt_text_badge.title": "Texto Alt",
|
"alt_text_badge.title": "Texto Alt",
|
||||||
"announcement.announcement": "Anuncio",
|
"announcement.announcement": "Anuncio",
|
||||||
|
"annual_report.summary.archetype.booster": "A axencia de noticias",
|
||||||
|
"annual_report.summary.archetype.lurker": "Volleur",
|
||||||
|
"annual_report.summary.archetype.oracle": "Sabichón/e",
|
||||||
|
"annual_report.summary.archetype.pollster": "O INE",
|
||||||
|
"annual_report.summary.archetype.replier": "Lareteire",
|
||||||
|
"annual_report.summary.followers.followers": "seguidoras",
|
||||||
|
"annual_report.summary.followers.total": "{count} en total",
|
||||||
|
"annual_report.summary.here_it_is": "Este é o resumo do teu {year}:",
|
||||||
|
"annual_report.summary.highlighted_post.by_favourites": "a publicación mais favorecida",
|
||||||
|
"annual_report.summary.highlighted_post.by_reblogs": "a publicación con mais promocións",
|
||||||
|
"annual_report.summary.highlighted_post.by_replies": "a publicación con mais respostas",
|
||||||
|
"annual_report.summary.highlighted_post.possessive": "de {name}",
|
||||||
|
"annual_report.summary.most_used_app.most_used_app": "app que mais usaches",
|
||||||
|
"annual_report.summary.most_used_hashtag.most_used_hashtag": "o cancelo mais utilizado",
|
||||||
|
"annual_report.summary.most_used_hashtag.none": "Nada",
|
||||||
|
"annual_report.summary.new_posts.new_posts": "novas publicacións",
|
||||||
|
"annual_report.summary.percentile.text": "<topLabel>Sitúante no top</topLabel><percentage></percentage><bottomLabel> das usuarias de Mastodon.</bottomLabel>",
|
||||||
|
"annual_report.summary.thanks": "Grazas por ser parte de Mastodon!",
|
||||||
"attachments_list.unprocessed": "(sen procesar)",
|
"attachments_list.unprocessed": "(sen procesar)",
|
||||||
"audio.hide": "Agochar audio",
|
"audio.hide": "Agochar audio",
|
||||||
"block_modal.remote_users_caveat": "Ímoslle pedir ao servidor {domain} que respecte a túa decisión. Emporiso, non hai garantía de que atenda a petición xa que os servidores xestionan os bloqueos de formas diferentes. As publicacións públicas poderían aínda ser visibles para usuarias que non iniciaron sesión.",
|
"block_modal.remote_users_caveat": "Ímoslle pedir ao servidor {domain} que respecte a túa decisión. Emporiso, non hai garantía de que atenda a petición xa que os servidores xestionan os bloqueos de formas diferentes. As publicacións públicas poderían aínda ser visibles para usuarias que non iniciaron sesión.",
|
||||||
|
@ -508,6 +526,8 @@
|
||||||
"notification.admin.report_statuses_other": "{name} denunciou a {target}",
|
"notification.admin.report_statuses_other": "{name} denunciou a {target}",
|
||||||
"notification.admin.sign_up": "{name} rexistrouse",
|
"notification.admin.sign_up": "{name} rexistrouse",
|
||||||
"notification.admin.sign_up.name_and_others": "{name} e {count, plural, one {# máis} other {# máis}} crearon unha conta",
|
"notification.admin.sign_up.name_and_others": "{name} e {count, plural, one {# máis} other {# máis}} crearon unha conta",
|
||||||
|
"notification.annual_report.message": "A #VidaEnMastodon de {year} agarda por ti! Desvela os momentos máis destacados e historias reseñables en Mastodon!",
|
||||||
|
"notification.annual_report.view": "Ver #VidaEnMastodon",
|
||||||
"notification.favourite": "{name} marcou como favorita a túa publicación",
|
"notification.favourite": "{name} marcou como favorita a túa publicación",
|
||||||
"notification.favourite.name_and_others_with_link": "{name} e <a>{count, plural, one {# máis} other {# máis}}</a> favoreceron a túa publicación",
|
"notification.favourite.name_and_others_with_link": "{name} e <a>{count, plural, one {# máis} other {# máis}}</a> favoreceron a túa publicación",
|
||||||
"notification.follow": "{name} comezou a seguirte",
|
"notification.follow": "{name} comezou a seguirte",
|
||||||
|
|
|
@ -87,6 +87,24 @@
|
||||||
"alert.unexpected.title": "אופס!",
|
"alert.unexpected.title": "אופס!",
|
||||||
"alt_text_badge.title": "כיתוב חלופי",
|
"alt_text_badge.title": "כיתוב חלופי",
|
||||||
"announcement.announcement": "הכרזה",
|
"announcement.announcement": "הכרזה",
|
||||||
|
"annual_report.summary.archetype.booster": "ההד-וניסט(ית)",
|
||||||
|
"annual_report.summary.archetype.lurker": "השורץ.ת השקט.ה",
|
||||||
|
"annual_report.summary.archetype.oracle": "כבוד הרב.ה",
|
||||||
|
"annual_report.summary.archetype.pollster": "הסקרן.ית",
|
||||||
|
"annual_report.summary.archetype.replier": "הפרפר.ית החברתי.ת",
|
||||||
|
"annual_report.summary.followers.followers": "עוקבים",
|
||||||
|
"annual_report.summary.followers.total": "{count} בסך הכל",
|
||||||
|
"annual_report.summary.here_it_is": "והנה סיכום {year} שלך:",
|
||||||
|
"annual_report.summary.highlighted_post.by_favourites": "התות הכי מחובב",
|
||||||
|
"annual_report.summary.highlighted_post.by_reblogs": "התות הכי מהודהד",
|
||||||
|
"annual_report.summary.highlighted_post.by_replies": "התות עם מספר התשובות הגבוה ביותר",
|
||||||
|
"annual_report.summary.highlighted_post.possessive": "של {name}",
|
||||||
|
"annual_report.summary.most_used_app.most_used_app": "היישומון שהכי בשימוש",
|
||||||
|
"annual_report.summary.most_used_hashtag.most_used_hashtag": "התג בשימוש הרב ביותר",
|
||||||
|
"annual_report.summary.new_posts.new_posts": "הודעות חדשות",
|
||||||
|
"annual_report.summary.percentile.text": "<topLabel>ממקם אותך באחוזון </topLabel><percentage></percentage><bottomLabel>של משמשי מסטודון.</bottomLabel>",
|
||||||
|
"annual_report.summary.percentile.we_wont_tell_bernie": "לא נגלה לברני.",
|
||||||
|
"annual_report.summary.thanks": "תודה על היותך חלק ממסטודון!",
|
||||||
"attachments_list.unprocessed": "(לא מעובד)",
|
"attachments_list.unprocessed": "(לא מעובד)",
|
||||||
"audio.hide": "השתק",
|
"audio.hide": "השתק",
|
||||||
"block_modal.remote_users_caveat": "אנו נבקש מהשרת {domain} לכבד את החלטתך. עם זאת, ציות למוסכמות איננו מובטח כיוון ששרתים מסויימים עשויים לטפל בחסימות בצורה אחרת. הודעות פומביות עדיין יהיו גלויות לעיני משתמשים שאינם מחוברים.",
|
"block_modal.remote_users_caveat": "אנו נבקש מהשרת {domain} לכבד את החלטתך. עם זאת, ציות למוסכמות איננו מובטח כיוון ששרתים מסויימים עשויים לטפל בחסימות בצורה אחרת. הודעות פומביות עדיין יהיו גלויות לעיני משתמשים שאינם מחוברים.",
|
||||||
|
@ -508,6 +526,8 @@
|
||||||
"notification.admin.report_statuses_other": "{name} דיווח.ה על {target}",
|
"notification.admin.report_statuses_other": "{name} דיווח.ה על {target}",
|
||||||
"notification.admin.sign_up": "{name} נרשמו",
|
"notification.admin.sign_up": "{name} נרשמו",
|
||||||
"notification.admin.sign_up.name_and_others": "{name} ועוד {count, plural,one {אחד אחר}other {# אחרים}} נרשמו",
|
"notification.admin.sign_up.name_and_others": "{name} ועוד {count, plural,one {אחד אחר}other {# אחרים}} נרשמו",
|
||||||
|
"notification.annual_report.message": "ה- #סיכומודון שלך לשנת {year} מחכה! גלו את רגעי השיא והזכרונות ממסטודון!",
|
||||||
|
"notification.annual_report.view": "לצפייה ב- #סיכומודון",
|
||||||
"notification.favourite": "הודעתך חובבה על ידי {name}",
|
"notification.favourite": "הודעתך חובבה על ידי {name}",
|
||||||
"notification.favourite.name_and_others_with_link": "{name} ועוד <a>{count, plural,one {אחד נוסף}other {# נוספים}}</a> חיבבו את הודעתך",
|
"notification.favourite.name_and_others_with_link": "{name} ועוד <a>{count, plural,one {אחד נוסף}other {# נוספים}}</a> חיבבו את הודעתך",
|
||||||
"notification.follow": "{name} במעקב אחרייך",
|
"notification.follow": "{name} במעקב אחרייך",
|
||||||
|
|
|
@ -87,6 +87,25 @@
|
||||||
"alert.unexpected.title": "Hoppá!",
|
"alert.unexpected.title": "Hoppá!",
|
||||||
"alt_text_badge.title": "Helyettesítő szöveg",
|
"alt_text_badge.title": "Helyettesítő szöveg",
|
||||||
"announcement.announcement": "Közlemény",
|
"announcement.announcement": "Közlemény",
|
||||||
|
"annual_report.summary.archetype.booster": "A cool-vadász",
|
||||||
|
"annual_report.summary.archetype.lurker": "A settenkedő",
|
||||||
|
"annual_report.summary.archetype.oracle": "Az orákulum",
|
||||||
|
"annual_report.summary.archetype.pollster": "A közvélemény-kutató",
|
||||||
|
"annual_report.summary.archetype.replier": "A társasági pillangó",
|
||||||
|
"annual_report.summary.followers.followers": "követő",
|
||||||
|
"annual_report.summary.followers.total": "{count} összesen",
|
||||||
|
"annual_report.summary.here_it_is": "Itt a {year}. év értékelése:",
|
||||||
|
"annual_report.summary.highlighted_post.by_favourites": "legkedvencebb bejegyzés",
|
||||||
|
"annual_report.summary.highlighted_post.by_reblogs": "legtöbbet megtolt bejegyzés",
|
||||||
|
"annual_report.summary.highlighted_post.by_replies": "bejegyzés a legtöbb válasszal",
|
||||||
|
"annual_report.summary.highlighted_post.possessive": "{name} fióktól",
|
||||||
|
"annual_report.summary.most_used_app.most_used_app": "legtöbbet használt app",
|
||||||
|
"annual_report.summary.most_used_hashtag.most_used_hashtag": "legtöbbet használt hashtag",
|
||||||
|
"annual_report.summary.most_used_hashtag.none": "Nincs",
|
||||||
|
"annual_report.summary.new_posts.new_posts": "új bejegyzés",
|
||||||
|
"annual_report.summary.percentile.text": "<topLabel>Ezzel a</topLabel><percentage></percentage><bottomLabel>csúcs Mastodon felhasználó között vagy.</bottomLabel>",
|
||||||
|
"annual_report.summary.percentile.we_wont_tell_bernie": "Nem mondjuk el Bernie-nek.",
|
||||||
|
"annual_report.summary.thanks": "Kösz, hogy a Mastodon része vagy!",
|
||||||
"attachments_list.unprocessed": "(feldolgozatlan)",
|
"attachments_list.unprocessed": "(feldolgozatlan)",
|
||||||
"audio.hide": "Hang elrejtése",
|
"audio.hide": "Hang elrejtése",
|
||||||
"block_modal.remote_users_caveat": "Arra kérjük a {domain} kiszolgálót, hogy tartsa tiszteletben a döntésedet. Ugyanakkor az együttműködés nem garantált, mivel néhány kiszolgáló másképp kezelheti a letiltásokat. A nyilvános bejegyzések a be nem jelentkezett felhasználók számára továbbra is látszódhatnak.",
|
"block_modal.remote_users_caveat": "Arra kérjük a {domain} kiszolgálót, hogy tartsa tiszteletben a döntésedet. Ugyanakkor az együttműködés nem garantált, mivel néhány kiszolgáló másképp kezelheti a letiltásokat. A nyilvános bejegyzések a be nem jelentkezett felhasználók számára továbbra is látszódhatnak.",
|
||||||
|
@ -508,6 +527,8 @@
|
||||||
"notification.admin.report_statuses_other": "{name} jelentette: {target}",
|
"notification.admin.report_statuses_other": "{name} jelentette: {target}",
|
||||||
"notification.admin.sign_up": "{name} regisztrált",
|
"notification.admin.sign_up": "{name} regisztrált",
|
||||||
"notification.admin.sign_up.name_and_others": "{name} és {count, plural, one {# másik} other {# másik}} regisztrált",
|
"notification.admin.sign_up.name_and_others": "{name} és {count, plural, one {# másik} other {# másik}} regisztrált",
|
||||||
|
"notification.annual_report.message": "Vár a {year}. év #Wrapstodon jelentése! Fedd fel az éved jelentős eseményeit és emlékezetes pillanatait a Mastodonon!",
|
||||||
|
"notification.annual_report.view": "#Wrapstodon Megtekintése",
|
||||||
"notification.favourite": "{name} kedvencnek jelölte a bejegyzésedet",
|
"notification.favourite": "{name} kedvencnek jelölte a bejegyzésedet",
|
||||||
"notification.favourite.name_and_others_with_link": "{name} és <a>{count, plural, one {# másik} other {# másik}}</a> kedvencnek jelölte a bejegyzésedet",
|
"notification.favourite.name_and_others_with_link": "{name} és <a>{count, plural, one {# másik} other {# másik}}</a> kedvencnek jelölte a bejegyzésedet",
|
||||||
"notification.follow": "{name} követ téged",
|
"notification.follow": "{name} követ téged",
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue