Compare commits

..

152 Commits

Author SHA1 Message Date
Claire
04903a45ce Merge pull request #3358 from ClearlyClaire/glitch-soc/merge-4.4
Merge upstream changes up to cbb1085855 into stable-4.4
2026-01-20 16:25:22 +01:00
Claire
d9bad1c407 Merge commit 'cbb10858555d3cbfde24d52859e2d690526c8173' into glitch-soc/merge-4.4 2026-01-20 15:58:26 +01:00
Claire
cbb1085855 Bump version to v4.4.12 (#37547) 2026-01-20 15:53:43 +01:00
Claire
3920feb8bd Merge commit from fork
* Add limit on inbox payload size

The 1MB limit is consistent with the limit we use when fetching remote resources

* Add limit to number of options from federated polls

* Add a limit to the number of federated profile fields

* Add limit on federated username length

* Add hard limits for federated display name and account bio

* Add hard limits for `alsoKnownAs` and `attributionDomains`

* Add hard limit on federated custom emoji shortcode

* Highlight most destructive limits and expand on their reasoning
2026-01-20 15:14:45 +01:00
Claire
4dbe15654a Merge commit from fork 2026-01-20 15:13:42 +01:00
Claire
27e06cdf20 Merge commit from fork 2026-01-20 15:13:10 +01:00
Claire
6ac8b52ccc Merge commit from fork 2026-01-20 15:10:38 +01:00
Claire
7ee99bbe81 Fix potential duplicate handling of quote accept/reject/delete (#37537) 2026-01-20 08:57:40 +01:00
Claire
6c1e77ff1f Skip tombstone creation on deleting from 404 (#37533) 2026-01-20 08:57:40 +01:00
Claire
2588d1ab47 Merge pull request #3354 from ClearlyClaire/glitch-soc/merge-4.4
Merge upstream changes up to 92be0fd12e into stable-4.4
2026-01-19 19:30:24 +01:00
Claire
c0f8640252 Merge commit '92be0fd12e78e7875107c04f239c57043e1876f5' into glitch-soc/merge-4.4 2026-01-19 18:51:52 +01:00
Claire
92be0fd12e Disable rubocop rule disabled in main 2026-01-19 11:37:44 +01:00
Claire
8450ebc7e8 Fix FeedManager#filter_from_home error when handling a reblog of a deleted status (#37486) 2026-01-19 11:37:44 +01:00
Claire
3d27ec34ac Simplify status batch removal SQL query (#37469) 2026-01-19 11:37:44 +01:00
Joshua Rogers
d3551e1ab6 Fix Vary parsing in cache control enforcement (#37426) 2026-01-19 11:37:44 +01:00
Joshua Rogers
0b9c741dac Fix thread-unsafe ActivityPub activity dispatch (#37423) 2026-01-19 11:37:44 +01:00
Shlee
a8c9923df9 Fix SignatureParser accepting duplicate parameters in HTTP Signature header (#37375)
Co-authored-by: Claire <claire.github-309c@sitedethib.com>
2026-01-19 11:37:44 +01:00
Shlee
f32067dc56 SharedConnectionPool - NoMethodError: undefined method 'site' for Integer (#37374) 2026-01-19 11:37:44 +01:00
Claire
36981fadf0 Update SECURITY.md (#37504) 2026-01-15 14:17:36 +01:00
Claire
b60edf59d8 Merge pull request #3337 from ClearlyClaire/glitch-soc/merge-4.4
Merge upstream changes up to ef4d722d6a to stable-4.4
2026-01-07 15:22:45 +01:00
Claire
3a87a63abf Merge commit 'ef4d722d6af8e0e9a25e30bb6c33aa0e14f6951f' into glitch-soc/merge-4.4 2026-01-07 14:46:45 +01:00
Claire
ef4d722d6a Bump version to v4.4.11 (#37410) 2026-01-07 14:45:02 +01:00
Claire
68e30985ca Merge commit from fork 2026-01-07 14:15:13 +01:00
Claire
1702290786 Merge commit from fork 2026-01-07 14:14:42 +01:00
Claire
abb3a02ce2 Merge pull request #3325 from ClearlyClaire/glitch-soc/merge-4.4
Merge upstream changes up to f5890040e1
2025-12-28 19:47:33 +01:00
Claire
25c79f526a Merge commit 'f5890040e12169e2ec27be68033ab0f1ad744c6e' into glitch-soc/merge-4.4 2025-12-28 11:19:25 +01:00
Claire
f5890040e1 Fix mentions of domain-blocked users being processed (#37257) 2025-12-19 11:00:14 +01:00
Claire
740f262e38 Change HTTP Signature verification status from 401 to 503 on temporary failure to get remote actor (#37221) 2025-12-19 11:00:14 +01:00
Claire
4d2b6795a4 Fix stable-4.4 branches being built with the latest tag (#37170) 2025-12-08 18:30:42 +01:00
Claire
6558a1e07a Merge pull request #3309 from ClearlyClaire/glitch-soc/merge-4.4
Merge upstream changes up to d5f12debe0 into stable-4.4
2025-12-08 17:29:58 +01:00
Echo
b64101ee64 [Glitch] Fixes YouTube embeds
Port 9bc9ebc59e to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-08 16:56:28 +01:00
Bruno Viveiros
0bde273b3d [Glitch] fix: YouTube iframe being able to start at a defined time
Port bdff970a5e to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-08 16:56:20 +01:00
Claire
22fe977ffe [Glitch] Fix error handling when re-fetching already-known statuses
Port edfbcfb3f5 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-08 16:55:59 +01:00
Claire
8e945bef2a Merge commit 'd5f12debe0fdd9033f3ef7ee84f9ddf366ffc2e3' into glitch-soc/merge-4.4 2025-12-08 16:54:12 +01:00
Claire
d5f12debe0 Bump version to v4.4.10 (#37162) 2025-12-08 16:20:18 +01:00
Claire
5d0ec718fd Merge commit from fork 2025-12-08 15:44:08 +01:00
Echo
c7aa312307 Fixes YouTube embeds (#37126) 2025-12-05 11:15:08 +01:00
Bruno Viveiros
dc1d4eda7c fix: YouTube iframe being able to start at a defined time (#26584) 2025-12-05 11:15:08 +01:00
Claire
931a29b4f3 Fix streamed quoted polls not being hydrated correctly (#37118) 2025-12-05 11:15:08 +01:00
Claire
99b2307350 Fix error handling when re-fetching already-known statuses (#37077) 2025-12-05 11:15:08 +01:00
Claire
375f2e6ebf Increase HTTP read timeout for expensive S3 batch delete operation (#37004) 2025-12-05 11:15:08 +01:00
Matt Jankowski
f0a1da78ba Suggest ES image version 7.17.29 in docker compose (#36972) 2025-12-05 11:15:08 +01:00
Claire
b554ecfcb4 Merge pull request #3292 from ClearlyClaire/glitch-soc/merge-4.4
Merge upstream changes up to 01cf5c103d into stable-4.4
2025-11-20 15:25:12 +01:00
Claire
50244ba682 Merge commit '01cf5c103de6c46b649d4db38b517b51f8bdfb56' into glitch-soc/merge-4.4 2025-11-20 14:58:00 +01:00
Claire
01cf5c103d Bump version to v4.4.9 (#36946) 2025-11-20 14:41:12 +01:00
Claire
5bda54d15a Merge pull request #3290 from ClearlyClaire/glitch-soc/merge-4.4
Merge upstream changes up to c49e261ad0 into stable-4.4
2025-11-19 22:59:55 +01:00
Claire
07f5573cd6 [Glitch] Fix filters not being applied to quotes in detailed view
Port 16ee628d24 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-19 22:30:31 +01:00
Claire
2b0b537152 Merge commit 'c49e261ad07d46515af50cdf103524ecf554b2f8' into glitch-soc/merge-4.4 2025-11-19 22:29:14 +01:00
Claire
c49e261ad0 Update dependency glob (#36942) 2025-11-19 16:29:45 +01:00
Shugo Maeda
915bcb267f Fix ArgumentError of tootctl upgrade storage-schema (#36914) 2025-11-19 13:55:30 +01:00
Claire
ff37011057 update dependency js-yaml to v4.1.1 2025-11-19 13:54:58 +01:00
Claire
8f5e95a159 Fix Update importing old previously-unknown activities and treating them as recent ones (#36848) 2025-11-19 13:50:16 +01:00
Claire
16ee628d24 Fix filters not being applied to quotes in detailed view (#36843) 2025-11-19 13:47:19 +01:00
Claire
64a0b060a8 Update security policy for 4.3 (#36755) 2025-11-06 14:58:24 +01:00
Claire
fa52f4361a Merge pull request #3248 from ClearlyClaire/glitch-soc/merge-4.4
Merge upstream changes up to c2fb12d22d to stable-4.4
2025-10-21 15:33:28 +02:00
Claire
7f7d6697c1 Merge commit 'c2fb12d22d52872b5905822c3d05f65516fa7f1d' into glitch-soc/merge-4.4 2025-10-21 15:14:15 +02:00
Claire
c2fb12d22d Bump version to v4.4.8 (#36542) 2025-10-21 15:12:37 +02:00
Claire
2dc4552229 Merge commit from fork
* Add validation to reject quotes of reblogs

* Do not process quotes of reblogs as potentially valid quotes

* Refuse to serve quoted reblogs over REST API
2025-10-21 15:00:28 +02:00
Claire
95868643a2 Merge pull request #3237 from ClearlyClaire/glitch-soc/merge-4.4
Merge upstream changes up to 8965e1bfa9 into stable-4.4
2025-10-15 11:32:36 +02:00
Claire
7c46fdfbf1 Merge commit '8965e1bfa9ce958ab16083a555ec6677b5f0f690' into glitch-soc/merge-4.4 2025-10-15 11:16:53 +02:00
Claire
8965e1bfa9 Bump version to v4.4.7 (#36473) 2025-10-15 10:12:23 +02:00
Claire
1e27ab0885 Fix moderation warning e-mails that include posts (#36462) 2025-10-14 17:15:58 +02:00
Jonathan de Jong
cef2c50a71 Fix allow_referrer_origin typo (#36460) 2025-10-14 17:15:58 +02:00
Claire
a54af6b06c Merge pull request #3232 from ClearlyClaire/glitch-soc/merge-4.4
Merge upstream changes up to d7f4eca801 into stable-4.4
2025-10-13 16:13:31 +02:00
Claire
81cf6715de Merge commit 'd7f4eca801bb702f487287eb218a9e7a133ee341' into glitch-soc/merge-4.4 2025-10-13 15:56:31 +02:00
Claire
d7f4eca801 Fix streaming still being authorized for suspended accounts (#36449) 2025-10-13 15:35:58 +02:00
Claire
adf291631e Bump version to v4.4.6 (#36444) 2025-10-13 14:43:01 +02:00
Emelia Smith
cbef4c9e65 Merge commit from fork 2025-10-13 14:20:57 +02:00
Claire
1631fb80e8 Merge commit from fork
* Ensure tootctl revokes sessions, access tokens and web push subscriptions

* Fix test coverage

---------

Co-authored-by: Emelia Smith <ThisIsMissEm@users.noreply.github.com>
2025-10-13 14:20:23 +02:00
Claire
8477bec2f2 Merge commit from fork
* Streaming: Ensure disabled users cannot connect to streaming

* Streaming: Disconnect when the user is disabled

---------

Co-authored-by: Emelia Smith <ThisIsMissEm@users.noreply.github.com>
2025-10-13 14:19:14 +02:00
Claire
6796765363 Update dependency openssl 2025-10-13 11:03:33 +02:00
Claire
044a20f12d Update dependency rack 2025-10-13 11:03:33 +02:00
Claire
15d05121df Merge pull request #3228 from ClearlyClaire/glitch-soc/merge-4.4
Merge upstream changes up to e4bdbccba8 into stable-4.4
2025-10-10 20:27:24 +02:00
Claire
07dea4e140 Merge commit 'e4bdbccba802318ebde6ab17f5adc1959bd82374' into glitch-soc/merge-4.4 2025-10-10 19:19:16 +02:00
github-actions[bot]
3c2570c88a New Crowdin Translations for stable-4.4 (automated) (#3226)
* New Crowdin translations

* Fix bogus no.yml

* Fix bogus simple_form.no.yml

---------

Co-authored-by: GitHub Actions <noreply@github.com>
Co-authored-by: Claire <claire.github-309c@sitedethib.com>
2025-10-10 19:08:08 +02:00
Claire
81955c10b1 Fix crowdin download script for glitch-soc stable branches 2025-10-10 18:45:27 +02:00
github-actions[bot]
e4bdbccba8 New Crowdin Translations for stable-4.4 (automated) (#36431)
Co-authored-by: GitHub Actions <noreply@github.com>
2025-10-10 18:19:25 +02:00
Claire
958d4df6cf Merge pull request #3222 from ClearlyClaire/glitch-soc/merge-4.4
Merge upstream changes up to c858fc77ef to stable-4.4
2025-10-10 10:29:48 +02:00
Claire
21d4abf7cc Merge commit 'd7d6407d4196ab6783485b20a3d9e2fbfc00ef01' into glitch-soc/merge-4.4 2025-10-09 18:15:33 +02:00
Claire
d7d6407d41 Explicitly record Tombstone quotes as deleted
This adds a `deleted` state to the internal representation, but this does
not change the API, which already included such a state.
2025-10-09 17:37:23 +02:00
Claire
a186bad399 Fix "quote": { "type": "Tombstone" } being ignored 2025-10-09 17:37:23 +02:00
Claire
67575e59e6 Fix quote post state sometimes not being updated through streaming server (#36408) 2025-10-09 17:37:23 +02:00
Matt Jankowski
d9113976c8 Use tag filter for pending tag count on admin dashboard (#36404) 2025-10-09 17:37:23 +02:00
Claire
3386f225e4 Merge pull request #3218 from ClearlyClaire/glitch-soc/merge-4.4
Merge upstream changes up to 670316499f into stable-4.4
2025-10-09 14:08:25 +02:00
diondiondion
97bc82c710 [Glitch] Allow quotes to be displayed in the featured carousel
Port 0d7af7e1fe to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-10-08 20:24:22 +02:00
Claire
0e7cb713d1 Merge commit '670316499fb4439a28d93aca2f40617dfb9bb2b0' into glitch-soc/merge-4.4 2025-10-08 18:00:57 +02:00
Claire
670316499f Update dependency uri 2025-10-08 16:26:13 +02:00
Claire
3c725240fd Update dependency rack 2025-10-08 16:26:13 +02:00
Claire
d8ddf95485 Fix JSON payload being potentially mutated when processing interaction policies (#36392) 2025-10-08 16:26:13 +02:00
Emelia Smith
4c12c2ed60 Add integration tests for mastodon-streaming (#36025)
Co-authored-by: Claire <claire.github-309c@sitedethib.com>
Co-authored-by: David Roetzel <david@roetzel.de>
2025-10-08 16:26:13 +02:00
diondiondion
636ecd1d03 Display quotes in email notifications (#36379) 2025-10-08 16:26:13 +02:00
Claire
cb0065cfe9 Fix redirect to external object when URL is missing or malformed (#36347) 2025-10-08 16:26:13 +02:00
diondiondion
6ae1b4fae9 Allow quotes to be displayed in the featured carousel (#36335) 2025-10-08 16:26:13 +02:00
Eugen Rochko
fd7adcc9d4 [Glitch] Fix wrong styles on rules and buttons in the sign-up form
Port 2df86d6413 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-10-06 20:12:00 +02:00
Claire
3c5f07c28e Merge pull request #3195 from ClearlyClaire/glitch-soc/merge-4.4
Merge upstream changes up to dc6d8f8825 in stable-4.4
2025-09-23 18:51:40 +02:00
Claire
048a42b8a7 [Glitch] Add click-through for quoted limited accounts
Port c8551a3eca to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-09-23 18:17:30 +02:00
Claire
c475623418 Merge commit 'dc6d8f882528803c06b2a71c23d6c1467880a7e1' into glitch-soc/merge-4.4 2025-09-23 18:10:55 +02:00
Claire
dc6d8f8825 Bump version to v4.4.5 2025-09-23 14:33:16 +02:00
Claire
dd0647ca45 Update dependency rexml 2025-09-23 14:33:16 +02:00
Claire
70e2eb49df Add support for has:quote in search (#36217) 2025-09-23 14:33:16 +02:00
Claire
bef28b2e51 Fix processing of out-of-order Update as implicit updates (#36190) 2025-09-22 16:54:04 +02:00
Claire
0b66bd591f Fix getting Create and Update out of order (#36176) 2025-09-22 16:54:04 +02:00
Claire
a94d7bf520 Change quoted posts from silenced accounts not to be hidden (#36166) 2025-09-22 16:54:04 +02:00
Claire
c8551a3eca Add click-through for quoted limited accounts (#36167) 2025-09-22 16:54:04 +02:00
Claire
df322e50c0 Merge pull request #3186 from ClearlyClaire/glitch-soc/merge-4.4
Merge upstream changes up to 06c2393805 into stable-4.4
2025-09-17 19:12:14 +02:00
Claire
1f3588a5a7 Merge commit '06c2393805eee6b2e4b4aa17787129a2d542b71d' into glitch-soc/merge-4.4 2025-09-17 18:09:26 +02:00
Claire
06c2393805 Fix quote with CW but no text being shown without CW (#36150) 2025-09-17 18:01:19 +02:00
Claire
4e85b9073b Fix typo in changelog (#36140) 2025-09-16 17:39:45 +02:00
Claire
cd573a346d Merge pull request #3182 from ClearlyClaire/glitch-soc/merge-4.4
Merge upstream changes up to c966d75600 in stable-4.4
2025-09-16 15:13:03 +02:00
Claire
793296b5eb [Glitch] Fix unresponsive areas around GIFV modals in some cases
Port 2347354bba to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-09-16 14:14:10 +02:00
Claire
661dbede1c [Glitch] Move quote post fallback removal import-time
Port 1c8990927a to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-09-16 14:14:10 +02:00
Claire
89f423aa00 [Glitch] Fix missing beforeUnload confirmation when a poll is being authored
Port 0d93801bde to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-09-16 14:14:10 +02:00
Claire
19c89f1bbd Merge commit 'c966d756007e0e4c4eb020055c999e4cf7a07ed0' into glitch-soc/merge-4.4 2025-09-16 14:14:05 +02:00
Claire
c966d75600 Bump version to v4.4.4 2025-09-16 13:54:27 +02:00
Claire
6f1fd0c2a7 Update axios dependency 2025-09-16 13:54:27 +02:00
Claire
68c219e753 Update vite dependency 2025-09-16 13:54:27 +02:00
Claire
a795743c3f Update rails dependencies 2025-09-16 13:54:27 +02:00
github-actions[bot]
1ab5ea9bfb New Crowdin Translations for stable-4.4 (automated) (#36122)
Co-authored-by: GitHub Actions <noreply@github.com>
2025-09-15 14:31:53 +02:00
Claire
48f55e3224 Fix quote posts with CW and no text being rejected
Fixes #36077
2025-09-12 16:27:29 +02:00
Claire
6044270d69 Fix missing memoization in Web::PushNotificationWorker (#36085) 2025-09-12 16:27:29 +02:00
Claire
be1bd91e6d Fix unresponsive areas around GIFV modals in some cases (#36059) 2025-09-12 16:27:29 +02:00
Claire
34cd5a716f Move quote post fallback removal import-time (#36055) 2025-09-12 16:27:29 +02:00
Claire
ec5128bc1f Fix missing beforeUnload confirmation when a poll is being authored (#36030) 2025-09-12 16:27:29 +02:00
Claire
28a79eb239 Merge pull request #3174 from ClearlyClaire/glitch-soc/merge-4.4
Merge upstream changes up to c0f9e7f4c3 into stable-4.4
2025-09-05 19:24:43 +02:00
Emelia Smith
1e2a9167bc [Glitch] Support displaying polls in Admin UI
Port 1137a0ca3a to glitch-soc

Co-authored-by: Claire <claire.github-309c@sitedethib.com>
Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-09-04 19:06:10 +02:00
diondiondion
1947f3a18b [Glitch] Fix error alerts for deleted quotes
Port 1faf520ce4 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-09-04 19:06:10 +02:00
Claire
5a46e3a234 [Glitch] Fix API return types for interaction API helpers
Port 8777443c9b to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-09-04 19:06:10 +02:00
Claire
75ba0f757a [Glitch] Fix WebUI fetching deleted quote in an endless loop
Port bd6d1f0e3f to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-09-04 19:06:10 +02:00
Claire
62ed8d633e [Glitch] Fix Edit as well as “Delete & Redraft” on a poll not inserting empty option
Port a48567784c to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-09-04 19:06:10 +02:00
Echo
02d92d3b68 [Glitch] Redirect on success for standalone compose
Port 1675eab561 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-09-04 19:06:10 +02:00
Emelia Smith
2a87fe5860 [Glitch] Refactor to reuse the one status partial across moderation tools
Port cbb9a4dbe3 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-09-04 18:38:00 +02:00
Claire
00c61317d3 Merge remote-tracking branch 'upstream/stable-4.4' into HEAD
Conflicts:
- `app/views/layouts/application.html.haml`:
  Conflict because of glitch-soc's theming system.
  Updated the line as upstream did.
2025-09-04 18:33:21 +02:00
fiona
c0f9e7f4c3 Fix handling of edited status with new media and no text (#35970) 2025-09-04 10:45:54 +02:00
Emelia Smith
1137a0ca3a Support displaying polls in Admin UI (#35933)
Co-authored-by: Claire <claire.github-309c@sitedethib.com>
2025-09-04 10:45:54 +02:00
diondiondion
1faf520ce4 Fix error alerts for deleted quotes (#35918) 2025-09-04 10:45:54 +02:00
Claire
8777443c9b Fix API return types for interaction API helpers (#35915) 2025-09-04 10:45:54 +02:00
Claire
bd6d1f0e3f Fix WebUI fetching deleted quote in an endless loop (#35909) 2025-09-04 10:45:54 +02:00
Claire
1a1a23f6f0 Consolidate labels for quote policy settings (#35893) 2025-09-04 10:45:54 +02:00
Claire
a48567784c Fix Edit as well as “Delete & Redraft” on a poll not inserting empty option (#35892) 2025-09-04 10:45:54 +02:00
Shlee
b71216a08a Add crossorigin back to inert css (regression? of #30687) (#35876) 2025-09-04 10:45:54 +02:00
Matt Jankowski
36974aaa99 Use debug? query method on httplog initializer check (#35833) 2025-09-04 10:45:54 +02:00
Claire
567f337db3 Fix self-destruct scheduler behavior on some Redis setups (#35823) 2025-09-04 10:45:54 +02:00
Matt Jankowski
97f118013a Include update in the resources args for api/web/push_subscriptions route (#35801) 2025-09-04 10:45:54 +02:00
Claire
ea5d1f0297 Fix tootctl admin create not bypassing reserved username checks (#35779) 2025-09-04 10:45:54 +02:00
Matt Jankowski
7a862d3308 First pass coverage addition for antispam class (#35771) 2025-09-04 10:45:54 +02:00
Echo
1675eab561 Redirect on success for standalone compose (#35763) 2025-09-04 10:45:54 +02:00
Claire
5f4116a311 Fix interaction policy changes in implicit updates not being saved (#35751) 2025-09-04 10:45:54 +02:00
Claire
0741381670 Add test for Delete of inlined QuoteAuthorization (#35724) 2025-09-04 10:45:54 +02:00
Claire
e61900cadc Fix quote revocation not being streamed (#35710) 2025-09-04 10:45:54 +02:00
Emelia Smith
cbb9a4dbe3 Refactor to reuse the one status partial across moderation tools (#35644) 2025-09-04 10:45:54 +02:00
Claire
4ef0ce033e Fix export of large user archives on 4.4 by enabling Zip64 (#35850) 2025-08-23 01:59:11 +02:00
Claire
48315a719d Change glitch flavor to show approximate reply count by default (#3157) 2025-08-22 22:31:39 +02:00
372 changed files with 7315 additions and 2246 deletions

View File

@@ -20,7 +20,7 @@ jobs:
# Only tag with latest when ran against the latest stable branch
# This needs to be updated after each minor version release
flavor: |
latest=${{ startsWith(github.ref, 'refs/tags/v4.4.') }}
latest=false
tags: |
type=pep440,pattern={{raw}}
type=pep440,pattern=v{{major}}.{{minor}}
@@ -37,7 +37,7 @@ jobs:
# Only tag with latest when ran against the latest stable branch
# This needs to be updated after each minor version release
flavor: |
latest=${{ startsWith(github.ref, 'refs/tags/v4.4.') }}
latest=false
tags: |
type=pep440,pattern={{raw}}
type=pep440,pattern=v{{major}}.{{minor}}

View File

@@ -9,7 +9,7 @@ permissions:
jobs:
download-translations-stable:
runs-on: ubuntu-latest
if: github.repository == 'mastodon/mastodon'
if: github.repository == 'glitch-soc/mastodon'
steps:
- name: Checkout

View File

@@ -21,11 +21,11 @@ Metrics/BlockNesting:
# Configuration parameters: AllowedMethods, AllowedPatterns.
Metrics/CyclomaticComplexity:
Max: 25
Enabled: false
# Configuration parameters: AllowedMethods, AllowedPatterns.
Metrics/PerceivedComplexity:
Max: 27
Enabled: false
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: AllowedVars, DefaultToNil.

View File

@@ -2,6 +2,149 @@
All notable changes to this project will be documented in this file.
## [4.4.12] - 2026-01-20
### Security
- Fix missing limits on various federated properties [GHSA-gg8q-rcg7-p79g](https://github.com/mastodon/mastodon/security/advisories/GHSA-gg8q-rcg7-p79g)
- Fix remote user suspension bypass [GHSA-5h2f-wg8j-xqwp](https://github.com/mastodon/mastodon/security/advisories/GHSA-5h2f-wg8j-xqwp)
- Fix missing length limits on some user-provided fields [GHSA-6x3w-9g92-gvf3](https://github.com/mastodon/mastodon/security/advisories/GHSA-6x3w-9g92-gvf3)
- Fix missing access check for push notification settings update [GHSA-f3q8-7vw3-69v4](https://github.com/mastodon/mastodon/security/advisories/GHSA-f3q8-7vw3-69v4)
### Changed
- Skip tombstone creation on deleting from 404 (#37533 by @ClearlyClaire)
### Fixed
- Fix potential duplicate handling of quote accept/reject/delete (#37537 by @ClearlyClaire)
- Fix `FeedManager#filter_from_home` error when handling a reblog of a deleted status (#37486 by @ClearlyClaire)
- Fix needlessly complicated SQL query in status batch removal (#37469 by @ClearlyClaire)
- Fix `Vary` parsing in cache control enforcement (#37426 by @MegaManSec)
- Fix thread-unsafe ActivityPub activity dispatch (#37423 by @MegaManSec)
- Fix SignatureParser accepting duplicate parameters in HTTP Signature header (#37375 by @shleeable)
## [4.4.11] - 2026-01-07
### Security
- Fix SSRF protection bypass ([GHSA](https://github.com/mastodon/mastodon/security/advisories/GHSA-xfrj-c749-jxxq))
- Fix missing ownership check in severed relationships controller ([GHSA](https://github.com/mastodon/mastodon/security/advisories/GHSA-ww85-x9cp-5v24))
### Changed
- Change HTTP Signature verification status from 401 to 503 on temporary failure to get remote actor (#37221 by @ClearlyClaire)
### Fixed
- Fix mentions of domain-blocked users being processed (#37257 by @ClearlyClaire)
## [4.4.10] - 2025-12-08
### Security
- Fix inconsistent error handling leaking information on existence of private posts ([GHSA-gwhw-gcjx-72v8](https://github.com/mastodon/mastodon/security/advisories/GHSA-gwhw-gcjx-72v8))
### Fixed
- Fix YouTube embeds by sending referer (#37126 by @ChaosExAnima)
- Fix YouTube iframe not being able to start at a defined time (#26584 by @BrunoViveiros)
- Fix streamed quoted polls not being hydrated correctly (#37118 by @ClearlyClaire)
- Fix error handling when re-fetching already-known statuses (#37077 by @ClearlyClaire)
- Fix known expensive S3 batch delete operation failing because of short timeouts (#37004 by @ClearlyClaire)
## [4.4.9] - 2025-11-20
### Fixed
- Fix `tootctl upgrade storage-schema` failing with `ArgumentError` (#36914 by @shugo)
- Fix old previously-undiscovered posts being treated as new when receiving an `Update` (#36848 by @ClearlyClaire)
- Fix filters not being applied to quotes in detailed view (#36843 by @ClearlyClaire)
## [4.4.8] - 2025-10-21
### Security
- Fix quote control bypass ([GHSA-8h43-rcqj-wpc6](https://github.com/mastodon/mastodon/security/advisories/GHSA-8h43-rcqj-wpc6))
## [4.4.7] - 2025-10-15
### Fixed
- Fix forwarder being called with `nil` status when quote post is soft-deleted (#36463 by @ClearlyClaire)
- Fix moderation warning e-mails that include posts (#36462 by @ClearlyClaire)
- Fix allow_referrer_origin typo (#36460 by @ShadowJonathan)
## [4.4.6] - 2025-10-13
### Security
- Update dependencies `rack` and `uri`
- Fix streaming server connection not being closed on user suspension (by @ThisIsMissEm, [GHSA-r2fh-jr9c-9pxh](https://github.com/mastodon/mastodon/security/advisories/GHSA-r2fh-jr9c-9pxh))
- Fix password change through admin CLI not invalidating existing sessions and access tokens (by @ThisIsMissEm, [GHSA-f3q3-rmf7-9655](https://github.com/mastodon/mastodon/security/advisories/GHSA-f3q3-rmf7-9655))
- Fix streaming server allowing access to public timelines even without the `read` or `read:statuses` OAuth scopes (by @ThisIsMissEm, [GHSA-7gwh-mw97-qjgp](https://github.com/mastodon/mastodon/security/advisories/GHSA-7gwh-mw97-qjgp))
### Added
- Add support for processing quotes of deleted posts signaled through a `Tombstone` (#36381 by @ClearlyClaire)
### Fixed
- Fix quote post state sometimes not being updated through streaming server (#36408 by @ClearlyClaire)
- Fix inconsistent “pending tags” count on admin dashboard (#36404 by @mjankowski)
- Fix JSON payload being potentially mutated when processing interaction policies (#36392 by @ClearlyClaire)
- Fix quotes not being displayed in email notifications (#36379 by @diondiondion)
- Fix redirect to external object when URL is missing or malformed (#36347 by @ClearlyClaire)
- Fix quotes not being displayed in the featured carousel (#36335 by @diondiondion)
## [4.4.5] - 2025-09-23
### Security
- Update dependencies
### Added
- Add support for `has:quote` in search (#36217 by @ClearlyClaire)
### Changed
- Change quoted posts from silenced accounts to use a click-through rather than being hidden (#36166 and #36167 by @ClearlyClaire)
### Fixed
- Fix processing of out-of-order `Update` as implicit updates (#36190 by @ClearlyClaire)
- Fix getting `Create` and `Update` out of order (#36176 by @ClearlyClaire)
- Fix quotes with Content Warnings but no text being shown without Content Warnings (#36150 by @ClearlyClaire)
## [4.4.4] - 2025-09-16
### Security
- Update dependencies
### Fixed
- Fix missing memoization in `Web::PushNotificationWorker` (#36085 by @ClearlyClaire)
- Fix unresponsive areas around GIFV modals in some cases (#36059 by @ClearlyClaire)
- Fix missing `beforeUnload` confirmation when a poll is being authored (#36030 by @ClearlyClaire)
- Fix processing of remote edited statuses with new media and no text (#35970 by @unfokus)
- Fix polls not being displayed in moderation interface (#35644 and #35933 by @ThisIsMissEm)
- Fix WebUI handling of deleted quoted posts (#35909 and #35918 by @ClearlyClaire and @diondiondion)
- Fix “Edit” and “Delete & Redraft” on a poll not inserting empty option (#35892 by @ClearlyClaire)
- Fix loading of some compatibility CSS on some configurations (#35876 by @shleeable)
- Fix HttpLog not being enabled with `RAILS_LOG_LEVEL=debug` (#35833 by @mjankowski)
- Fix self-destruct scheduler behavior on some Redis setups (#35823 by @ClearlyClaire)
- Fix `tootctl admin create` not bypassing reserved username checks (#35779 by @ClearlyClaire)
- Fix interaction policy changes in implicit updates not being saved (#35751 by @ClearlyClaire)
- Fix quote revocation not being streamed (#35710 by @ClearlyClaire)
- Fix export of large user archives by enabling Zip64 (#35850 by @ClearlyClaire)
### Changed
- Change labels for quote policy settings (#35893 by @ClearlyClaire)
- Change standalone “Share” page to redirect to web interface after posting (#35763 by @ChaosExAnima)
## [4.4.3] - 2025-08-05
### Security

View File

@@ -48,3 +48,22 @@ Mastodon requires all `POST` requests to be signed, and MAY require `GET` reques
### Additional documentation
- [Mastodon documentation](https://docs.joinmastodon.org/)
## Size limits
Mastodon imposes a few hard limits on federated content.
These limits are intended to be very generous and way above what the Mastodon user experience is optimized for, so as to accomodate future changes and unusual or unforeseen usage patterns, while still providing some limits for performance reasons.
The following table attempts to summary those limits.
| Limited property | Size limit | Consequence of exceeding the limit |
| ------------------------------------------------------------- | ---------- | ---------------------------------- |
| Serialized JSON-LD | 1MB | **Activity is rejected/dropped** |
| Profile fields (actor `PropertyValue` attachments) name/value | 2047 | Field name/value is truncated |
| Number of profile fields (actor `PropertyValue` attachments) | 50 | Fields list is truncated |
| Poll options (number of `anyOf`/`oneOf` in a `Question`) | 500 | Items list is truncated |
| Account username (actor `preferredUsername`) length | 2048 | **Actor will be rejected** |
| Account display name (actor `name`) length | 2048 | Display name will be truncated |
| Account note (actor `summary`) length | 20kB | Account note will be truncated |
| Account `attributionDomains` | 256 | List will be truncated |
| Account aliases (actor `alsoKnownAs`) | 256 | List will be truncated |
| Custom emoji shortcode (`Emoji` `name`) | 2048 | Emoji will be rejected |

View File

@@ -159,6 +159,9 @@ group :test do
# Stub web requests for specs
gem 'webmock', '~> 3.18'
# Websocket driver for testing integration between rails/sidekiq and streaming
gem 'websocket-driver', '~> 0.8', require: false
end
group :development do

View File

@@ -10,29 +10,29 @@ GIT
GEM
remote: https://rubygems.org/
specs:
actioncable (8.0.2)
actionpack (= 8.0.2)
activesupport (= 8.0.2)
actioncable (8.0.2.1)
actionpack (= 8.0.2.1)
activesupport (= 8.0.2.1)
nio4r (~> 2.0)
websocket-driver (>= 0.6.1)
zeitwerk (~> 2.6)
actionmailbox (8.0.2)
actionpack (= 8.0.2)
activejob (= 8.0.2)
activerecord (= 8.0.2)
activestorage (= 8.0.2)
activesupport (= 8.0.2)
actionmailbox (8.0.2.1)
actionpack (= 8.0.2.1)
activejob (= 8.0.2.1)
activerecord (= 8.0.2.1)
activestorage (= 8.0.2.1)
activesupport (= 8.0.2.1)
mail (>= 2.8.0)
actionmailer (8.0.2)
actionpack (= 8.0.2)
actionview (= 8.0.2)
activejob (= 8.0.2)
activesupport (= 8.0.2)
actionmailer (8.0.2.1)
actionpack (= 8.0.2.1)
actionview (= 8.0.2.1)
activejob (= 8.0.2.1)
activesupport (= 8.0.2.1)
mail (>= 2.8.0)
rails-dom-testing (~> 2.2)
actionpack (8.0.2)
actionview (= 8.0.2)
activesupport (= 8.0.2)
actionpack (8.0.2.1)
actionview (= 8.0.2.1)
activesupport (= 8.0.2.1)
nokogiri (>= 1.8.5)
rack (>= 2.2.4)
rack-session (>= 1.0.1)
@@ -40,15 +40,15 @@ GEM
rails-dom-testing (~> 2.2)
rails-html-sanitizer (~> 1.6)
useragent (~> 0.16)
actiontext (8.0.2)
actionpack (= 8.0.2)
activerecord (= 8.0.2)
activestorage (= 8.0.2)
activesupport (= 8.0.2)
actiontext (8.0.2.1)
actionpack (= 8.0.2.1)
activerecord (= 8.0.2.1)
activestorage (= 8.0.2.1)
activesupport (= 8.0.2.1)
globalid (>= 0.6.0)
nokogiri (>= 1.8.5)
actionview (8.0.2)
activesupport (= 8.0.2)
actionview (8.0.2.1)
activesupport (= 8.0.2.1)
builder (~> 3.1)
erubi (~> 1.11)
rails-dom-testing (~> 2.2)
@@ -58,22 +58,22 @@ GEM
activemodel (>= 4.1)
case_transform (>= 0.2)
jsonapi-renderer (>= 0.1.1.beta1, < 0.3)
activejob (8.0.2)
activesupport (= 8.0.2)
activejob (8.0.2.1)
activesupport (= 8.0.2.1)
globalid (>= 0.3.6)
activemodel (8.0.2)
activesupport (= 8.0.2)
activerecord (8.0.2)
activemodel (= 8.0.2)
activesupport (= 8.0.2)
activemodel (8.0.2.1)
activesupport (= 8.0.2.1)
activerecord (8.0.2.1)
activemodel (= 8.0.2.1)
activesupport (= 8.0.2.1)
timeout (>= 0.4.0)
activestorage (8.0.2)
actionpack (= 8.0.2)
activejob (= 8.0.2)
activerecord (= 8.0.2)
activesupport (= 8.0.2)
activestorage (8.0.2.1)
actionpack (= 8.0.2.1)
activejob (= 8.0.2.1)
activerecord (= 8.0.2.1)
activesupport (= 8.0.2.1)
marcel (~> 1.0)
activesupport (8.0.2)
activesupport (8.0.2.1)
base64
benchmark (>= 0.3)
bigdecimal
@@ -494,7 +494,7 @@ GEM
tzinfo
validate_url
webfinger (~> 2.0)
openssl (3.3.0)
openssl (3.3.1)
openssl-signature_algorithm (1.3.0)
openssl (> 2.0)
opentelemetry-api (1.5.0)
@@ -642,7 +642,7 @@ GEM
activesupport (>= 3.0.0)
raabro (1.4.0)
racc (1.8.1)
rack (3.1.16)
rack (3.1.18)
rack-attack (6.7.0)
rack (>= 1.0, < 4)
rack-cors (3.0.0)
@@ -668,20 +668,20 @@ GEM
rack (>= 1.3)
rackup (2.2.1)
rack (>= 3)
rails (8.0.2)
actioncable (= 8.0.2)
actionmailbox (= 8.0.2)
actionmailer (= 8.0.2)
actionpack (= 8.0.2)
actiontext (= 8.0.2)
actionview (= 8.0.2)
activejob (= 8.0.2)
activemodel (= 8.0.2)
activerecord (= 8.0.2)
activestorage (= 8.0.2)
activesupport (= 8.0.2)
rails (8.0.2.1)
actioncable (= 8.0.2.1)
actionmailbox (= 8.0.2.1)
actionmailer (= 8.0.2.1)
actionpack (= 8.0.2.1)
actiontext (= 8.0.2.1)
actionview (= 8.0.2.1)
activejob (= 8.0.2.1)
activemodel (= 8.0.2.1)
activerecord (= 8.0.2.1)
activestorage (= 8.0.2.1)
activesupport (= 8.0.2.1)
bundler (>= 1.15.0)
railties (= 8.0.2)
railties (= 8.0.2.1)
rails-dom-testing (2.2.0)
activesupport (>= 5.0.0)
minitest
@@ -692,9 +692,9 @@ GEM
rails-i18n (8.0.1)
i18n (>= 0.7, < 2)
railties (>= 8.0.0, < 9)
railties (8.0.2)
actionpack (= 8.0.2)
activesupport (= 8.0.2)
railties (8.0.2.1)
actionpack (= 8.0.2.1)
activesupport (= 8.0.2.1)
irb (~> 1.13)
rackup (>= 1.0.0)
rake (>= 12.2)
@@ -725,7 +725,7 @@ GEM
responders (3.1.1)
actionpack (>= 5.2)
railties (>= 5.2)
rexml (3.4.1)
rexml (3.4.4)
rotp (6.3.0)
rouge (4.5.2)
rpam2 (4.0.2)
@@ -899,7 +899,7 @@ GEM
unicode-display_width (3.1.4)
unicode-emoji (~> 4.0, >= 4.0.4)
unicode-emoji (4.0.4)
uri (1.0.3)
uri (1.0.4)
useragent (0.16.11)
validate_url (1.0.15)
activemodel (>= 3.0.0)
@@ -932,7 +932,7 @@ GEM
crack (>= 0.3.2)
hashdiff (>= 0.4.0, < 2.0.0)
webrick (1.9.1)
websocket-driver (0.7.7)
websocket-driver (0.8.0)
base64
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.5)
@@ -1096,6 +1096,7 @@ DEPENDENCIES
webauthn (~> 3.0)
webmock (~> 3.18)
webpush!
websocket-driver (~> 0.8)
xorcist (~> 1.1)
RUBY VERSION

View File

@@ -16,6 +16,5 @@ A "vulnerability in Mastodon" is a vulnerability in the code distributed through
| Version | Supported |
| ------- | ---------------- |
| 4.4.x | Yes |
| 4.3.x | Yes |
| 4.2.x | Until 2026-01-08 |
| < 4.2 | No |
| 4.3.x | Until 2026-05-06 |
| < 4.3 | No |

View File

@@ -3,6 +3,7 @@
class ActivityPub::InboxesController < ActivityPub::BaseController
include JsonLdHelper
before_action :skip_large_payload
before_action :skip_unknown_actor_activity
before_action :require_actor_signature!
skip_before_action :authenticate_user!
@@ -16,6 +17,10 @@ class ActivityPub::InboxesController < ActivityPub::BaseController
private
def skip_large_payload
head 413 if request.content_length > ActivityPub::Activity::MAX_JSON_SIZE
end
def skip_unknown_actor_activity
head 202 if unknown_affected_account?
end

View File

@@ -22,7 +22,7 @@ class ActivityPub::LikesController < ActivityPub::BaseController
def set_status
@status = @account.statuses.find(params[:status_id])
authorize @status, :show?
rescue Mastodon::NotPermittedError
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
not_found
end

View File

@@ -25,7 +25,7 @@ class ActivityPub::RepliesController < ActivityPub::BaseController
def set_status
@status = @account.statuses.find(params[:status_id])
authorize @status, :show?
rescue Mastodon::NotPermittedError
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
not_found
end

View File

@@ -22,7 +22,7 @@ class ActivityPub::SharesController < ActivityPub::BaseController
def set_status
@status = @account.statuses.find(params[:status_id])
authorize @status, :show?
rescue Mastodon::NotPermittedError
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
not_found
end

View File

@@ -9,10 +9,16 @@ module Admin
@pending_appeals_count = Appeal.pending.async_count
@pending_reports_count = Report.unresolved.async_count
@pending_tags_count = Tag.pending_review.async_count
@pending_tags_count = pending_tags.async_count
@pending_users_count = User.pending.async_count
@system_checks = Admin::SystemCheck.perform(current_user)
@time_period = (29.days.ago.to_date...Time.now.utc.to_date)
end
private
def pending_tags
::Trends::TagFilter.new(status: :pending_review).results
end
end
end

View File

@@ -17,7 +17,7 @@ class Api::V1::Polls::VotesController < Api::BaseController
def set_poll
@poll = Poll.find(params[:poll_id])
authorize @poll.status, :show?
rescue Mastodon::NotPermittedError
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
not_found
end

View File

@@ -17,7 +17,7 @@ class Api::V1::PollsController < Api::BaseController
def set_poll
@poll = Poll.find(params[:id])
authorize @poll.status, :show?
rescue Mastodon::NotPermittedError
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
not_found
end

View File

@@ -10,7 +10,7 @@ class Api::V1::Statuses::BaseController < Api::BaseController
def set_status
@status = Status.find(params[:status_id])
authorize @status, :show?
rescue Mastodon::NotPermittedError
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
not_found
end
end

View File

@@ -23,7 +23,7 @@ class Api::V1::Statuses::BookmarksController < Api::V1::Statuses::BaseController
bookmark&.destroy!
render json: @status, serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new([@status], current_account.id, bookmarks_map: { @status.id => false })
rescue Mastodon::NotPermittedError
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
not_found
end
end

View File

@@ -25,7 +25,7 @@ class Api::V1::Statuses::FavouritesController < Api::V1::Statuses::BaseControlle
relationships = StatusRelationshipsPresenter.new([@status], current_account.id, favourites_map: { @status.id => false }, attributes_map: { @status.id => { favourites_count: count } })
render json: @status, serializer: REST::StatusSerializer, relationships: relationships
rescue Mastodon::NotPermittedError
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
not_found
end
end

View File

@@ -36,7 +36,7 @@ class Api::V1::Statuses::ReblogsController < Api::V1::Statuses::BaseController
relationships = StatusRelationshipsPresenter.new([@status], current_account.id, reblogs_map: { @reblog.id => false }, attributes_map: { @reblog.id => { reblogs_count: count } })
render json: @reblog, serializer: REST::StatusSerializer, relationships: relationships
rescue Mastodon::NotPermittedError
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
not_found
end
@@ -45,7 +45,7 @@ class Api::V1::Statuses::ReblogsController < Api::V1::Statuses::BaseController
def set_reblog
@reblog = Status.find(params[:status_id])
authorize @reblog, :show?
rescue Mastodon::NotPermittedError
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
not_found
end

View File

@@ -129,7 +129,7 @@ class Api::V1::StatusesController < Api::BaseController
def set_status
@status = Status.find(params[:id])
authorize @status, :show?
rescue Mastodon::NotPermittedError
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
not_found
end

View File

@@ -30,7 +30,7 @@ class Api::Web::EmbedsController < Api::Web::BaseController
def set_status
@status = Status.find(params[:id])
authorize @status, :show?
rescue Mastodon::NotPermittedError
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
not_found
end
end

View File

@@ -62,7 +62,7 @@ class Api::Web::PushSubscriptionsController < Api::Web::BaseController
end
def set_push_subscription
@push_subscription = ::Web::PushSubscription.find(params[:id])
@push_subscription = ::Web::PushSubscription.where(user_id: active_session.user_id).find(params[:id])
end
def subscription_params

View File

@@ -21,7 +21,7 @@ class AuthorizeInteractionsController < ApplicationController
def set_resource
@resource = located_resource
authorize(@resource, :show?) if @resource.is_a?(Status)
rescue Mastodon::NotPermittedError
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
not_found
end

View File

@@ -19,7 +19,7 @@ module CacheConcern
# from being used as cache keys, while allowing to `Vary` on them (to not serve
# anonymous cached data to authenticated requests when authentication matters)
def enforce_cache_control!
vary = response.headers['Vary']&.split&.map { |x| x.strip.downcase }
vary = response.headers['Vary'].to_s.split(',').map { |x| x.strip.downcase }.reject(&:empty?)
return unless vary.present? && %w(cookie authorization signature).any? { |header| vary.include?(header) && request.headers[header].present? }
response.cache_control.replace(private: true, no_store: true)

View File

@@ -70,10 +70,13 @@ module SignatureVerification
rescue Mastodon::SignatureVerificationError => e
fail_with! e.message
rescue *Mastodon::HTTP_CONNECTION_ERRORS => e
@signature_verification_failure_code ||= 503
fail_with! "Failed to fetch remote data: #{e.message}"
rescue Mastodon::UnexpectedResponseError
@signature_verification_failure_code ||= 503
fail_with! 'Failed to fetch remote data (got unexpected reply from server)'
rescue Stoplight::Error::RedLight
@signature_verification_failure_code ||= 503
fail_with! 'Fetching attempt skipped because of recent connection failure'
end

View File

@@ -34,7 +34,7 @@ class MediaController < ApplicationController
def verify_permitted_status!
authorize @media_attachment.status, :show?
rescue Mastodon::NotPermittedError
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
not_found
end

View File

@@ -26,7 +26,7 @@ class SeveredRelationshipsController < ApplicationController
private
def set_event
@event = AccountRelationshipSeveranceEvent.find(params[:id])
@event = AccountRelationshipSeveranceEvent.where(account: current_account).find(params[:id])
end
def following_data

View File

@@ -59,7 +59,7 @@ class StatusesController < ApplicationController
def set_status
@status = @account.statuses.find(params[:id])
authorize @status, :show?
rescue Mastodon::NotPermittedError
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
not_found
end

View File

@@ -102,6 +102,16 @@ module ApplicationHelper
policy(record).public_send(:"#{action}?")
end
def conditional_link_to(condition, name, options = {}, html_options = {}, &block)
if condition && !current_page?(block_given? ? name : options)
link_to(name, options, html_options, &block)
elsif block_given?
content_tag(:span, options, html_options, &block)
else
content_tag(:span, name, html_options)
end
end
def material_symbol(icon, attributes = {})
safe_join(
[

View File

@@ -101,12 +101,17 @@ export const ensureComposeIsVisible = (getState) => {
};
export function setComposeToStatus(status, text, spoiler_text, content_type) {
return{
type: COMPOSE_SET_STATUS,
status,
text,
spoiler_text,
content_type,
return (dispatch, getState) => {
const maxOptions = getState().server.getIn(['server', 'configuration', 'polls', 'max_options']);
dispatch({
type: COMPOSE_SET_STATUS,
status,
text,
spoiler_text,
content_type,
maxOptions
});
};
}
@@ -193,8 +198,9 @@ export function directCompose(account) {
/**
* @param {null | string} overridePrivacy
* @param {undefined | Function} successCallback
*/
export function submitCompose(overridePrivacy = null) {
export function submitCompose(overridePrivacy = null, successCallback = undefined) {
return function (dispatch, getState) {
let status = getState().getIn(['compose', 'text'], '');
const media = getState().getIn(['compose', 'media_attachments']);
@@ -259,6 +265,9 @@ export function submitCompose(overridePrivacy = null) {
dispatch(insertIntoTagHistory(response.data.tags, status));
dispatch(submitComposeSuccess({ ...response.data }));
if (typeof successCallback === 'function') {
successCallback(response.data);
}
// To make the app more responsive, immediately push the status
// into the columns

View File

@@ -21,6 +21,15 @@ export function normalizeFilterResult(result) {
return normalResult;
}
function stripQuoteFallback(text) {
const wrapper = document.createElement('div');
wrapper.innerHTML = text;
wrapper.querySelector('.quote-inline')?.remove();
return wrapper.innerHTML;
}
export function normalizeStatus(status, normalOldStatus, settings) {
const normalStatus = { ...status };
@@ -78,6 +87,11 @@ export function normalizeStatus(status, normalOldStatus, settings) {
normalStatus.spoilerHtml = emojify(escapeTextContentForBrowser(spoilerText), emojiMap);
normalStatus.hidden = (spoilerText.length > 0 || normalStatus.sensitive) && autoHideCW(settings, spoilerText);
// Remove quote fallback link from the DOM so it doesn't mess with paragraph margins
if (normalStatus.quote) {
normalStatus.contentHtml = stripQuoteFallback(normalStatus.contentHtml);
}
if (normalStatus.url && !(normalStatus.url.startsWith('http://') || normalStatus.url.startsWith('https://'))) {
normalStatus.url = null;
}
@@ -117,6 +131,11 @@ export function normalizeStatusTranslation(translation, status) {
spoiler_text: translation.spoiler_text,
};
// Remove quote fallback link from the DOM so it doesn't mess with paragraph margins
if (status.get('quote')) {
normalTranslation.contentHtml = stripQuoteFallback(normalTranslation.contentHtml);
}
return normalTranslation;
}

View File

@@ -3,7 +3,7 @@ import { browserHistory } from 'flavours/glitch/components/router';
import api from '../api';
import { ensureComposeIsVisible, setComposeToStatus } from './compose';
import { importFetchedStatus, importFetchedStatuses, importFetchedAccount } from './importer';
import { importFetchedStatus, importFetchedAccount } from './importer';
import { fetchContext } from './statuses_typed';
import { deleteFromTimelines } from './timelines';
@@ -48,7 +48,18 @@ export function fetchStatusRequest(id, skipLoading) {
};
}
export function fetchStatus(id, forceFetch = false, alsoFetchContext = true) {
/**
* @param {string} id
* @param {Object} [options]
* @param {boolean} [options.forceFetch]
* @param {boolean} [options.alsoFetchContext]
* @param {string | null | undefined} [options.parentQuotePostId]
*/
export function fetchStatus(id, {
forceFetch = false,
alsoFetchContext = true,
parentQuotePostId,
} = {}) {
return (dispatch, getState) => {
const skipLoading = !forceFetch && getState().getIn(['statuses', id], null) !== null;
@@ -66,7 +77,9 @@ export function fetchStatus(id, forceFetch = false, alsoFetchContext = true) {
dispatch(importFetchedStatus(response.data));
dispatch(fetchStatusSuccess(skipLoading));
}).catch(error => {
dispatch(fetchStatusFail(id, error, skipLoading));
dispatch(fetchStatusFail(id, error, skipLoading, parentQuotePostId));
if (error.status === 404)
dispatch(deleteFromTimelines(id));
});
};
}
@@ -78,22 +91,28 @@ export function fetchStatusSuccess(skipLoading) {
};
}
export function fetchStatusFail(id, error, skipLoading) {
export function fetchStatusFail(id, error, skipLoading, parentQuotePostId) {
return {
type: STATUS_FETCH_FAIL,
id,
error,
parentQuotePostId,
skipLoading,
skipAlert: true,
};
}
export function redraft(status, raw_text, content_type) {
return {
type: REDRAFT,
status,
raw_text,
content_type,
return (dispatch, getState) => {
const maxOptions = getState().server.getIn(['server', 'configuration', 'polls', 'max_options']);
dispatch({
type: REDRAFT,
status,
raw_text,
content_type,
maxOptions,
});
};
}

View File

@@ -1,10 +1,11 @@
import { apiRequestPost } from 'flavours/glitch/api';
import type { Status, StatusVisibility } from 'flavours/glitch/models/status';
import type { ApiStatusJSON } from 'flavours/glitch/api_types/statuses';
import type { StatusVisibility } from 'flavours/glitch/models/status';
export const apiReblog = (statusId: string, visibility: StatusVisibility) =>
apiRequestPost<{ reblog: Status }>(`v1/statuses/${statusId}/reblog`, {
apiRequestPost<{ reblog: ApiStatusJSON }>(`v1/statuses/${statusId}/reblog`, {
visibility,
});
export const apiUnreblog = (statusId: string) =>
apiRequestPost<Status>(`v1/statuses/${statusId}/unreblog`);
apiRequestPost<ApiStatusJSON>(`v1/statuses/${statusId}/unreblog`);

View File

@@ -20,7 +20,7 @@ import { useDrag } from '@use-gesture/react';
import { expandAccountFeaturedTimeline } from '@/flavours/glitch/actions/timelines';
import { Icon } from '@/flavours/glitch/components/icon';
import { IconButton } from '@/flavours/glitch/components/icon_button';
import StatusContainer from '@/flavours/glitch/containers/status_container';
import { StatusQuoteManager } from '@/flavours/glitch/components/status_quoted';
import { usePrevious } from '@/flavours/glitch/hooks/usePrevious';
import { useAppDispatch, useAppSelector } from '@/flavours/glitch/store';
import ChevronLeftIcon from '@/material-icons/400-24px/chevron_left.svg?react';
@@ -218,12 +218,7 @@ const FeaturedCarouselItem: React.FC<
ref={handleRef}
{...props}
>
<StatusContainer
// @ts-expect-error inferred props are wrong
id={statusId}
contextType='account'
withCounters
/>
<StatusQuoteManager id={statusId} contextType='account' withCounters />
</animated.div>
);
};

View File

@@ -1,4 +1,4 @@
import { useEffect, useMemo } from 'react';
import { useCallback, useEffect, useMemo } from 'react';
import { FormattedMessage } from 'react-intl';
@@ -12,12 +12,15 @@ import ArticleIcon from '@/material-icons/400-24px/article.svg?react';
import ChevronRightIcon from '@/material-icons/400-24px/chevron_right.svg?react';
import { Icon } from 'flavours/glitch/components/icon';
import StatusContainer from 'flavours/glitch/containers/status_container';
import { domain } from 'flavours/glitch/initial_state';
import type { Status } from 'flavours/glitch/models/status';
import type { RootState } from 'flavours/glitch/store';
import { useAppDispatch, useAppSelector } from 'flavours/glitch/store';
import { revealAccount } from '../actions/accounts_typed';
import { fetchStatus } from '../actions/statuses';
import { makeGetStatus } from '../selectors';
import { getAccountHidden } from '../selectors/accounts';
const MAX_QUOTE_POSTS_NESTING_LEVEL = 1;
@@ -37,9 +40,7 @@ const QuoteWrapper: React.FC<{
);
};
const NestedQuoteLink: React.FC<{
status: Status;
}> = ({ status }) => {
const NestedQuoteLink: React.FC<{ status: Status }> = ({ status }) => {
const accountId = status.get('account') as string;
const account = useAppSelector((state) =>
accountId ? state.accounts.get(accountId) : undefined,
@@ -75,24 +76,74 @@ type GetStatusSelector = (
props: { id?: string | null; contextType?: string },
) => Status | null;
const LimitedAccountHint: React.FC<{ accountId: string }> = ({ accountId }) => {
const dispatch = useAppDispatch();
const reveal = useCallback(() => {
dispatch(revealAccount({ id: accountId }));
}, [dispatch, accountId]);
return (
<>
<FormattedMessage
id='status.quote_error.limited_account_hint.title'
defaultMessage='This account has been hidden by the moderators of {domain}.'
values={{ domain }}
/>
<button onClick={reveal} className='link-button'>
<FormattedMessage
id='status.quote_error.limited_account_hint.action'
defaultMessage='Show anyway'
/>
</button>
</>
);
};
export const QuotedStatus: React.FC<{
quote: QuoteMap;
contextType?: string;
parentQuotePostId?: string | null;
variant?: 'full' | 'link';
nestingLevel?: number;
}> = ({ quote, contextType, nestingLevel = 1, variant = 'full' }) => {
}> = ({
quote,
contextType,
parentQuotePostId,
nestingLevel = 1,
variant = 'full',
}) => {
const dispatch = useAppDispatch();
const quoteState = useAppSelector((state) =>
parentQuotePostId
? state.statuses.getIn([parentQuotePostId, 'quote', 'state'])
: quote.get('state'),
);
const quotedStatusId = quote.get('quoted_status');
const quoteState = quote.get('state');
const status = useAppSelector((state) =>
quotedStatusId ? state.statuses.get(quotedStatusId) : undefined,
);
const shouldLoadQuote = !status?.get('isLoading') && quoteState !== 'deleted';
const accountId: string | null = status?.get('account', null) as
| string
| null;
const hiddenAccount = useAppSelector(
(state) => accountId && getAccountHidden(state, accountId),
);
useEffect(() => {
if (!status && quotedStatusId) {
dispatch(fetchStatus(quotedStatusId));
if (shouldLoadQuote && quotedStatusId) {
dispatch(
fetchStatus(quotedStatusId, {
parentQuotePostId,
alsoFetchContext: false,
}),
);
}
}, [status, quotedStatusId, dispatch]);
}, [shouldLoadQuote, quotedStatusId, parentQuotePostId, dispatch]);
// In order to find out whether the quoted post should be completely hidden
// due to a matching filter, we run it through the selector used by `status_container`.
@@ -147,6 +198,8 @@ export const QuotedStatus: React.FC<{
defaultMessage='This post cannot be displayed.'
/>
);
} else if (hiddenAccount && accountId) {
quoteError = <LimitedAccountHint accountId={accountId} />;
}
if (quoteError) {
@@ -173,6 +226,7 @@ export const QuotedStatus: React.FC<{
{canRenderChildQuote && (
<QuotedStatus
quote={childQuote}
parentQuotePostId={quotedStatusId}
contextType={contextType}
variant={
nestingLevel === MAX_QUOTE_POSTS_NESTING_LEVEL ? 'link' : 'full'
@@ -209,7 +263,11 @@ export const StatusQuoteManager = (props: StatusQuoteManagerProps) => {
return (
/* @ts-expect-error Status is not yet typed */
<StatusContainer {...props}>
<QuotedStatus quote={quote} contextType={props.contextType} />
<QuotedStatus
quote={quote}
parentQuotePostId={status?.get('id') as string}
contextType={props.contextType}
/>
</StatusContainer>
);
}

View File

@@ -81,6 +81,7 @@ class ComposeForm extends ImmutablePureComponent {
singleColumn: PropTypes.bool,
lang: PropTypes.string,
maxChars: PropTypes.number,
redirectOnSuccess: PropTypes.bool,
};
static defaultProps = {
@@ -336,7 +337,7 @@ class ComposeForm extends ImmutablePureComponent {
>
{intl.formatMessage(
this.props.isEditing ?
messages.saveChanges :
messages.saveChanges :
(this.props.isInReply ? messages.reply : messages.publish)
)}
</Button>

View File

@@ -56,7 +56,7 @@ const mapStateToProps = state => ({
maxChars: state.getIn(['server', 'server', 'configuration', 'statuses', 'max_characters'], 500),
});
const mapDispatchToProps = (dispatch) => ({
const mapDispatchToProps = (dispatch, props) => ({
onChange (text) {
dispatch(changeCompose(text));
@@ -69,7 +69,11 @@ const mapDispatchToProps = (dispatch) => ({
modalProps: { overridePrivacy },
}));
} else {
dispatch(submitCompose(overridePrivacy));
dispatch(submitCompose(overridePrivacy, (status) => {
if (props.redirectOnSuccess) {
window.location.assign(status.url);
}
}));
}
},

View File

@@ -5,7 +5,7 @@ import ModalContainer from 'flavours/glitch/features/ui/containers/modal_contain
const Compose = () => (
<>
<ComposeFormContainer autoFocus withoutNavigation />
<ComposeFormContainer autoFocus withoutNavigation redirectOnSuccess />
<AlertsController />
<ModalContainer />
<LoadingBarContainer className='loading-bar' />

View File

@@ -38,7 +38,7 @@ const Embed: React.FC<{ id: string }> = ({ id }) => {
const dispatchRenderSignal = useRenderSignal();
useEffect(() => {
dispatch(fetchStatus(id, false, false));
dispatch(fetchStatus(id, { alsoFetchContext: false }));
}, [dispatch, id]);
const handleToggleHidden = useCallback(() => {

View File

@@ -26,18 +26,23 @@ const getHostname = url => {
const domParser = new DOMParser();
const addAutoPlay = html => {
const handleIframeUrl = (html, url, providerName) => {
const document = domParser.parseFromString(html, 'text/html').documentElement;
const iframe = document.querySelector('iframe');
const startTime = new URL(url).searchParams.get('t')
if (iframe) {
if (iframe.src.indexOf('?') !== -1) {
iframe.src += '&';
} else {
iframe.src += '?';
const iframeUrl = new URL(iframe.src)
iframeUrl.searchParams.set('autoplay', 1)
iframeUrl.searchParams.set('auto_play', 1)
if (providerName === 'YouTube') {
iframeUrl.searchParams.set('start', startTime || '');
iframe.referrerPolicy = 'strict-origin-when-cross-origin';
}
iframe.src += 'autoplay=1&auto_play=1';
iframe.src = iframeUrl.href
// DOM parser creates html/body elements around original HTML fragment,
// so we need to get innerHTML out of the body and not the entire document
@@ -103,7 +108,7 @@ export default class Card extends PureComponent {
renderVideo () {
const { card } = this.props;
const content = { __html: addAutoPlay(card.get('html')) };
const content = { __html: handleIframeUrl(card.get('html'), card.get('url'), card.get('provider_name')) };
return (
<div

View File

@@ -418,7 +418,11 @@ export const DetailedStatus: React.FC<{
{hashtagBar}
{status.get('quote') && (
<QuotedStatus quote={status.get('quote')} />
<QuotedStatus
quote={status.get('quote')}
parentQuotePostId={status.get('id')}
contextType='thread'
/>
)}
</>
)}

View File

@@ -38,7 +38,7 @@ class FilterModal extends ImmutablePureComponent {
handleSuccess = () => {
const { dispatch, statusId } = this.props;
dispatch(fetchStatus(statusId, true));
dispatch(fetchStatus(statusId, {forceFetch: true}));
this.setState({ isSubmitting: false, isSubmitted: true, step: 'submitted' });
};

View File

@@ -201,8 +201,6 @@ class MediaModal extends ImmutablePureComponent {
preview={image.get('preview_url')}
blurhash={image.get('blurhash')}
src={image.get('url')}
width={image.get('width')}
height={image.get('height')}
frameRate={image.getIn(['meta', 'original', 'frame_rate'])}
startTime={currentTime || 0}
startPlaying={autoPlay || false}
@@ -218,8 +216,6 @@ class MediaModal extends ImmutablePureComponent {
return (
<GIFV
src={image.get('url')}
width={width}
height={height}
key={image.get('url')}
alt={description}
lang={lang}

View File

@@ -92,8 +92,7 @@ const messages = defineMessages({
const mapStateToProps = state => ({
layout: state.getIn(['meta', 'layout']),
hasComposingText: state.getIn(['compose', 'text']).trim().length !== 0,
hasMediaAttachments: state.getIn(['compose', 'media_attachments']).size > 0,
hasComposingContents: state.getIn(['compose', 'text']).trim().length !== 0 || state.getIn(['compose', 'media_attachments']).size > 0 || state.getIn(['compose', 'poll']) !== null,
canUploadMore: !state.getIn(['compose', 'media_attachments']).some(x => ['audio', 'video'].includes(x.get('type'))) && state.getIn(['compose', 'media_attachments']).size < 4,
isWide: state.getIn(['local_settings', 'stretch']),
fullWidthColumns: state.getIn(['local_settings', 'fullwidth_columns']),
@@ -284,8 +283,7 @@ class UI extends PureComponent {
fullWidthColumns: PropTypes.bool,
systemFontUi: PropTypes.bool,
isComposing: PropTypes.bool,
hasComposingText: PropTypes.bool,
hasMediaAttachments: PropTypes.bool,
hasComposingContents: PropTypes.bool,
canUploadMore: PropTypes.bool,
intl: PropTypes.object.isRequired,
unreadNotifications: PropTypes.number,
@@ -304,11 +302,11 @@ class UI extends PureComponent {
};
handleBeforeUnload = e => {
const { intl, dispatch, hasComposingText, hasMediaAttachments } = this.props;
const { intl, dispatch, hasComposingContents } = this.props;
dispatch(synchronouslySubmitMarkers());
if (hasComposingText || hasMediaAttachments) {
if (hasComposingContents) {
// Setting returnValue to any string causes confirmation dialog.
// Many browsers no longer display this text to users,
// but we set user-friendly message for other browsers, e.g. Edge.

View File

@@ -6,12 +6,8 @@
"account.view_full_profile": "عرض الملف الشخصي كاملاً",
"boost_modal.missing_description": "هذا المنشور يحتوي على وسائط بلا وصف",
"column.favourited_by": "المفضلة من قبل",
"column.heading": "متنوعة",
"column.reblogged_by": "المرقى من قبل",
"column.subheading": "خيارات متنوعة",
"column_header.profile": "الملف الشخصي",
"column_subheading.lists": "القوائم",
"column_subheading.navigation": "التنقل",
"community.column_settings.allow_local_only": "إظهار المنشورات المحلية فقط",
"compose.attach.doodle": "الرسوم و التخمين",
"compose.change_federation": "تغيير اعدادات الفيديرالية",
@@ -36,8 +32,6 @@
"keyboard_shortcuts.secondary_toot": "لإرسال التبويق باستخدام إعدادات الخصوصية الثانوية",
"moved_to_warning": "عُلِّم هذا الحساب بأنه انتقل إلى {moved_to_link}، لذا قد لا يقبل متابعات جديدة.",
"navigation_bar.app_settings": "إعدادات التطبيق",
"navigation_bar.keyboard_shortcuts": "اختصارات لوحة المفاتيح",
"navigation_bar.misc": "متنوع",
"settings.always_show_spoilers_field": "تمكين دائما حقل تحذير المحتوى",
"settings.close": "إغلاق",
"settings.content_warnings": "Content warnings",

View File

@@ -6,12 +6,8 @@
"account.view_full_profile": "Zobrazit celý profil",
"boost_modal.missing_description": "Příspěvek obsahuje obrázky bez popisků",
"column.favourited_by": "Oblíbeno uživatelem",
"column.heading": "Různé",
"column.reblogged_by": "Boostnuto uživatelem",
"column.subheading": "Různé",
"column_header.profile": "Profil",
"column_subheading.lists": "Seznamy",
"column_subheading.navigation": "Navigace",
"community.column_settings.allow_local_only": "Zobrazit pouze místní tooty",
"compose.attach.doodle": "Nakreslete něco",
"compose.change_federation": "Změnit nastavení federace",
@@ -45,8 +41,6 @@
"keyboard_shortcuts.secondary_toot": "pro odeslání příspěvku s sekundárním nastavením soukromí",
"moved_to_warning": "Tento účet je označen jako přesunut na {moved_to_link}, a proto nemusí přijímat nové sledování.",
"navigation_bar.app_settings": "Nastavení aplikace",
"navigation_bar.keyboard_shortcuts": "Klávesové zkratky",
"navigation_bar.misc": "Různé",
"notifications.column_settings.filter_bar.show_bar": "Zobrazit panel filtrů",
"settings.always_show_spoilers_field": "Vždy zobrazit pole pro varování o obsahu",
"settings.close": "Zavřít",

View File

@@ -6,12 +6,8 @@
"account.view_full_profile": "Dangos proffil cyfan",
"boost_modal.missing_description": "Mae'r tŵt yma'n cynnwys ychydig gyfryngau heb ddisgrifiad",
"column.favourited_by": "Wedi'i hoffi gan",
"column.heading": "Misg",
"column.reblogged_by": "Wedi'i bŵstio gan",
"column.subheading": "Opsiynnau arall",
"column_header.profile": "Proffil",
"column_subheading.lists": "Rhestri",
"column_subheading.navigation": "Llywio",
"community.column_settings.allow_local_only": "Dangos tŵtiau lleol yn unig",
"compose.content-type.html": "HTML",
"compose.content-type.markdown": "Markdown",

View File

@@ -2,7 +2,6 @@
"home.column_settings.advanced": "Avanceret",
"home.column_settings.show_direct": "Vis private omtaler",
"navigation_bar.app_settings": "Appindstillinger",
"navigation_bar.misc": "Diverse",
"settings.always_show_spoilers_field": "Vis altid feltet til indholdsadvarsel",
"settings.close": "Luk",
"settings.content_warnings": "Indholdsadvarsler",

View File

@@ -6,12 +6,8 @@
"account.view_full_profile": "Vollständiges Profil anzeigen",
"boost_modal.missing_description": "Dieser Toot enthält Medien ohne Beschreibung",
"column.favourited_by": "Favorisiert von",
"column.heading": "Sonstiges",
"column.reblogged_by": "Geteilt von",
"column.subheading": "Sonstige Optionen",
"column_header.profile": "Profil",
"column_subheading.lists": "Listen",
"column_subheading.navigation": "Navigation",
"community.column_settings.allow_local_only": "Nur-lokale Toots anzeigen",
"compose.attach.doodle": "Male etwas",
"compose.change_federation": "Föderationseinstellungen ändern",
@@ -45,8 +41,6 @@
"keyboard_shortcuts.secondary_toot": "Toot mit sekundärer Privatsphäreeinstellung absenden",
"moved_to_warning": "Dieses Konto ist als verschoben zu {moved_to_link} markiert und akzeptiert daher keine neuen Follower.",
"navigation_bar.app_settings": "App-Einstellungen",
"navigation_bar.keyboard_shortcuts": "Tastaturkürzel",
"navigation_bar.misc": "Sonstiges",
"notifications.column_settings.filter_bar.show_bar": "Filterleiste anzeigen",
"settings.always_show_spoilers_field": "Das Inhaltswarnungs-Feld immer aktivieren",
"settings.close": "Schließen",

View File

@@ -1,4 +1,92 @@
{
"settings.content_warnings": "Content warnings",
"settings.preferences": "Preferences"
"about.fork_disclaimer": "Το Glitch-soc είναι ελεύθερο λογισμικό ανοιχτού κώδικα που είναι αντιγραφή από το Mastodon.",
"account.disclaimer_full": "Οι παρακάτω πληροφορίες μπορεί να αντικατοπτρίζουν το προφίλ του χρήστη ελλιπώς.",
"account.follows": "Ακολουθεί",
"account.suspended_disclaimer_full": "Αυτός ο χρήστης έχει ανασταλεί από έναν συντονιστή.",
"account.view_full_profile": "Προβολή πλήρους προφίλ",
"boost_modal.missing_description": "Αυτό το τουτ περιέχει κάποια μέσα χωρίς περιγραφή",
"column.favourited_by": "Αγαπήθηκε από",
"column.reblogged_by": "Ενισχύθηκε από",
"column_header.profile": "Προφίλ",
"community.column_settings.allow_local_only": "Εμφάνιση τοπικών τουτ",
"compose.attach.doodle": "Σχεδίασε κάτι",
"compose.change_federation": "Αλλαγή ρυθμίσεων ομοσπονδίας",
"compose.content-type.change": "Αλλαγή προηγμένων επιλογών μορφοποίησης",
"compose.content-type.html": "HTML",
"compose.content-type.html_meta": "Μορφοποίηση των αναρτήσεων σας με χρήση HTML",
"compose.content-type.markdown": "Markdown",
"compose.content-type.markdown_meta": "Μορφοποίηση των αναρτήσεων σας με χρήση Markdown",
"compose.content-type.plain": "Απλό κείμενο",
"compose.content-type.plain_meta": "Γράψιμο χωρίς προηγμένη μορφοποίηση",
"compose.disable_threaded_mode": "Απενεργοποίηση λειτουργίας νημάτων",
"compose.enable_threaded_mode": "Ενεργοποίηση λειτουργίας νημάτων",
"compose_form.sensitive.hide": "{count, plural, one {Επισήμανση πολυμέσου ως ευαίσθητο} other {Επισήμανση πολυμέσων ως ευαίσθητα}}",
"compose_form.sensitive.marked": "{count, plural, one {Το πολυμέσο έχει σημανθεί ως ευαίσθητο} other {Τα πολυμέσα έχουν σημανθεί ως ευαίσθητα}}",
"compose_form.sensitive.unmarked": "{count, plural, one {Το πολυμέσο δεν έχει σημανθεί ως ευαίσθητο} other {Τα πολυμέσα δεν έχουν σημανθεί ως ευαίσθητα}}",
"confirmation_modal.do_not_ask_again": "Να μην ζητηθεί επιβεβαίωση ξανά",
"confirmations.deprecated_settings.confirm": "Χρήση προτιμήσεων του Mastodon",
"direct.group_by_conversations": "Ομαδοποίηση ανά συζήτηση",
"favourite_modal.favourite": "Αγάπησε την ανάρτηση;",
"federation.federated.long": "Επιτρέψτε σε αυτήν την ανάρτηση να φτάσει σε άλλους διακομιστές",
"federation.local_only.long": "Αποτρέψτε αυτήν την ανάρτηση να φτάσει σε άλλους διακομιστές",
"federation.local_only.short": "Τοπικά μόνο",
"firehose.column_settings.allow_local_only": "Εμφάνιση τοπικών αναρτήσεων σε \"Όλα\"",
"home.column_settings.advanced": "Για προχωρημένους",
"home.column_settings.filter_regex": "Φιλτράρισμα βάσει των κανονικών εκφράσεων",
"home.column_settings.show_direct": "Εμφάνιση ιδιωτικών επισημάνσεων",
"home.settings": "Ρυθμίσεις στήλης",
"keyboard_shortcuts.bookmark": "για να σελιδοποιήσει",
"keyboard_shortcuts.secondary_toot": "για αποστολή τουτ χρησιμοποιώντας δευτερεύουσα ρύθμιση απορρήτου",
"moved_to_warning": "Αυτός ο λογαριασμός έχει σημανθεί ως μετακινημένος στο {moved_to_link} και έτσι δεν μπορεί να δεχτεί νέους ακολούθους.",
"navigation_bar.app_settings": "Ρυθμίσεις εφαρμογής",
"notifications.column_settings.filter_bar.show_bar": "Εμφάνιση μπάρας φίλτρου",
"settings.always_show_spoilers_field": "Πάντα ενεργοποίηση του πεδίου Προειδοποίηση Περιεχομένου",
"settings.close": "Κλείσιμο",
"settings.compose_box_opts": "Πλαίσιο σύνθεσης",
"settings.content_warnings": "Προειδοποιήσεις περιεχομένου",
"settings.content_warnings.regexp": "Κανονική έκφραση (regex)",
"settings.content_warnings_filter": "Προειδοποιήσεις περιεχομένου να μην ξεδιπλώνονται αυτόματα:",
"settings.content_warnings_shared_state": "Εμφάνιση/απόκρυψη περιεχομένου όλων των αντιγράφων ταυτόχρονα",
"settings.content_warnings_unfold_opts": "Επιλογές αυτόματου ξεδιπλώματος",
"settings.deprecated_setting": "Αυτή η ρύθμιση τώρα ελέγχεται από τις {settings_page_link} του Mastodon",
"settings.enable_content_warnings_auto_unfold": "Αυτόματη ξεδίπλωμα προειδοποιήσεων περιεχομένου",
"settings.general": "Γενικά",
"settings.layout_opts": "Επιλογές διάταξης",
"settings.media": "Πολυμέσα",
"settings.notifications.tab_badge": "Σήμα μη αναγνωσμένων ειδοποιήσεων",
"settings.notifications.tab_badge.hint": "Εμφανίζει ένα σήμα για μη αναγνωσμένες ειδοποιήσεις στα εικονίδια της στήλης όταν η στήλη ειδοποιήσεων δεν είναι ανοιχτή",
"settings.notifications_opts": "Ρυθμίσεις ειδοποιήσεων",
"settings.pop_in_left": "Αριστερά",
"settings.pop_in_right": "Δεξιά",
"settings.preferences": "Προτιμήσεις χρήστη",
"settings.preselect_on_reply": "Προεπιλογή ονομάτων χρηστών στην απάντηση",
"settings.preselect_on_reply_hint": "Όταν απαντάτε σε μια συνομιλία με πολλαπλούς συμμετέχοντες, προεπιλέξτε τα ονόματα χρηστών μετά τον πρώτο",
"settings.rewrite_mentions": "Ξαναγράψε επισημάνσεις στις προβαλλόμενες καταστάσεις",
"settings.rewrite_mentions_acct": "Ξαναγράψε με όνομα χρήστη και τομέα (όταν ο λογαριασμός είναι απομακρυσμένος)",
"settings.rewrite_mentions_no": "Μην ξαναγράψεις επισημάνσεις",
"settings.rewrite_mentions_username": "Ξαναγράψε με όνομα χρήστη",
"settings.shared_settings_link": "προτιμήσεις χρήστη",
"settings.side_arm": "Δευτερεύον κουμπί τουτ:",
"settings.side_arm.none": "Κανένα",
"settings.side_arm_reply_mode": "Όταν απαντάτε σε ένα τουτ, το κουμπί δευτερεύοντος τουτ πρέπει να:",
"settings.side_arm_reply_mode.copy": "Αντιγράψει τη ρύθμιση απορρήτου του τουτ που απαντάται",
"settings.side_arm_reply_mode.keep": "Διατηρήσει το καθορισμένο απόρρητο",
"settings.side_arm_reply_mode.restrict": "Περιορίσει τη ρύθμιση απορρήτου σε εκείνη του τουτ που απαντάται",
"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": "Σήμανση παραπλανητικών συνδέσμων",
"settings.tag_misleading_links.hint": "Προσθήκη οπτικής ένδειξης με τον εξυπηρετητή στόχο του συνδέσμου σε κάθε σύνδεσμο που δεν αναφέρεται ρητά",
"status.filtered": "Φιλτραρισμένο",
"status.has_audio": "Διαθέτει συνημμένα αρχεία ήχου",
"status.has_pictures": "Διαθέτει συνημμένες εικόνες",
"status.has_preview_card": "Διαθέτει συνημμένη κάρτα προεπισκόπησης",
"status.has_video": "Διαθέτει συνημμένα βίντεο",
"status.hide": "Απόκρυψη ανάρτησης",
"status.in_reply_to": "Αυτό το τουτ είναι απάντηση",
"status.is_poll": "Αυτό το τουτ είναι δημοσκόπηση",
"status.show_filter_reason": "Εμφάνιση ούτως ή άλλως"
}

View File

@@ -6,12 +6,8 @@
"account.view_full_profile": "Vidi plenan profilon",
"boost_modal.missing_description": "Ĉi tiu afiŝo enhavas plurmedion, ke ne havas priskribon",
"column.favourited_by": "Stelumita per",
"column.heading": "Diversaj aferoj",
"column.reblogged_by": "Diskonigita de",
"column.subheading": "Diversaj agordoj",
"column_header.profile": "Profilo",
"column_subheading.lists": "Listoj",
"column_subheading.navigation": "Navigado",
"community.column_settings.allow_local_only": "Montri nur-lokajn afiŝojn",
"compose.attach.doodle": "Skribu ion",
"compose.change_federation": "Ŝanĝi agordojn de federacio",
@@ -45,8 +41,6 @@
"keyboard_shortcuts.secondary_toot": "sendi afiŝon per dua agordo de privateco",
"moved_to_warning": "Ĉi tiun konton sigelas, kiel movinta al {moved_to_link}, kaj pro ne permesos novajn sekvantojn.",
"navigation_bar.app_settings": "Agordoj de aplikaĵo",
"navigation_bar.keyboard_shortcuts": "Fulmoklavoj",
"navigation_bar.misc": "Aliaj",
"notifications.column_settings.filter_bar.show_bar": "Montri mezuron de filtrilo",
"settings.always_show_spoilers_field": "Ĉiam ŝaltiĝu la arealo de Enhava Averto",
"settings.close": "Fermi",

View File

@@ -6,12 +6,8 @@
"account.view_full_profile": "Ver perfil completo",
"boost_modal.missing_description": "Esta publicación contiene medios sin descripción",
"column.favourited_by": "Marcado como favorito por",
"column.heading": "Misc",
"column.reblogged_by": "Impulsado por",
"column.subheading": "Opciones misceláneas",
"column_header.profile": "Perfil",
"column_subheading.lists": "Listas",
"column_subheading.navigation": "Navegación",
"community.column_settings.allow_local_only": "Mostrar sólo toots locales",
"compose.attach.doodle": "Dibujá algo",
"compose.change_federation": "Cambiar configuración de la federación",
@@ -45,8 +41,6 @@
"keyboard_shortcuts.secondary_toot": "para enviar un toot usando lac onfiguración de privacidad secundaria",
"moved_to_warning": "Esta cuenta está marcada como movida a {moved_to_link}, y por lo tanto no aceptará nuevos seguimientos.",
"navigation_bar.app_settings": "Ajustes de aplicación",
"navigation_bar.keyboard_shortcuts": "Atajos de teclado",
"navigation_bar.misc": "Misc",
"notifications.column_settings.filter_bar.show_bar": "Mostrar barra de filtros",
"settings.always_show_spoilers_field": "Siempre mostrar el campo de advertencia de contenido",
"settings.close": "Cerrar",

View File

@@ -6,12 +6,8 @@
"account.view_full_profile": "Ver perfil completo",
"boost_modal.missing_description": "Esta publicación contiene medios sin descripción",
"column.favourited_by": "Marcado como favorito por",
"column.heading": "Misc",
"column.reblogged_by": "Impulsado por",
"column.subheading": "Opciones misceláneas",
"column_header.profile": "Perfil",
"column_subheading.lists": "Listas",
"column_subheading.navigation": "Navegación",
"community.column_settings.allow_local_only": "Mostrar sólo toots locales",
"compose.attach.doodle": "Dibujar algo",
"compose.change_federation": "Cambiar configuración de la federación",
@@ -41,8 +37,6 @@
"keyboard_shortcuts.secondary_toot": "para enviar un toot usando lac onfiguración de privacidad secundaria",
"moved_to_warning": "Esta cuenta está marcada como movida a {moved_to_link}, y por lo tanto no aceptará nuevos seguimientos.",
"navigation_bar.app_settings": "Ajustes de aplicación",
"navigation_bar.keyboard_shortcuts": "Atajos de teclado",
"navigation_bar.misc": "Misc",
"settings.always_show_spoilers_field": "Siempre mostrar el campo de advertencia de contenido",
"settings.close": "Cerrar",
"settings.compose_box_opts": "Cuadro de redacción",

View File

@@ -6,12 +6,8 @@
"account.view_full_profile": "Ver perfil completo",
"boost_modal.missing_description": "Esta publicación contiene medios sin descripción",
"column.favourited_by": "Marcado como favorito por",
"column.heading": "Misc",
"column.reblogged_by": "Impulsado por",
"column.subheading": "Opciones misceláneas",
"column_header.profile": "Perfil",
"column_subheading.lists": "Listas",
"column_subheading.navigation": "Navegación",
"community.column_settings.allow_local_only": "Mostrar toots solo-locales",
"compose.attach.doodle": "Dibujar algo",
"compose.change_federation": "Cambiar configuración de la federación",
@@ -41,8 +37,6 @@
"keyboard_shortcuts.secondary_toot": "para enviar un toot usando lac onfiguración de privacidad secundaria",
"moved_to_warning": "Esta cuenta está marcada como movida a {moved_to_link}, y por lo tanto no aceptará nuevos seguimientos.",
"navigation_bar.app_settings": "Ajustes de la aplicación",
"navigation_bar.keyboard_shortcuts": "Atajos de teclado",
"navigation_bar.misc": "Misc",
"settings.always_show_spoilers_field": "Siempre mostrar el campo de advertencia de contenido",
"settings.close": "Cerrar",
"settings.compose_box_opts": "Cuadro de redacción",

View File

@@ -8,7 +8,6 @@
"compose.content-type.plain": "متن ساده",
"home.column_settings.advanced": "پیشرفته",
"navigation_bar.app_settings": "تنظیمات کاره",
"navigation_bar.keyboard_shortcuts": "میان‌برهای صفحه‌کلید",
"settings.close": "بستن",
"settings.content_warnings": "هشدارهای محتوا",
"settings.media": "رسانه",

View File

@@ -6,12 +6,8 @@
"account.view_full_profile": "Voir le profil complet",
"boost_modal.missing_description": "Ce post contient des médias sans description",
"column.favourited_by": "Ajouté en favori par",
"column.heading": "Divers",
"column.reblogged_by": "Partagé par",
"column.subheading": "Autres options",
"column_header.profile": "Profil",
"column_subheading.lists": "Listes",
"column_subheading.navigation": "Navigation",
"community.column_settings.allow_local_only": "Afficher seulement les posts locaux",
"compose.attach.doodle": "Dessinez quelque chose",
"compose.change_federation": "Changer les paramètres de fédération",
@@ -24,6 +20,9 @@
"compose.content-type.plain_meta": "Écrire sans formatage avancé",
"compose.disable_threaded_mode": "Désactiver le mode thread",
"compose.enable_threaded_mode": "Activer le mode thread",
"compose_form.sensitive.hide": "{count, plural, one {Marquer le média comme sensible} other {Marquer les médias comme sensibles}}",
"compose_form.sensitive.marked": "{count, plural, one {Le média est marqué comme sensible} other {Les médias sont marqués comme sensibles}}",
"compose_form.sensitive.unmarked": "{count, plural, one {Le média nest pas marqué comme sensible} other {Les médias ne sont pas marqué comme sensible}}",
"confirmation_modal.do_not_ask_again": "Ne plus demander confirmation",
"confirmations.deprecated_settings.confirm": "Utiliser les préférences de Mastodon",
"confirmations.deprecated_settings.message": "Certaines {app_settings} de glitch-soc que vous utilisez ont été remplacées par les {preferences} de Mastodon et seront remplacées :",
@@ -42,8 +41,7 @@
"keyboard_shortcuts.secondary_toot": "Envoyer le post en utilisant les paramètres secondaires de confidentialité",
"moved_to_warning": "Ce compte a déménagé vers {moved_to_link} et ne peut donc plus accepter de nouveaux abonné·e·s.",
"navigation_bar.app_settings": "Paramètres de l'application",
"navigation_bar.keyboard_shortcuts": "Raccourcis clavier",
"navigation_bar.misc": "Autres",
"notifications.column_settings.filter_bar.show_bar": "Afficher la barre de filtre",
"settings.always_show_spoilers_field": "Toujours activer le champ de rédaction de l'avertissement de contenu",
"settings.close": "Fermer",
"settings.compose_box_opts": "Zone de rédaction",
@@ -57,6 +55,8 @@
"settings.content_warnings_unfold_opts": "Options de dépliement automatique",
"settings.deprecated_setting": "Cette option est maintenant définie par les {settings_page_link} de Mastodon",
"settings.enable_content_warnings_auto_unfold": "Déplier automatiquement les avertissements de contenu",
"settings.fullwidth_view": "Étirer les colonnes sur toute la largeur (mode bureau uniquement)",
"settings.fullwidth_view_hint": "Étire les colonnes pour remplir tout l'espace disponible.",
"settings.general": "Général",
"settings.hicolor_privacy_icons": "Indicateurs de confidentialité en couleurs",
"settings.hicolor_privacy_icons.hint": "Affiche les indicateurs de confidentialité dans des couleurs facilement distinguables",
@@ -105,11 +105,14 @@
"settings.tag_misleading_links.hint": "Ajouter une indication visuelle avec l'hôte cible du lien à chaque lien ne le mentionnant pas explicitement",
"settings.wide_view": "Vue élargie (mode ordinateur uniquement)",
"settings.wide_view_hint": "Étire les colonnes pour mieux remplir l'espace disponible.",
"status.filtered": "Filtré",
"status.has_audio": "Contient des fichiers audio attachés",
"status.has_pictures": "Contient des images attachées",
"status.has_preview_card": "Contient une carte de prévisualisation attachée",
"status.has_video": "Contient des vidéos attachées",
"status.hide": "Masquer la publication",
"status.in_reply_to": "Ce post est une réponse",
"status.is_poll": "Ce post est un sondage",
"status.local_only": "Visible uniquement depuis votre instance"
"status.local_only": "Visible uniquement depuis votre instance",
"status.show_filter_reason": "Afficher quand même"
}

View File

@@ -2,16 +2,12 @@
"about.fork_disclaimer": "Glitch-soc est un logiciel gratuit et open source, fork de Mastodon.",
"account.disclaimer_full": "Les informations ci-dessous peuvent être incomplètes.",
"account.follows": "Abonnements",
"account.suspended_disclaimer_full": "Cet utilisateur a été suspendu par un modérateur.",
"account.suspended_disclaimer_full": "Ce compte a été suspendu par un modérateur.",
"account.view_full_profile": "Voir le profil complet",
"boost_modal.missing_description": "Ce post contient des médias sans description",
"column.favourited_by": "Ajouté en favori par",
"column.heading": "Divers",
"column.reblogged_by": "Partagé par",
"column.subheading": "Autres options",
"column_header.profile": "Profil",
"column_subheading.lists": "Listes",
"column_subheading.navigation": "Navigation",
"community.column_settings.allow_local_only": "Afficher seulement les posts locaux",
"compose.attach.doodle": "Dessinez quelque chose",
"compose.change_federation": "Changer les paramètres de fédération",
@@ -20,10 +16,13 @@
"compose.content-type.html_meta": "Formatez vos messages en HTML",
"compose.content-type.markdown": "Markdown",
"compose.content-type.markdown_meta": "Formatez vos messages en Markdown",
"compose.content-type.plain": "Text brut",
"compose.content-type.plain": "Texte brut",
"compose.content-type.plain_meta": "Écrire sans formatage avancé",
"compose.disable_threaded_mode": "Désactiver le mode thread",
"compose.enable_threaded_mode": "Activer le mode thread",
"compose_form.sensitive.hide": "{count, plural, one {Marquer le média comme sensible} other {Marquer les médias comme sensibles}}",
"compose_form.sensitive.marked": "{count, plural, one {Le média est marqué comme sensible} other {Les médias sont marqués comme sensibles}}",
"compose_form.sensitive.unmarked": "{count, plural, one {Le média nest pas marqué comme sensible} other {Les médias ne sont pas marqué comme sensible}}",
"confirmation_modal.do_not_ask_again": "Ne plus demander confirmation",
"confirmations.deprecated_settings.confirm": "Utiliser les préférences de Mastodon",
"confirmations.deprecated_settings.message": "Certaines {app_settings} de glitch-soc que vous utilisez ont été remplacées par les {preferences} de Mastodon et seront remplacées :",
@@ -42,8 +41,7 @@
"keyboard_shortcuts.secondary_toot": "Envoyer le post en utilisant les paramètres secondaires de confidentialité",
"moved_to_warning": "Ce compte a déménagé vers {moved_to_link} et ne peut donc plus accepter de nouveaux abonné·e·s.",
"navigation_bar.app_settings": "Paramètres de l'application",
"navigation_bar.keyboard_shortcuts": "Raccourcis clavier",
"navigation_bar.misc": "Autres",
"notifications.column_settings.filter_bar.show_bar": "Afficher la barre de filtre",
"settings.always_show_spoilers_field": "Toujours activer le champ de rédaction de l'avertissement de contenu",
"settings.close": "Fermer",
"settings.compose_box_opts": "Zone de rédaction",
@@ -57,6 +55,8 @@
"settings.content_warnings_unfold_opts": "Options de dépliement automatique",
"settings.deprecated_setting": "Cette option est maintenant définie par les {settings_page_link} de Mastodon",
"settings.enable_content_warnings_auto_unfold": "Déplier automatiquement les avertissements de contenu",
"settings.fullwidth_view": "Étirer les colonnes sur toute la largeur (mode bureau uniquement)",
"settings.fullwidth_view_hint": "Étire les colonnes pour remplir tout l'espace disponible.",
"settings.general": "Général",
"settings.hicolor_privacy_icons": "Indicateurs de confidentialité en couleurs",
"settings.hicolor_privacy_icons.hint": "Affiche les indicateurs de confidentialité dans des couleurs facilement distinguables",
@@ -76,7 +76,7 @@
"settings.pop_in_player": "Activer le lecteur pop-in",
"settings.pop_in_position": "Position du lecteur pop-in :",
"settings.pop_in_right": "Droite",
"settings.preferences": "Preferences",
"settings.preferences": "Préferences",
"settings.prepend_cw_re": "Préfixer les avertissements avec \"re: \" lors d'une réponse",
"settings.preselect_on_reply": "Présélectionner les noms dutilisateur·rices lors de la réponse",
"settings.preselect_on_reply_hint": "Présélectionner les noms d'utilisateurs après le premier lors d'une réponse à une conversation à plusieurs participants",
@@ -105,11 +105,14 @@
"settings.tag_misleading_links.hint": "Ajouter une indication visuelle avec l'hôte cible du lien à chaque lien ne le mentionnant pas explicitement",
"settings.wide_view": "Vue élargie (mode ordinateur uniquement)",
"settings.wide_view_hint": "Étire les colonnes pour mieux remplir l'espace disponible.",
"status.filtered": "Filtré",
"status.has_audio": "Contient des fichiers audio attachés",
"status.has_pictures": "Contient des images attachées",
"status.has_preview_card": "Contient une carte de prévisualisation attachée",
"status.has_video": "Contient des vidéos attachées",
"status.hide": "Masquer la publication",
"status.in_reply_to": "Ce post est une réponse",
"status.is_poll": "Ce post est un sondage",
"status.local_only": "Visible uniquement depuis votre instance"
"status.local_only": "Visible uniquement depuis votre instance",
"status.show_filter_reason": "Afficher quand même"
}

View File

@@ -6,12 +6,8 @@
"account.view_full_profile": "Ver perfil completo",
"boost_modal.missing_description": "Esta publicación contén multimedia sen descrición",
"column.favourited_by": "Favorecida por",
"column.heading": "Varios",
"column.reblogged_by": "Promovida por",
"column.subheading": "Opcións diversas",
"column_header.profile": "Perfil",
"column_subheading.lists": "Listas",
"column_subheading.navigation": "Navegación",
"community.column_settings.allow_local_only": "Ver só mensaxes de ámbito local",
"compose.attach.doodle": "Debuxa algo",
"compose.change_federation": "Cambiar axustes de federación",
@@ -45,8 +41,6 @@
"keyboard_shortcuts.secondary_toot": "para enviar publicación usando axuste secundario de privacidade",
"moved_to_warning": "Esta conta moveuse a {moved_to_link}, e non acepta novos seguimentos.",
"navigation_bar.app_settings": "Axustes da app",
"navigation_bar.keyboard_shortcuts": "Atallos de teclado",
"navigation_bar.misc": "Varios",
"notifications.column_settings.filter_bar.show_bar": "Amosar barra de filtros",
"settings.always_show_spoilers_field": "Activar sempre o campo de Aviso sobre o contido CW",
"settings.close": "Pechar",

View File

@@ -6,12 +6,8 @@
"account.view_full_profile": "Tampilkan profil lengkap",
"boost_modal.missing_description": "Toot ini berisi beberapa media tanpa deskripsi",
"column.favourited_by": "Disukai oleh",
"column.heading": "Lainnya",
"column.reblogged_by": "Dibagikan oleh",
"column.subheading": "Opsi lain-lain",
"column_header.profile": "Profil",
"column_subheading.lists": "Daftar",
"column_subheading.navigation": "Penelusuran",
"community.column_settings.allow_local_only": "Tampilkan toot lokal saja",
"compose.change_federation": "Ubah pengaturan federasi",
"compose.content-type.change": "Ubah opsi pemformatan lanjutan",
@@ -38,8 +34,6 @@
"keyboard_shortcuts.secondary_toot": "untuk mengirim toot menggunakan pengaturan privasi sekunder",
"moved_to_warning": "Akun ini ditandai sebagai dipindahkan ke {moved_to_link}, dan karenanya tidak menerima pengikut baru.",
"navigation_bar.app_settings": "Pengaturan aplikasi",
"navigation_bar.keyboard_shortcuts": "Pintasan keyboard",
"navigation_bar.misc": "Lainnya",
"settings.always_show_spoilers_field": "Selalu aktifkan bidang Peringatan Konten",
"settings.close": "Tutup",
"settings.compose_box_opts": "Kotak tulis",
@@ -49,6 +43,7 @@
"settings.content_warnings.regexp": "Ekspresi reguler",
"settings.content_warnings_filter": "Peringatan konten yang tidak akan dibuka secara otomatis:",
"settings.content_warnings_shared_state": "Tampilkan/sembunyikan konten semua salinan sekaligus",
"settings.pop_in_right": "Kanan",
"settings.preferences": "Preferences",
"settings.status_icons_reply": "Indikator balasan",
"settings.status_icons_visibility": "Indikator privasi toot",

View File

@@ -6,12 +6,8 @@
"account.view_full_profile": "正確な情報を見る",
"boost_modal.missing_description": "このトゥートには少なくとも1つの画像に説明が付与されていません",
"column.favourited_by": "お気に入りしたユーザー",
"column.heading": "その他",
"column.reblogged_by": "ブーストしたユーザー",
"column.subheading": "その他のオプション",
"column_header.profile": "プロフィール",
"column_subheading.lists": "リスト",
"column_subheading.navigation": "ナビゲーション",
"community.column_settings.allow_local_only": "ローカル限定投稿を表示する",
"compose.content-type.html": "HTML",
"compose.content-type.html_meta": "投稿に HTML を使用する",
@@ -33,8 +29,6 @@
"keyboard_shortcuts.secondary_toot": "セカンダリートゥートの公開範囲でトゥートする",
"moved_to_warning": "このアカウント{moved_to_link}に引っ越したため、新しいフォロワーを受け入れていません。",
"navigation_bar.app_settings": "アプリ設定",
"navigation_bar.keyboard_shortcuts": "キーボードショートカット",
"navigation_bar.misc": "その他",
"settings.always_show_spoilers_field": "常にコンテンツワーニング設定を表示する(指定がない場合は通常投稿)",
"settings.close": "閉じる",
"settings.compose_box_opts": "コンポーズボックス設定",

View File

@@ -1,6 +1,5 @@
{
"compose.attach.doodle": "Ssuneɣ-d kra",
"navigation_bar.keyboard_shortcuts": "Inezgumen n unasiw",
"settings.close": "Mdel",
"settings.content_warnings": "Content warnings",
"settings.preferences": "Preferences"

View File

@@ -6,12 +6,8 @@
"account.view_full_profile": "전체 프로필 보기",
"boost_modal.missing_description": "이 게시물은 설명이 없는 미디어를 포함하고 있습니다",
"column.favourited_by": "즐겨찾기 한 사람",
"column.heading": "기타",
"column.reblogged_by": "부스트 한 사람",
"column.subheading": "다양한 옵션",
"column_header.profile": "프로필",
"column_subheading.lists": "리스트",
"column_subheading.navigation": "탐색",
"community.column_settings.allow_local_only": "로컬 전용 글 보기",
"compose.attach.doodle": "뭔가 그려보세요",
"compose.change_federation": "연합 설정 변경",
@@ -45,8 +41,6 @@
"keyboard_shortcuts.secondary_toot": "보조 프라이버시 설정으로 글 보내기",
"moved_to_warning": "이 계정은 {moved_to_link}로 이동한 것으로 표시되었고, 새 팔로우를 받지 않는 것 같습니다.",
"navigation_bar.app_settings": "앱 설정",
"navigation_bar.keyboard_shortcuts": "키보드 단축기",
"navigation_bar.misc": "다양한 옵션들",
"notifications.column_settings.filter_bar.show_bar": "필터 막대 표시",
"settings.always_show_spoilers_field": "열람주의 항목을 언제나 활성화",
"settings.close": "닫기",

View File

@@ -6,12 +6,8 @@
"account.view_full_profile": "Peržiūrėti visą profilį",
"boost_modal.missing_description": "Šis įrašas turi šiek tiek medijų be aprašų.",
"column.favourited_by": "Pamėgo",
"column.heading": "Įvairūs",
"column.reblogged_by": "Pasidalino",
"column.subheading": "Įvairios parinktys",
"column_header.profile": "Profilis",
"column_subheading.lists": "Sąrašai",
"column_subheading.navigation": "Naršymas",
"community.column_settings.allow_local_only": "Rodyti tik vietinius įrašus",
"compose.attach.doodle": "Nupiešti kažką",
"compose.change_federation": "Keisti federacijos nustatymus",
@@ -45,8 +41,6 @@
"keyboard_shortcuts.secondary_toot": "siųsti įrašą naudojant antrinį privatumo nustatymą",
"moved_to_warning": "Ši paskyra pažymėta kaip perkelta į {moved_to_link}, todėl negali priimti naujų sekimų.",
"navigation_bar.app_settings": "Programėlės nustatymai",
"navigation_bar.keyboard_shortcuts": "Spartieji klavišai",
"navigation_bar.misc": "Įvairūs",
"notifications.column_settings.filter_bar.show_bar": "Rodyti filtro juostą",
"settings.always_show_spoilers_field": "Visada įjungti turinio įspėjimo lauką",
"settings.close": "Užverti",

View File

@@ -3,12 +3,8 @@
"account.view_full_profile": "Volledig profiel weergeven",
"boost_modal.missing_description": "Deze toot bevat media zonder beschrijving",
"column.favourited_by": "Favoriet door",
"column.heading": "Overige",
"column.reblogged_by": "Geboost door",
"column.subheading": "Diverse opties",
"column_header.profile": "Profiel",
"column_subheading.lists": "Lijsten",
"column_subheading.navigation": "Navigatie",
"community.column_settings.allow_local_only": "Toon alleen lokale toots",
"compose.content-type.html": "HTML",
"compose.content-type.markdown": "Markdown",

View File

@@ -6,12 +6,8 @@
"account.view_full_profile": "Pokaż pełny profil",
"boost_modal.missing_description": "Ten wpis zawiera multimedialne załączniki bez opisu",
"column.favourited_by": "Polubiony przez",
"column.heading": "Różne",
"column.reblogged_by": "Podbity przez",
"column.subheading": "Różne opcje",
"column_header.profile": "Profil",
"column_subheading.lists": "Listy",
"column_subheading.navigation": "Nawigacja",
"community.column_settings.allow_local_only": "Pokazuj wyłącznie wpisy lokalne",
"compose.content-type.html": "HTML",
"compose.content-type.markdown": "Markdown",
@@ -28,8 +24,6 @@
"keyboard_shortcuts.secondary_toot": "aby opublikować wpis używając dodatkowych ustawień prywatności",
"moved_to_warning": "To konto oznaczone jest jako przeniesione do {moved_to_link} i może z tego powodu nie akceptować nowych obserwujących.",
"navigation_bar.app_settings": "Ustawienia aplikacji",
"navigation_bar.keyboard_shortcuts": "Skróty klawiszowe",
"navigation_bar.misc": "Różne",
"settings.always_show_spoilers_field": "Zawsze pokazuj pole ostrzeżenia o zawartości",
"settings.close": "Zamknij",
"settings.compose_box_opts": "Pole edycji",

View File

@@ -6,12 +6,8 @@
"account.view_full_profile": "Ver o perfil completo",
"boost_modal.missing_description": "Este toot contém algumas mídias sem descrição",
"column.favourited_by": "Favoritado por",
"column.heading": "Diversos",
"column.reblogged_by": "Inpulsionado por",
"column.subheading": "Opções diversas",
"column_header.profile": "Perfil",
"column_subheading.lists": "Listas",
"column_subheading.navigation": "Navegação",
"community.column_settings.allow_local_only": "Mostrar os toots apenas locais",
"compose.content-type.html": "HTML",
"compose.content-type.markdown": "Markdown",
@@ -28,8 +24,6 @@
"keyboard_shortcuts.secondary_toot": "para enviar toot usando a configuração de privacidade secundária",
"moved_to_warning": "Esta conta foi como movida para {moved_to_link} e, portanto, pode não aceitar novos seguidores.",
"navigation_bar.app_settings": "Configurações do aplicativo",
"navigation_bar.keyboard_shortcuts": "Atalhos de teclado",
"navigation_bar.misc": "Diversos",
"settings.always_show_spoilers_field": "Sempre ativar o campo Aviso de Conteúdo",
"settings.close": "Fechar",
"settings.compose_box_opts": "Caixa de composição",

View File

@@ -6,7 +6,6 @@
"account.view_full_profile": "Ver o perfil completo",
"boost_modal.missing_description": "Este post contém alguns media sem descrição",
"column.favourited_by": "Adicionado aos favoritos de",
"column.heading": "Diversos",
"moved_to_warning": "Esta conta mudou-se para {moved_to_link} e, portanto, pode não aceitar novos seguidores.",
"notifications.column_settings.filter_bar.show_bar": "Mostrar barra de filtros",
"settings.always_show_spoilers_field": "Mostrar sempre o campo Aviso de Conteúdo",

View File

@@ -6,12 +6,8 @@
"account.view_full_profile": "Открыть полный профиль",
"boost_modal.missing_description": "Этот пост содержит медиафайлы без описания",
"column.favourited_by": "Добавили в избранное",
"column.heading": "Прочее",
"column.reblogged_by": "Продвинули",
"column.subheading": "Прочие разделы",
"column_header.profile": "Профиль",
"column_subheading.lists": "Списки",
"column_subheading.navigation": "Навигация",
"community.column_settings.allow_local_only": "Показывать нефедерируемые посты",
"compose.attach.doodle": "Нарисовать что-нибудь",
"compose.change_federation": "Изменить настройки федерации",
@@ -39,8 +35,6 @@
"keyboard_shortcuts.bookmark": "добавить закладку",
"moved_to_warning": "Этот аккаунт переехал на {moved_to_link}, и скорее всего не принимает новых подписчиков.",
"navigation_bar.app_settings": "Настройки приложения",
"navigation_bar.keyboard_shortcuts": "Сочетания клавиш",
"navigation_bar.misc": "Прочее",
"notifications.column_settings.filter_bar.show_bar": "Показать панель фильтров",
"settings.always_show_spoilers_field": "Всегда ставить предупреждение о содержании",
"settings.close": "Закрыть",

View File

@@ -6,12 +6,8 @@
"account.view_full_profile": "View full profile",
"boost_modal.missing_description": "This post contains some media withoot description",
"column.favourited_by": "Favouritit by",
"column.heading": "Misc",
"column.reblogged_by": "Boosted by",
"column.subheading": "Miscellaneous options",
"column_header.profile": "Profile",
"column_subheading.lists": "Lists",
"column_subheading.navigation": "Navigation",
"community.column_settings.allow_local_only": "Show local-only posts",
"compose.attach.doodle": "Draw something",
"compose.change_federation": "Change federation settins",
@@ -45,8 +41,6 @@
"keyboard_shortcuts.secondary_toot": "tae send post using secondary privacy settin",
"moved_to_warning": "This account is marked as moved tae {moved_to_link}, an' may not accept new follows.",
"navigation_bar.app_settings": "App settins",
"navigation_bar.keyboard_shortcuts": "Keyboard shortcuts",
"navigation_bar.misc": "Misc",
"notifications.column_settings.filter_bar.show_bar": "Show filter bar",
"settings.always_show_spoilers_field": "Always enable the Content Warning field",
"settings.close": "Close",

View File

@@ -4,12 +4,8 @@
"account.view_full_profile": "Visa full profil",
"boost_modal.missing_description": "Denna toot innehåller viss media utan beskrivning",
"column.favourited_by": "Favoritmarkerad av",
"column.heading": "Övrigt",
"column.reblogged_by": "Boostad av",
"column.subheading": "Övriga val",
"column_header.profile": "Profil",
"column_subheading.lists": "Listor",
"column_subheading.navigation": "Navigering",
"community.column_settings.allow_local_only": "Visa endast lokala toots",
"compose.content-type.html": "HTML",
"compose.content-type.markdown": "Markdown",

View File

@@ -1,8 +1,5 @@
{
"about.fork_disclaimer": ".",
"account.disclaimer_full": ".",
"account.follows": "",
"community.column_settings.allow_local_only": "",
"account.follows": "ติดตาม",
"settings.content_warnings": "Content warnings",
"settings.preferences": "Preferences"
}

View File

@@ -5,12 +5,8 @@
"account.view_full_profile": "Tam görünüm",
"boost_modal.missing_description": "Bu gönderi açıklaması olmayan medya içerir",
"column.favourited_by": "Tarafından favorilere eklendi",
"column.heading": "Diğer",
"column.reblogged_by": "Tarafından yükseltildi",
"column.subheading": "Diğer seçenekler",
"column_header.profile": "Profil",
"column_subheading.lists": "Listeler",
"column_subheading.navigation": "Gezinme",
"community.column_settings.allow_local_only": "Sadece yerel gönderileri göster",
"compose.content-type.html": "HTML",
"compose.content-type.markdown": "Markdown modu",

View File

@@ -6,12 +6,8 @@
"account.view_full_profile": "Переглянути повний профіль",
"boost_modal.missing_description": "Цей дмух містить деякі медіа без опису",
"column.favourited_by": "Уподобані",
"column.heading": "Різне",
"column.reblogged_by": "Поширено",
"column.subheading": "Інші параметри",
"column_header.profile": "Профіль",
"column_subheading.lists": "Списки",
"column_subheading.navigation": "Навігація",
"community.column_settings.allow_local_only": "Показувати тільки локальні дмухи",
"compose.content-type.html": "HTML",
"compose.content-type.markdown": "Markdown",
@@ -29,8 +25,6 @@
"keyboard_shortcuts.secondary_toot": "надсилати повідомлення з використанням вторинних налаштувань конфіденційності",
"moved_to_warning": "Цей обліковий запис позначено як переміщений до {moved_to_link} і тому не може прийняти нових підписок.",
"navigation_bar.app_settings": "Налаштування програми",
"navigation_bar.keyboard_shortcuts": "Комбінації клавіш",
"navigation_bar.misc": "Різне",
"settings.always_show_spoilers_field": "Завжди вмикати попередження про вміст",
"settings.close": "Закрити",
"settings.compose_box_opts": "Compose box",

View File

@@ -6,12 +6,8 @@
"account.view_full_profile": "查看完整资料",
"boost_modal.missing_description": "这条嘟文未包含媒体描述",
"column.favourited_by": "点赞",
"column.heading": "杂项",
"column.reblogged_by": "转嘟",
"column.subheading": "其他选项",
"column_header.profile": "资料卡",
"column_subheading.lists": "列表",
"column_subheading.navigation": "导航",
"community.column_settings.allow_local_only": "只显示仅本站可见的嘟文",
"compose.attach.doodle": "涂鸦",
"compose.change_federation": "更改联动设置",
@@ -45,8 +41,6 @@
"keyboard_shortcuts.secondary_toot": "使用另一隐私设置发送嘟文",
"moved_to_warning": "此账户已被标记为移至 {moved_to_link},并且似乎没有收到新粉丝。",
"navigation_bar.app_settings": "应用设置",
"navigation_bar.keyboard_shortcuts": "键盘快捷键",
"navigation_bar.misc": "杂项",
"notifications.column_settings.filter_bar.show_bar": "显示筛选栏",
"settings.always_show_spoilers_field": "始终显示内容警告框",
"settings.close": "关闭",

View File

@@ -6,12 +6,8 @@
"account.view_full_profile": "查看完整個人資料",
"boost_modal.missing_description": "此貼文包含未加說明的媒體檔案",
"column.favourited_by": "誰按了最愛",
"column.heading": "雜項",
"column.reblogged_by": "被誰轉貼",
"column.subheading": "其他選項",
"column_header.profile": "個人檔案",
"column_subheading.lists": "列表",
"column_subheading.navigation": "導覽",
"community.column_settings.allow_local_only": "顯示僅限本地的貼文",
"compose.attach.doodle": "塗鴉",
"compose.change_federation": "變更聯邦設定",
@@ -24,6 +20,9 @@
"compose.content-type.plain_meta": "不使用進階格式撰寫",
"compose.disable_threaded_mode": "停用貼文串模式",
"compose.enable_threaded_mode": "啟用貼文串模式",
"compose_form.sensitive.hide": "{count, plural, other {將媒體標記為敏感內容}}",
"compose_form.sensitive.marked": "{count, plural, other {媒體已被標記為敏感內容}}",
"compose_form.sensitive.unmarked": "{count, plural, other {媒體未被標記為敏感內容}}",
"confirmation_modal.do_not_ask_again": "不要再顯示確認訊息",
"confirmations.deprecated_settings.confirm": "使用 Mastodon 偏好",
"confirmations.deprecated_settings.message": "您正在使用的某些特定於 glitch-soc 設備的 {app_settings} 已被 Mastodon {preferences} 所取代,並將被覆蓋:",
@@ -42,8 +41,6 @@
"keyboard_shortcuts.secondary_toot": "使用次要隱私設定來發布貼文",
"moved_to_warning": "此帳戶已標記為移至 {moved_to_link},因此可能不接受新的追隨者。",
"navigation_bar.app_settings": "應用程式設定",
"navigation_bar.keyboard_shortcuts": "鍵盤快速鍵",
"navigation_bar.misc": "雜項",
"notifications.column_settings.filter_bar.show_bar": "顯示過濾器",
"settings.always_show_spoilers_field": "永遠啟用內容警告欄位",
"settings.close": "關閉",
@@ -58,6 +55,8 @@
"settings.content_warnings_unfold_opts": "自動展開選項",
"settings.deprecated_setting": "此設定現在已由 Mastodon 的 {settings_page_link} 控制。",
"settings.enable_content_warnings_auto_unfold": "自動展開內容警告",
"settings.fullwidth_view": "將欄位延展至全寬(僅限桌面模式)",
"settings.fullwidth_view_hint": "將欄位延展以填滿所有可用空間。",
"settings.general": "一般設定",
"settings.hicolor_privacy_icons": "隱私圖示使用對比色",
"settings.hicolor_privacy_icons.hint": "用明亮且易於區分的顏色顯示隱私圖示",

View File

@@ -619,8 +619,13 @@ export const composeReducer = (state = initialState, action) => {
}
if (action.status.get('poll')) {
let options = ImmutableList(action.status.get('poll').options.map(x => x.title));
if (options.size < action.maxOptions) {
options = options.push('');
}
map.set('poll', ImmutableMap({
options: ImmutableList(action.status.get('poll').options.map(x => x.title)),
options: options,
multiple: action.status.get('poll').multiple,
expires_in: expiresInFromExpiresAt(action.status.get('poll').expires_at),
}));
@@ -650,8 +655,13 @@ export const composeReducer = (state = initialState, action) => {
}
if (action.status.get('poll')) {
let options = ImmutableList(action.status.get('poll').options.map(x => x.title));
if (options.size < action.maxOptions) {
options = options.push('');
}
map.set('poll', ImmutableMap({
options: ImmutableList(action.status.get('poll').options.map(x => x.title)),
options: options,
multiple: action.status.get('poll').multiple,
expires_in: expiresInFromExpiresAt(action.status.get('poll').expires_at),
}));

View File

@@ -10,7 +10,7 @@ const initialState = ImmutableMap({
stretch : true,
side_arm : 'none',
side_arm_reply_mode : 'keep',
show_reply_count : false,
show_reply_count : true,
always_show_spoilers_field: false,
confirm_boost_missing_media_description: false,
confirm_before_clearing_draft: true,

View File

@@ -64,6 +64,10 @@ const statusTranslateUndo = (state, id) => {
});
};
const removeStatusStub = (state, id) => {
return state.getIn([id, 'id']) ? state.deleteIn([id, 'isLoading']) : state.delete(id);
}
/** @type {ImmutableMap<string, import('flavours/glitch/models/status').Status>} */
const initialState = ImmutableMap();
@@ -73,8 +77,14 @@ export default function statuses(state = initialState, action) {
switch(action.type) {
case STATUS_FETCH_REQUEST:
return state.setIn([action.id, 'isLoading'], true);
case STATUS_FETCH_FAIL:
return state.delete(action.id);
case STATUS_FETCH_FAIL: {
if (action.parentQuotePostId && action.error.status === 404) {
return removeStatusStub(state, action.id)
.setIn([action.parentQuotePostId, 'quote', 'state'], 'deleted')
} else {
return removeStatusStub(state, action.id);
}
}
case STATUS_IMPORT:
return importStatus(state, action.status);
case STATUSES_IMPORT:

View File

@@ -1893,7 +1893,7 @@ a.sparkline {
font-size: 15px;
line-height: 22px;
li {
> li {
counter-increment: step 1;
padding-inline-start: 2.5rem;
padding-bottom: 8px;

View File

@@ -2398,6 +2398,7 @@ a .account__avatar {
.detailed-status__display-name,
.detailed-status__datetime,
.detailed-status__application,
.detailed-status__link,
.account__display-name {
text-decoration: none;
}
@@ -2430,7 +2431,8 @@ a.account__display-name {
}
.detailed-status__application,
.detailed-status__datetime {
.detailed-status__datetime,
.detailed-status__link {
color: inherit;
}
@@ -2616,8 +2618,9 @@ a.account__display-name {
}
.status__relative-time,
.detailed-status__datetime {
&:hover {
.detailed-status__datetime,
.detailed-status__link {
&:is(a):hover {
text-decoration: underline;
}
}

View File

@@ -589,11 +589,14 @@ code {
}
.stacked-actions {
display: flex;
flex-direction: column;
gap: 10px;
margin-top: 30px;
margin-bottom: 15px;
}
button:not(.button, .link-button, .help-button) {
.btn {
display: block;
width: 100%;
border: 0;
@@ -610,8 +613,6 @@ code {
cursor: pointer;
font-weight: 500;
outline: 0;
margin-bottom: 10px;
margin-inline-end: 10px;
&:last-child {
margin-inline-end: 0;

View File

@@ -107,7 +107,8 @@
cursor: pointer;
}
&.editable {
&.editable,
&.disabled {
align-items: center;
overflow: visible;
}
@@ -165,7 +166,8 @@
}
}
&__option.editable &__input {
&__option.editable &__input,
&__option.disabled &__input {
&:active,
&:focus,
&:hover {

View File

@@ -96,12 +96,17 @@ export const ensureComposeIsVisible = (getState) => {
};
export function setComposeToStatus(status, text, spoiler_text) {
return{
type: COMPOSE_SET_STATUS,
status,
text,
spoiler_text,
};
return (dispatch, getState) => {
const maxOptions = getState().server.getIn(['server', 'configuration', 'polls', 'max_options']);
dispatch({
type: COMPOSE_SET_STATUS,
status,
text,
spoiler_text,
maxOptions,
});
}
}
export function changeCompose(text) {
@@ -183,7 +188,7 @@ export function directCompose(account) {
};
}
export function submitCompose() {
export function submitCompose(successCallback) {
return function (dispatch, getState) {
const status = getState().getIn(['compose', 'text'], '');
const media = getState().getIn(['compose', 'media_attachments']);
@@ -239,6 +244,9 @@ export function submitCompose() {
dispatch(insertIntoTagHistory(response.data.tags, status));
dispatch(submitComposeSuccess({ ...response.data }));
if (typeof successCallback === 'function') {
successCallback(response.data);
}
// To make the app more responsive, immediately push the status
// into the columns

View File

@@ -21,6 +21,15 @@ export function normalizeFilterResult(result) {
return normalResult;
}
function stripQuoteFallback(text) {
const wrapper = document.createElement('div');
wrapper.innerHTML = text;
wrapper.querySelector('.quote-inline')?.remove();
return wrapper.innerHTML;
}
export function normalizeStatus(status, normalOldStatus) {
const normalStatus = { ...status };
@@ -72,7 +81,7 @@ export function normalizeStatus(status, normalOldStatus) {
} else {
// If the status has a CW but no contents, treat the CW as if it were the
// status' contents, to avoid having a CW toggle with seemingly no effect.
if (normalStatus.spoiler_text && !normalStatus.content) {
if (normalStatus.spoiler_text && !normalStatus.content && !normalStatus.quote) {
normalStatus.content = normalStatus.spoiler_text;
normalStatus.spoiler_text = '';
}
@@ -86,6 +95,11 @@ export function normalizeStatus(status, normalOldStatus) {
normalStatus.spoilerHtml = emojify(escapeTextContentForBrowser(spoilerText), emojiMap);
normalStatus.hidden = expandSpoilers ? false : spoilerText.length > 0 || normalStatus.sensitive;
// Remove quote fallback link from the DOM so it doesn't mess with paragraph margins
if (normalStatus.quote) {
normalStatus.contentHtml = stripQuoteFallback(normalStatus.contentHtml);
}
if (normalStatus.url && !(normalStatus.url.startsWith('http://') || normalStatus.url.startsWith('https://'))) {
normalStatus.url = null;
}
@@ -125,6 +139,11 @@ export function normalizeStatusTranslation(translation, status) {
spoiler_text: translation.spoiler_text,
};
// Remove quote fallback link from the DOM so it doesn't mess with paragraph margins
if (status.get('quote')) {
normalTranslation.contentHtml = stripQuoteFallback(normalTranslation.contentHtml);
}
return normalTranslation;
}

View File

@@ -3,7 +3,7 @@ import { browserHistory } from 'mastodon/components/router';
import api from '../api';
import { ensureComposeIsVisible, setComposeToStatus } from './compose';
import { importFetchedStatus, importFetchedStatuses, importFetchedAccount } from './importer';
import { importFetchedStatus, importFetchedAccount } from './importer';
import { fetchContext } from './statuses_typed';
import { deleteFromTimelines } from './timelines';
@@ -48,7 +48,18 @@ export function fetchStatusRequest(id, skipLoading) {
};
}
export function fetchStatus(id, forceFetch = false, alsoFetchContext = true) {
/**
* @param {string} id
* @param {Object} [options]
* @param {boolean} [options.forceFetch]
* @param {boolean} [options.alsoFetchContext]
* @param {string | null | undefined} [options.parentQuotePostId]
*/
export function fetchStatus(id, {
forceFetch = false,
alsoFetchContext = true,
parentQuotePostId,
} = {}) {
return (dispatch, getState) => {
const skipLoading = !forceFetch && getState().getIn(['statuses', id], null) !== null;
@@ -66,7 +77,9 @@ export function fetchStatus(id, forceFetch = false, alsoFetchContext = true) {
dispatch(importFetchedStatus(response.data));
dispatch(fetchStatusSuccess(skipLoading));
}).catch(error => {
dispatch(fetchStatusFail(id, error, skipLoading));
dispatch(fetchStatusFail(id, error, skipLoading, parentQuotePostId));
if (error.status === 404)
dispatch(deleteFromTimelines(id));
});
};
}
@@ -78,21 +91,27 @@ export function fetchStatusSuccess(skipLoading) {
};
}
export function fetchStatusFail(id, error, skipLoading) {
export function fetchStatusFail(id, error, skipLoading, parentQuotePostId) {
return {
type: STATUS_FETCH_FAIL,
id,
error,
parentQuotePostId,
skipLoading,
skipAlert: true,
};
}
export function redraft(status, raw_text) {
return {
type: REDRAFT,
status,
raw_text,
return (dispatch, getState) => {
const maxOptions = getState().server.getIn(['server', 'configuration', 'polls', 'max_options']);
dispatch({
type: REDRAFT,
status,
raw_text,
maxOptions,
});
};
}

View File

@@ -1,10 +1,11 @@
import { apiRequestPost } from 'mastodon/api';
import type { Status, StatusVisibility } from 'mastodon/models/status';
import type { ApiStatusJSON } from 'mastodon/api_types/statuses';
import type { StatusVisibility } from 'mastodon/models/status';
export const apiReblog = (statusId: string, visibility: StatusVisibility) =>
apiRequestPost<{ reblog: Status }>(`v1/statuses/${statusId}/reblog`, {
apiRequestPost<{ reblog: ApiStatusJSON }>(`v1/statuses/${statusId}/reblog`, {
visibility,
});
export const apiUnreblog = (statusId: string) =>
apiRequestPost<Status>(`v1/statuses/${statusId}/unreblog`);
apiRequestPost<ApiStatusJSON>(`v1/statuses/${statusId}/unreblog`);

View File

@@ -20,7 +20,7 @@ import { useDrag } from '@use-gesture/react';
import { expandAccountFeaturedTimeline } from '@/mastodon/actions/timelines';
import { Icon } from '@/mastodon/components/icon';
import { IconButton } from '@/mastodon/components/icon_button';
import StatusContainer from '@/mastodon/containers/status_container';
import { StatusQuoteManager } from '@/mastodon/components/status_quoted';
import { usePrevious } from '@/mastodon/hooks/usePrevious';
import { useAppDispatch, useAppSelector } from '@/mastodon/store';
import ChevronLeftIcon from '@/material-icons/400-24px/chevron_left.svg?react';
@@ -218,12 +218,7 @@ const FeaturedCarouselItem: React.FC<
ref={handleRef}
{...props}
>
<StatusContainer
// @ts-expect-error inferred props are wrong
id={statusId}
contextType='account'
withCounters
/>
<StatusQuoteManager id={statusId} contextType='account' withCounters />
</animated.div>
);
};

View File

@@ -1,4 +1,4 @@
import { useEffect, useMemo } from 'react';
import { useCallback, useEffect, useMemo } from 'react';
import { FormattedMessage } from 'react-intl';
@@ -11,13 +11,16 @@ import ArticleIcon from '@/material-icons/400-24px/article.svg?react';
import ChevronRightIcon from '@/material-icons/400-24px/chevron_right.svg?react';
import { Icon } from 'mastodon/components/icon';
import StatusContainer from 'mastodon/containers/status_container';
import { domain } from 'mastodon/initial_state';
import type { Status } from 'mastodon/models/status';
import type { RootState } from 'mastodon/store';
import { useAppDispatch, useAppSelector } from 'mastodon/store';
import QuoteIcon from '../../images/quote.svg?react';
import { revealAccount } from '../actions/accounts_typed';
import { fetchStatus } from '../actions/statuses';
import { makeGetStatus } from '../selectors';
import { getAccountHidden } from '../selectors/accounts';
const MAX_QUOTE_POSTS_NESTING_LEVEL = 1;
@@ -37,9 +40,7 @@ const QuoteWrapper: React.FC<{
);
};
const NestedQuoteLink: React.FC<{
status: Status;
}> = ({ status }) => {
const NestedQuoteLink: React.FC<{ status: Status }> = ({ status }) => {
const accountId = status.get('account') as string;
const account = useAppSelector((state) =>
accountId ? state.accounts.get(accountId) : undefined,
@@ -75,24 +76,74 @@ type GetStatusSelector = (
props: { id?: string | null; contextType?: string },
) => Status | null;
const LimitedAccountHint: React.FC<{ accountId: string }> = ({ accountId }) => {
const dispatch = useAppDispatch();
const reveal = useCallback(() => {
dispatch(revealAccount({ id: accountId }));
}, [dispatch, accountId]);
return (
<>
<FormattedMessage
id='status.quote_error.limited_account_hint.title'
defaultMessage='This account has been hidden by the moderators of {domain}.'
values={{ domain }}
/>
<button onClick={reveal} className='link-button'>
<FormattedMessage
id='status.quote_error.limited_account_hint.action'
defaultMessage='Show anyway'
/>
</button>
</>
);
};
export const QuotedStatus: React.FC<{
quote: QuoteMap;
contextType?: string;
parentQuotePostId?: string | null;
variant?: 'full' | 'link';
nestingLevel?: number;
}> = ({ quote, contextType, nestingLevel = 1, variant = 'full' }) => {
}> = ({
quote,
contextType,
parentQuotePostId,
nestingLevel = 1,
variant = 'full',
}) => {
const dispatch = useAppDispatch();
const quoteState = useAppSelector((state) =>
parentQuotePostId
? state.statuses.getIn([parentQuotePostId, 'quote', 'state'])
: quote.get('state'),
);
const quotedStatusId = quote.get('quoted_status');
const quoteState = quote.get('state');
const status = useAppSelector((state) =>
quotedStatusId ? state.statuses.get(quotedStatusId) : undefined,
);
const shouldLoadQuote = !status?.get('isLoading') && quoteState !== 'deleted';
const accountId: string | null = status?.get('account', null) as
| string
| null;
const hiddenAccount = useAppSelector(
(state) => accountId && getAccountHidden(state, accountId),
);
useEffect(() => {
if (!status && quotedStatusId) {
dispatch(fetchStatus(quotedStatusId));
if (shouldLoadQuote && quotedStatusId) {
dispatch(
fetchStatus(quotedStatusId, {
parentQuotePostId,
alsoFetchContext: false,
}),
);
}
}, [status, quotedStatusId, dispatch]);
}, [shouldLoadQuote, quotedStatusId, parentQuotePostId, dispatch]);
// In order to find out whether the quoted post should be completely hidden
// due to a matching filter, we run it through the selector used by `status_container`.
@@ -147,6 +198,8 @@ export const QuotedStatus: React.FC<{
defaultMessage='This post cannot be displayed.'
/>
);
} else if (hiddenAccount && accountId) {
quoteError = <LimitedAccountHint accountId={accountId} />;
}
if (quoteError) {
@@ -173,6 +226,7 @@ export const QuotedStatus: React.FC<{
{canRenderChildQuote && (
<QuotedStatus
quote={childQuote}
parentQuotePostId={quotedStatusId}
contextType={contextType}
variant={
nestingLevel === MAX_QUOTE_POSTS_NESTING_LEVEL ? 'link' : 'full'
@@ -208,7 +262,11 @@ export const StatusQuoteManager = (props: StatusQuoteManagerProps) => {
if (quote) {
return (
<StatusContainer {...props}>
<QuotedStatus quote={quote} contextType={props.contextType} />
<QuotedStatus
quote={quote}
parentQuotePostId={status?.get('id') as string}
contextType={props.contextType}
/>
</StatusContainer>
);
}

View File

@@ -73,6 +73,7 @@ class ComposeForm extends ImmutablePureComponent {
singleColumn: PropTypes.bool,
lang: PropTypes.string,
maxChars: PropTypes.number,
redirectOnSuccess: PropTypes.bool,
};
static defaultProps = {
@@ -310,7 +311,7 @@ class ComposeForm extends ImmutablePureComponent {
>
{intl.formatMessage(
this.props.isEditing ?
messages.saveChanges :
messages.saveChanges :
(this.props.isInReply ? messages.reply : messages.publish)
)}
</Button>

View File

@@ -34,7 +34,7 @@ const mapStateToProps = state => ({
maxChars: state.getIn(['server', 'server', 'configuration', 'statuses', 'max_characters'], 500),
});
const mapDispatchToProps = (dispatch) => ({
const mapDispatchToProps = (dispatch, props) => ({
onChange (text) {
dispatch(changeCompose(text));
@@ -47,7 +47,11 @@ const mapDispatchToProps = (dispatch) => ({
modalProps: {},
}));
} else {
dispatch(submitCompose());
dispatch(submitCompose((status) => {
if (props.redirectOnSuccess) {
window.location.assign(status.url);
}
}));
}
},

View File

@@ -5,7 +5,7 @@ import ModalContainer from 'mastodon/features/ui/containers/modal_container';
const Compose = () => (
<>
<ComposeFormContainer autoFocus withoutNavigation />
<ComposeFormContainer autoFocus withoutNavigation redirectOnSuccess />
<AlertsController />
<ModalContainer />
<LoadingBarContainer className='loading-bar' />

View File

@@ -32,7 +32,7 @@ const Embed: React.FC<{ id: string }> = ({ id }) => {
const dispatchRenderSignal = useRenderSignal();
useEffect(() => {
dispatch(fetchStatus(id, false, false));
dispatch(fetchStatus(id, { alsoFetchContext: false }));
}, [dispatch, id]);
const handleToggleHidden = useCallback(() => {

View File

@@ -37,18 +37,23 @@ const getHostname = url => {
const domParser = new DOMParser();
const addAutoPlay = html => {
const handleIframeUrl = (html, url, providerName) => {
const document = domParser.parseFromString(html, 'text/html').documentElement;
const iframe = document.querySelector('iframe');
const startTime = new URL(url).searchParams.get('t')
if (iframe) {
if (iframe.src.indexOf('?') !== -1) {
iframe.src += '&';
} else {
iframe.src += '?';
const iframeUrl = new URL(iframe.src)
iframeUrl.searchParams.set('autoplay', 1)
iframeUrl.searchParams.set('auto_play', 1)
if (providerName === 'YouTube') {
iframeUrl.searchParams.set('start', startTime || '');
iframe.referrerPolicy = 'strict-origin-when-cross-origin';
}
iframe.src += 'autoplay=1&auto_play=1';
iframe.src = iframeUrl.href
// DOM parser creates html/body elements around original HTML fragment,
// so we need to get innerHTML out of the body and not the entire document
@@ -114,7 +119,7 @@ export default class Card extends PureComponent {
renderVideo () {
const { card } = this.props;
const content = { __html: addAutoPlay(card.get('html')) };
const content = { __html: handleIframeUrl(card.get('html'), card.get('url'), card.get('provider_name')) };
return (
<div

View File

@@ -381,7 +381,11 @@ export const DetailedStatus: React.FC<{
{hashtagBar}
{status.get('quote') && (
<QuotedStatus quote={status.get('quote')} />
<QuotedStatus
quote={status.get('quote')}
parentQuotePostId={status.get('id')}
contextType='thread'
/>
)}
</>
)}

View File

@@ -38,7 +38,7 @@ class FilterModal extends ImmutablePureComponent {
handleSuccess = () => {
const { dispatch, statusId } = this.props;
dispatch(fetchStatus(statusId, true));
dispatch(fetchStatus(statusId, {forceFetch: true}));
this.setState({ isSubmitting: false, isSubmitted: true, step: 'submitted' });
};

View File

@@ -201,8 +201,6 @@ class MediaModal extends ImmutablePureComponent {
preview={image.get('preview_url')}
blurhash={image.get('blurhash')}
src={image.get('url')}
width={image.get('width')}
height={image.get('height')}
frameRate={image.getIn(['meta', 'original', 'frame_rate'])}
aspectRatio={`${image.getIn(['meta', 'original', 'width'])} / ${image.getIn(['meta', 'original', 'height'])}`}
startTime={currentTime || 0}
@@ -219,8 +217,6 @@ class MediaModal extends ImmutablePureComponent {
return (
<GIFV
src={image.get('url')}
width={width}
height={height}
key={image.get('url')}
alt={description}
lang={lang}

View File

@@ -90,8 +90,7 @@ const messages = defineMessages({
const mapStateToProps = state => ({
layout: state.getIn(['meta', 'layout']),
isComposing: state.getIn(['compose', 'is_composing']),
hasComposingText: state.getIn(['compose', 'text']).trim().length !== 0,
hasMediaAttachments: state.getIn(['compose', 'media_attachments']).size > 0,
hasComposingContents: state.getIn(['compose', 'text']).trim().length !== 0 || state.getIn(['compose', 'media_attachments']).size > 0 || state.getIn(['compose', 'poll']) !== null,
canUploadMore: !state.getIn(['compose', 'media_attachments']).some(x => ['audio', 'video'].includes(x.get('type'))) && state.getIn(['compose', 'media_attachments']).size < state.getIn(['server', 'server', 'configuration', 'statuses', 'max_media_attachments']),
firstLaunch: state.getIn(['settings', 'introductionVersion'], 0) < INTRODUCTION_VERSION,
newAccount: !state.getIn(['accounts', me, 'note']) && !state.getIn(['accounts', me, 'bot']) && state.getIn(['accounts', me, 'following_count'], 0) === 0 && state.getIn(['accounts', me, 'statuses_count'], 0) === 0,
@@ -272,8 +271,7 @@ class UI extends PureComponent {
dispatch: PropTypes.func.isRequired,
children: PropTypes.node,
isComposing: PropTypes.bool,
hasComposingText: PropTypes.bool,
hasMediaAttachments: PropTypes.bool,
hasComposingContents: PropTypes.bool,
canUploadMore: PropTypes.bool,
intl: PropTypes.object.isRequired,
layout: PropTypes.string.isRequired,
@@ -288,11 +286,11 @@ class UI extends PureComponent {
};
handleBeforeUnload = e => {
const { intl, dispatch, isComposing, hasComposingText, hasMediaAttachments } = this.props;
const { intl, dispatch, isComposing, hasComposingContents } = this.props;
dispatch(synchronouslySubmitMarkers());
if (isComposing && (hasComposingText || hasMediaAttachments)) {
if (isComposing && hasComposingContents) {
e.preventDefault();
// Setting returnValue to any string causes confirmation dialog.
// Many browsers no longer display this text to users,

View File

@@ -1,6 +1,7 @@
{
"about.blocks": "Gemodereerde bedieners",
"about.contact": "Kontak:",
"about.default_locale": "Verstek",
"about.disclaimer": "Mastodon is gratis oopbronsagteware en n handelsmerk van Mastodon gGmbH.",
"about.domain_blocks.no_reason_available": "Rede nie beskikbaar nie",
"about.domain_blocks.preamble": "Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.",

View File

@@ -1,7 +1,7 @@
{
"about.blocks": "خوادم تحت الإشراف",
"about.contact": "للاتصال:",
"about.default_locale": "افتراضيالافتراضية",
"about.default_locale": "افتراضي",
"about.disclaimer": "ماستدون برنامج حر ومفتوح المصدر وعلامة تجارية لـ Mastodon GmbH.",
"about.domain_blocks.no_reason_available": "السبب غير متوفر",
"about.domain_blocks.preamble": "يتيح مَستُدون عمومًا لمستخدميه مطالعة المحتوى من المستخدمين من الخواديم الأخرى في الفدرالية والتفاعل معهم. وهذه هي الاستثناءات التي وضعت على هذا الخادوم.",
@@ -115,7 +115,7 @@
"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.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": "المنشور بأعلى عدد تعليقات",
@@ -873,6 +873,7 @@
"status.open": "وسّع هذا المنشور",
"status.pin": "دبّسه على الصفحة التعريفية",
"status.quote_error.filtered": "مُخفي بسبب إحدى إعدادات التصفية خاصتك",
"status.quote_error.limited_account_hint.action": "إظهاره على أي حال",
"status.quote_error.not_found": "لا يمكن عرض هذا المنشور.",
"status.quote_error.pending_approval": "هذا المنشور ينتظر موافقة صاحب المنشور الأصلي.",
"status.quote_error.rejected": "لا يمكن عرض هذا المنشور لأن صاحب المنشور الأصلي لا يسمح له بأن يكون مقتبس.",

View File

@@ -1,13 +1,15 @@
{
"about.blocks": "Moderasiya olunan serverlər",
"about.blocks": "Moderasiya edilmiş serverlər",
"about.contact": "Əlaqə:",
"about.disclaimer": "Mastodon pulsuz, açıq-mənbəli proqram təminatıdır və Mastodon gGmbH-nin əmtəə nişanıdır.",
"about.domain_blocks.no_reason_available": "Səbəb naməlumdur",
"about.domain_blocks.preamble": "Mastodon adətən fediversedəki hər hansısa bir serverdən olan məzmuna baxmaq və istifadəçilərlə qarşılıqlı əlaqədə olmaq imkanı verir. Bunlar bu serverdə edilmiş istisnalardır.",
"about.default_locale": "İlkin",
"about.disclaimer": "Mastodon ödənişsiz, açıq-mənbəli yazılımdır və Mastodon gGmbH-nin əmtəə nişanıdır.",
"about.domain_blocks.no_reason_available": "Səbəb mövcud deyil",
"about.domain_blocks.preamble": "Mastodon, adətən fediverse-dəki hər hansısa bir serverdən məzmuna baxmağınıza və istifadəçilərlə qarşılıqlı əlaqədə olmağınıza imkanı verir. Bunlar, bu serverdə edilmiş istisnalardır.",
"about.domain_blocks.silenced.explanation": "Siz bu serverdəki profilləri və məzmunu xüsusi olaraq axtarmasanız və ya izləməsəniz ümumiyyətlə görməyəcəksiniz.",
"about.domain_blocks.silenced.title": "Məhdudlaşdırılmış",
"about.domain_blocks.suspended.explanation": "Bu serverdən heç bir data emal edilməyəcək, saxlanılmayacaq və ya mübadilə edilməyəcək bu serverdən olan istifadəçilərlə hər hansı qarşılıqlı əlaqə qeyri-mümkün olacaq.",
"about.domain_blocks.suspended.explanation": "Bu serverdəki heç bir veri emal edilməyəcək, saxlanılmayacaq və ya mübadilə edilməyəcək, bu serverdəki istifadəçilərlə hər hansısa bir qarşılıqlı əlaqə və ya ünsiyyət mümkünsüz olacaq.",
"about.domain_blocks.suspended.title": "Qadağa qoyulub",
"about.language_label": "Dil",
"about.not_available": "Bu məlumat bu serverdə əlçatan edilməyib.",
"about.powered_by": "{mastodon} tərəfindən təchiz edilən desentralizasiya edilmiş sosial media",
"about.rules": "Server qaydaları",
@@ -19,6 +21,7 @@
"account.block_domain": "{domain} domenini blokla",
"account.block_short": "Blok",
"account.blocked": "Bloklanıb",
"account.blocking": "Əngəlləmə",
"account.cancel_follow_request": "İzləməni ləğv et",
"account.copy": "Profil linkini kopyala",
"account.direct": "@{name} istifadəçisini fərdi olaraq etiketlə",
@@ -27,6 +30,11 @@
"account.edit_profile": "Profili redaktə et",
"account.enable_notifications": "@{name} paylaşım edəndə mənə bildiriş göndər",
"account.endorse": "Profildə seçilmişlərə əlavə et",
"account.familiar_followers_many": "{name1}, {name2} və tanıdığınız digər {othersCount, plural, one {digər bir nəfər} other {# nəfər}} izləyir",
"account.familiar_followers_one": "{name1} izləyir",
"account.familiar_followers_two": "{name1} və {name2} izləyir",
"account.featured": "Seçilmiş",
"account.featured.accounts": "Profillər",
"account.featured.hashtags": "Etiketler",
"account.featured_tags.last_status_at": "Son paylaşım {date} tarixində olub",
"account.featured_tags.last_status_never": "Paylaşım yoxdur",
@@ -35,16 +43,18 @@
"account.followers": "İzləyicilər",
"account.followers.empty": "Bu istifadəçini hələ ki, heç kim izləmir.",
"account.followers_counter": "{count, plural, one {{counter} izləyici} other {{counter} izləyici}}",
"account.followers_you_know_counter": "bildiyiniz {counter}",
"account.following": "İzləyir",
"account.following_counter": "{count, plural, one {{counter} izləyir} other {{counter} izləyir}}",
"account.follows.empty": "Bu istifadəçi hələ ki, heç kimi izləmir.",
"account.follows_you": "Sizi izləyir",
"account.go_to_profile": "Profilə get",
"account.hide_reblogs": "@{name} istifadəçisindən olan gücləndirmələri gizlət",
"account.hide_reblogs": "@{name} - təkrar paylaşımlarını gizlət",
"account.in_memoriam": "Xatirə.",
"account.joined_short": "Qoşulub",
"account.languages": "Abunə olunmuş dilləri dəyiş",
"account.link_verified_on": "Bu linkin dəqiqliyi {date} tarixində yoxlanılıb",
"account.locked_info": "Bu hesabın məxfilik statusu kilidlənib. Hesabın sahibi onu kimin izləyə biləcəyini manual olaraq təyin edir.",
"account.locked_info": "Bu hesabın məxfilik statusu kilidlənib. Sahibi, onu kimin izləyə biləcəyini manual olaraq incələyir.",
"account.media": "Media",
"account.mention": "@{name} istifadəçisini teq et",
"account.moved_to": "{name} onun yeni hesabının artıq bu olduğunu bildirdi:",
@@ -52,18 +62,23 @@
"account.mute_notifications_short": "Bildirişləri səssizləşdir",
"account.mute_short": "Səssizləşdir",
"account.muted": "Səssizləşdirilib",
"account.muting": "Səssizə alınır",
"account.mutual": "Bir-birinizi izləyirsiniz",
"account.no_bio": "Təsvir göstərilməyib.",
"account.open_original_page": "Orijinal səhifəni aç",
"account.posts": "Paylaşım",
"account.posts_with_replies": "Paylaşım və cavablar",
"account.remove_from_followers": "{name} - izləyicilərdən çıxart",
"account.report": "@{name} istifadəçisini şikayət et",
"account.requested": "Təsdiq edilməsi gözlənilir. İzləmə sorğusunu ləğv etmək üçün kliklə",
"account.requested_follow": "{name} sizi izləmək sorğusu göndərib",
"account.requests_to_follow_you": "Sizi izləmək istəyir",
"account.share": "@{name} profilini paylaş",
"account.show_reblogs": "@{name} istifadəçisindən olan gücləndirmələri göstər",
"account.show_reblogs": "@{name} - təkrar paylaşımlarını göstər",
"account.statuses_counter": "{count, plural, one {{counter} paylaşım} other {{counter} paylaşım}}",
"account.unblock": "@{name} blokunu aç",
"account.unblock_domain": "{domain} domeninin blokunu aç",
"account.unblock_domain_short": "Əngəldən çıxart",
"account.unblock_short": "Bloku aç",
"account.unendorse": "Profildə seçilmişlərə əlavə etmə",
"account.unfollow": "İzləmədən çıxar",
@@ -102,7 +117,7 @@
"annual_report.summary.followers.total": "Cəmi {count}",
"annual_report.summary.here_it_is": "{year} icmalınız:",
"annual_report.summary.highlighted_post.by_favourites": "ən çox sevilən postu",
"annual_report.summary.highlighted_post.by_reblogs": "ən çox gücləndirilən paylaşımı",
"annual_report.summary.highlighted_post.by_reblogs": "ən çox təkrar paylaşılan göndəriş",
"annual_report.summary.highlighted_post.by_replies": "ən çox cavabı olan paylaşımı",
"annual_report.summary.highlighted_post.possessive": "{name} istifadəçisinin",
"annual_report.summary.most_used_app.most_used_app": "ən çox istifadə etdiyi tətbiq",
@@ -114,7 +129,7 @@
"annual_report.summary.thanks": "Mastodonun bir parçası olduğunuz üçün təşəkkür edirik!",
"attachments_list.unprocessed": "(emal edilməyib)",
"audio.hide": "Audionu gizlət",
"block_modal.remote_users_caveat": "Biz {domain} serverindən qərarınıza hörmət etməsini xahiş edəcəyik. Bununla belə, bəzi serverlər blokları fərqli şəkildə idarə edə bildiyi üçün uyğunluğa zəmanət verilmir. İctimai paylaşımlar hələ də daxil olmayan istifadəçilərə görünə bilər.",
"block_modal.remote_users_caveat": "{domain} serverindən qərarınıza hörmət etməsini xahiş edəcəyik. Ancaq, bəzi serverlər əngəlləmələri fərqli şəkildə idarə edə bilər deyə, qərarınıza uymağına zəmanət verilmir. Hər kəsə açıq göndərişlər, hələ də sistemə giriş etməmiş istifadəçilərə görünə bilər.",
"block_modal.show_less": "Daha az göstər",
"block_modal.show_more": "Daha çox göstər",
"block_modal.they_cant_mention": "O səni teq edə bilməz və ya izləyə bilməz.",
@@ -123,8 +138,8 @@
"block_modal.title": "İstifadəçi bloklansın?",
"block_modal.you_wont_see_mentions": "Onu teq edən postları görməyəcəksən.",
"boost_modal.combo": "Növbəti dəfə bunu atlamaq üçün {combo} klikləyə bilərsən",
"boost_modal.reblog": "Paylaşım gücləndirilsin?",
"boost_modal.undo_reblog": "Paylaşımın gücləndirilməsi ləğv edilsin?",
"boost_modal.reblog": "Paylaşım təkrar paylaşılsın?",
"boost_modal.undo_reblog": "Təkrar paylaşım ləğv edilsin?",
"bundle_column_error.copy_stacktrace": "Xəta hesabatını kopyala",
"bundle_column_error.error.body": "Tələb olunan səhifəni göstərmək mümkün olmadı. Bu, kodumuzdakı səhv və ya brauzer uyğunluğu problemi ilə bağlı ola bilər.",
"bundle_column_error.error.title": "Ah, yox!",
@@ -159,14 +174,14 @@
"column.lists": "Siyahılar",
"column.mutes": "Səssizləşdirilmiş istifadəçilər",
"column.notifications": "Bildirişlər",
"column.pins": "Bərkidilmiş paylaşımlar",
"column.pins": "Sancılmış göndərişlər",
"column.public": "Federasiya zaman qrafiki",
"column_back_button.label": "Geriyə",
"column_header.hide_settings": "Parametrləri gizlət",
"column_header.hide_settings": "Ayarları gizlət",
"column_header.moveLeft_settings": "Sütunu sola köçür",
"column_header.moveRight_settings": "Sütunu sağa köçür",
"column_header.pin": "Bərkit",
"column_header.show_settings": "Parametrləri göstər",
"column_header.show_settings": "Ayarları göstər",
"column_header.unpin": "Bərkitmə",
"column_search.cancel": "İmtina",
"community.column_settings.local_only": "Sadəcə lokalda",
@@ -192,7 +207,7 @@
"compose_form.poll.type": "Stil",
"compose_form.publish": "Paylaş",
"compose_form.reply": "Cavabla",
"compose_form.save_changes": "Yenilə",
"compose_form.save_changes": "Güncəllə",
"compose_form.spoiler.marked": "Məzmun xəbərdarlığını sil",
"compose_form.spoiler.unmarked": "Məzmun xəbərdarlığı əlavə et",
"compose_form.spoiler_placeholder": "Məzmun xəbərdarlığı (məcburi deyil)",
@@ -204,6 +219,13 @@
"confirmations.delete_list.confirm": "Sil",
"confirmations.delete_list.message": "Bu siyahını həmişəlik silmək istədiyinizə əminsiniz?",
"confirmations.delete_list.title": "Siyahı silinsin?",
"confirmations.discard_draft.confirm": "Silib davam et",
"confirmations.discard_draft.edit.cancel": "Düzəliş etməyə davam",
"confirmations.discard_draft.edit.message": "Davam etsəniz, hazırda düzəliş etdiyiniz göndərişdəki bütün dəyişikliklər silinəcək.",
"confirmations.discard_draft.edit.title": "Göndərişinizə etdiyiniz bütün dəyişikliklər silinsin?",
"confirmations.discard_draft.post.cancel": "Qaralama kimi davam etdir",
"confirmations.discard_draft.post.message": "Davam etsəniz, hazırda tərtib etdiyiniz göndəriş silinəcək.",
"confirmations.discard_draft.post.title": "Qaralama göndərişiniz silinsin?",
"confirmations.discard_edit_media.confirm": "Ləğv et",
"confirmations.discard_edit_media.message": "Media təsvirində və ya önizləmədə yadda saxlanmamış dəyişiklikləriniz var, ləğv edilsin?",
"confirmations.follow_to_list.confirm": "İzlə və siyahıya əlavə et",
@@ -213,13 +235,16 @@
"confirmations.logout.message": ıxmaq istədiyinizə əminsiniz?",
"confirmations.logout.title": ıxış edilsin?",
"confirmations.missing_alt_text.confirm": "Alternativ mətn əlavə et",
"confirmations.missing_alt_text.message": "Paylaşımınız alternativ mətn ehtiva etmir. Təsvir əlavə etmək onun daha çox insan üçün əlçatan olmasına kömək edir.",
"confirmations.missing_alt_text.message": "Göndərişinizdə alternativ mətn yoxdur. Daha çox insanın məzmununuza erişməsinə kömək etmək üçün açıqlama əlavə edin.",
"confirmations.missing_alt_text.secondary": "Yenə də paylaş",
"confirmations.missing_alt_text.title": "Alternativ mətn əlavə edilsin?",
"confirmations.mute.confirm": "Səssizləşdir",
"confirmations.redraft.confirm": "Sil və qaralamaya köçür",
"confirmations.redraft.message": "Bu paylaşımı silmək və qaralamaya köçürmək istədiyinizə əminsiniz? Bəyənmələr və gücləndirmələr itəcək orijinal paylaşıma olan cavablar tənha qalacaq.",
"confirmations.redraft.message": "Bu göndərişi silib yenidən qaralama kimi saxlamaq istədiyinizə əminsiniz? Sevimlilər və təkrar paylaşımlar silinəcək, orijinal göndərişə verilən cavablar isə əlaqəsiz qalacaq.",
"confirmations.redraft.title": "Paylaşım silinsin & qaralamaya köçürülsün?",
"confirmations.remove_from_followers.confirm": "İzləyicini çıxart",
"confirmations.remove_from_followers.message": "{name} sizi izləməyəcək. Davam etmək istədiyinizə əminsiniz?",
"confirmations.remove_from_followers.title": "İzləyici çıxarılsın?",
"confirmations.unfollow.confirm": "İzləmədən çıxar",
"confirmations.unfollow.message": "{name} izləmədən çıxmaq istədiyinizə əminsiniz?",
"confirmations.unfollow.title": "İstifadəçi izləmədən çıxarılsın?",
@@ -232,12 +257,12 @@
"conversation.with": "{names} ilə",
"copy_icon_button.copied": "Mübadilə buferinə köçürüldü",
"copypaste.copied": "Kopyalandı",
"copypaste.copy_to_clipboard": "Kopyala",
"copypaste.copy_to_clipboard": "Lövhəyə kopyala",
"directory.federated": "Bilinən fediversedən",
"directory.local": "Sadəcə {domain}",
"directory.new_arrivals": "Yeni gələnlər",
"directory.recently_active": "Bayaq aktiv olanlar",
"disabled_account_banner.account_settings": "Hesab parametrləri",
"disabled_account_banner.account_settings": "Hesab ayarları",
"disabled_account_banner.text": "Sizin hesabınız {disabledAccount} hal-hazırda deaktiv edilib.",
"dismissable_banner.community_timeline": "Bunlar, hesabları {domain} serverində yerləşən insanların ən son ictimai paylaşımlarıdır.",
"dismissable_banner.dismiss": "Bağla",
@@ -273,7 +298,7 @@
"emoji_button.food": "Yemək və içki",
"emoji_button.label": "Emoji daxil et",
"emoji_button.nature": "Təbiət",
"emoji_button.not_found": "Uyğun emoji tapılmadı",
"emoji_button.not_found": "Uyuşan emoji tapılmadı",
"emoji_button.objects": "Obyektlər",
"emoji_button.people": "İnsanlar",
"emoji_button.recent": "Tez-tez istifadə edilən",
@@ -296,6 +321,620 @@
"empty_column.follow_requests": "İzləmə sorğularınız yoxdur. Qəbul etdikdə burada görəcəksiniz.",
"empty_column.followed_tags": "Heç bir heşteq izləmirsiniz. İzlədikdə burada görünəcək.",
"empty_column.hashtag": "Bu heşteqdə hələ ki, heç nə yoxdur.",
"empty_column.home": "Əsas zaman xəttiniz boşdur! Doldurmaq üçün bir neçə istifadəçini izləyin.",
"empty_column.list": "Hələ bu siyahıda heç nə yoxdur. Bu siyahıdakı üzvlər yeni göndəriş paylaşdığı zaman burada görünəcək.",
"empty_column.mutes": "Hələ heç bir istifadəçini səssizə almamısınız.",
"empty_column.notification_requests": "Hamısı hazırdır! Burada heç nə yoxdur. Yeni bildiriş aldığınız zaman, ayarlarınıza görə burada görünəcək.",
"empty_column.notifications": "Hələ heç bir bildirişiniz yoxdur. Başqaları sizinlə qarşılıqlı əlaqə qurduğu zaman, onu burada görəcəksiniz.",
"empty_column.public": "Burada hələ heç nə yoxdur! Buranı doldurmaq üçün hər kəsə açıq bir şey yazın və ya digər serverlərdəki istifadəçiləri izləyin.",
"error.unexpected_crash.explanation": "Kodumuzdakı bir xətaya, ya da brauzer uyumluluq probleminə görə, bu səhifə düzgün nümayiş etdirilə bilmədi.",
"error.unexpected_crash.explanation_addons": "Bu səhifə düzgün nümayiş etdirilə bilmədi. Bu xəta, yəqin ki, brauzer əlavəsi və ya avtomatik tərcümə alətlərindən qaynaqlanır.",
"error.unexpected_crash.next_steps": "Səhifəni təzələməyi sınayın. Bu kömək etməzsə, Mastodon-u başqa bir brauzer və ya yerli tətbiq vasitəsilə istifadə edə bilərsiniz.",
"error.unexpected_crash.next_steps_addons": "Onları sıradan çıxartmağı və səhifəni təzələməyi sınayın. Bu kömək etməzsə, Mastodon-u başqa bir brauzer və ya yerli tətbiq vasitəsilə istifadə edə bilərsiniz.",
"errors.unexpected_crash.report_issue": "Problemi bildir",
"explore.suggested_follows": "İnsanlar",
"explore.title": "Trendlər",
"explore.trending_links": "Xəbərlər",
"explore.trending_statuses": "Göndərişlər",
"explore.trending_tags": "Mövzu etiketləri",
"featured_carousel.header": "{count, plural, one {Sancılmış göndəriş} other {Sancılmış göndərişlər}}",
"featured_carousel.next": "Növbəti",
"featured_carousel.post": "Göndəriş",
"featured_carousel.previous": "Əvvəlki",
"featured_carousel.slide": "{index}/{total}",
"filter_modal.added.context_mismatch_explanation": "Bu filtr kateqoriyası, bu göndərişdə erişdiyiniz kontekstə aid deyil. Əgər göndərişin bu kontekstdə də filtrlənməsini istəyirsinizsə, filtrə düzəliş etməyiniz lazımdır.",
"filter_modal.added.context_mismatch_title": "Kontekst uyuşmur!",
"filter_modal.added.expired_explanation": "Bu filtr kateqoriyasının vaxtı bitib, filtri tətbiq etmək üçün bitmə tarixini dəyişdirməlisiniz.",
"filter_modal.added.expired_title": "Vaxtı bitmiş filtr!",
"filter_modal.added.review_and_configure": "Bu filt kateqoriyasını incələmək və daha detallı konfiqurasiya etmək üçün {settings_link} ünvanına gedin.",
"filter_modal.added.review_and_configure_title": "Filtr ayarları",
"filter_modal.added.settings_link": "ayarlar səhifəsi",
"filter_modal.added.short_explanation": "Bu göndəriş, aşağıdakı filtr kateqoriyasına əlavə edilib: {title}.",
"filter_modal.added.title": "Filtr əlavə edilib!",
"filter_modal.select_filter.context_mismatch": "bu kontektsə tətbiq olunmur",
"filter_modal.select_filter.expired": "müddəti bitib",
"filter_modal.select_filter.prompt_new": "Yeni kateqoriya: {name}",
"filter_modal.select_filter.search": "Axtar və ya yarat",
"filter_modal.select_filter.subtitle": "Mövcud bir kateqoriyanı istifadə et, ya da yenisini yarat",
"filter_modal.select_filter.title": "Bu göndərişi filtrlə",
"filter_modal.title.status": "Bir göndərişi filtrlə",
"filter_warning.matches_filter": "“<span>{title}</span>” filtri ilə uyuşur",
"filtered_notifications_banner.pending_requests": "Tanıdığınız {count, plural, =0 {heç kimdən} one {bir şəxsdən} other {# şəxsdən}}",
"filtered_notifications_banner.title": "Filtrlənmiş bildirişlər",
"firehose.all": "Hamısı",
"firehose.local": "Bu server",
"firehose.remote": "Digər serverlər",
"follow_request.authorize": "Səlahiyyət ver",
"follow_request.reject": "Rədd et",
"follow_requests.unlocked_explanation": "Hesabınız kilidli olmasa da, {domain} heyəti bu hesabların izləmə tələblərini manual olaraq incələmək istəyə biləcəyinizi düşündü.",
"follow_suggestions.curated_suggestion": "Heyətin seçimi",
"follow_suggestions.dismiss": "Təkrar göstərmə",
"follow_suggestions.featured_longer": "{domain} komandası tərəfindən əllə seçildi",
"follow_suggestions.friends_of_friends_longer": "İzlədiyiniz insanlar arasında məşhur",
"follow_suggestions.hints.featured": "Bu profil {domain} komandası tərəfindən əllə seçilib.",
"follow_suggestions.hints.friends_of_friends": "Bu profil izlədiyiniz insanlar arasında populyardır.",
"follow_suggestions.hints.most_followed": "Bu profil {domain} serverində ən çox izlənilənlərdən biridir."
"follow_suggestions.hints.most_followed": "Bu profil {domain} serverində ən çox izlənilənlərdən biridir.",
"follow_suggestions.hints.most_interactions": "Bu profil son zamanlar {domain} üzərində çox diqqət çəkir.",
"follow_suggestions.hints.similar_to_recently_followed": "Bu profil, son vaxtlar izlədiyiniz profillərə bənzəyir.",
"follow_suggestions.personalized_suggestion": "Fərdiləşdirilmiş təklif",
"follow_suggestions.popular_suggestion": "Məşhur təklif",
"follow_suggestions.popular_suggestion_longer": "{domain} üzərində məşhur",
"follow_suggestions.similar_to_recently_followed_longer": "Son zaman izlədiyiniz profillərə oxşar",
"follow_suggestions.view_all": "Hamısına bax",
"follow_suggestions.who_to_follow": "İzləyə bilərsən",
"followed_tags": "İzlənilən mövzu etiketləri",
"footer.about": "Haqqında",
"footer.directory": "Profil kataloqu",
"footer.get_app": "Tətbiqi əldə et",
"footer.keyboard_shortcuts": "Klaviatura qısayolları",
"footer.privacy_policy": "Gizlilik siyasəti",
"footer.source_code": "Mənbə koduna bax",
"footer.status": "Status",
"footer.terms_of_service": "Xidmət şərtləri",
"generic.saved": "Saxlanıldı",
"getting_started.heading": "Başlayaq",
"hashtag.admin_moderation": "#{name} üçün moderasiya interfeysini aç",
"hashtag.browse": "#{hashtag} göndərişlərinə bax",
"hashtag.browse_from_account": "@{name} - #{hashtag} göndərişlərinə bax",
"hashtag.column_header.tag_mode.all": "və {additional}",
"hashtag.column_header.tag_mode.any": "və ya {additional}",
"hashtag.column_header.tag_mode.none": "{additional} olmadan",
"hashtag.column_settings.select.no_options_message": "Heç bir təklif tapılmadı",
"hashtag.column_settings.select.placeholder": "Mövzu etiketlərini daxil edin…",
"hashtag.column_settings.tag_mode.all": "Bunların hamısı",
"hashtag.column_settings.tag_mode.any": "Bunlardan hər hansısa biri",
"hashtag.column_settings.tag_mode.none": "Bunların heç biri",
"hashtag.column_settings.tag_toggle": "Bu sütun üçün əlavə etiketləri daxil et",
"hashtag.counter_by_accounts": "{count, plural, one {{counter} iştirakçı} other {{counter} iştirakçı}}",
"hashtag.counter_by_uses": "{count, plural, one {{counter} göndəriş} other {{counter} göndəriş}}",
"hashtag.counter_by_uses_today": "Bu gün {count, plural, one {{counter} göndəriş} other {{counter} göndəriş}}",
"hashtag.feature": "Profildə önə çıxart",
"hashtag.follow": "Mövzu etiketini izlə",
"hashtag.mute": "#{hashtag} - səssizə al",
"hashtag.unfeature": "Profildə önə çıxarılmasın",
"hashtag.unfollow": "Mövzu etiketini izləmə",
"hashtags.and_other": "…və daha {count, plural, one {}other {# ədəd}}",
"hints.profiles.followers_may_be_missing": "Bu profilin izləyiciləri əskik ola bilər.",
"hints.profiles.follows_may_be_missing": "Bu profilin izləyənləri əskik ola bilər.",
"hints.profiles.posts_may_be_missing": "Bu profilin bəzi göndərişləri əskik ola bilər.",
"hints.profiles.see_more_followers": "{domain} üzərində daha çox izləyici gör",
"hints.profiles.see_more_follows": "{domain} üzərində izlənilən gör",
"hints.profiles.see_more_posts": "{domain} üzərində daha çox göndəriş gör",
"hints.threads.replies_may_be_missing": "Digər serverlərdən gələn cavablar əskik ola bilər.",
"hints.threads.see_more": "{domain} üzərində daha çox cavabı gör",
"home.column_settings.show_quotes": "Sitatları göstər",
"home.column_settings.show_reblogs": "Təkrar paylaşmaları göstər",
"home.column_settings.show_replies": "Cavabları göstər",
"home.hide_announcements": "Elanları gizlət",
"home.pending_critical_update.body": "Lütfən Mastodon serverinizi mümkün olan ən qısa müddətdə güncəlləyin!",
"home.pending_critical_update.link": "Güncəlləmələrə bax",
"home.pending_critical_update.title": "Kritik güvənlik güncəlləməsi mövcuddur!",
"home.show_announcements": "Elanları göstər",
"ignore_notifications_modal.disclaimer": "Mastodon, bildirişlərini yox saydığınız istifadəçiləri məlumatlandırmır. Bildirişləri yox saymaq, mesajların göndərilməsini dayandırmayacaq.",
"ignore_notifications_modal.filter_instead": "Əvəzinə filtrlə",
"ignore_notifications_modal.filter_to_act_users": "Hələ də istifadəçiləri qəbul edə, rədd edə və ya bildirə bilərsiniz",
"ignore_notifications_modal.filter_to_avoid_confusion": "Filtrləmə, mümkün çaşqınlığın qarşısını almağa kömək edir.",
"ignore_notifications_modal.filter_to_review_separately": "Filtrlənmiş bildirişləri ayrı-ayrı incələyə bilərsiniz",
"ignore_notifications_modal.ignore": "Bildirişləri yox say",
"ignore_notifications_modal.limited_accounts_title": "Moderasiya edilmiş hesabların bildirişləri yox sayılsın?",
"ignore_notifications_modal.new_accounts_title": "Yeni hesabların bildirişləri yox sayılsın?",
"ignore_notifications_modal.not_followers_title": "Sizi izləməyən şəxslərin bildirişləri yox sayılsın?",
"ignore_notifications_modal.not_following_title": "İzləmədiyiniz şəxslərin bildirişləri yox sayılsın?",
"ignore_notifications_modal.private_mentions_title": "İstənilməyən Şəxsi Adçəkmələrdən gələn bildirişlər yox sayılsın?",
"info_button.label": "Kömək",
"interaction_modal.action.favourite": "Davam etmək üçün hesabınızdan sevimlilərə əlavə etməlisiniz.",
"interaction_modal.action.follow": "Davam etmək üçün hesabınızdan izləməlisiniz.",
"interaction_modal.action.reblog": "Davam etmək üçün hesabınızdan təkrar göndərməlisiniz.",
"interaction_modal.action.reply": "Davam etmək üçün hesabınızdan cavab verməlisiniz.",
"interaction_modal.action.vote": "Davam etmək üçün hesabınızdan səs verməlisiniz.",
"interaction_modal.go": "Get",
"interaction_modal.no_account_yet": "Hələ heç bir hesabınız yoxdur?",
"interaction_modal.on_another_server": "Fərqli bir serverdə",
"interaction_modal.on_this_server": "Bu serverdə",
"interaction_modal.title.favourite": "{name} - göndərişini sevimlilərə əlavə et",
"interaction_modal.title.follow": "{name} - izlə",
"interaction_modal.title.reblog": "{name} - göndərişini təkrar paylaş",
"interaction_modal.title.reply": "{name} - göndərişinə cavab ver",
"interaction_modal.title.vote": "{name} - anketində səs ver",
"interaction_modal.username_prompt": "Məs: {example}",
"intervals.full.days": "{number, plural, one {# gün} other {# gün}}",
"intervals.full.hours": "{number, plural, one {# saat} other {# saat}}",
"intervals.full.minutes": "{number, plural, one {# dəqiqə} other {# dəqiqə}}",
"keyboard_shortcuts.back": "Geri get",
"keyboard_shortcuts.blocked": "Əngəllənən istifadəçilərin siyahısını aç",
"keyboard_shortcuts.boost": "Göndərişi təkrar paylaş",
"keyboard_shortcuts.column": "Sütuna fokuslan",
"keyboard_shortcuts.compose": "Mətn yazma sahəsinə fokuslan",
"keyboard_shortcuts.description": "Açıqlama",
"keyboard_shortcuts.direct": "şəxsi adçəkmələr sütununu açmaq üçün",
"keyboard_shortcuts.down": "Siyahıda aşağı daşı",
"keyboard_shortcuts.enter": "Göndərişi aç",
"keyboard_shortcuts.favourite": "Göndərişi sevimlilərə əlavə et",
"keyboard_shortcuts.favourites": "Sevimli siyahını aç",
"keyboard_shortcuts.heading": "Klaviatura qısayolları",
"keyboard_shortcuts.home": "Əsas ekran zaman xəttini aç",
"keyboard_shortcuts.hotkey": "Qısayol düyməsi",
"keyboard_shortcuts.legend": "Bu əfsanəni nümayiş etdir",
"keyboard_shortcuts.local": "Lokal zaman xəttini aç",
"keyboard_shortcuts.mention": "Müəllifin adını çək",
"keyboard_shortcuts.muted": "Səssizdəki istifadəçilərin siyahısını aç",
"keyboard_shortcuts.my_profile": "Profilinizi açın",
"keyboard_shortcuts.notifications": "Bildirişlər sütununu aç",
"keyboard_shortcuts.open_media": "Medianı aç",
"keyboard_shortcuts.pinned": "Sancılmış göndərişlərin siyahısını aç",
"keyboard_shortcuts.profile": "Müəllifin profilini aç",
"keyboard_shortcuts.reply": "Göndərişə cavab ver",
"keyboard_shortcuts.requests": "İzləmə istəyi siyahısını aç",
"keyboard_shortcuts.search": "Axtarış çubuğuna fokuslan",
"keyboard_shortcuts.spoilers": "CW xanasını göstər/gizlət",
"keyboard_shortcuts.start": "\"Başlayaq\" sütununu aç",
"keyboard_shortcuts.toggle_hidden": "CW arxasındakı mətni göstər/gizlət",
"keyboard_shortcuts.toggle_sensitivity": "Medianı göstər/gizlət",
"keyboard_shortcuts.toot": "Yeni bir göndəriş başlat",
"keyboard_shortcuts.translate": "bir göndərişi tərcümə etmək üçün",
"keyboard_shortcuts.unfocus": "Fokusu göndəriş yazma xanasından/axtarışdan götür",
"keyboard_shortcuts.up": "Siyahıda yuxarı daşı",
"lightbox.close": "Bağla",
"lightbox.next": "Növbəti",
"lightbox.previous": "Əvvəlki",
"lightbox.zoom_in": "Həqiqi ölçüyə qayıt",
"lightbox.zoom_out": "Sığacaq şəkildə yaxınlaşdır",
"limited_account_hint.action": "Yenə də profili göstər",
"limited_account_hint.title": "Bu profil, {domain} moderatorları tərəfindən gizlədildi.",
"link_preview.author": "Müəllif: {name}",
"link_preview.more_from_author": "{name} - daha çox",
"link_preview.shares": "{count, plural, one {{counter} göndəriş} other {{counter} göndəriş}}",
"lists.add_member": "Əlavə et",
"lists.add_to_list": "Siyahıya əlavə et",
"lists.add_to_lists": "{name} - siyahılara əlavə et",
"lists.create": "Yarat",
"lists.create_a_list_to_organize": "Əsas ekran lentinizi təşkil etmək üçün yeni bir siyahı yaradın",
"lists.create_list": "Siyahı yarat",
"lists.delete": "Siyahını sil",
"lists.done": "Hazırdır",
"lists.edit": "Siyahıya düzəliş et",
"lists.exclusive": "Əsas ekranda üzvləri gizlət",
"lists.exclusive_hint": "Kimsə bu siyahıdadırsa, onun göndərişləri bir dəfədən çox görünməməsi üçün Əsas ekran lentində gizlədilir.",
"lists.find_users_to_add": "Əlavə ediləcək istifadəçiləri tap",
"lists.list_members_count": "{count, plural, one {# üzv} other {# üzv}}",
"lists.list_name": "Siyahı adı",
"lists.new_list_name": "Yeni siyahı adı",
"lists.no_lists_yet": "Hələ siyahı yoxdur.",
"lists.no_members_yet": "Hələ üzv yoxdur.",
"lists.no_results_found": "Heç bir nəticə tapılmadı.",
"lists.remove_member": ıxart",
"lists.replies_policy.followed": "İstənilən izlənilən istifadəçi",
"lists.replies_policy.list": "Siyahıdakı üzvlər",
"lists.replies_policy.none": "Heç kim",
"lists.save": "Saxla",
"lists.search": "Axtar",
"lists.show_replies_to": "Siyahı üzvlərinin cavablarını daxil et",
"load_pending": "{count, plural, one {# yeni element} other {# yeni element}}",
"loading_indicator.label": "Yüklənir…",
"media_gallery.hide": "Gizlət",
"moved_to_account_banner.text": "{disabledAccount} hesabınız, {movedToAccount} hesabına keçdiyiniz üçün hazırda sıradan çıxarılıb.",
"mute_modal.hide_from_notifications": "Bildirişlərdə gizlət",
"mute_modal.hide_options": "Seçimləri gizlət",
"mute_modal.indefinite": "Mən səsini açana qədər",
"mute_modal.show_options": "Seçimləri göstər",
"mute_modal.they_can_mention_and_follow": "Sizin adınızı çəkə və sizi izləyə bilər, ancaq siz onları görə bilməzsiniz.",
"mute_modal.they_wont_know": "Onlar, səssizə alındıqlarını bilməyəcəklər.",
"mute_modal.title": "İstifadəçi səssizə alınsın?",
"mute_modal.you_wont_see_mentions": "Onların adı çəkilən göndərişləri görməyəcəksiniz.",
"mute_modal.you_wont_see_posts": "Onlar hələ də göndərişlərinizi görə biləcək, ancaq onların göndərişlərini görməyəcəksiniz.",
"navigation_bar.about": "Haqqında",
"navigation_bar.account_settings": "Parol və təhlükəsizlik",
"navigation_bar.administration": "Administrasiya",
"navigation_bar.advanced_interface": "Qabaqcıl veb interfeysində aç",
"navigation_bar.automated_deletion": "Göndərişin avtomatik silinməsi",
"navigation_bar.blocks": "Əngəllənmiş istifadəçilər",
"navigation_bar.bookmarks": "Əlfəcinlər",
"navigation_bar.direct": "Şəxsi adçəkmələr",
"navigation_bar.domain_blocks": "Əngəllənmiş domenlər",
"navigation_bar.favourites": "Sevimlilər",
"navigation_bar.filters": "Səssizə alınmış sözlər",
"navigation_bar.follow_requests": "İzləmə istəkləri",
"navigation_bar.followed_tags": "İzlənilən mövzu etiketləri",
"navigation_bar.follows_and_followers": "İzlənilənlər və izləyicilər",
"navigation_bar.import_export": "Daxilə və xaricə köçürmə",
"navigation_bar.lists": "Siyahılar",
"navigation_bar.live_feed_local": "Canlı lent (lokal)",
"navigation_bar.live_feed_public": "Canlı lent (hər kəsə açıq)",
"navigation_bar.logout": ıxış",
"navigation_bar.moderation": "Moderasiya",
"navigation_bar.more": "Daha çox",
"navigation_bar.mutes": "Səssizə alınmış istifadəçilər",
"navigation_bar.opened_in_classic_interface": "Göndərişlər, hesablar və digər müəyyən səhifələr klassik veb interfeysində ilkin olaraq açılır.",
"navigation_bar.preferences": "Tərcihlər",
"navigation_bar.privacy_and_reach": "Gizlilik və əlçatanlıq",
"navigation_bar.search": "Axtar",
"navigation_bar.search_trends": "Axtar / Trendlər",
"navigation_panel.collapse_followed_tags": "İzlənilən mövzu etiketləri menyusunu yığcamlaşdır",
"navigation_panel.collapse_lists": "Siyahı menyusunu yığcamlaşdır",
"navigation_panel.expand_followed_tags": "İzlənilən mövzu etiketləri menyusunu genişləndir",
"navigation_panel.expand_lists": "Siyahı menyusunu genişləndir",
"not_signed_in_indicator.not_signed_in": "Bu resursa erişmək üçün giriş etməlisiniz.",
"notification.admin.report": "{name} şikayət etdi: {target}",
"notification.admin.report_account": "{name}, {category} üçün şikayət etdi: {target} - {count, plural, one {bir göndəriş} other {# göndəriş}}",
"notification.admin.report_account_other": "{name} şikayət etdi: {target} - {count, plural, one {bir göndəriş} other {# göndəriş}}",
"notification.admin.report_statuses": "{name}, {category} üçün şikayət etdi: {target}",
"notification.admin.report_statuses_other": "{name} şikayət etdi: {target}",
"notification.admin.sign_up": "{name} qeydiyyatdan keçib",
"notification.admin.sign_up.name_and_others": "{name} və digər {count, plural, one {# nəfər} other {# nəfər}} qeydiyyatdan keçib",
"notification.annual_report.view": "#Wrapstodon-a bax",
"notification.favourite": "{name} göndərişinizi sevimlilərinə əlavə etdi",
"notification.favourite.name_and_others_with_link": "{name} və digər <a>{count, plural, one {# nəfər} other {# nəfər}}</a> göndərişinizi sevimlilərinə əlavə etdi",
"notification.favourite_pm": "{name}, şəxsi adçəkmənizi sevimlilərinə əlavə etdi",
"notification.favourite_pm.name_and_others_with_link": "{name} və digər <a>{count, plural, one {# nəfər} other {# nəfər}}</a> şəxsi adçəkmənizi sevimlilərinə əlavə etdi",
"notification.follow": "{name} sizi izləyir",
"notification.follow.name_and_others": "{name} və digər <a>{count, plural, one {# nəfər} other {# nəfər}}</a> sizi izləyir",
"notification.follow_request": "{name} sizi izləmək üçün istək göndərdi",
"notification.follow_request.name_and_others": "{name} və digər {count, plural, one {# nəfər} other {# nəfər}} sizi izləmək üçün istək göndərdi",
"notification.label.mention": "Adçəkmə",
"notification.label.private_mention": "Şəxsi adçəkmə",
"notification.label.private_reply": "Şəxsi cavab",
"notification.label.reply": "Cavab",
"notification.mention": "Adçəkmə",
"notification.mentioned_you": "{name} adınızı çəkdi",
"notification.moderation-warning.learn_more": "Daha ətraflı",
"notification.moderation_warning": "Bir moderasiya xəbərdarlığı aldınız",
"notification.moderation_warning.action_delete_statuses": "Bəzi göndərişləriniz silindi.",
"notification.moderation_warning.action_disable": "Hesabınız sıradan çıxarılıb.",
"notification.moderation_warning.action_mark_statuses_as_sensitive": "Bəzi göndərişləriniz həssas olaraq işarələnib.",
"notification.moderation_warning.action_none": "Hesabınız bir moderasiya xəbərdarlığı aldı.",
"notification.moderation_warning.action_sensitive": "Göndərişləriniz artıq həssas olaraq işarələnəcək.",
"notification.moderation_warning.action_silence": "Hesabınız məhdudlaşdırılıb.",
"notification.moderation_warning.action_suspend": "Hesabınızın fəaliyyəti dayandırılıb.",
"notification.own_poll": "Anketiniz bitdi",
"notification.poll": "Səs verdiyiniz anket bitdi",
"notification.reblog": "{name} göndərişinizi təkrar paylaşdı",
"notification.reblog.name_and_others_with_link": "{name} və <a>{count, plural, one {digər # nəfər} other {digər # nəfər}}</a> göndərişinizi təkrar paylaşdı",
"notification.relationships_severance_event": "{name} ilə bağlantı qopdu",
"notification.relationships_severance_event.account_suspension": "{from} admini {target} fəaliyyətini dayandırıb, bu da o deməkdir ki, artıq onlardan güncəlləmələr ala və ya onlarla qarşılıqlı əlaqə qura bilməyəcəyiniz.",
"notification.relationships_severance_event.domain_block": "{target}, {from} admini tərəfindən əngəllənib, buna {followersCount} izləyiciniz və izlədiyiniz {followingCount, plural, one {# hesab} other {# hesab}} daxildir.",
"notification.relationships_severance_event.learn_more": "Daha ətraflı",
"notification.relationships_severance_event.user_domain_block": "{target} əngəlləmisiniz, bununla {followersCount} izləyiciniz və izlədiyiniz {followingCount, plural, one {# hesab} other {# hesab}} silinib.",
"notification.status": "{name} indicə paylaşdı",
"notification.update": "{name} bir göndərişə düzəliş etdi",
"notification_requests.accept": "Qəbul et",
"notification_requests.accept_multiple": "{count, plural, one {# istəyi qəbul et…} other {# istəyi qəbul et…}}",
"notification_requests.confirm_accept_multiple.button": "{count, plural, one {İstəyi qəbul et} other {İstəkləri qəbul et}}",
"notification_requests.confirm_accept_multiple.message": "{count, plural, one {Bir bildiriş istəyini} other {# bildiriş istəklərini}} qəbul etmək üzrəsiniz. Davam etmək istədiyinizə əminsiniz?",
"notification_requests.confirm_accept_multiple.title": "Bildiriş istəkləri qəbul edilsin?",
"notification_requests.confirm_dismiss_multiple.button": "{count, plural, one {İstəyi rədd et} other {İstəkləri rədd et}}",
"notification_requests.confirm_dismiss_multiple.message": "{count, plural, one {bir bildiriş sorğusunu} other {# bildiriş sorğusunu}} bağlamaq üzrəsiniz. {count, plural, one {Ona} other {Onlara}} yenidən asanlıqla erişə bilməyəcəksiniz. Davam etmək istədiyinizə əminsiniz?",
"notification_requests.confirm_dismiss_multiple.title": "Bildiriş istəklərinə rədd cavabı verilsin?",
"notification_requests.dismiss": "Rədd et",
"notification_requests.dismiss_multiple": "{count, plural, one {# istəyi rədd et…} other {# istəyi rədd et…}}",
"notification_requests.edit_selection": "Düzəliş et",
"notification_requests.exit_selection": "Hazırdır",
"notification_requests.explainer_for_limited_account": "Hesab, bir moderator tərəfindən məhdudlaşdırıldığı üçün bu hesabın bildirişləri filtrləndi.",
"notification_requests.explainer_for_limited_remote_account": "Hesab və ya onun serveri, bir moderator tərəfindən məhdudlaşdırıldığı üçün bu hesabın bildirişləri filtrləndi.",
"notification_requests.maximize": "Böyüt",
"notification_requests.minimize_banner": "Filtrlənmiş bildirişlər bannerini kiçilt",
"notification_requests.notifications_from": "{name} - bildirişləri",
"notification_requests.title": "Filtrlənmiş bildirişlər",
"notification_requests.view": "Bildirişlərə bax",
"notifications.clear": "Bildirişləri təmizlə",
"notifications.clear_confirmation": "Bütün bildirişlərinizi həmişəlik təmizləmək istədiyinizə əminsiniz?",
"notifications.clear_title": "Bildirişlər təmizlənsin?",
"notifications.column_settings.admin.report": "Yeni hesabatlar:",
"notifications.column_settings.admin.sign_up": "Yeni qeydiyyatlar:",
"notifications.column_settings.alert": "Masaüstü bildirişlər",
"notifications.column_settings.favourite": "Sevimlilər:",
"notifications.column_settings.filter_bar.advanced": "Bütün kateqoriyaları nümayiş etdir",
"notifications.column_settings.filter_bar.category": "Cəld filtr çubuğu",
"notifications.column_settings.follow": "Yeni izləyicilər:",
"notifications.column_settings.follow_request": "Yeni izləmə istəkləri:",
"notifications.column_settings.group": "Qrup",
"notifications.column_settings.mention": "Adçəkmələr:",
"notifications.column_settings.poll": "Anket nəticələri:",
"notifications.column_settings.push": "Ani bildirişlər",
"notifications.column_settings.reblog": "Təkrar paylaşmalar:",
"notifications.column_settings.show": "Sütunda göstər",
"notifications.column_settings.sound": "Səs oxut",
"notifications.column_settings.status": "Yeni göndərişlər:",
"notifications.column_settings.unread_notifications.category": "Oxunmamış bildirişlər",
"notifications.column_settings.unread_notifications.highlight": "Oxunmamış bildirişləri vurğula",
"notifications.column_settings.update": "Düzəlişlər:",
"notifications.filter.all": "Hamısı",
"notifications.filter.boosts": "Təkrar paylaşmalar",
"notifications.filter.favourites": "Sevimlilər",
"notifications.filter.follows": "İzlənilənlər",
"notifications.filter.mentions": "Adçəkmələr",
"notifications.filter.polls": "Anket nəticələri",
"notifications.filter.statuses": "İzlədiyiniz şəxslərdən güncəlləmələr",
"notifications.grant_permission": "İcazəni ver.",
"notifications.group": "{count} bildiriş",
"notifications.mark_as_read": "Hər bir bildiriş oxunmuş olaraq işarələ",
"notifications.permission_denied": "Brauzer icazələri istəyinə daha əvvəl rədd cavabı verildiyi üçün masaüstü bildirişləri əlçatmazdır",
"notifications.permission_denied_alert": "Brauzer icazəsinə daha əvvəl rədd cavabı verildiyi üçün masaüstü bildirişləri fəallaşdırıla bilmir",
"notifications.permission_required": "Tələb olunan icazə verilmədiyi üçün masaüstü bildirişləri əlçatmazdır.",
"notifications.policy.accept": "Qəbul et",
"notifications.policy.accept_hint": "Bildirişlərdə göstər",
"notifications.policy.drop": "Yox say",
"notifications.policy.filter": "Filtr",
"notifications.policy.filter_hint": "Filtrlənmiş bildirişlər gələn qutusuna göndər",
"notifications.policy.filter_limited_accounts_hint": "Server moderatorları tərəfindən məhdudlaşdırılıb",
"notifications.policy.filter_limited_accounts_title": "Moderasiya edilmiş hesablar",
"notifications.policy.filter_new_accounts.hint": "Son {days, plural, one {bir gündə} other {# gündə}} yaradıldı",
"notifications.policy.filter_new_accounts_title": "Yeni hesablar",
"notifications.policy.filter_not_followers_hint": "Sizi {days, plural, one {bir gündən} other {# gündən}} az müddətdir izləyən insanlar daxildir",
"notifications.policy.filter_not_followers_title": "Sizi izləməyən insanlar",
"notifications.policy.filter_not_following_hint": "Onları manual qəbul edənə qədər",
"notifications.policy.filter_not_following_title": "İzləmədiyiniz insanlar",
"notifications.policy.title": "Bildirişləri idarə et…",
"notifications_permission_banner.enable": "Masaüstü bildirişləri fəallaşdır",
"notifications_permission_banner.title": "Heç nəyi buraxmayın",
"onboarding.follows.back": "Geri",
"onboarding.follows.done": "Hazırdır",
"onboarding.follows.search": "Axtar",
"onboarding.follows.title": "Başlamaq üçün insanları izləyin",
"onboarding.profile.discoverable": "Profilimi kəşf edilə bilən et",
"onboarding.profile.discoverable_hint": "Mastodon-da kəşf edilə bilməni aktivləşdirsəniz, göndərişləriniz axtarış nəticələrində və trendlərdə görünə bilər və profiliniz sizinlə oxşar maraqlara sahib şəxslərə təklif edilə bilər.",
"onboarding.profile.display_name": "Ekran adı",
"onboarding.profile.display_name_hint": "Tam adınız və ya ləqəbiniz…",
"onboarding.profile.note": "Bioqrafiya",
"onboarding.profile.note_hint": "Digər insanların @adını_çəkə və ya #mövzu_etiketləri istifadə edə bilərsiniz…",
"onboarding.profile.save_and_continue": "Saxla və davam et",
"onboarding.profile.title": "Profili ayarla",
"onboarding.profile.upload_avatar": "Profil şəkli yüklə",
"onboarding.profile.upload_header": "Profil başlığı yüklə",
"password_confirmation.exceeds_maxlength": "Parol təsdiqi, maksimum parol uzunluğunu aşır",
"password_confirmation.mismatching": "Parol təsdiqi uyuşmur",
"picture_in_picture.restore": "Geri qoy",
"poll.closed": "Bağlandı",
"poll.refresh": "Təzələ",
"poll.reveal": "Nəticələrə bax",
"poll.total_people": "{count, plural, one {# nəfər} other {# nəfər}}",
"poll.total_votes": "{count, plural, one {# səs} other {# səs}}",
"poll.vote": "Səs ver",
"poll.voted": "Bu cavaba səs verdiniz",
"poll.votes": "{votes, plural, one {# səs} other {# səs}}",
"poll_button.add_poll": "Bir anket əlavə et",
"poll_button.remove_poll": "Anketi sil",
"privacy.change": "Göndəriş gizliliyini dəyişdir",
"privacy.direct.long": "Göndərişdə adı çəkilən hər kəs",
"privacy.direct.short": "Şəxsi adçəkmə",
"privacy.private.long": "Yalnız izləyiciləriniz",
"privacy.private.short": "İzləyicilər",
"privacy.public.long": "Mastodon-da olan və olmayan hər kəs",
"privacy.public.short": "Hər kəsə açıq",
"privacy.unlisted.short": "Səssiz hər kəsə açıq",
"privacy_policy.last_updated": "Son güncəlləmə {date}",
"privacy_policy.title": "Gizlilik Siyasəti",
"recommended": "Tövsiyə edilən",
"refresh": "Təzələ",
"regeneration_indicator.please_stand_by": "Lütfən gözləyin.",
"regeneration_indicator.preparing_your_home_feed": "Əsas ekran lentiniz hazırlanır…",
"relative_time.days": "{number} gü",
"relative_time.full.days": "{number, plural, one {# gün} other {# gün}} əvvəl",
"relative_time.full.hours": "{number, plural, one {# saat} other {# saat}} əvvəl",
"relative_time.full.just_now": "indicə",
"relative_time.full.minutes": "{number, plural, one {# dəqiqə} other {# dəqiqə}} əvvəl",
"relative_time.full.seconds": "{number, plural, one {# saniyə} other {# saniyə}} əvvəl",
"relative_time.hours": "{number} sa",
"relative_time.just_now": "indi",
"relative_time.minutes": "{number} dəq",
"relative_time.seconds": "{number} san",
"relative_time.today": "bu gün",
"reply_indicator.attachments": "{count, plural, one {# qoşma} other {# qoşma}}",
"reply_indicator.cancel": "İmtina",
"reply_indicator.poll": "Anket",
"report.block": "Əngəllə",
"report.block_explanation": "Onun göndərişlərini görməyəcəksiniz. O, göndərişlərinizi görə və ya sizi izləyə bilməz. Əngəllədiyinizi anlaya biləcək.",
"report.categories.legal": "Hüquqi",
"report.categories.other": "Digər",
"report.categories.spam": "Spam",
"report.categories.violation": "Məzmun, bir və ya daha çox server qaydasını pozur",
"report.category.subtitle": "Ən çox uyuşanı seçin",
"report.category.title": "Bu {type} ilə bağlı nələrin baş verdiyini bizə deyin",
"report.category.title_account": "profil",
"report.category.title_status": "göndəriş",
"report.close": "Hazırdır",
"report.comment.title": "Bilməyimizi istədiyiniz başqa nəsə var?",
"report.forward": "Bura yönləndir: {target}",
"report.forward_hint": "Hesab, başqa bir serverdəndir. Hesabatın anonim bir kopyası ora da göndərilsin?",
"report.mute": "Səssizə al",
"report.mute_explanation": "Onun göndərişlərini görməyəcəksiniz. O, sizi izləməyə və göndərişlərinizi görməyə davam edə bilər, ancaq səssizə alındığını bilməyəcək.",
"report.next": "Növbəti",
"report.placeholder": "Əlavə rəylər",
"report.reasons.dislike": "Bunu bəyənmədim",
"report.reasons.dislike_description": "Bu, görmək istədiyiniz bir şey deyil",
"report.reasons.legal": "Qanunsuzdur",
"report.reasons.legal_description": "Sizin və ya serverinizin olduğu ölkənin qanunlarını pozduğuna inanırsınız",
"report.reasons.other": "Başqa bir şeydir",
"report.reasons.other_description": "Problem, digər kateqoriyalara uyğun gəlmir",
"report.reasons.spam": "Spamdır",
"report.reasons.spam_description": "Zərərli keçidlər, saxta qarşılıqlı əlaqə və ya təkrarlanan cavablar",
"report.reasons.violation": "Server qaydalarını pozur",
"report.reasons.violation_description": "Müəyyən qaydaları pozduğundan xəbərdarsınız",
"report.rules.subtitle": "Uyğun olanların hamısını seçin",
"report.rules.title": "Hansı qaydalar pozulub?",
"report.statuses.subtitle": "Uyğun olanların hamısını seçin",
"report.statuses.title": "Bu şikayəti dəstəkləyən hər hansısa bir göndəriş var?",
"report.submit": "Təqdim et",
"report.target": "{target} şikayət edilir",
"report.thanks.take_action": "Mastodon-da nə görə biləcəyinizi idarə etmək üçün seçimləriniz bunlardır:",
"report.thanks.take_action_actionable": "Biz bunu incələdiyimiz müddətdə, siz @{name} ilə bağlı bunları edə bilərsiniz:",
"report.thanks.title": "Bunu görmək istəmirsiniz?",
"report.thanks.title_actionable": "Şikayət etdiyiniz üçün təşəkkürlər, məsələyə baxacağıq.",
"report.unfollow": "@{name} - izləmədən çıxart",
"report.unfollow_explanation": "Bu hesabı izləyirsiniz. Əsas ekran lentinizdə onun göndərişlərini artıq görmək istəmirsinizsə, onu izləmədən çıxarın.",
"report_notification.attached_statuses": "{count, plural, one {{count} göndəriş} other {{count} göndəriş}} əlavə edildi",
"report_notification.categories.legal": "Hüquqi",
"report_notification.categories.legal_sentence": "qanunsuz məzmun",
"report_notification.categories.other": "Digər",
"report_notification.categories.other_sentence": "digər",
"report_notification.categories.spam": "Spam",
"report_notification.categories.spam_sentence": "spam",
"report_notification.categories.violation": "Qayda pozuntusu",
"report_notification.categories.violation_sentence": "qayda pozuntusu",
"report_notification.open": "Hesabatı aç",
"search.clear": "Axtarışı təmizlə",
"search.no_recent_searches": "Son axtarışlar yoxdur",
"search.placeholder": "Axtar",
"search.quick_action.account_search": "Uyuşan profillər {x}",
"search.quick_action.go_to_account": "{x} profilinə get",
"search.quick_action.go_to_hashtag": "{x} mövzu etiketinə get",
"search.quick_action.open_url": "URL-ni Mastodon-da aç",
"search.quick_action.status_search": "Uyuşan göndərişlər {x}",
"search.search_or_paste": "Axtar və ya URL-ni yapışdır",
"search_popout.full_text_search_disabled_message": "{domain} domenində mövcud deyil.",
"search_popout.full_text_search_logged_out_message": "Yalnız giriş edildiyi zaman əlçatandır.",
"search_popout.language_code": "ISO dil kodu",
"search_popout.options": "Axtarış seçimləri",
"search_popout.quick_actions": "Cəld əməliyyatlar",
"search_popout.recent": "Son axtarışlar",
"search_popout.specific_date": "müəyyən tarix",
"search_popout.user": "istifadəçi",
"search_results.accounts": "Profillər",
"search_results.all": "Hamısı",
"search_results.hashtags": "Mövzu etiketləri",
"search_results.no_results": "Nəticə yoxdur.",
"search_results.no_search_yet": "Göndərişləri, profilləri və ya mövzu etiketlərini axtarmağa çalışın.",
"search_results.see_all": "Hamısına bax",
"search_results.statuses": "Göndərişlər",
"search_results.title": "\"{q}\" axtar",
"server_banner.about_active_users": "Son 30 gündə bu serveri istifadə edənlər (aylıq aktiv istifadəçilər)",
"server_banner.active_users": "aktiv istifadəçilər",
"server_banner.administered_by": "Administrasiya:",
"server_banner.is_one_of_many": "{domain}, fediverse-də iştirak etmək üçün istifadə edə biləcəyiniz bir neçə müstəqil Mastodon serverlərindən biridir.",
"server_banner.server_stats": "Server statistikaları:",
"sign_in_banner.create_account": "Hesab yarat",
"sign_in_banner.follow_anyone": "fediverse-dəki hər kəsi izləyin və hamısına xronoloji ardıcıllıqla baxın. Heç bir alqoritm, reklam və ya klikləmə tələsi yoxdur.",
"sign_in_banner.mastodon_is": "Mastodon, baş verənlərdən xəbərdar olmağın ən yaxşı yoldur.",
"sign_in_banner.sign_in": "Giriş",
"sign_in_banner.sso_redirect": "Giriş və ya Qeydiyyat",
"status.admin_account": "@{name} üçün moderasiya interfeysini aç",
"status.admin_domain": "{domain} üçün moderasiya interfeysini aç",
"status.admin_status": "Moderasiya interfeysində bu göndərişi aç",
"status.block": "Əngəllə: @{name}",
"status.bookmark": "Əlfəcin",
"status.cancel_reblog_private": "Təkrar paylaşımı geri al",
"status.cannot_reblog": "Bu göndəriş təkrar paylaşıla bilməz",
"status.continued_thread": "Davam edən mövzu",
"status.copy": "Göndəriş keçidini kopyala",
"status.delete": "Sil",
"status.detailed_status": "Detallı danışıq görünüşü",
"status.direct": "Şəxsi olaraq adını çək: @{name}",
"status.direct_indicator": "Şəxsi olaraq adını çək",
"status.edit": "Düzəliş et",
"status.edited": "Son düzəliş {date}",
"status.edited_x_times": "{count, plural, one {{count} dəfə} other {{count} dəfə}} düzəliş edilib",
"status.favourite": "Sevimli",
"status.favourites": "{count, plural, one {sevimli} other {sevimli}}",
"status.filter": "Bu göndərişi filtrlə",
"status.history.created": "{name}, {date} yaratdı",
"status.history.edited": "{name}, {date} düzəliş etdi",
"status.load_more": "Daha çoxunu yüklə",
"status.media.open": "Açmaq üçün kliklə",
"status.media.show": "Göstərmək üçün kliklə",
"status.media_hidden": "Media gizlidir",
"status.mention": "Adını çək: @{name}",
"status.more": "Daha çox",
"status.mute": "@{name} - səssizə al",
"status.mute_conversation": "Danışığın səsini kəs",
"status.open": "Bu göndərişi genişləndir",
"status.pin": "Profildə sanc",
"status.quote_error.filtered": "Bəzi filtrlərinizə görə gizlidir",
"status.quote_error.not_found": "Bu göndəriş nümayiş edilə bilməz.",
"status.quote_error.pending_approval": "Bu göndəriş, orijinal müəllifin təsdiqini gözləyir.",
"status.quote_error.rejected": "Orijinal müəllif, bundan sitat gətirməyə icazə vermədiyi üçün bu göndəriş nümayiş etdirilə bilməz.",
"status.quote_error.removed": "Bu göndəriş, müəllifi tərəfindən silinib.",
"status.quote_error.unauthorized": "Baxmağa səlahiyyətiniz olmadığı üçün bu göndəriş nümayiş etdirilə bilməz.",
"status.quote_post_author": "{name} - göndərişi",
"status.read_more": "Daha çoxunu oxu",
"status.reblog": "Təkrar paylaş",
"status.reblog_private": "Orijinal görünmə ilə təkrar paylaş",
"status.reblogged_by": "{name} təkrar paylaşdı",
"status.reblogs": "{count, plural, one {təkrar paylaşma} other {təkrar paylaşma}}",
"status.reblogs.empty": "Hələ heç kim bu göndərişi təkrar paylaşmayıb. Kimsə paylaşdığı zaman, burada görünəcək.",
"status.remove_bookmark": "Əlfəcini sil",
"status.remove_favourite": "Sevimlilərdən sil",
"status.replied_in_thread": "Mövzuda cavablandırıldı",
"status.replied_to": "Cavab verildi: {name}",
"status.reply": "Cavabla",
"status.replyAll": "Mövzuda cavab ver",
"status.report": "Bildir: @{name}",
"status.sensitive_warning": "Həssas məzmun",
"status.share": "Paylaş",
"status.show_less_all": "Hamısı üçün daha az göstər",
"status.show_more_all": "Hamısı üçün daha çox göstər",
"status.show_original": "Orijinalı göstər",
"status.title.with_attachments": "{user} {attachmentCount, plural, one {bir qoşma} other {{attachmentCount} qoşma}} paylaşdı",
"status.translate": "Tərcümə et",
"status.translated_from_with": "{provider} ilə {lang} dilindən tərcümə edilib",
"status.uncached_media_warning": "Önizləmə mövcud deyil",
"status.unmute_conversation": "Danışığın səsini aç",
"status.unpin": "Profil sancağı götür",
"subscribed_languages.lead": "Dəyişiklikdən sonra əsas ekran və siyahı zaman xəttinizdə yalnız seçdiyiniz dillərdəki göndərişlər görünəcək. Bütün dillərdə göndəriş almaq üçün heç birini seçməyin.",
"subscribed_languages.save": "Dəyişiklikləri saxla",
"subscribed_languages.target": "{target} üçün abunə olunmuş dilləri dəyişdir",
"tabs_bar.home": "Ana səhifə",
"tabs_bar.menu": "Menyu",
"tabs_bar.notifications": "Bildirişlər",
"tabs_bar.publish": "Yeni göndəriş",
"tabs_bar.search": "Axtar",
"terms_of_service.effective_as_of": "{date} etibarilə qüvvədə",
"terms_of_service.title": "Xidmət Şərtləri",
"terms_of_service.upcoming_changes_on": "{date} tarixində ediləcək dəyişikliklər",
"time_remaining.days": "{number, plural, one {# gün} other {# gün}} qalıb",
"time_remaining.hours": "{number, plural, one {# saat} other {# saat}} qalıb",
"time_remaining.minutes": "{number, plural, one {# dəqiqə} other {# dəqiqə}} qalıb",
"time_remaining.moments": "Bir neçə dəqiqə qalıb",
"time_remaining.seconds": "{number, plural, one {# saniyə} other {# saniyə}} qalıb",
"trends.counter_by_accounts": "Son {days, plural, one {bir gündə} other {{days} gündə}} {count, plural, one {{counter} nəfər} other {{counter} nəfər}}",
"trends.trending_now": "İndi trenddədir",
"ui.beforeunload": "Mastodon-u tərk etsəniz, qaralamanız itəcək.",
"units.short.billion": "{count} mlyrd",
"units.short.million": "{count} mlyn",
"units.short.thousand": "{count} min",
"upload_area.title": "Yükləmək üçün sürüklə və burax",
"upload_button.label": "Təsvir, video və ya səs faylı əlavə et",
"upload_error.limit": "Fayl yükləmə limiti aşılıb.",
"upload_error.poll": "Anketlərdə fayl yükləməyə icazə verilmir.",
"upload_form.drag_and_drop.instructions": "Bir media qoşmasını daşımaq üçün boşluq və ya enter düyməsinə basın. Sürükləmə zamanı, media qoşmasını hər hansısa bir yönə hərəkət etdirmək üçün ox düymələrini istifadə edin. Media qoşmasını yeni mövqeyinə buraxmaq üçün təkrar boşluq və ya enter düyməsinə basın, ləğv etmək üçün escape düyməsinə basın.",
"upload_form.drag_and_drop.on_drag_cancel": "Sürükləmə ləğv edilib. {item} media qoşması buraxıldı.",
"upload_form.drag_and_drop.on_drag_end": "{item} media qoşması buraxıldı.",
"upload_form.drag_and_drop.on_drag_over": "{item} media qoşması daşındı.",
"upload_form.drag_and_drop.on_drag_start": "{item} media qoşması alındı.",
"upload_form.edit": "Düzəliş et",
"upload_progress.label": "Yüklənir...",
"upload_progress.processing": "Emal edilir…",
"username.taken": "Bu istifadəçi adı götürülüb. Başqasını sınayın",
"video.close": "Videonu bağla",
"video.download": "Faylı endir",
"video.exit_fullscreen": "Tam ekrandan çıx",
"video.expand": "Videonu genişləndir",
"video.fullscreen": "Tam ekran",
"video.hide": "Videonu gizlət",
"video.mute": "Səsi kəs",
"video.pause": "Fasilə ver",
"video.play": "Oxut",
"video.skip_backward": "Geri ötür",
"video.skip_forward": "İrəli ötür",
"video.unmute": "Səsi aç",
"video.volume_down": "Həcmi azalt",
"video.volume_up": "Həcmi artır"
}

Some files were not shown because too many files have changed in this diff Show More