Compare commits

...

76 Commits

Author SHA1 Message Date
Eugen Rochko
9924ca8810 Fix UniqueUsernameValidator comparison
Comparison was downcasing only one side, therefore if previously
existing account had a non-lowercase spelling, it would be ignored
when checking for duplicates.

New rake task `mastodon:maintenance:find_duplicate_usernames` will
help find constraint violations that might have occured from the
presence of this bug.

Bump version to 2.3.3
2018-03-27 02:14:05 +02:00
Eugen Rochko
6cc432bbc4 Bump version to 2.3.2 2018-03-22 14:13:46 +01:00
Eugen Rochko
dafae9818d Bump version to 2.3.2rc5 2018-03-22 11:31:52 +01:00
Eugen Rochko
9fe1619db9 Do not re-query mentions from serializers (#6858)
Fix performance regression from #6836
2018-03-22 11:31:17 +01:00
Eugen Rochko
da70aca28e Restore username validation to disallow dots, for now (#6863)
Usernames with dots in them do not work with routes, because the dot usually separates the desired page format (e.g. json). I don't want to mess with changing route constraints for this patch release.
2018-03-22 11:30:22 +01:00
ThibG
6f531d140b Fix MENTION_RE to not match nil usernames (#6862) 2018-03-22 10:45:48 +01:00
Eugen Rochko
f66a786029 Hide floating action button on thread views (#6859) 2018-03-22 09:33:14 +01:00
Patrick Figel
d97903a358 Update sanitize and loofah (#6855)
Fixes CVE-2018-8048 and CVE-2018-3740, two medium-severity XSS
vulnerabilities present in these gems when built against
libxml2 >= 2.9.2.
2018-03-21 17:43:28 +01:00
Eugen Rochko
93897134ca Permit dots in usernames with conditions (#6844)
* Permit dots in usernames with conditions

- Dot cannot be the start or end of username
- a.lice and al.ice are considered the same during sign-up

* Fix regex mixin flags
2018-03-21 10:26:53 +01:00
Akihiko Odaki
a6b59cd1a3 Remove debug option from Babel preset env (#6852) 2018-03-21 10:26:15 +01:00
Eugen Rochko
f64af6473f Bump version to 2.3.2rc4 2018-03-20 23:49:24 +01:00
Eugen Rochko
ac49c7932d Add LDAP_TLS_NO_VERIFY option, don't require LDAP_ENABLED outside .env (#6845)
Fix #6816, fix #6790
2018-03-20 19:41:51 +01:00
Akihiko Odaki
61dcb686a8 Fix i18n fallback configuration conflicts with environment configurations (#6843) 2018-03-20 16:36:20 +01:00
Eugen Rochko
9381a7d9d5 Use username/domain to match existing accounts in ActivityPub (#6842)
See also: #6837, #6667
2018-03-20 14:57:46 +01:00
ThibG
a5c6c748e0 Cancel outdated pending compose suggestions (#6838) 2018-03-20 12:40:12 +01:00
Rey Tucker
36b5703796 request: in the event of failure, try other IPs (#6761) (#6813)
* request: in the event of failure, try other IPs (#6761)

In the case where a name has multiple A/AAAA records, we should
try subsequent records instead of immediately failing when we have a
failure on the first IP address.

This significantly improves delivery success when there are network
connectivity problems affecting only IPv4 or IPv6.

* fix method call style

* request_spec: adjust test case to use Addrinfo

* request: Request/open: move private addr check to within begin/rescue

* request_spec: add case to test failover, fix exception check

* Double Addrinfo.foreach so that it correctly yields instances
2018-03-20 09:06:08 +01:00
ThibG
ff6b8a6443 Serialize mentions in the order they are added (#6836)
Up until now, the order seemed to be in the *opposite* order,
which caused the WebUI to populate mentions in reversed order
when replying to toots local to one's instance.
2018-03-19 20:19:35 +01:00
ThibG
6b76a6212d Display content warning in mail notification emails (#6832) 2018-03-19 20:12:20 +01:00
Alexander
33ee347c99 rename pam email environment variable to something more understandable and default to LOCAL_DOMAIN (better fallback) (#6833) 2018-03-19 20:09:26 +01:00
Alexander
0306e3e9be bugfixes and gem update (#6831)
* update to new version of devise_pam_authenticatable2

* fix behaviour if suffix is nil, fix environment loading, fix user email creation

* code cleanup/fix linter warning
2018-03-19 20:08:56 +01:00
ThibG
357f9298bd Fix e-mail changed notification (fixes #6778) (#6835)
In Devise::Mailer#email_changed, the new email might be in the email attr.
See: https://github.com/plataformatec/devise/blob/master/app/views/devise/mailer/email_changed.html.erb
2018-03-19 20:07:47 +01:00
Renato "Lond" Cerqueira
f7c46fc113 Weblate translations 20180319 (#6827)
* Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (280 of 280 strings)

Translation: Mastodon/React
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/pt_BR/

* Translated using Weblate (Spanish)

Currently translated at 99.6% (579 of 581 strings)

Translation: Mastodon/Backend
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/es/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (58 of 58 strings)

Translation: Mastodon/Preferences
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/simple_form/es/

* Translated using Weblate (Japanese)

Currently translated at 100.0% (280 of 280 strings)

Translation: Mastodon/React
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/ja/

* Translated using Weblate (French)

Currently translated at 100.0% (280 of 280 strings)

Translation: Mastodon/React
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/fr/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (58 of 58 strings)

Translation: Mastodon/Preferences
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/simple_form/es/

* Translated using Weblate (Indonesian)

Currently translated at 100.0% (280 of 280 strings)

Translation: Mastodon/React
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/id/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (280 of 280 strings)

Translation: Mastodon/React
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/es/

* Translated using Weblate (Indonesian)

Currently translated at 94.6% (71 of 75 strings)

Translation: Mastodon/Doorkeeper
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/doorkeeper/id/

* Translated using Weblate (Indonesian)

Currently translated at 100.0% (280 of 280 strings)

Translation: Mastodon/React
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/id/

* Translated using Weblate (Arabic)

Currently translated at 100.0% (62 of 62 strings)

Translation: Mastodon/Devise
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/devise/ar/

* Translated using Weblate (Indonesian)

Currently translated at 100.0% (280 of 280 strings)

Translation: Mastodon/React
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/id/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (280 of 280 strings)

Translation: Mastodon/React
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/nl/

* Translated using Weblate (Arabic)

Currently translated at 75.5% (439 of 581 strings)

Translation: Mastodon/Backend
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/ar/

* Translated using Weblate (Arabic)

Currently translated at 76.2% (443 of 581 strings)

Translation: Mastodon/Backend
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/ar/

* Translated using Weblate (Russian)

Currently translated at 95.8% (557 of 581 strings)

Translation: Mastodon/Backend
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/ru/

* Translated using Weblate (Finnish)

Currently translated at 100.0% (280 of 280 strings)

Translation: Mastodon/React
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/fi/

* Translated using Weblate (Slovak)

Currently translated at 100.0% (280 of 280 strings)

Translation: Mastodon/React
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/sk/

* Translated using Weblate (Slovak)

Currently translated at 91.7% (533 of 581 strings)

Translation: Mastodon/Backend
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/sk/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (280 of 280 strings)

Translation: Mastodon/React
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/nl/

* Translated using Weblate (Spanish)

Currently translated at 99.8% (580 of 581 strings)

Translation: Mastodon/Backend
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/es/

* Translated using Weblate (Finnish)

Currently translated at 100.0% (280 of 280 strings)

Translation: Mastodon/React
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/fi/

* Translated using Weblate (Slovak)

Currently translated at 100.0% (280 of 280 strings)

Translation: Mastodon/React
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/sk/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (280 of 280 strings)

Translation: Mastodon/React
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/es/

* Translated using Weblate (Swedish)

Currently translated at 100.0% (280 of 280 strings)

Translation: Mastodon/React
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/sv/

* Translated using Weblate (Finnish)

Currently translated at 93.1% (54 of 58 strings)

Translation: Mastodon/Preferences
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/simple_form/fi/

* Translated using Weblate (Arabic)

Currently translated at 76.7% (446 of 581 strings)

Translation: Mastodon/Backend
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/ar/

* Translated using Weblate (Slovak)

Currently translated at 93.2% (542 of 581 strings)

Translation: Mastodon/Backend
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/sk/

* Translated using Weblate (Arabic)

Currently translated at 100.0% (280 of 280 strings)

Translation: Mastodon/React
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/ar/

* Normalize translations
Ran i18n-tasks normalize && yarn manage:translations
2018-03-19 15:12:06 +01:00
Eugen Rochko
74c39fada0 Bump version to 2.3.2rc3 2018-03-19 12:20:57 +01:00
Eugen Rochko
f02411da40 Ignore media validation when attaching to status during processing (#6822)
Fix #6821
2018-03-19 01:51:19 +01:00
Eugen Rochko
a568e3ca8e Revert #6479, hide sensitive text/images from OpenGraph previews (#6818)
Display summary of attachments in description, and mark up content
warning if present, e.g.:

    Attached: 3 images · Content warning: Dota 2

When text is not supposed to be hidden, it looks more like:

    Attached: 3 images

    Here is the text of the toot

With #6817, multilinguagility should be assured...
2018-03-18 20:33:07 +01:00
Eugen Rochko
3b440bd5af Fix elephant graphic being draggable and selectable (#6819) 2018-03-18 20:32:44 +01:00
Eugen Rochko
39f27b6cf3 If DEFAULT_LOCALE is set, enforce it instead of HTTP request locale (#6817)
Fix #6784
2018-03-18 16:57:04 +01:00
Akihiko Odaki
721234230c Synchronize HTML page cache with sessions (#6815) 2018-03-18 15:14:38 +01:00
nightpool
566ace2d64 Add entropy to download filenames (#6811)
pretty quick fix, and with the 1 week expiration i don't think we need to be too worried about the existing files

closes #6798
2018-03-17 17:39:28 +01:00
Eugen Rochko
092f1df9d0 Bump version to 2.3.2rc2 2018-03-17 15:28:52 +01:00
Eugen Rochko
844616e950 Re-add git and nodejs-npm to Dockerfile (#6810)
Fix #6809

I don't know why, either
2018-03-17 15:28:09 +01:00
Eugen Rochko
40871caa4b Revert "Upgrade Paperclip to version 6.0.0" (#6807)
* Revert "Bump version to 2.3.2rc1"

This reverts commit cdf8b92fea.

* Revert "Downgrade Dockerfile to Ruby 2.4.3 on Alpine 3.6 (#6806)"

This reverts commit 0074cad44f.

* Revert "Handle Mastodon::HostValidationError when pulling remoteable assets (#6782)"

This reverts commit 4a0a19fe54.

* Revert "Correct the reference to user's password in mastodon:add_user task (#6800)"

This reverts commit 338bff8b93.

* Revert "Upgrade Paperclip to version 6.0.0 (#6754)"

This reverts commit b88fcd53f7.
2018-03-17 14:20:35 +01:00
Eugen Rochko
cdf8b92fea Bump version to 2.3.2rc1 2018-03-17 14:07:00 +01:00
Eugen Rochko
0074cad44f Downgrade Dockerfile to Ruby 2.4.3 on Alpine 3.6 (#6806)
Fix 6734
2018-03-17 14:06:25 +01:00
Daniel Hunsaker
4a0a19fe54 Handle Mastodon::HostValidationError when pulling remoteable assets (#6782)
This will prevent, for example, `rake mastodon:redownload_avatars` from crashing when an instance is no longer responding to connection attempts, instead silently continuing as expected.
2018-03-17 13:27:50 +01:00
Akihiko Odaki
338bff8b93 Correct the reference to user's password in mastodon:add_user task (#6800) 2018-03-17 13:27:19 +01:00
Yamagishi Kazutoshi
b88fcd53f7 Upgrade Paperclip to version 6.0.0 (#6754) 2018-03-17 12:37:58 +01:00
trwnh
ca7e6a6d2e Properly center .nothing-here (#6787) (#6788)
Apply "margin: 0 auto;" at line 443 to fix issue #6787
2018-03-17 12:35:35 +01:00
Akihiko Odaki
f0cd957c7a Cache HTML page with Service Worker (#6802)
This is the first step to make Mastodon work offline. It is also required
by Chromium to trigger Web Manifest automated install prompt.
2018-03-17 12:35:13 +01:00
Daniel Hunsaker
64fc8d2b07 [Nanobox] Stream backups to the warehouse (#6799)
The `curl` docs are terrible. Use `-X POST -T` instead of `--data-binary`, to avoid loading entire backups into memory _before_ transferring to the warehouse, and just stream the data across as it comes in.
2018-03-17 08:39:14 +01:00
Marcin Mikołajczak
fd385e256d i18n: Update Polish translation (#6780)
Signed-off-by: Marcin Mikołajczak <me@m4sk.in>
2018-03-14 02:17:48 +09:00
Renato "Lond" Cerqueira
03119c857b Weblate translations (2018-03-13) (#6777)
* Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (280 of 280 strings)

Translation: Mastodon/React
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/pt_BR/

* Translated using Weblate (Spanish)

Currently translated at 99.6% (579 of 581 strings)

Translation: Mastodon/Backend
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/es/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (58 of 58 strings)

Translation: Mastodon/Preferences
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/simple_form/es/

* Translated using Weblate (Japanese)

Currently translated at 100.0% (280 of 280 strings)

Translation: Mastodon/React
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/ja/

* Translated using Weblate (French)

Currently translated at 100.0% (280 of 280 strings)

Translation: Mastodon/React
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/fr/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (58 of 58 strings)

Translation: Mastodon/Preferences
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/simple_form/es/

* Translated using Weblate (Indonesian)

Currently translated at 100.0% (280 of 280 strings)

Translation: Mastodon/React
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/id/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (280 of 280 strings)

Translation: Mastodon/React
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/es/

* Translated using Weblate (Indonesian)

Currently translated at 94.6% (71 of 75 strings)

Translation: Mastodon/Doorkeeper
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/doorkeeper/id/

* Translated using Weblate (Indonesian)

Currently translated at 100.0% (280 of 280 strings)

Translation: Mastodon/React
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/id/

* Translated using Weblate (Arabic)

Currently translated at 100.0% (62 of 62 strings)

Translation: Mastodon/Devise
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/devise/ar/

* Translated using Weblate (Indonesian)

Currently translated at 100.0% (280 of 280 strings)

Translation: Mastodon/React
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/id/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (280 of 280 strings)

Translation: Mastodon/React
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/nl/

* Translated using Weblate (Arabic)

Currently translated at 75.5% (439 of 581 strings)

Translation: Mastodon/Backend
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/ar/

* Translated using Weblate (Arabic)

Currently translated at 76.2% (443 of 581 strings)

Translation: Mastodon/Backend
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/ar/

* Translated using Weblate (Russian)

Currently translated at 95.8% (557 of 581 strings)

Translation: Mastodon/Backend
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/ru/

* Normalize translations
Ran i18n-tasks normalize && yarn manage:translations
2018-03-13 16:16:51 +01:00
Eugen Rochko
2ef1ce1182 Bump version to 2.3.1 2018-03-13 15:50:15 +01:00
Eugen Rochko
eb2425b53b Hide loading bar on status interactions (#6774) 2018-03-13 14:30:01 +01:00
Eugen Rochko
79d3a8553f Bump version to 2.3.1rc3 2018-03-13 09:21:21 +01:00
Eugen Rochko
7709556673 Merge branch 'kagucho-spoiler' 2018-03-13 09:18:27 +01:00
Eugen Rochko
f0ae6b4cc5 Merge branch 'spoiler' of git://github.com/kagucho/mastodon into kagucho-spoiler 2018-03-13 09:18:11 +01:00
Eugen Rochko
9e3a6d6784 Log BackupWorker backtrace, delete Backup if retries exhausted (#6769) 2018-03-13 08:15:24 +01:00
Eugen Rochko
8bf3e750ab Fix #6757: Adjust RTL styles for landing page (#6768) 2018-03-13 08:14:08 +01:00
Akihiko Odaki
18241ccbe1 Change the title of sensitive button by state (#6771)
Icon showing the state may be confusing. (does the slahed eye icon mean
the state that it is sensitive, or to mark it as sensitive?) Moreover, it
may not help for blind people.

The title will give the precise representation of the current state.
2018-03-13 08:10:12 +01:00
Akihiko Odaki
0dccb398bd Change the title of spoiler button by state
The title will give the precise representation of the current state. It
would be helpful for blind people.
2018-03-13 15:58:55 +09:00
Eugen Rochko
386365090c Fix #6762: Do not overwrite some status attributes in reducer (#6767) 2018-03-13 07:16:43 +01:00
Daniel Hunsaker
d9500c8a3b [Nanobox] Fix DB backup task (#6766)
Not sure how I missed that it had been using the wrong evar this entire time...
2018-03-13 06:07:02 +01:00
Akihiko Odaki
f7c1668bf6 Do not run lint in Travis CI (#6763)
Lint is done by codeclimate
2018-03-13 06:06:14 +01:00
Ushitora Anqou
051b649628 Detailed SMTP setup (#6759)
* add detailed SMTP settings setup in mastodon:setup

* add localhost SMTP settings setup in mastodon:setup

* SMTP settings setup should exit after successful delivery of test mail
2018-03-12 21:41:26 +01:00
艮 鮟鱇
f5f165a5eb set SAFETY_ASSURED=1 of db:setup in mastodon:setup (#6758) 2018-03-12 16:21:48 +01:00
Eugen Rochko
f89ff65ec7 Bump version to 2.3.1rc2 2018-03-12 12:48:49 +01:00
Akihiko Odaki
48b940d5c6 Insert space before shortcode if necessary (#6751) 2018-03-12 12:47:51 +01:00
Yamagishi Kazutoshi
6ae70a92c9 Hide pinned toots on with replies (#6753) 2018-03-12 12:47:18 +01:00
Yuto Tokunaga
fa5c867e0e Avoid using JS to set height in MediaModal (#6750)
avoid using JS to set height of ReactSwipeableViews component
reduce max-height of <img/> to 80% to avoid the screen covered by image
2018-03-12 03:52:05 +01:00
nightpool
641abe2db7 Fix Procfile on OS X (#6748) 2018-03-12 03:50:40 +01:00
Eugen Rochko
4f7f6b3922 Fix follow relationships not loading after notifications fetch (#6746) 2018-03-12 03:20:56 +01:00
Yamagishi Kazutoshi
8b14726f5b Weblate translations (2018-03-11) (#6742)
* Translated using Weblate (Japanese)

Currently translated at 100.0% (276 of 276 strings)

Translation: Mastodon/React
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/ja/

* Translated using Weblate (Finnish)

Currently translated at 100.0% (276 of 276 strings)

Translation: Mastodon/React
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/fi/

* Translated using Weblate (Finnish)

Currently translated at 25.1% (146 of 581 strings)

Translation: Mastodon/Backend
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/fi/

* Translated using Weblate (Slovak)

Currently translated at 91.2% (530 of 581 strings)

Translation: Mastodon/Backend
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/sk/

* Translated using Weblate (Arabic)

Currently translated at 67.6% (393 of 581 strings)

Translation: Mastodon/Backend
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/ar/

* Translated using Weblate (Swedish)

Currently translated at 100.0% (58 of 58 strings)

Translation: Mastodon/Preferences
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/simple_form/sv/

* Translated using Weblate (Swedish)

Currently translated at 100.0% (581 of 581 strings)

Translation: Mastodon/Backend
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/sv/

* Translated using Weblate (Finnish)

Currently translated at 100.0% (276 of 276 strings)

Translation: Mastodon/React
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/fi/

* Translated using Weblate (Finnish)

Currently translated at 92.0% (69 of 75 strings)

Translation: Mastodon/Doorkeeper
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/doorkeeper/fi/

* Translated using Weblate (Finnish)

Currently translated at 60.3% (35 of 58 strings)

Translation: Mastodon/Preferences
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/simple_form/fi/

* Translated using Weblate (Swedish)

Currently translated at 100.0% (75 of 75 strings)

Translation: Mastodon/Doorkeeper
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/doorkeeper/sv/

* Translated using Weblate (Swedish)

Currently translated at 100.0% (276 of 276 strings)

Translation: Mastodon/React
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/sv/

* Translated using Weblate (Arabic)

Currently translated at 68.3% (397 of 581 strings)

Translation: Mastodon/Backend
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/ar/

* Translated using Weblate (Arabic)

Currently translated at 99.2% (274 of 276 strings)

Translation: Mastodon/React
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/ar/

* Translated using Weblate (Slovak)

Currently translated at 100.0% (276 of 276 strings)

Translation: Mastodon/React
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/sk/

* Translated using Weblate (Arabic)

Currently translated at 73.8% (429 of 581 strings)

Translation: Mastodon/Backend
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/ar/

* Translated using Weblate (Slovak)

Currently translated at 91.2% (530 of 581 strings)

Translation: Mastodon/Backend
Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/sk/

* bundle exec i18n-tasks normalize && yarn manage:translations
2018-03-11 16:21:26 +01:00
Marcin Mikołajczak
9090b63831 i18n: Update Polish translation and “yarn manage:translations” (#6743)
Signed-off-by: Marcin Mikołajczak <me@m4sk.in>
2018-03-11 16:21:16 +01:00
Eugen Rochko
ab27dccba5 Bump version to 2.3.1rc1 2018-03-11 15:13:13 +01:00
Eugen Rochko
56eb5c3f34 Fix focal point cropping in MediaGallery, fix focal point modal (#6740)
* Use object-position with object-fit instead of JS top/left

* Fix focal point modal
2018-03-11 15:12:33 +01:00
TrashMacNugget
56333cca88 Add license info to README (#6583)
* Add license info to README

* Reference AUTHORS file
2018-03-11 15:12:23 +01:00
Eugen Rochko
1aaec701bb Fix #6715: Make catalan words with the L geminate letter work in hashtags (#6741) 2018-03-11 14:55:49 +01:00
Konrad Pozniak
cd252b794e add new avatar placeholder missing.png (#6728) 2018-03-11 14:55:38 +01:00
Eugen Rochko
b6003afcdb Add show more/less toggle for entire threads in web UI (#6733)
Fix #1258
2018-03-11 09:52:59 +01:00
Marcin Mikołajczak
f5ee2d469b i18n: Update Polish translation (#6731)
Signed-off-by: Marcin Mikołajczak <me@m4sk.in>
2018-03-11 01:56:30 +09:00
abcang
37b043d447 Improve performance of account_media_status_ids (#6729) 2018-03-10 17:44:26 +01:00
Akihiko Odaki
36579bac88 Use Alpine Linux yarn package in Docker (#6725)
Yarn was manually installed to meet the Yarn version requirement of
webpacker. Today, Alpine Linux 3.7 provides Yarn new enough.
2018-03-10 11:49:04 +01:00
Eugen Rochko
4476a45444 Fix #6717: Do not double html-encode page titles (#6720) 2018-03-10 11:43:20 +01:00
Akihiko Odaki
58a4633707 Remove su-exec from Docker image (#6722)
It is no longer necessary since commit
be9bab171d.
2018-03-10 11:42:42 +01:00
Akihiko Odaki
494969d394 Remove git from Docker image (#6724) 2018-03-10 11:42:28 +01:00
124 changed files with 1237 additions and 552 deletions

View File

@@ -4,6 +4,7 @@
[
"env",
{
"exclude": ["transform-async-to-generator", "transform-regenerator"],
"loose": true,
"modules": false,
"targets": {

View File

@@ -155,8 +155,8 @@ STREAMING_CLUSTER_NUM=1
# The pam environment variable "email" is provided by:
# https://github.com/devkral/pam_email_extractor
# PAM_ENABLED=true
# Fallback Suffix for email address generation (nil by default)
# PAM_DEFAULT_SUFFIX=pam
# Fallback email domain for email address generation (LOCAL_DOMAIN by default)
# PAM_EMAIL_DOMAIN=example.com
# Name of the pam service (pam "auth" section is evaluated)
# PAM_DEFAULT_SERVICE=rpam
# Name of the pam service used for checking if an user can register (pam "account" section is evaluated) (nil (disabled) by default)

View File

@@ -55,5 +55,5 @@ before_script:
script:
- travis_retry bundle exec parallel_test spec/ --group-by filesize --type rspec
- yarn test
- yarn run test:jest
- bundle exec i18n-tasks check-normalized && bundle exec i18n-tasks unused

View File

@@ -1,4 +1,4 @@
FROM ruby:2.5.0-alpine3.7
FROM ruby:2.4.3-alpine3.6
LABEL maintainer="https://github.com/tootsuite/mastodon" \
description="Your self-hosted, globally interconnected microblogging community"
@@ -9,8 +9,8 @@ ARG GID=991
ENV RAILS_SERVE_STATIC_FILES=true \
RAILS_ENV=production NODE_ENV=production
ARG YARN_VERSION=1.5.1
ARG YARN_DOWNLOAD_SHA256=cd31657232cf48d57fdbff55f38bfa058d2fb4950450bd34af72dac796af4de1
ARG YARN_VERSION=1.3.2
ARG YARN_DOWNLOAD_SHA256=6cfe82e530ef0837212f13e45c1565ba53f5199eec2527b85ecbcd88bf26821d
ARG LIBICONV_VERSION=1.15
ARG LIBICONV_DOWNLOAD_SHA256=ccf536620a45458d26ba83887a983b96827001e92a13847b45e4925cc8913178
@@ -38,8 +38,8 @@ RUN apk -U upgrade \
libidn \
libpq \
nodejs \
nodejs-npm \
protobuf \
su-exec \
tini \
tzdata \
&& update-ca-certificates \

View File

@@ -32,7 +32,9 @@ gem 'cld3', '~> 3.2.0'
gem 'devise', '~> 4.4'
gem 'devise-two-factor', '~> 3.0'
gem 'devise_pam_authenticatable2', '~> 8.0', install_if: -> { ENV['PAM_ENABLED'] == 'true' }
group :pam_authentication, optional: true do
gem 'devise_pam_authenticatable2', '~> 9.0'
end
gem 'net-ldap', '~> 0.10'
gem 'omniauth-cas', '~> 1.1'
gem 'omniauth-saml', '~> 1.10'
@@ -69,7 +71,7 @@ gem 'mario-redis-lock', '~> 1.2', require: 'redis_lock'
gem 'rqrcode', '~> 0.10'
gem 'ruby-oembed', '~> 0.12', require: 'oembed'
gem 'ruby-progressbar', '~> 1.4'
gem 'sanitize', '~> 4.4'
gem 'sanitize', '~> 4.6.4'
gem 'sidekiq', '~> 5.0'
gem 'sidekiq-scheduler', '~> 2.1'
gem 'sidekiq-unique-jobs', '~> 5.0'

View File

@@ -141,7 +141,7 @@ GEM
devise (~> 4.0)
railties (< 5.2)
rotp (~> 2.0)
devise_pam_authenticatable2 (8.0.1)
devise_pam_authenticatable2 (9.0.0)
devise (>= 4.0.0)
rpam2 (~> 3.0)
diff-lcs (1.3)
@@ -288,7 +288,7 @@ GEM
activesupport (>= 4, < 5.2)
railties (>= 4, < 5.2)
request_store (~> 1.0)
loofah (2.1.1)
loofah (2.2.1)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
mail (2.7.0)
@@ -316,9 +316,9 @@ GEM
net-ssh (>= 2.6.5)
net-ssh (4.2.0)
nio4r (2.1.0)
nokogiri (1.8.1)
nokogiri (1.8.2)
mini_portile2 (~> 2.3.0)
nokogumbo (1.4.13)
nokogumbo (1.5.0)
nokogiri
nsa (0.2.4)
activesupport (>= 4.2, < 6)
@@ -496,10 +496,10 @@ GEM
rufus-scheduler (3.4.2)
et-orbi (~> 1.0)
safe_yaml (1.0.4)
sanitize (4.5.0)
sanitize (4.6.4)
crass (~> 1.0.2)
nokogiri (>= 1.4.4)
nokogumbo (~> 1.4.1)
nokogumbo (~> 1.4)
sass (3.5.3)
sass-listen (~> 4.0.0)
sass-listen (4.0.0)
@@ -631,7 +631,7 @@ DEPENDENCIES
climate_control (~> 0.2)
devise (~> 4.4)
devise-two-factor (~> 3.0)
devise_pam_authenticatable2 (~> 8.0)
devise_pam_authenticatable2 (~> 9.0)
doorkeeper (~> 4.2)
dotenv-rails (~> 2.2)
fabrication (~> 2.18)
@@ -699,7 +699,7 @@ DEPENDENCIES
rubocop
ruby-oembed (~> 0.12)
ruby-progressbar (~> 1.4)
sanitize (~> 4.4)
sanitize (~> 4.6.4)
scss_lint (~> 0.55)
sidekiq (~> 5.0)
sidekiq-bulk (~> 0.1.1)

View File

@@ -1,4 +1,4 @@
web: PORT=3000 bundle exec puma -C config/puma.rb
sidekiq: PORT=3000 bundle exec sidekiq
stream: PORT=4000 yarn run start
web: env PORT=3000 bundle exec puma -C config/puma.rb
sidekiq: env PORT=3000 bundle exec sidekiq
stream: env PORT=4000 yarn run start
webpack: ./bin/webpack-dev-server --listen-host 0.0.0.0

View File

@@ -79,6 +79,16 @@ You can open issues for bugs you've found or features you think are missing. You
**IRC channel**: #mastodon on irc.freenode.net
## License
Copyright (C) 2016-2018 Eugen Rochko & other Mastodon contributors (see AUTHORS.md)
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
---
## Extra credits

View File

@@ -51,7 +51,13 @@ class Api::V1::Accounts::StatusesController < Api::BaseController
end
def account_media_status_ids
@account.media_attachments.attached.reorder(nil).select(:status_id).distinct
# `SELECT DISTINCT id, updated_at` is too slow, so pluck ids at first, and then select id, updated_at with ids.
# Also, Avoid getting slow by not narrowing down by `statuses.account_id`.
# When narrowing down by `statuses.account_id`, `index_statuses_20180106` will be used
# and the table will be joined by `Merge Semi Join`, so the query will be slow.
Status.joins(:media_attachments).merge(@account.media_attachments).permitted_for(@account, current_account)
.paginate_by_max_id(limit_param(DEFAULT_STATUSES_LIMIT), params[:max_id], params[:since_id])
.reorder(id: :desc).distinct(:id).pluck(:id)
end
def pinned_scope

View File

@@ -17,7 +17,11 @@ module Localized
end
def default_locale
request_locale || I18n.default_locale
if ENV['DEFAULT_LOCALE'].present?
I18n.default_locale
else
request_locale || I18n.default_locale
end
end
def request_locale

View File

@@ -29,6 +29,35 @@ module StreamEntriesHelper
[prepend_str, account.note].join(' · ')
end
def media_summary(status)
attachments = { image: 0, video: 0 }
status.media_attachments.each do |media|
if media.video?
attachments[:video] += 1
else
attachments[:image] += 1
end
end
text = attachments.to_a.reject { |_, value| value.zero? }.map { |key, value| t("statuses.attached.#{key}", count: value) }.join(' · ')
return if text.blank?
t('statuses.attached.description', attached: text)
end
def status_text_summary(status)
return if status.spoiler_text.blank?
t('statuses.content_warning', warning: status.spoiler_text)
end
def status_description(status)
components = [[media_summary(status), status_text_summary(status)].reject(&:blank?).join(' · ')]
components << status.text if status.spoiler_text.blank?
components.reject(&:blank?).join("\n\n")
end
def stream_link_target
embedded_view? ? '_blank' : nil
end

View File

@@ -1,4 +1,5 @@
import api from '../api';
import { CancelToken } from 'axios';
import { throttle } from 'lodash';
import { search as emojiSearch } from '../features/emoji/emoji_mart_search_light';
import { tagHistory } from '../settings';
@@ -11,6 +12,8 @@ import {
refreshPublicTimeline,
} from './timelines';
let cancelFetchComposeSuggestionsAccounts;
export const COMPOSE_CHANGE = 'COMPOSE_CHANGE';
export const COMPOSE_SUBMIT_REQUEST = 'COMPOSE_SUBMIT_REQUEST';
export const COMPOSE_SUBMIT_SUCCESS = 'COMPOSE_SUBMIT_SUCCESS';
@@ -257,13 +260,22 @@ export function undoUploadCompose(media_id) {
};
export function clearComposeSuggestions() {
if (cancelFetchComposeSuggestionsAccounts) {
cancelFetchComposeSuggestionsAccounts();
}
return {
type: COMPOSE_SUGGESTIONS_CLEAR,
};
};
const fetchComposeSuggestionsAccounts = throttle((dispatch, getState, token) => {
if (cancelFetchComposeSuggestionsAccounts) {
cancelFetchComposeSuggestionsAccounts();
}
api(getState).get('/api/v1/accounts/search', {
cancelToken: new CancelToken(cancel => {
cancelFetchComposeSuggestionsAccounts = cancel;
}),
params: {
q: token.slice(1),
resolve: false,

View File

@@ -62,6 +62,7 @@ export function reblogRequest(status) {
return {
type: REBLOG_REQUEST,
status: status,
skipLoading: true,
};
};
@@ -70,6 +71,7 @@ export function reblogSuccess(status, response) {
type: REBLOG_SUCCESS,
status: status,
response: response,
skipLoading: true,
};
};
@@ -78,6 +80,7 @@ export function reblogFail(status, error) {
type: REBLOG_FAIL,
status: status,
error: error,
skipLoading: true,
};
};
@@ -85,6 +88,7 @@ export function unreblogRequest(status) {
return {
type: UNREBLOG_REQUEST,
status: status,
skipLoading: true,
};
};
@@ -93,6 +97,7 @@ export function unreblogSuccess(status, response) {
type: UNREBLOG_SUCCESS,
status: status,
response: response,
skipLoading: true,
};
};
@@ -101,6 +106,7 @@ export function unreblogFail(status, error) {
type: UNREBLOG_FAIL,
status: status,
error: error,
skipLoading: true,
};
};
@@ -132,6 +138,7 @@ export function favouriteRequest(status) {
return {
type: FAVOURITE_REQUEST,
status: status,
skipLoading: true,
};
};
@@ -140,6 +147,7 @@ export function favouriteSuccess(status, response) {
type: FAVOURITE_SUCCESS,
status: status,
response: response,
skipLoading: true,
};
};
@@ -148,6 +156,7 @@ export function favouriteFail(status, error) {
type: FAVOURITE_FAIL,
status: status,
error: error,
skipLoading: true,
};
};
@@ -155,6 +164,7 @@ export function unfavouriteRequest(status) {
return {
type: UNFAVOURITE_REQUEST,
status: status,
skipLoading: true,
};
};
@@ -163,6 +173,7 @@ export function unfavouriteSuccess(status, response) {
type: UNFAVOURITE_SUCCESS,
status: status,
response: response,
skipLoading: true,
};
};
@@ -171,6 +182,7 @@ export function unfavouriteFail(status, error) {
type: UNFAVOURITE_FAIL,
status: status,
error: error,
skipLoading: true,
};
};
@@ -258,6 +270,7 @@ export function pinRequest(status) {
return {
type: PIN_REQUEST,
status,
skipLoading: true,
};
};
@@ -266,6 +279,7 @@ export function pinSuccess(status, response) {
type: PIN_SUCCESS,
status,
response,
skipLoading: true,
};
};
@@ -274,6 +288,7 @@ export function pinFail(status, error) {
type: PIN_FAIL,
status,
error,
skipLoading: true,
};
};
@@ -293,6 +308,7 @@ export function unpinRequest(status) {
return {
type: UNPIN_REQUEST,
status,
skipLoading: true,
};
};
@@ -301,6 +317,7 @@ export function unpinSuccess(status, response) {
type: UNPIN_SUCCESS,
status,
response,
skipLoading: true,
};
};
@@ -309,5 +326,6 @@ export function unpinFail(status, error) {
type: UNPIN_FAIL,
status,
error,
skipLoading: true,
};
};

View File

@@ -24,7 +24,7 @@ defineMessages({
const fetchRelatedRelationships = (dispatch, notifications) => {
const accountIds = notifications.filter(item => item.type === 'follow').map(item => item.account.id);
if (accountIds > 0) {
if (accountIds.length > 0) {
dispatch(fetchRelationships(accountIds));
}
};

View File

@@ -23,6 +23,9 @@ export const STATUS_UNMUTE_REQUEST = 'STATUS_UNMUTE_REQUEST';
export const STATUS_UNMUTE_SUCCESS = 'STATUS_UNMUTE_SUCCESS';
export const STATUS_UNMUTE_FAIL = 'STATUS_UNMUTE_FAIL';
export const STATUS_REVEAL = 'STATUS_REVEAL';
export const STATUS_HIDE = 'STATUS_HIDE';
export function fetchStatusRequest(id, skipLoading) {
return {
type: STATUS_FETCH_REQUEST,
@@ -215,3 +218,25 @@ export function unmuteStatusFail(id, error) {
error,
};
};
export function hideStatus(ids) {
if (!Array.isArray(ids)) {
ids = [ids];
}
return {
type: STATUS_HIDE,
ids,
};
};
export function revealStatus(ids) {
if (!Array.isArray(ids)) {
ids = [ids];
}
return {
type: STATUS_REVEAL,
ids,
};
};

View File

@@ -19,10 +19,11 @@ export default class ColumnHeader extends React.PureComponent {
static propTypes = {
intl: PropTypes.object.isRequired,
title: PropTypes.node.isRequired,
icon: PropTypes.string.isRequired,
title: PropTypes.node,
icon: PropTypes.string,
active: PropTypes.bool,
multiColumn: PropTypes.bool,
extraButton: PropTypes.node,
showBackButton: PropTypes.bool,
children: PropTypes.node,
pinned: PropTypes.bool,
@@ -63,7 +64,7 @@ export default class ColumnHeader extends React.PureComponent {
}
render () {
const { title, icon, active, children, pinned, onPin, multiColumn, showBackButton, intl: { formatMessage } } = this.props;
const { title, icon, active, children, pinned, onPin, multiColumn, extraButton, showBackButton, intl: { formatMessage } } = this.props;
const { collapsed, animating } = this.state;
const wrapperClassName = classNames('column-header__wrapper', {
@@ -125,19 +126,26 @@ export default class ColumnHeader extends React.PureComponent {
}
if (children || multiColumn) {
collapseButton = <button className={collapsibleButtonClassName} aria-label={formatMessage(collapsed ? messages.show : messages.hide)} aria-pressed={collapsed ? 'false' : 'true'} onClick={this.handleToggleClick}><i className='fa fa-sliders' /></button>;
collapseButton = <button className={collapsibleButtonClassName} title={formatMessage(collapsed ? messages.show : messages.hide)} aria-label={formatMessage(collapsed ? messages.show : messages.hide)} aria-pressed={collapsed ? 'false' : 'true'} onClick={this.handleToggleClick}><i className='fa fa-sliders' /></button>;
}
const hasTitle = icon && title;
return (
<div className={wrapperClassName}>
<h1 className={buttonClassName}>
<button onClick={this.handleTitleClick}>
<i className={`fa fa-fw fa-${icon} column-header__icon`} />
{title}
</button>
{hasTitle && (
<button onClick={this.handleTitleClick}>
<i className={`fa fa-fw fa-${icon} column-header__icon`} />
{title}
</button>
)}
{!hasTitle && backButton}
<div className='column-header__buttons'>
{backButton}
{hasTitle && backButton}
{extraButton}
{collapseButton}
</div>
</h1>

View File

@@ -12,26 +12,6 @@ const messages = defineMessages({
toggle_visible: { id: 'media_gallery.toggle_visible', defaultMessage: 'Toggle visibility' },
});
const shiftToPoint = (containerToImageRatio, containerSize, imageSize, focusSize, toMinus) => {
const containerCenter = Math.floor(containerSize / 2);
const focusFactor = (focusSize + 1) / 2;
const scaledImage = Math.floor(imageSize / containerToImageRatio);
let focus = Math.floor(focusFactor * scaledImage);
if (toMinus) focus = scaledImage - focus;
let focusOffset = focus - containerCenter;
const remainder = scaledImage - focus;
const containerRemainder = containerSize - containerCenter;
if (remainder < containerRemainder) focusOffset -= containerRemainder - remainder;
if (focusOffset < 0) focusOffset = 0;
return (focusOffset * -100 / containerSize) + '%';
};
class Item extends React.PureComponent {
static contextTypes = {
@@ -44,8 +24,6 @@ class Item extends React.PureComponent {
index: PropTypes.number.isRequired,
size: PropTypes.number.isRequired,
onClick: PropTypes.func.isRequired,
containerWidth: PropTypes.number,
containerHeight: PropTypes.number,
};
static defaultProps = {
@@ -84,7 +62,7 @@ class Item extends React.PureComponent {
}
render () {
const { attachment, index, size, standalone, containerWidth, containerHeight } = this.props;
const { attachment, index, size, standalone } = this.props;
let width = 50;
let height = 100;
@@ -143,45 +121,16 @@ class Item extends React.PureComponent {
const originalUrl = attachment.get('url');
const originalWidth = attachment.getIn(['meta', 'original', 'width']);
const originalHeight = attachment.getIn(['meta', 'original', 'height']);
const hasSize = typeof originalWidth === 'number' && typeof previewWidth === 'number';
const srcSet = hasSize ? `${originalUrl} ${originalWidth}w, ${previewUrl} ${previewWidth}w` : null;
const sizes = hasSize ? `(min-width: 1025px) ${320 * (width / 100)}px, ${width}vw` : null;
const focusX = attachment.getIn(['meta', 'focus', 'x']);
const focusY = attachment.getIn(['meta', 'focus', 'y']);
const imageStyle = {};
if (originalWidth && originalHeight && containerWidth && containerHeight && focusX && focusY) {
const widthRatio = originalWidth / (containerWidth * (width / 100));
const heightRatio = originalHeight / (containerHeight * (height / 100));
let hShift = 0;
let vShift = 0;
if (widthRatio > heightRatio) {
hShift = shiftToPoint(heightRatio, (containerWidth * (width / 100)), originalWidth, focusX);
} else if(widthRatio < heightRatio) {
vShift = shiftToPoint(widthRatio, (containerHeight * (height / 100)), originalHeight, focusY, true);
}
if (originalWidth > originalHeight) {
imageStyle.height = '100%';
imageStyle.width = 'auto';
imageStyle.minWidth = '100%';
} else {
imageStyle.height = 'auto';
imageStyle.width = '100%';
imageStyle.minHeight = '100%';
}
imageStyle.top = vShift;
imageStyle.left = hShift;
} else {
imageStyle.height = '100%';
}
const focusX = attachment.getIn(['meta', 'focus', 'x']) || 0;
const focusY = attachment.getIn(['meta', 'focus', 'y']) || 0;
const x = ((focusX / 2) + .5) * 100;
const y = ((focusY / -2) + .5) * 100;
thumbnail = (
<a
@@ -196,7 +145,7 @@ class Item extends React.PureComponent {
sizes={sizes}
alt={attachment.get('description')}
title={attachment.get('description')}
style={imageStyle}
style={{ objectPosition: `${x}% ${y}%` }}
/>
</a>
);
@@ -320,7 +269,7 @@ export default class MediaGallery extends React.PureComponent {
if (this.isStandaloneEligible()) {
children = <Item standalone onClick={this.handleClick} attachment={media.get(0)} />;
} else {
children = media.take(4).map((attachment, i) => <Item key={attachment.get('id')} onClick={this.handleClick} attachment={attachment} index={i} size={size} containerWidth={width} containerHeight={style.height} />);
children = media.take(4).map((attachment, i) => <Item key={attachment.get('id')} onClick={this.handleClick} attachment={attachment} index={i} size={size} />);
}
}

View File

@@ -37,16 +37,13 @@ export default class Status extends ImmutablePureComponent {
onBlock: PropTypes.func,
onEmbed: PropTypes.func,
onHeightChange: PropTypes.func,
onToggleHidden: PropTypes.func,
muted: PropTypes.bool,
hidden: PropTypes.bool,
onMoveUp: PropTypes.func,
onMoveDown: PropTypes.func,
};
state = {
isExpanded: false,
}
// Avoid checking props that are functions (and whose equality will always
// evaluate to false. See react-immutable-pure-component for usage.
updateOnProps = [
@@ -56,8 +53,6 @@ export default class Status extends ImmutablePureComponent {
'hidden',
]
updateOnStates = ['isExpanded']
handleClick = () => {
if (!this.context.router) {
return;
@@ -76,7 +71,7 @@ export default class Status extends ImmutablePureComponent {
}
handleExpandedToggle = () => {
this.setState({ isExpanded: !this.state.isExpanded });
this.props.onToggleHidden(this._properStatus());
};
renderLoadingMediaGallery () {
@@ -140,7 +135,6 @@ export default class Status extends ImmutablePureComponent {
let statusAvatar, prepend;
const { hidden, featured } = this.props;
const { isExpanded } = this.state;
let { status, account, ...other } = this.props;
@@ -248,7 +242,7 @@ export default class Status extends ImmutablePureComponent {
</a>
</div>
<StatusContent status={status} onClick={this.handleClick} expanded={isExpanded} onExpandedToggle={this.handleExpandedToggle} />
<StatusContent status={status} onClick={this.handleClick} expanded={!status.get('hidden')} onExpandedToggle={this.handleExpandedToggle} />
{media}

View File

@@ -154,7 +154,7 @@ export default class StatusContent extends React.PureComponent {
}
return (
<div className={classNames} ref={this.setRef} tabIndex='0' onMouseDown={this.handleMouseDown} onMouseUp={this.handleMouseUp}>
<div className={classNames} ref={this.setRef} tabIndex='0' style={directionStyle} onMouseDown={this.handleMouseDown} onMouseUp={this.handleMouseUp}>
<p style={{ marginBottom: hidden && status.get('mentions').isEmpty() ? '0px' : null }}>
<span dangerouslySetInnerHTML={spoilerContent} />
{' '}

View File

@@ -15,7 +15,13 @@ import {
unpin,
} from '../actions/interactions';
import { blockAccount } from '../actions/accounts';
import { muteStatus, unmuteStatus, deleteStatus } from '../actions/statuses';
import {
muteStatus,
unmuteStatus,
deleteStatus,
hideStatus,
revealStatus,
} from '../actions/statuses';
import { initMuteModal } from '../actions/mutes';
import { initReport } from '../actions/reports';
import { openModal } from '../actions/modal';
@@ -128,6 +134,14 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
}
},
onToggleHidden (status) {
if (status.get('hidden')) {
dispatch(revealStatus(status.get('id')));
} else {
dispatch(hideStatus(status.get('id')));
}
},
});
export default injectIntl(connect(makeMapStateToProps, mapDispatchToProps)(Status));

View File

@@ -17,7 +17,7 @@ const mapStateToProps = (state, { params: { accountId }, withReplies = false })
return {
statusIds: state.getIn(['timelines', `account:${path}`, 'items'], ImmutableList()),
featuredStatusIds: state.getIn(['timelines', `account:${accountId}:pinned`, 'items'], ImmutableList()),
featuredStatusIds: withReplies ? ImmutableList() : state.getIn(['timelines', `account:${accountId}:pinned`, 'items'], ImmutableList()),
isLoading: state.getIn(['timelines', `account:${path}`, 'isLoading']),
hasMore: !!state.getIn(['timelines', `account:${path}`, 'next']),
};
@@ -40,14 +40,18 @@ export default class AccountTimeline extends ImmutablePureComponent {
const { params: { accountId }, withReplies } = this.props;
this.props.dispatch(fetchAccount(accountId));
this.props.dispatch(refreshAccountFeaturedTimeline(accountId));
if (!withReplies) {
this.props.dispatch(refreshAccountFeaturedTimeline(accountId));
}
this.props.dispatch(refreshAccountTimeline(accountId, withReplies));
}
componentWillReceiveProps (nextProps) {
if ((nextProps.params.accountId !== this.props.params.accountId && nextProps.params.accountId) || nextProps.withReplies !== this.props.withReplies) {
this.props.dispatch(fetchAccount(nextProps.params.accountId));
this.props.dispatch(refreshAccountFeaturedTimeline(nextProps.params.accountId));
if (!nextProps.withReplies) {
this.props.dispatch(refreshAccountFeaturedTimeline(nextProps.params.accountId));
}
this.props.dispatch(refreshAccountTimeline(nextProps.params.accountId, nextProps.params.withReplies));
}
}

View File

@@ -9,7 +9,8 @@ import spring from 'react-motion/lib/spring';
import { injectIntl, defineMessages } from 'react-intl';
const messages = defineMessages({
title: { id: 'compose_form.sensitive', defaultMessage: 'Mark media as sensitive' },
marked: { id: 'compose_form.sensitive.marked', defaultMessage: 'Media is marked as sensitive' },
unmarked: { id: 'compose_form.sensitive.unmarked', defaultMessage: 'Media is not marked as sensitive' },
});
const mapStateToProps = state => ({
@@ -50,7 +51,7 @@ class SensitiveButton extends React.PureComponent {
<div className={className} style={{ transform: `scale(${scale})` }}>
<IconButton
className='compose-form__sensitive-button__icon'
title={intl.formatMessage(messages.title)}
title={intl.formatMessage(active ? messages.marked : messages.unmarked)}
icon={icon}
onClick={onClick}
size={18}

View File

@@ -4,12 +4,13 @@ import { changeComposeSpoilerness } from '../../../actions/compose';
import { injectIntl, defineMessages } from 'react-intl';
const messages = defineMessages({
title: { id: 'compose_form.spoiler', defaultMessage: 'Hide text behind warning' },
marked: { id: 'compose_form.spoiler.marked', defaultMessage: 'Text is hidden behind warning' },
unmarked: { id: 'compose_form.spoiler.unmarked', defaultMessage: 'Text is not hidden' },
});
const mapStateToProps = (state, { intl }) => ({
label: 'CW',
title: intl.formatMessage(messages.title),
title: intl.formatMessage(state.getIn(['compose', 'spoiler']) ? messages.marked : messages.unmarked),
active: state.getIn(['compose', 'spoiler']),
ariaControls: 'cw-spoiler-input',
});

View File

@@ -5,7 +5,7 @@ import PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl';
import { me } from '../../../initial_state';
const APPROX_HASHTAG_RE = /(?:^|[^\/\)\w])#(\w*[a-zA-Z]\w*)/i;
const APPROX_HASHTAG_RE = /(?:^|[^\/\)\w])#(\w*[a-zA-Z·]\w*)/i;
const mapStateToProps = state => ({
needsLockWarning: state.getIn(['compose', 'privacy']) === 'private' && !state.getIn(['accounts', me, 'locked']),

View File

@@ -97,7 +97,7 @@ export default class Compose extends React.PureComponent {
<ComposeFormContainer />
{multiColumn && (
<div className='drawer__inner__mastodon'>
<img alt='' src={elephantUIPlane} />
<img alt='' draggable='false' src={elephantUIPlane} />
</div>
)}
</div>

View File

@@ -22,6 +22,7 @@ export default class DetailedStatus extends ImmutablePureComponent {
status: ImmutablePropTypes.map.isRequired,
onOpenMedia: PropTypes.func.isRequired,
onOpenVideo: PropTypes.func.isRequired,
onToggleHidden: PropTypes.func.isRequired,
};
handleAccountClick = (e) => {
@@ -37,6 +38,10 @@ export default class DetailedStatus extends ImmutablePureComponent {
this.props.onOpenVideo(this.props.status.getIn(['media_attachments', 0]), startTime);
}
handleExpandedToggle = () => {
this.props.onToggleHidden(this.props.status);
}
render () {
const status = this.props.status.get('reblog') ? this.props.status.get('reblog') : this.props.status;
@@ -105,7 +110,7 @@ export default class DetailedStatus extends ImmutablePureComponent {
<DisplayName account={status.get('account')} />
</a>
<StatusContent status={status} />
<StatusContent status={status} expanded={!status.get('hidden')} onExpandedToggle={this.handleExpandedToggle} />
{media}

View File

@@ -21,12 +21,19 @@ import {
mentionCompose,
} from '../../actions/compose';
import { blockAccount } from '../../actions/accounts';
import { muteStatus, unmuteStatus, deleteStatus } from '../../actions/statuses';
import {
muteStatus,
unmuteStatus,
deleteStatus,
hideStatus,
revealStatus,
} from '../../actions/statuses';
import { initMuteModal } from '../../actions/mutes';
import { initReport } from '../../actions/reports';
import { makeGetStatus } from '../../selectors';
import { ScrollContainer } from 'react-router-scroll-4';
import ColumnBackButton from '../../components/column_back_button';
import ColumnHeader from '../../components/column_header';
import StatusContainer from '../../containers/status_container';
import { openModal } from '../../actions/modal';
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
@@ -39,6 +46,8 @@ const messages = defineMessages({
deleteConfirm: { id: 'confirmations.delete.confirm', defaultMessage: 'Delete' },
deleteMessage: { id: 'confirmations.delete.message', defaultMessage: 'Are you sure you want to delete this status?' },
blockConfirm: { id: 'confirmations.block.confirm', defaultMessage: 'Block' },
revealAll: { id: 'status.show_more_all', defaultMessage: 'Show more for all' },
hideAll: { id: 'status.show_less_all', defaultMessage: 'Show less for all' },
});
const makeMapStateToProps = () => {
@@ -163,6 +172,25 @@ export default class Status extends ImmutablePureComponent {
}
}
handleToggleHidden = (status) => {
if (status.get('hidden')) {
this.props.dispatch(revealStatus(status.get('id')));
} else {
this.props.dispatch(hideStatus(status.get('id')));
}
}
handleToggleAll = () => {
const { status, ancestorsIds, descendantsIds } = this.props;
const statusIds = [status.get('id')].concat(ancestorsIds.toJS(), descendantsIds.toJS());
if (status.get('hidden')) {
this.props.dispatch(revealStatus(statusIds));
} else {
this.props.dispatch(hideStatus(statusIds));
}
}
handleBlockClick = (account) => {
const { dispatch, intl } = this.props;
@@ -293,7 +321,7 @@ export default class Status extends ImmutablePureComponent {
render () {
let ancestors, descendants;
const { status, ancestorsIds, descendantsIds } = this.props;
const { status, ancestorsIds, descendantsIds, intl } = this.props;
const { fullscreen } = this.state;
if (status === null) {
@@ -325,7 +353,12 @@ export default class Status extends ImmutablePureComponent {
return (
<Column>
<ColumnBackButton />
<ColumnHeader
showBackButton
extraButton={(
<button className='column-header__button' title={intl.formatMessage(status.get('hidden') ? messages.revealAll : messages.hideAll)} aria-label={intl.formatMessage(status.get('hidden') ? messages.revealAll : messages.hideAll)} onClick={this.handleToggleAll} aria-pressed={status.get('hidden') ? 'false' : 'true'}><i className={`fa fa-${status.get('hidden') ? 'eye-slash' : 'eye'}`} /></button>
)}
/>
<ScrollContainer scrollKey='thread'>
<div className={classNames('scrollable', 'detailed-status__wrapper', { fullscreen })} ref={this.setRef}>
@@ -337,6 +370,7 @@ export default class Status extends ImmutablePureComponent {
status={status}
onOpenVideo={this.handleOpenVideo}
onOpenMedia={this.handleOpenMedia}
onToggleHidden={this.handleToggleHidden}
/>
<ActionBar

View File

@@ -28,6 +28,8 @@ const componentMap = {
'LIST': ListTimeline,
};
const shouldHideFAB = path => path.match(/^\/statuses\//);
@component => injectIntl(component, { withRef: true })
export default class ColumnsArea extends ImmutablePureComponent {
@@ -153,7 +155,7 @@ export default class ColumnsArea extends ImmutablePureComponent {
this.pendingIndex = null;
if (singleColumn) {
const floatingActionButton = this.context.router.history.location.pathname === '/statuses/new' ? null : <Link key='floating-action-button' to='/statuses/new' className='floating-action-button'><i className='fa fa-pencil' /></Link>;
const floatingActionButton = shouldHideFAB(this.context.router.history.location.pathname) ? null : <Link key='floating-action-button' to='/statuses/new' className='floating-action-button'><i className='fa fa-pencil' /></Link>;
return columnIndex !== -1 ? [
<ReactSwipeableViews key='content' index={columnIndex} onChangeIndex={this.handleSwipe} onTransitionEnd={this.handleAnimationEnd} animateTransitions={shouldAnimate} springConfig={{ duration: '400ms', delay: '0s', easeFunction: 'ease' }} style={{ height: '100%' }}>

View File

@@ -103,7 +103,7 @@ export default class FocalPointModal extends ImmutablePureComponent {
const height = media.getIn(['meta', 'original', 'height']) || null;
return (
<div className='modal-root__modal video-modal'>
<div className='modal-root__modal video-modal focal-point-modal'>
<div className={classNames('focal-point', { dragging })} ref={this.setRef}>
<ImageLoader
previewSrc={media.get('preview_url')}

View File

@@ -130,6 +130,15 @@ export default class MediaModal extends ImmutablePureComponent {
return null;
}).toArray();
// you can't use 100vh, because the viewport height is taller
// than the visible part of the document in some mobile
// browsers when it's address bar is visible.
// https://developers.google.com/web/updates/2016/12/url-bar-resizing
const swipeableViewsStyle = {
width: '100%',
height: '100%',
};
const containerStyle = {
alignItems: 'center', // center vertically
};
@@ -145,23 +154,15 @@ export default class MediaModal extends ImmutablePureComponent {
role='presentation'
onClick={onClose}
>
<div className='media-modal__content'>
<ReactSwipeableViews
style={{
// you can't use 100vh, because the viewport height is taller
// than the visible part of the document in some mobile
// browsers when it's address bar is visible.
// https://developers.google.com/web/updates/2016/12/url-bar-resizing
height: `${document.body.clientHeight}px`,
}}
containerStyle={containerStyle}
onChangeIndex={this.handleSwipe}
onSwitching={this.handleSwitching}
index={index}
>
{content}
</ReactSwipeableViews>
</div>
<ReactSwipeableViews
style={swipeableViewsStyle}
containerStyle={containerStyle}
onChangeIndex={this.handleSwipe}
onSwitching={this.handleSwitching}
index={index}
>
{content}
</ReactSwipeableViews>
</div>
<div className={navigationClassName}>
<IconButton className='media-modal__close' title={intl.formatMessage(messages.close)} icon='times' onClick={onClose} size={40} />

View File

@@ -3,7 +3,7 @@
"account.block_domain": "إخفاء كل شيئ قادم من إسم النطاق {domain}",
"account.blocked": "محظور",
"account.disclaimer_full": "قد لا تعكس المعلومات أدناه الملف الشخصي الكامل للمستخدم.",
"account.domain_blocked": "Domain hidden",
"account.domain_blocked": "النطاق مخفي",
"account.edit_profile": "تعديل الملف الشخصي",
"account.follow": "تابِع",
"account.followers": "المتابعون",
@@ -60,8 +60,10 @@
"compose_form.placeholder": "فيمَ تفكّر؟",
"compose_form.publish": "بوّق",
"compose_form.publish_loud": "{publish}!",
"compose_form.sensitive": "ضع علامة على الوسيط باعتباره حسّاس",
"compose_form.spoiler": "أخفِ النص واعرض تحذيرا",
"compose_form.sensitive.marked": "لقد تم تحديد هذه الصورة كحساسة",
"compose_form.sensitive.unmarked": "Media is not marked as sensitive",
"compose_form.spoiler.marked": "إنّ النص مخفي وراء تحذير",
"compose_form.spoiler.unmarked": "النص غير مخفي",
"compose_form.spoiler_placeholder": "تنبيه عن المحتوى",
"confirmation_modal.cancel": "إلغاء",
"confirmations.block.confirm": "حجب",
@@ -252,7 +254,9 @@
"status.sensitive_warning": "محتوى حساس",
"status.share": "مشاركة",
"status.show_less": "إعرض أقلّ",
"status.show_less_all": "طي الكل",
"status.show_more": "أظهر المزيد",
"status.show_more_all": "توسيع الكل",
"status.unmute_conversation": "فك الكتم عن المحادثة",
"status.unpin": "فك التدبيس من الملف الشخصي",
"tabs_bar.federated_timeline": "الموحَّد",

View File

@@ -60,8 +60,10 @@
"compose_form.placeholder": "Какво си мислиш?",
"compose_form.publish": "Раздумай",
"compose_form.publish_loud": "{publish}!",
"compose_form.sensitive": "Отбележи съдържанието като деликатно",
"compose_form.spoiler": "Скрий текста зад предупреждение",
"compose_form.sensitive.marked": "Media is marked as sensitive",
"compose_form.sensitive.unmarked": "Media is not marked as sensitive",
"compose_form.spoiler.marked": "Text is hidden behind warning",
"compose_form.spoiler.unmarked": "Text is not hidden",
"compose_form.spoiler_placeholder": "Content warning",
"confirmation_modal.cancel": "Cancel",
"confirmations.block.confirm": "Block",
@@ -252,7 +254,9 @@
"status.sensitive_warning": "Деликатно съдържание",
"status.share": "Share",
"status.show_less": "Show less",
"status.show_less_all": "Show less for all",
"status.show_more": "Show more",
"status.show_more_all": "Show more for all",
"status.unmute_conversation": "Unmute conversation",
"status.unpin": "Unpin from profile",
"tabs_bar.federated_timeline": "Federated",

View File

@@ -60,8 +60,10 @@
"compose_form.placeholder": "En què estàs pensant?",
"compose_form.publish": "Toot",
"compose_form.publish_loud": "{publish}!",
"compose_form.sensitive": "Marca el contingut multimèdia com a sensible",
"compose_form.spoiler": "Amaga el text darrera darrere un avís",
"compose_form.sensitive.marked": "Media is marked as sensitive",
"compose_form.sensitive.unmarked": "Media is not marked as sensitive",
"compose_form.spoiler.marked": "Text is hidden behind warning",
"compose_form.spoiler.unmarked": "Text is not hidden",
"compose_form.spoiler_placeholder": "Escriu l'avís aquí",
"confirmation_modal.cancel": "Cancel·la",
"confirmations.block.confirm": "Bloca",
@@ -252,7 +254,9 @@
"status.sensitive_warning": "Contingut sensible",
"status.share": "Compartir",
"status.show_less": "Mostra menys",
"status.show_less_all": "Show less for all",
"status.show_more": "Mostra més",
"status.show_more_all": "Show more for all",
"status.unmute_conversation": "Activar conversació",
"status.unpin": "Deslliga del perfil",
"tabs_bar.federated_timeline": "Federada",

View File

@@ -60,8 +60,10 @@
"compose_form.placeholder": "Worüber möchtest du schreiben?",
"compose_form.publish": "Tröt",
"compose_form.publish_loud": "{publish}!",
"compose_form.sensitive": "Medien als heikel markieren",
"compose_form.spoiler": "Text hinter Warnung verbergen",
"compose_form.sensitive.marked": "Media is marked as sensitive",
"compose_form.sensitive.unmarked": "Media is not marked as sensitive",
"compose_form.spoiler.marked": "Text is hidden behind warning",
"compose_form.spoiler.unmarked": "Text is not hidden",
"compose_form.spoiler_placeholder": "Inhaltswarnung",
"confirmation_modal.cancel": "Abbrechen",
"confirmations.block.confirm": "Blockieren",
@@ -252,7 +254,9 @@
"status.sensitive_warning": "Heikle Inhalte",
"status.share": "Teilen",
"status.show_less": "Weniger anzeigen",
"status.show_less_all": "Show less for all",
"status.show_more": "Mehr anzeigen",
"status.show_more_all": "Show more for all",
"status.unmute_conversation": "Stummschaltung von Thread aufheben",
"status.unpin": "Vom Profil lösen",
"tabs_bar.federated_timeline": "Föderation",

View File

@@ -768,8 +768,12 @@
{
"descriptors": [
{
"defaultMessage": "Mark media as sensitive",
"id": "compose_form.sensitive"
"defaultMessage": "Media is marked as sensitive",
"id": "compose_form.sensitive.marked"
},
{
"defaultMessage": "Media is not marked as sensitive",
"id": "compose_form.sensitive.unmarked"
}
],
"path": "app/javascript/mastodon/features/compose/containers/sensitive_button_container.json"
@@ -777,8 +781,12 @@
{
"descriptors": [
{
"defaultMessage": "Hide text behind warning",
"id": "compose_form.spoiler"
"defaultMessage": "Text is hidden behind warning",
"id": "compose_form.spoiler.marked"
},
{
"defaultMessage": "Text is not hidden",
"id": "compose_form.spoiler.unmarked"
}
],
"path": "app/javascript/mastodon/features/compose/containers/spoiler_button_container.json"
@@ -1375,6 +1383,14 @@
"defaultMessage": "Block",
"id": "confirmations.block.confirm"
},
{
"defaultMessage": "Show more for all",
"id": "status.show_more_all"
},
{
"defaultMessage": "Show less for all",
"id": "status.show_less_all"
},
{
"defaultMessage": "Are you sure you want to block {name}?",
"id": "confirmations.block.message"

View File

@@ -60,8 +60,10 @@
"compose_form.placeholder": "What is on your mind?",
"compose_form.publish": "Toot",
"compose_form.publish_loud": "{publish}!",
"compose_form.sensitive": "Mark media as sensitive",
"compose_form.spoiler": "Hide text behind warning",
"compose_form.sensitive.marked": "Media is marked as sensitive",
"compose_form.sensitive.unmarked": "Media is not marked as sensitive",
"compose_form.spoiler.marked": "Text is hidden behind warning",
"compose_form.spoiler.unmarked": "Text is not hidden",
"compose_form.spoiler_placeholder": "Write your warning here",
"confirmation_modal.cancel": "Cancel",
"confirmations.block.confirm": "Block",
@@ -252,7 +254,9 @@
"status.sensitive_warning": "Sensitive content",
"status.share": "Share",
"status.show_less": "Show less",
"status.show_less_all": "Show less for all",
"status.show_more": "Show more",
"status.show_more_all": "Show more for all",
"status.unmute_conversation": "Unmute conversation",
"status.unpin": "Unpin from profile",
"tabs_bar.federated_timeline": "Federated",

View File

@@ -60,8 +60,10 @@
"compose_form.placeholder": "Pri kio vi pensas?",
"compose_form.publish": "Hup",
"compose_form.publish_loud": "{publish}!",
"compose_form.sensitive": "Marki aŭdovidaĵon tikla",
"compose_form.spoiler": "Kaŝi tekston malantaŭ averto",
"compose_form.sensitive.marked": "Media is marked as sensitive",
"compose_form.sensitive.unmarked": "Media is not marked as sensitive",
"compose_form.spoiler.marked": "Text is hidden behind warning",
"compose_form.spoiler.unmarked": "Text is not hidden",
"compose_form.spoiler_placeholder": "Skribu vian averton ĉi tie",
"confirmation_modal.cancel": "Nuligi",
"confirmations.block.confirm": "Bloki",
@@ -252,7 +254,9 @@
"status.sensitive_warning": "Tikla enhavo",
"status.share": "Diskonigi",
"status.show_less": "Malgrandigi",
"status.show_less_all": "Show less for all",
"status.show_more": "Grandigi",
"status.show_more_all": "Show more for all",
"status.unmute_conversation": "Malsilentigi konversacion",
"status.unpin": "Depingli de profilo",
"tabs_bar.federated_timeline": "Fratara tempolinio",

View File

@@ -1,9 +1,9 @@
{
"account.block": "Bloquear",
"account.block_domain": "Ocultar todo de {domain}",
"account.blocked": "Blocked",
"account.blocked": "Bloqueado",
"account.disclaimer_full": "La siguiente información del usuario puede estar incompleta.",
"account.domain_blocked": "Domain hidden",
"account.domain_blocked": "Dominio oculto",
"account.edit_profile": "Editar perfil",
"account.follow": "Seguir",
"account.followers": "Seguidores",
@@ -15,9 +15,9 @@
"account.moved_to": "{name} se ha mudado a:",
"account.mute": "Silenciar a @{name}",
"account.mute_notifications": "Silenciar notificaciones de @{name}",
"account.muted": "Muted",
"account.posts": "Publicaciones",
"account.posts_with_replies": "Toots with replies",
"account.muted": "Silenciado",
"account.posts": "Toots",
"account.posts_with_replies": "Toots con respuestas",
"account.report": "Reportar a @{name}",
"account.requested": "Esperando aprobación",
"account.share": "Compartir el perfil de @{name}",
@@ -54,14 +54,16 @@
"column_header.unpin": "Dejar de fijar",
"column_subheading.navigation": "Navegación",
"column_subheading.settings": "Ajustes",
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
"compose_form.hashtag_warning": "Este toot no se mostrará bajo hashtags porque no es público. Sólo los toots públicos se pueden buscar por hashtag.",
"compose_form.lock_disclaimer": "Tu cuenta no está bloqueada. Todos pueden seguirte para ver tus toots solo para seguidores.",
"compose_form.lock_disclaimer.lock": "bloqueado",
"compose_form.placeholder": "¿En qué estás pensando?",
"compose_form.publish": "Tootear",
"compose_form.publish_loud": "{publish}!",
"compose_form.sensitive": "Marcar contenido como sensible",
"compose_form.spoiler": "Ocultar texto tras una advertencia",
"compose_form.sensitive.marked": "Material marcado como sensible",
"compose_form.sensitive.unmarked": "Material no marcado como sensible",
"compose_form.spoiler.marked": "Texto oculto tras la advertencia",
"compose_form.spoiler.unmarked": "Texto no oculto",
"compose_form.spoiler_placeholder": "Advertencia de contenido",
"confirmation_modal.cancel": "Cancelar",
"confirmations.block.confirm": "Bloquear",
@@ -69,7 +71,7 @@
"confirmations.delete.confirm": "Eliminar",
"confirmations.delete.message": "¿Estás seguro de que quieres borrar este toot?",
"confirmations.delete_list.confirm": "Delete",
"confirmations.delete_list.message": "Are you sure you want to permanently delete this list?",
"confirmations.delete_list.message": "¿Seguro que quieres borrar esta lista permanentemente?",
"confirmations.domain_block.confirm": "Ocultar dominio entero",
"confirmations.domain_block.message": "¿Seguro de que quieres bloquear al dominio entero? En algunos casos es preferible bloquear o silenciar objetivos determinados.",
"confirmations.mute.confirm": "Silenciar",
@@ -132,18 +134,18 @@
"lightbox.close": "Cerrar",
"lightbox.next": "Siguiente",
"lightbox.previous": "Anterior",
"lists.account.add": "Add to list",
"lists.account.remove": "Remove from list",
"lists.account.add": "Añadir a lista",
"lists.account.remove": "Quitar de lista",
"lists.delete": "Delete list",
"lists.edit": "Edit list",
"lists.new.create": "Add list",
"lists.new.title_placeholder": "New list title",
"lists.search": "Search among people you follow",
"lists.subheading": "Your lists",
"lists.edit": "Editar lista",
"lists.new.create": "Añadir lista",
"lists.new.title_placeholder": "Título de la nueva lista",
"lists.search": "Buscar entre la gente a la que sigues",
"lists.subheading": "Tus listas",
"loading_indicator.label": "Cargando…",
"media_gallery.toggle_visible": "Cambiar visibilidad",
"missing_indicator.label": "No encontrado",
"missing_indicator.sublabel": "This resource could not be found",
"missing_indicator.sublabel": "No se encontró este recurso",
"mute_modal.hide_notifications": "Ocultar notificaciones de este usuario?",
"navigation_bar.blocks": "Usuarios bloqueados",
"navigation_bar.community_timeline": "Historia local",
@@ -152,7 +154,7 @@
"navigation_bar.follow_requests": "Solicitudes para seguirte",
"navigation_bar.info": "Información adicional",
"navigation_bar.keyboard_shortcuts": "Atajos de teclado",
"navigation_bar.lists": "Lists",
"navigation_bar.lists": "Listas",
"navigation_bar.logout": "Cerrar sesión",
"navigation_bar.mutes": "Usuarios silenciados",
"navigation_bar.pins": "Toots fijados",
@@ -179,8 +181,8 @@
"onboarding.page_four.home": "La línea de tiempo principal muestra toots de gente que sigues.",
"onboarding.page_four.notifications": "Las notificaciones se muestran cuando alguien interactúa contigo.",
"onboarding.page_one.federation": "Mastodon es una red de servidores federados que conforman una red social aún más grande. Llamamos a estos servidores instancias.",
"onboarding.page_one.full_handle": "Your full handle",
"onboarding.page_one.handle_hint": "This is what you would tell your friends to search for.",
"onboarding.page_one.full_handle": "Tu sobrenombre completo",
"onboarding.page_one.handle_hint": "Esto es lo que dirías a tus amistades que buscaran.",
"onboarding.page_one.welcome": "¡Bienvenido a Mastodon!",
"onboarding.page_six.admin": "El administrador de tu instancia es {admin}.",
"onboarding.page_six.almost_done": "Ya casi…",
@@ -203,28 +205,28 @@
"privacy.public.short": "Público",
"privacy.unlisted.long": "No mostrar en la historia federada",
"privacy.unlisted.short": "Sin federar",
"regeneration_indicator.label": "Loading…",
"regeneration_indicator.sublabel": "Your home feed is being prepared!",
"regeneration_indicator.label": "Cargando…",
"regeneration_indicator.sublabel": "¡Tu historia de inicio se está preparando!",
"relative_time.days": "{number}d",
"relative_time.hours": "{number}h",
"relative_time.just_now": "ahora",
"relative_time.minutes": "{number}m",
"relative_time.seconds": "{number}s",
"reply_indicator.cancel": "Cancelar",
"report.forward": "Forward to {target}",
"report.forward_hint": "The account is from another server. Send an anonymized copy of the report there as well?",
"report.hint": "The report will be sent to your instance moderators. You can provide an explanation of why you are reporting this account below:",
"report.forward": "Reenviar a {target}",
"report.forward_hint": "Esta cuenta es de otro servidor. ¿Enviar una copia anonimizada del informe allí también?",
"report.hint": "El informe se enviará a los moderadores de tu instancia. Puedes proporcionar una explicación de por qué informas sobre esta cuenta a continuación:",
"report.placeholder": "Comentarios adicionales",
"report.submit": "Publicar",
"report.target": "Reportando",
"search.placeholder": "Buscar",
"search_popout.search_format": "Formato de búsqueda avanzada",
"search_popout.tips.full_text": "Simple text returns statuses you have written, favourited, boosted, or have been mentioned in, as well as matching usernames, display names, and hashtags.",
"search_popout.tips.full_text": "Búsquedas de texto recuperan posts que has escrito, marcado como favoritos, retooteado o en los que has sido mencionado, así como usuarios, nombres y hashtags.",
"search_popout.tips.hashtag": "etiqueta",
"search_popout.tips.status": "status",
"search_popout.tips.text": "El texto simple devuelve correspondencias de nombre, usuario y hashtag",
"search_popout.tips.user": "usuario",
"search_results.accounts": "People",
"search_results.accounts": "Gente",
"search_results.hashtags": "Hashtags",
"search_results.statuses": "Toots",
"search_results.total": "{count, number} {count, plural, one {resultado} other {resultados}}",
@@ -238,11 +240,11 @@
"status.media_hidden": "Contenido multimedia oculto",
"status.mention": "Mencionar",
"status.more": "Más",
"status.mute": "Mute @{name}",
"status.mute": "Silenciar @{name}",
"status.mute_conversation": "Silenciar conversación",
"status.open": "Expandir estado",
"status.pin": "Fijar",
"status.pinned": "Pinned toot",
"status.pinned": "Toot fijado",
"status.reblog": "Retootear",
"status.reblogged_by": "Retooteado por {name}",
"status.reply": "Responder",
@@ -252,7 +254,9 @@
"status.sensitive_warning": "Contenido sensible",
"status.share": "Compartir",
"status.show_less": "Mostrar menos",
"status.show_less_all": "Mostrar menos para todo",
"status.show_more": "Mostrar más",
"status.show_more_all": "Mostrar más para todo",
"status.unmute_conversation": "Dejar de silenciar conversación",
"status.unpin": "Dejar de fijar",
"tabs_bar.federated_timeline": "Federado",
@@ -263,7 +267,7 @@
"upload_area.title": "Arrastra y suelta para subir",
"upload_button.label": "Subir multimedia",
"upload_form.description": "Describir para los usuarios con dificultad visual",
"upload_form.focus": "Crop",
"upload_form.focus": "Recortar",
"upload_form.undo": "Deshacer",
"upload_progress.label": "Subiendo…",
"video.close": "Cerrar video",

View File

@@ -60,8 +60,10 @@
"compose_form.placeholder": "تازه چه خبر؟",
"compose_form.publish": "بوق",
"compose_form.publish_loud": "{publish}!",
"compose_form.sensitive": "تصاویر حساس هستند",
"compose_form.spoiler": "نوشته را پشت هشدار پنهان کنید",
"compose_form.sensitive.marked": "Media is marked as sensitive",
"compose_form.sensitive.unmarked": "Media is not marked as sensitive",
"compose_form.spoiler.marked": "Text is hidden behind warning",
"compose_form.spoiler.unmarked": "Text is not hidden",
"compose_form.spoiler_placeholder": "هشدار محتوا",
"confirmation_modal.cancel": "بی‌خیال",
"confirmations.block.confirm": "مسدود کن",
@@ -252,7 +254,9 @@
"status.sensitive_warning": "محتوای حساس",
"status.share": "هم‌رسانی",
"status.show_less": "نهفتن",
"status.show_less_all": "Show less for all",
"status.show_more": "نمایش",
"status.show_more_all": "Show more for all",
"status.unmute_conversation": "باصداکردن گفتگو",
"status.unpin": "برداشتن نوشتهٔ ثابت نمایه",
"tabs_bar.federated_timeline": "همگانی",

View File

@@ -1,9 +1,9 @@
{
"account.block": "Estä @{name}",
"account.block_domain": "Piilota kaikki sisältö verkkotunnuksesta {domain}",
"account.blocked": "Blocked",
"account.blocked": "Estetty",
"account.disclaimer_full": "Alla olevat käyttäjän profiilitiedot saattavat olla epätäydellisiä.",
"account.domain_blocked": "Domain hidden",
"account.domain_blocked": "Verkko-osoite piilotettu",
"account.edit_profile": "Muokkaa",
"account.follow": "Seuraa",
"account.followers": "Seuraajia",
@@ -15,9 +15,9 @@
"account.moved_to": "{name} on muuttanut instanssiin:",
"account.mute": "Mykistä @{name}",
"account.mute_notifications": "Mykistä ilmoitukset käyttäjältä @{name}",
"account.muted": "Muted",
"account.muted": "Mykistetty",
"account.posts": "Töötit",
"account.posts_with_replies": "Toots with replies",
"account.posts_with_replies": "Töötit ja vastaukset",
"account.report": "Report @{name}",
"account.requested": "Odottaa hyväksyntää. Klikkaa peruuttaaksesi seurauspyynnön",
"account.share": "Jaa käyttäjän @{name} profiili",
@@ -60,8 +60,10 @@
"compose_form.placeholder": "Mitä sinulla on mielessä?",
"compose_form.publish": "Toot",
"compose_form.publish_loud": "{publish}!",
"compose_form.sensitive": "Merkitse media herkäksi",
"compose_form.spoiler": "Piiloita teksti varoituksen taakse",
"compose_form.sensitive.marked": "Media on merkitty arkaluontoiseksi",
"compose_form.sensitive.unmarked": "Mediaa ei ole merkitty arkaluontoiseksi",
"compose_form.spoiler.marked": "Teksti on piilotettu varoituksen taakse",
"compose_form.spoiler.unmarked": "Teksti ei ole piilotettu",
"compose_form.spoiler_placeholder": "Content warning",
"confirmation_modal.cancel": "Peruuta",
"confirmations.block.confirm": "Estä",
@@ -180,13 +182,13 @@
"onboarding.page_four.notifications": "Ilmoitukset-sarake näyttää sinulle, kun joku on viestii kanssasi.",
"onboarding.page_one.federation": "Mastodon on yhteisöpalvelu, joka toimii monen itsenäisen palvelimen muodostamassa verkossa. Me kutsumme näitä palvelimia instansseiksi.",
"onboarding.page_one.full_handle": "Koko käyttäjänimesi",
"onboarding.page_one.handle_hint": "This is what you would tell your friends to search for.",
"onboarding.page_one.handle_hint": "Tämä on se, mitä voisit ehdottaa ystäviäsi etsimään.",
"onboarding.page_one.welcome": "Tervetuloa Mastodoniin!",
"onboarding.page_six.admin": "Instanssisi ylläpitäjä on {admin}.",
"onboarding.page_six.almost_done": "Melkein valmista...",
"onboarding.page_six.appetoot": "Bon Appetööt!",
"onboarding.page_six.apps_available": "{apps} on saatavilla iOS:lle, Androidille ja muille alustoille.",
"onboarding.page_six.github": "Mastodon is free open-source software. You can report bugs, request features, or contribute to the code on {github}.",
"onboarding.page_six.github": "Mastodon on ilmainen, vapaan lähdekoodin ohjelma. Voit raportoida bugeja, pyytää ominaisuuksia tai osallistua kehittämiseen GitHub-palvelussa: {github}.",
"onboarding.page_six.guidelines": "yhteisön säännöt",
"onboarding.page_six.read_guidelines": "Ole hyvä ja lue {domain}:n {guidelines}!",
"onboarding.page_six.various_app": "mobiilisovellukset",
@@ -211,22 +213,22 @@
"relative_time.minutes": "{number}m",
"relative_time.seconds": "{number}s",
"reply_indicator.cancel": "Peruuta",
"report.forward": "Forward to {target}",
"report.forward_hint": "The account is from another server. Send an anonymized copy of the report there as well?",
"report.hint": "The report will be sent to your instance moderators. You can provide an explanation of why you are reporting this account below:",
"report.forward": "Uudelleenohjaa kohteeseen {target}",
"report.forward_hint": "Tämä tili on toiselta serveriltä. Haluatko, että myös sinne lähetetään anonymisoitu kopio ilmiantoraportista?",
"report.hint": "Ilmianto lähetetään instanssisi moderaattoreille. Voit antaa kuvauksen käyttäjän ilmiantamisen syystä alle:",
"report.placeholder": "Lisäkommentit",
"report.submit": "Submit",
"report.target": "Reporting",
"search.placeholder": "Hae",
"search_popout.search_format": "Tarkennettu haku",
"search_popout.tips.full_text": "Simple text returns statuses you have written, favourited, boosted, or have been mentioned in, as well as matching usernames, display names, and hashtags.",
"search_popout.tips.full_text": "Tekstihaku palauttaa statuspäivitykset jotka olet kirjoittanut, lisännyt suosikkeihisi, boostannut tai joissa sinut mainitaan, sekä käyttäjänimet, nimimerkit ja hastagit jotka sisältävät tekstin.",
"search_popout.tips.hashtag": "hashtagi",
"search_popout.tips.status": "status",
"search_popout.tips.text": "Pelkkä tekstihaku palauttaa hakua vastaavat nimimerkit, käyttäjänimet ja hastagit",
"search_popout.tips.user": "käyttäjä",
"search_results.accounts": "People",
"search_results.hashtags": "Hashtags",
"search_results.statuses": "Toots",
"search_results.accounts": "Ihmiset",
"search_results.hashtags": "Hashtagit",
"search_results.statuses": "Töötit",
"search_results.total": "{count, number} {count, plural, one {result} other {results}}",
"standalone.public_title": "Kurkistus sisälle...",
"status.block": "Block @{name}",
@@ -242,7 +244,7 @@
"status.mute_conversation": "Mykistä keskustelu",
"status.open": "Laajenna statuspäivitys",
"status.pin": "Kiinnitä profiiliin",
"status.pinned": "Pinned toot",
"status.pinned": "Kiinnitetty töötti",
"status.reblog": "Buustaa",
"status.reblogged_by": "{name} buustasi",
"status.reply": "Vastaa",
@@ -252,10 +254,12 @@
"status.sensitive_warning": "Arkaluontoista sisältöä",
"status.share": "Jaa",
"status.show_less": "Näytä vähemmän",
"status.show_less_all": "Näytä vähemmän kaikista",
"status.show_more": "Näytä lisää",
"status.show_more_all": "Näytä enemmän kaikista",
"status.unmute_conversation": "Poista mykistys keskustelulta",
"status.unpin": "Irrota profiilista",
"tabs_bar.federated_timeline": "Federated",
"tabs_bar.federated_timeline": "Yleinen",
"tabs_bar.home": "Koti",
"tabs_bar.local_timeline": "Paikallinen",
"tabs_bar.notifications": "Ilmoitukset",
@@ -263,7 +267,7 @@
"upload_area.title": "Raahaa ja pudota tähän ladataksesi",
"upload_button.label": "Lisää mediaa",
"upload_form.description": "Anna kuvaus näkörajoitteisia varten",
"upload_form.focus": "Crop",
"upload_form.focus": "Rajaa",
"upload_form.undo": "Peru",
"upload_progress.label": "Ladataan...",
"video.close": "Sulje video",

View File

@@ -60,8 +60,10 @@
"compose_form.placeholder": "Quavez-vous en tête?",
"compose_form.publish": "Pouet",
"compose_form.publish_loud": "{publish}!",
"compose_form.sensitive": "Marquer le média comme sensible",
"compose_form.spoiler": "Masquer le texte derrière un avertissement",
"compose_form.sensitive.marked": "Média marqué comme sensible",
"compose_form.sensitive.unmarked": "Média non marqué comme sensible",
"compose_form.spoiler.marked": "Le texte est caché derrière un avertissement",
"compose_form.spoiler.unmarked": "Le texte n'est pas caché",
"compose_form.spoiler_placeholder": "Écrivez ici votre avertissement",
"confirmation_modal.cancel": "Annuler",
"confirmations.block.confirm": "Bloquer",
@@ -252,7 +254,9 @@
"status.sensitive_warning": "Contenu sensible",
"status.share": "Partager",
"status.show_less": "Replier",
"status.show_less_all": "Tout replier",
"status.show_more": "Déplier",
"status.show_more_all": "Tout déplier",
"status.unmute_conversation": "Ne plus masquer la conversation",
"status.unpin": "Retirer du profil",
"tabs_bar.federated_timeline": "Fil public global",

View File

@@ -60,8 +60,10 @@
"compose_form.placeholder": "A qué andas?",
"compose_form.publish": "Toot",
"compose_form.publish_loud": "{publish}!",
"compose_form.sensitive": "Marcar medios como sensibles",
"compose_form.spoiler": "Agochar texto detrás de un aviso",
"compose_form.sensitive.marked": "Media is marked as sensitive",
"compose_form.sensitive.unmarked": "Media is not marked as sensitive",
"compose_form.spoiler.marked": "Text is hidden behind warning",
"compose_form.spoiler.unmarked": "Text is not hidden",
"compose_form.spoiler_placeholder": "Escriba o aviso aquí",
"confirmation_modal.cancel": "Cancelar",
"confirmations.block.confirm": "Bloquear",
@@ -252,7 +254,9 @@
"status.sensitive_warning": "Contido sensible",
"status.share": "Compartir",
"status.show_less": "Mostrar menos",
"status.show_less_all": "Show less for all",
"status.show_more": "Mostrar máis",
"status.show_more_all": "Show more for all",
"status.unmute_conversation": "Non acalar a conversa",
"status.unpin": "Despegar do perfil",
"tabs_bar.federated_timeline": "Federado",

View File

@@ -60,8 +60,10 @@
"compose_form.placeholder": "מה עובר לך בראש?",
"compose_form.publish": "ללחוש",
"compose_form.publish_loud": "לחצרץ!",
"compose_form.sensitive": "סימון תוכן כרגיש",
"compose_form.spoiler": "הסתרה מאחורי אזהרת תוכן",
"compose_form.sensitive.marked": "Media is marked as sensitive",
"compose_form.sensitive.unmarked": "Media is not marked as sensitive",
"compose_form.spoiler.marked": "Text is hidden behind warning",
"compose_form.spoiler.unmarked": "Text is not hidden",
"compose_form.spoiler_placeholder": "אזהרת תוכן",
"confirmation_modal.cancel": "ביטול",
"confirmations.block.confirm": "לחסום",
@@ -252,7 +254,9 @@
"status.sensitive_warning": "תוכן רגיש",
"status.share": "שיתוף",
"status.show_less": "הראה פחות",
"status.show_less_all": "Show less for all",
"status.show_more": "הראה יותר",
"status.show_more_all": "Show more for all",
"status.unmute_conversation": "הסרת השתקת שיחה",
"status.unpin": "לשחרר מקיבוע באודות",
"tabs_bar.federated_timeline": "ציר זמן בין-קהילתי",

View File

@@ -60,8 +60,10 @@
"compose_form.placeholder": "Što ti je na umu?",
"compose_form.publish": "Toot",
"compose_form.publish_loud": "{publish}!",
"compose_form.sensitive": "Označi media sadržaj kao osjetljiv",
"compose_form.spoiler": "Sakrij text iza upozorenja",
"compose_form.sensitive.marked": "Media is marked as sensitive",
"compose_form.sensitive.unmarked": "Media is not marked as sensitive",
"compose_form.spoiler.marked": "Text is hidden behind warning",
"compose_form.spoiler.unmarked": "Text is not hidden",
"compose_form.spoiler_placeholder": "Upozorenje o sadržaju",
"confirmation_modal.cancel": "Otkaži",
"confirmations.block.confirm": "Blokiraj",
@@ -252,7 +254,9 @@
"status.sensitive_warning": "Osjetljiv sadržaj",
"status.share": "Share",
"status.show_less": "Pokaži manje",
"status.show_less_all": "Show less for all",
"status.show_more": "Pokaži više",
"status.show_more_all": "Show more for all",
"status.unmute_conversation": "Poništi utišavanje razgovora",
"status.unpin": "Unpin from profile",
"tabs_bar.federated_timeline": "Federalni",

View File

@@ -60,8 +60,10 @@
"compose_form.placeholder": "Mire gondolsz?",
"compose_form.publish": "Tülk",
"compose_form.publish_loud": "{publish}!",
"compose_form.sensitive": "Tartalom érzékenynek jelölése",
"compose_form.spoiler": "Szöveg figyelmeztetés mögé rejtése",
"compose_form.sensitive.marked": "Media is marked as sensitive",
"compose_form.sensitive.unmarked": "Media is not marked as sensitive",
"compose_form.spoiler.marked": "Text is hidden behind warning",
"compose_form.spoiler.unmarked": "Text is not hidden",
"compose_form.spoiler_placeholder": "Figyelmeztetését írja ide",
"confirmation_modal.cancel": "Bezár",
"confirmations.block.confirm": "Letilt",
@@ -252,7 +254,9 @@
"status.sensitive_warning": "Érzékeny tartalom",
"status.share": "Megosztás",
"status.show_less": "Kevesebb",
"status.show_less_all": "Show less for all",
"status.show_more": "Többet",
"status.show_more_all": "Show more for all",
"status.unmute_conversation": "Beszélgetés némításának elvonása",
"status.unpin": "Kitűzés eltávolítása a profilról",
"tabs_bar.federated_timeline": "Federált",

View File

@@ -60,8 +60,10 @@
"compose_form.placeholder": "Ի՞նչ կա մտքիդ",
"compose_form.publish": "Թթել",
"compose_form.publish_loud": "Թթե՜լ",
"compose_form.sensitive": "Նշել բովանդակությունը որպես կասկածելի",
"compose_form.spoiler": "Թաքցնել տեքստը նախազգուշացման ետեւում",
"compose_form.sensitive.marked": "Media is marked as sensitive",
"compose_form.sensitive.unmarked": "Media is not marked as sensitive",
"compose_form.spoiler.marked": "Text is hidden behind warning",
"compose_form.spoiler.unmarked": "Text is not hidden",
"compose_form.spoiler_placeholder": "Գրիր նախազգուշացումդ այստեղ",
"confirmation_modal.cancel": "Չեղարկել",
"confirmations.block.confirm": "Արգելափակել",
@@ -252,7 +254,9 @@
"status.sensitive_warning": "Կասկածելի բովանդակություն",
"status.share": "Կիսվել",
"status.show_less": "Պակաս",
"status.show_less_all": "Show less for all",
"status.show_more": "Ավելին",
"status.show_more_all": "Show more for all",
"status.unmute_conversation": "Ապալռեցնել խոսակցությունը",
"status.unpin": "Հանել անձնական էջից",
"tabs_bar.federated_timeline": "Դաշնային",

View File

@@ -1,131 +1,133 @@
{
"account.block": "Blokir @{name}",
"account.block_domain": "Hide everything from {domain}",
"account.blocked": "Blocked",
"account.disclaimer_full": "Information below may reflect the user's profile incompletely.",
"account.domain_blocked": "Domain hidden",
"account.block_domain": "Sembunyikan segalanya dari {domain}",
"account.blocked": "Terblokir",
"account.disclaimer_full": "Informasi di bawah mungkin tidak mencerminkan profil user secara lengkap.",
"account.domain_blocked": "Domain disembunyikan",
"account.edit_profile": "Ubah profil",
"account.follow": "Ikuti",
"account.followers": "Pengikut",
"account.follows": "Mengikuti",
"account.follows_you": "Mengikuti anda",
"account.hide_reblogs": "Hide boosts from @{name}",
"account.hide_reblogs": "Sembunyikan boosts dari @{name}",
"account.media": "Media",
"account.mention": "Balasan @{name}",
"account.moved_to": "{name} has moved to:",
"account.moved_to": "{name} telah pindah ke:",
"account.mute": "Bisukan @{name}",
"account.mute_notifications": "Mute notifications from @{name}",
"account.muted": "Muted",
"account.posts": "Postingan",
"account.posts_with_replies": "Toots with replies",
"account.mute_notifications": "Sembunyikan notifikasi dari @{name}",
"account.muted": "Dibisukan",
"account.posts": "Toots",
"account.posts_with_replies": "Postingan dengan balasan",
"account.report": "Laporkan @{name}",
"account.requested": "Menunggu persetujuan",
"account.share": "Share @{name}'s profile",
"account.show_reblogs": "Show boosts from @{name}",
"account.requested": "Menunggu persetujuan. Klik untuk membatalkan permintaan",
"account.share": "Bagikan profil @{name}",
"account.show_reblogs": "Tampilkan boost dari @{name}",
"account.unblock": "Hapus blokir @{name}",
"account.unblock_domain": "Unhide {domain}",
"account.unblock_domain": "Tampilkan {domain}",
"account.unfollow": "Berhenti mengikuti",
"account.unmute": "Berhenti membisukan @{name}",
"account.unmute_notifications": "Unmute notifications from @{name}",
"account.view_full_profile": "View full profile",
"account.unmute_notifications": "Munculkan notifikasi dari @{name}",
"account.view_full_profile": "Lihat profil lengkap",
"boost_modal.combo": "Anda dapat menekan {combo} untuk melewati ini",
"bundle_column_error.body": "Something went wrong while loading this component.",
"bundle_column_error.retry": "Try again",
"bundle_column_error.body": "Kesalahan terjadi saat memuat komponen ini.",
"bundle_column_error.retry": "Coba lagi",
"bundle_column_error.title": "Network error",
"bundle_modal_error.close": "Close",
"bundle_modal_error.message": "Something went wrong while loading this component.",
"bundle_modal_error.retry": "Try again",
"bundle_modal_error.close": "Tutup",
"bundle_modal_error.message": "Kesalahan terjadi saat memuat komponen ini.",
"bundle_modal_error.retry": "Coba lagi",
"column.blocks": "Pengguna diblokir",
"column.community": "Linimasa Lokal",
"column.favourites": "Favorit",
"column.follow_requests": "Permintaan mengikuti",
"column.home": "Beranda",
"column.lists": "Lists",
"column.mutes": "Pengguna dibisukan",
"column.lists": "List",
"column.mutes": "Pengguna yang dibisukan",
"column.notifications": "Notifikasi",
"column.pins": "Pinned toot",
"column.public": "Linimasa gabunggan",
"column.public": "Linimasa gabungan",
"column_back_button.label": "Kembali",
"column_header.hide_settings": "Hide settings",
"column_header.moveLeft_settings": "Move column to the left",
"column_header.moveRight_settings": "Move column to the right",
"column_header.pin": "Pin",
"column_header.show_settings": "Show settings",
"column_header.unpin": "Unpin",
"column_header.hide_settings": "Sembunyikan pengaturan",
"column_header.moveLeft_settings": "Pindahkan kolom ke kiri",
"column_header.moveRight_settings": "Pindahkan kolom ke kanan",
"column_header.pin": "Sematkan",
"column_header.show_settings": "Tampilkan pengaturan",
"column_header.unpin": "Lepaskan",
"column_subheading.navigation": "Navigasi",
"column_subheading.settings": "Pengaturan",
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
"compose_form.hashtag_warning": "Toot ini tidak akan ada dalam daftar tagar manapun karena telah di set sebagai tidak terdaftar. Hanya postingan publik yang bisa dicari dengan tagar.",
"compose_form.lock_disclaimer": "Akun anda tidak {locked}. Semua orang dapat mengikuti anda untuk melihat postingan khusus untuk pengikut anda.",
"compose_form.lock_disclaimer.lock": "dikunci",
"compose_form.lock_disclaimer.lock": "terkunci",
"compose_form.placeholder": "Apa yang ada di pikiran anda?",
"compose_form.publish": "Toot",
"compose_form.publish_loud": "{publish}!",
"compose_form.sensitive": "Tandai media sensitif",
"compose_form.spoiler": "Sembunyikan teks dibalik peringatan",
"compose_form.sensitive.marked": "Sumber ini telah ditandai sebagai sumber sensitif.",
"compose_form.sensitive.unmarked": "Sumber ini tidak ditandai sebagai sumber sensitif",
"compose_form.spoiler.marked": "Teks disembunyikan dibalik peringatan",
"compose_form.spoiler.unmarked": "Teks tidak tersembunyi",
"compose_form.spoiler_placeholder": "Peringatan konten",
"confirmation_modal.cancel": "Batal",
"confirmations.block.confirm": "Blokir",
"confirmations.block.message": "Apa anda yakin ingin memblokir {name}?",
"confirmations.delete.confirm": "Hapus",
"confirmations.delete.message": "Apa anda yakin akan menghapus status ini?",
"confirmations.delete.message": "Apa anda yakin untuk menghapus status ini?",
"confirmations.delete_list.confirm": "Delete",
"confirmations.delete_list.message": "Are you sure you want to permanently delete this list?",
"confirmations.domain_block.confirm": "Hide entire domain",
"confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.",
"confirmations.delete_list.message": "Apakah anda yakin untuk menghapus daftar ini secara permanen?",
"confirmations.domain_block.confirm": "Sembunyikan keseluruhan domain",
"confirmations.domain_block.message": "Apakah anda benar benar yakin untuk memblokir keseluruhan {domain}? Dalam kasus tertentu beberapa pemblokiran atau penyembunyian lebih baik.",
"confirmations.mute.confirm": "Bisukan",
"confirmations.mute.message": "Apa anda yakin ingin membisukan {name}?",
"confirmations.unfollow.confirm": "Unfollow",
"confirmations.unfollow.message": "Are you sure you want to unfollow {name}?",
"embed.instructions": "Embed this status on your website by copying the code below.",
"embed.preview": "Here is what it will look like:",
"confirmations.unfollow.confirm": "Berhenti mengikuti",
"confirmations.unfollow.message": "Apakah anda ingin berhenti mengikuti {name}?",
"embed.instructions": "Sematkan status ini di website anda dengan menyalin kode di bawah ini.",
"embed.preview": "Seperti ini nantinya:",
"emoji_button.activity": "Aktivitas",
"emoji_button.custom": "Custom",
"emoji_button.custom": "Kustom",
"emoji_button.flags": "Bendera",
"emoji_button.food": "Makanan & Minuman",
"emoji_button.label": "Tambahkan emoji",
"emoji_button.nature": "Alam",
"emoji_button.not_found": "No emojos!! (╯°□°)╯︵ ┻━┻",
"emoji_button.not_found": "Katakan tidak pada emoji!! (╯°□°)╯︵ ┻━┻",
"emoji_button.objects": "Benda-benda",
"emoji_button.people": "Orang",
"emoji_button.recent": "Frequently used",
"emoji_button.recent": "Yang sering digunakan",
"emoji_button.search": "Cari...",
"emoji_button.search_results": "Search results",
"emoji_button.search_results": "Hasil pencarian",
"emoji_button.symbols": "Simbol",
"emoji_button.travel": "Tempat Wisata",
"empty_column.community": "Linimasa lokal masih kosong. Tulis sesuatu secara publik dan buat roda berputar!",
"empty_column.hashtag": "Tidak ada apapun dalam hashtag ini.",
"empty_column.home": "Anda sedang tidak mengikuti siapapun. Kunjungi {public} atau gunakan pencarian untuk memulai dan bertemu pengguna lain.",
"empty_column.home": "Linimasa anda kosong! Kunjungi {public} atau gunakan pencarian untuk memulai dan bertemu pengguna lain.",
"empty_column.home.public_timeline": "linimasa publik",
"empty_column.list": "There is nothing in this list yet.",
"empty_column.list": "Tidak ada postingan di list ini. Ketika anggota dari list ini memposting status baru, status tersebut akan tampil disini.",
"empty_column.notifications": "Anda tidak memiliki notifikasi apapun. Berinteraksi dengan orang lain untuk memulai percakapan.",
"empty_column.public": "Tidak ada apapun disini! Tulis sesuatu, atau ikuti pengguna lain dari server lain untuk mengisinya secara manual",
"empty_column.public": "Tidak ada apapun disini! Tulis sesuatu, atau ikuti pengguna lain dari server lain untuk mengisi ini",
"follow_request.authorize": "Izinkan",
"follow_request.reject": "Tolak",
"getting_started.appsshort": "Apps",
"getting_started.appsshort": "Aplikasi",
"getting_started.faq": "FAQ",
"getting_started.heading": "Mulai",
"getting_started.open_source_notice": "Mastodon adalah perangkat lunak yang bersifat open source. Anda dapat berkontribusi atau melaporkan permasalahan/bug di Github {github}.",
"getting_started.userguide": "User Guide",
"getting_started.open_source_notice": "Mastodon adalah perangkat lunak yang bersifat terbuka. Anda dapat berkontribusi atau melaporkan permasalahan/bug di Github {github}.",
"getting_started.userguide": "Panduan Pengguna",
"home.column_settings.advanced": "Tingkat Lanjut",
"home.column_settings.basic": "Dasar",
"home.column_settings.filter_regex": "Penyaringan dengan Regular Expression",
"home.column_settings.show_reblogs": "Tampilkan Boost",
"home.column_settings.filter_regex": "Saring dengan regular expressions",
"home.column_settings.show_reblogs": "Tampilkan boost",
"home.column_settings.show_replies": "Tampilkan balasan",
"home.settings": "Pengaturan kolom",
"keyboard_shortcuts.back": "to navigate back",
"keyboard_shortcuts.boost": "to boost",
"keyboard_shortcuts.column": "to focus a status in one of the columns",
"keyboard_shortcuts.compose": "to focus the compose textarea",
"keyboard_shortcuts.description": "Description",
"keyboard_shortcuts.down": "to move down in the list",
"keyboard_shortcuts.enter": "to open status",
"keyboard_shortcuts.favourite": "to favourite",
"keyboard_shortcuts.heading": "Keyboard Shortcuts",
"keyboard_shortcuts.back": "untuk kembali",
"keyboard_shortcuts.boost": "untuk menyebarkan",
"keyboard_shortcuts.column": "untuk fokus kepada sebuah status di sebuah kolom",
"keyboard_shortcuts.compose": "untuk fokus ke area penulisan",
"keyboard_shortcuts.description": "Deskripsi",
"keyboard_shortcuts.down": "untuk pindah ke bawah dalam sebuah daftar",
"keyboard_shortcuts.enter": "untuk membuka status",
"keyboard_shortcuts.favourite": "untuk memfavoritkan",
"keyboard_shortcuts.heading": "Pintasan keyboard",
"keyboard_shortcuts.hotkey": "Hotkey",
"keyboard_shortcuts.legend": "to display this legend",
"keyboard_shortcuts.mention": "to mention author",
"keyboard_shortcuts.reply": "to reply",
"keyboard_shortcuts.search": "to focus search",
"keyboard_shortcuts.search": "untuk fokus mencari",
"keyboard_shortcuts.toot": "to start a brand new toot",
"keyboard_shortcuts.unfocus": "to un-focus compose textarea/search",
"keyboard_shortcuts.up": "to move up in the list",
@@ -197,14 +199,14 @@
"privacy.change": "Tentukan privasi status",
"privacy.direct.long": "Kirim hanya ke pengguna yang disebut",
"privacy.direct.short": "Langsung",
"privacy.private.long": "Kirim hanya ke pengikut",
"privacy.private.long": "Kirim postingan hanya kepada pengikut",
"privacy.private.short": "Pribadi",
"privacy.public.long": "Kirim ke linimasa publik",
"privacy.public.short": "Publik",
"privacy.unlisted.long": "Tidak ditampilkan di linimasa publik",
"privacy.unlisted.short": "Tak Terdaftar",
"regeneration_indicator.label": "Loading…",
"regeneration_indicator.sublabel": "Your home feed is being prepared!",
"regeneration_indicator.sublabel": "Linimasa anda sedang disiapkan!",
"relative_time.days": "{number}d",
"relative_time.hours": "{number}h",
"relative_time.just_now": "now",
@@ -220,14 +222,14 @@
"search.placeholder": "Pencarian",
"search_popout.search_format": "Advanced search format",
"search_popout.tips.full_text": "Simple text returns statuses you have written, favourited, boosted, or have been mentioned in, as well as matching usernames, display names, and hashtags.",
"search_popout.tips.hashtag": "hashtag",
"search_popout.tips.hashtag": "tagar",
"search_popout.tips.status": "status",
"search_popout.tips.text": "Simple text returns matching display names, usernames and hashtags",
"search_popout.tips.user": "user",
"search_results.accounts": "People",
"search_results.hashtags": "Hashtags",
"search_results.statuses": "Toots",
"search_results.total": "{count} {count, plural, one {hasil} other {hasil}}",
"search_results.total": "{count, number} {count, plural, one {hasil} other {hasil}}",
"standalone.public_title": "A look inside...",
"status.block": "Block @{name}",
"status.cannot_reblog": "This post cannot be boosted",
@@ -252,23 +254,25 @@
"status.sensitive_warning": "Konten sensitif",
"status.share": "Share",
"status.show_less": "Tampilkan lebih sedikit",
"status.show_less_all": "Show less for all",
"status.show_more": "Tampilkan semua",
"status.show_more_all": "Show more for all",
"status.unmute_conversation": "Unmute conversation",
"status.unpin": "Unpin from profile",
"tabs_bar.federated_timeline": "Gabungan",
"tabs_bar.home": "Beranda",
"tabs_bar.local_timeline": "Lokal",
"tabs_bar.notifications": "Notifikasi",
"ui.beforeunload": "Your draft will be lost if you leave Mastodon.",
"ui.beforeunload": "Naskah anda akan hilang jika anda keluar dari Mastodon.",
"upload_area.title": "Seret & lepaskan untuk mengunggah",
"upload_button.label": "Tambahkan media",
"upload_form.description": "Describe for the visually impaired",
"upload_form.focus": "Crop",
"upload_form.description": "Deskripsikan untuk mereka yang tidak bisa melihat dengan jelas",
"upload_form.focus": "Potong",
"upload_form.undo": "Undo",
"upload_progress.label": "Mengunggah...",
"video.close": "Close video",
"video.exit_fullscreen": "Exit full screen",
"video.expand": "Expand video",
"video.exit_fullscreen": "Keluar dari layar penuh",
"video.expand": "Perbesar video",
"video.fullscreen": "Full screen",
"video.hide": "Hide video",
"video.mute": "Mute sound",

View File

@@ -60,8 +60,10 @@
"compose_form.placeholder": "Quo esas en tua spirito?",
"compose_form.publish": "Siflar",
"compose_form.publish_loud": "{publish}!",
"compose_form.sensitive": "Markizar kontenajo kom trubliva",
"compose_form.spoiler": "Celar texto dop averto",
"compose_form.sensitive.marked": "Media is marked as sensitive",
"compose_form.sensitive.unmarked": "Media is not marked as sensitive",
"compose_form.spoiler.marked": "Text is hidden behind warning",
"compose_form.spoiler.unmarked": "Text is not hidden",
"compose_form.spoiler_placeholder": "Averto di kontenajo",
"confirmation_modal.cancel": "Cancel",
"confirmations.block.confirm": "Block",
@@ -252,7 +254,9 @@
"status.sensitive_warning": "Trubliva kontenajo",
"status.share": "Share",
"status.show_less": "Montrar mine",
"status.show_less_all": "Show less for all",
"status.show_more": "Montrar plue",
"status.show_more_all": "Show more for all",
"status.unmute_conversation": "Unmute conversation",
"status.unpin": "Unpin from profile",
"tabs_bar.federated_timeline": "Federata",

View File

@@ -60,8 +60,10 @@
"compose_form.placeholder": "A cosa stai pensando?",
"compose_form.publish": "Toot",
"compose_form.publish_loud": "{publish}!",
"compose_form.sensitive": "Segnala file come sensibile",
"compose_form.spoiler": "Nascondi testo con avvertimento",
"compose_form.sensitive.marked": "Media is marked as sensitive",
"compose_form.sensitive.unmarked": "Media is not marked as sensitive",
"compose_form.spoiler.marked": "Text is hidden behind warning",
"compose_form.spoiler.unmarked": "Text is not hidden",
"compose_form.spoiler_placeholder": "Content warning",
"confirmation_modal.cancel": "Cancel",
"confirmations.block.confirm": "Block",
@@ -252,7 +254,9 @@
"status.sensitive_warning": "Materiale sensibile",
"status.share": "Share",
"status.show_less": "Mostra meno",
"status.show_less_all": "Show less for all",
"status.show_more": "Mostra di più",
"status.show_more_all": "Show more for all",
"status.unmute_conversation": "Unmute conversation",
"status.unpin": "Unpin from profile",
"tabs_bar.federated_timeline": "Federazione",

View File

@@ -3,7 +3,7 @@
"account.block_domain": "{domain}全体を非表示",
"account.blocked": "ブロック済み",
"account.disclaimer_full": "以下の情報は不正確な可能性があります。",
"account.domain_blocked": "Domain hidden",
"account.domain_blocked": "ドメイン非表示中",
"account.edit_profile": "プロフィールを編集",
"account.follow": "フォロー",
"account.followers": "フォロワー",
@@ -60,8 +60,10 @@
"compose_form.placeholder": "今なにしてる?",
"compose_form.publish": "トゥート",
"compose_form.publish_loud": "{publish}",
"compose_form.sensitive": "メディア閲覧注意としてマークする",
"compose_form.spoiler": "テキストを隠す",
"compose_form.sensitive.marked": "メディア閲覧注意が設定されています",
"compose_form.sensitive.unmarked": "メディアに閲覧注意が設定されていません",
"compose_form.spoiler.marked": "閲覧注意が設定されています",
"compose_form.spoiler.unmarked": "閲覧注意が設定されていません",
"compose_form.spoiler_placeholder": "ここに警告を書いてください",
"confirmation_modal.cancel": "キャンセル",
"confirmations.block.confirm": "ブロック",
@@ -252,7 +254,9 @@
"status.sensitive_warning": "閲覧注意",
"status.share": "共有",
"status.show_less": "隠す",
"status.show_less_all": "全て隠す",
"status.show_more": "もっと見る",
"status.show_more_all": "全て見る",
"status.unmute_conversation": "会話のミュートを解除",
"status.unpin": "プロフィールの固定表示を解除",
"tabs_bar.federated_timeline": "連合",

View File

@@ -60,8 +60,10 @@
"compose_form.placeholder": "지금 무엇을 하고 있나요?",
"compose_form.publish": "툿",
"compose_form.publish_loud": "{publish}!",
"compose_form.sensitive": "이 미디어를 민감한 미디어로 취급",
"compose_form.spoiler": "텍스트 숨기기",
"compose_form.sensitive.marked": "Media is marked as sensitive",
"compose_form.sensitive.unmarked": "Media is not marked as sensitive",
"compose_form.spoiler.marked": "Text is hidden behind warning",
"compose_form.spoiler.unmarked": "Text is not hidden",
"compose_form.spoiler_placeholder": "경고",
"confirmation_modal.cancel": "취소",
"confirmations.block.confirm": "차단",
@@ -252,7 +254,9 @@
"status.sensitive_warning": "민감한 미디어",
"status.share": "공유",
"status.show_less": "숨기기",
"status.show_less_all": "Show less for all",
"status.show_more": "더 보기",
"status.show_more_all": "Show more for all",
"status.unmute_conversation": "이 대화의 뮤트 해제하기",
"status.unpin": "고정 해제",
"tabs_bar.federated_timeline": "연합",

View File

@@ -60,8 +60,10 @@
"compose_form.placeholder": "Wat wil je kwijt?",
"compose_form.publish": "Toot",
"compose_form.publish_loud": "{publish}!",
"compose_form.sensitive": "Media als gevoelig markeren (nsfw)",
"compose_form.spoiler": "Tekst achter waarschuwing verbergen",
"compose_form.sensitive.marked": "Media is als gevoelig gemarkeerd",
"compose_form.sensitive.unmarked": "Media is niet als gevoelig gemarkeerd",
"compose_form.spoiler.marked": "Tekst is achter een waarschuwing verborgen",
"compose_form.spoiler.unmarked": "Tekst is niet verborgen",
"compose_form.spoiler_placeholder": "Waarschuwingstekst",
"confirmation_modal.cancel": "Annuleren",
"confirmations.block.confirm": "Blokkeren",
@@ -219,7 +221,7 @@
"report.target": "Rapporteer {target}",
"search.placeholder": "Zoeken",
"search_popout.search_format": "Geavanceerd zoeken",
"search_popout.tips.full_text": "Gebruik gewone tekst om te zoeken naar toots die jij hebt geschreven, als favoriet markeerde, hebt geboost of waarin jij bent vermeldt, en ook om te zoeken naar gebruikersnamen, weergavenamen en hashtags.",
"search_popout.tips.full_text": "Gebruik gewone tekst om te zoeken naar jouw toots, gebooste toots, favorieten en naar toots waarin jij bent vermeldt, en naar gebruikersnamen, weergavenamen en hashtags.",
"search_popout.tips.hashtag": "hashtag",
"search_popout.tips.status": "toot",
"search_popout.tips.text": "Gebruik gewone tekst om te zoeken op weergavenamen, gebruikersnamen en hashtags",
@@ -252,7 +254,9 @@
"status.sensitive_warning": "Gevoelige inhoud",
"status.share": "Delen",
"status.show_less": "Minder tonen",
"status.show_less_all": "Alles minder tonen",
"status.show_more": "Meer tonen",
"status.show_more_all": "Alles meer tonen",
"status.unmute_conversation": "Conversatie niet meer negeren",
"status.unpin": "Van profielpagina losmaken",
"tabs_bar.federated_timeline": "Globaal",

View File

@@ -60,8 +60,10 @@
"compose_form.placeholder": "Hva har du på hjertet?",
"compose_form.publish": "Tut",
"compose_form.publish_loud": "{publish}!",
"compose_form.sensitive": "Merk media som følsomt",
"compose_form.spoiler": "Skjul tekst bak advarsel",
"compose_form.sensitive.marked": "Media is marked as sensitive",
"compose_form.sensitive.unmarked": "Media is not marked as sensitive",
"compose_form.spoiler.marked": "Text is hidden behind warning",
"compose_form.spoiler.unmarked": "Text is not hidden",
"compose_form.spoiler_placeholder": "Innholdsadvarsel",
"confirmation_modal.cancel": "Avbryt",
"confirmations.block.confirm": "Blokkèr",
@@ -252,7 +254,9 @@
"status.sensitive_warning": "Følsomt innhold",
"status.share": "Del",
"status.show_less": "Vis mindre",
"status.show_less_all": "Show less for all",
"status.show_more": "Vis mer",
"status.show_more_all": "Show more for all",
"status.unmute_conversation": "Ikke demp samtale",
"status.unpin": "Angre festing på profilen",
"tabs_bar.federated_timeline": "Felles",

View File

@@ -60,8 +60,10 @@
"compose_form.placeholder": "A de qué pensatz?",
"compose_form.publish": "Tut",
"compose_form.publish_loud": "{publish}!",
"compose_form.sensitive": "Marcar lo mèdia coma sensible",
"compose_form.spoiler": "Rescondre lo tèxte darrièr un avertiment",
"compose_form.sensitive.marked": "Media is marked as sensitive",
"compose_form.sensitive.unmarked": "Media is not marked as sensitive",
"compose_form.spoiler.marked": "Text is hidden behind warning",
"compose_form.spoiler.unmarked": "Text is not hidden",
"compose_form.spoiler_placeholder": "Escrivètz lavertiment aquí",
"confirmation_modal.cancel": "Anullar",
"confirmations.block.confirm": "Blocar",
@@ -252,7 +254,9 @@
"status.sensitive_warning": "Contengut sensible",
"status.share": "Partejar",
"status.show_less": "Tornar plegar",
"status.show_less_all": "Show less for all",
"status.show_more": "Desplegar",
"status.show_more_all": "Show more for all",
"status.unmute_conversation": "Tornar mostrar la conversacion",
"status.unpin": "Tirar del perfil",
"tabs_bar.federated_timeline": "Flux public global",

View File

@@ -3,7 +3,7 @@
"account.block_domain": "Blokuj wszystko z {domain}",
"account.blocked": "Zablokowany",
"account.disclaimer_full": "Poniższe informacje mogą nie odwzorowywać bezbłędnie profilu użytkownika.",
"account.domain_blocked": "Domain hidden",
"account.domain_blocked": "Ukryto domenę",
"account.edit_profile": "Edytuj profil",
"account.follow": "Śledź",
"account.followers": "Śledzący",
@@ -60,8 +60,10 @@
"compose_form.placeholder": "Co Ci chodzi po głowie?",
"compose_form.publish": "Wyślij",
"compose_form.publish_loud": "{publish}!",
"compose_form.sensitive": "Oznacz treści jako wrażliwe",
"compose_form.spoiler": "Ukryj tekst za ostrzeżeniem",
"compose_form.sensitive.marked": "Zawartość multimedia jest oznaczona jako wrażliwa",
"compose_form.sensitive.unmarked": "Zawartość multimedialna nie jest oznaczona jako wrażliwa",
"compose_form.spoiler.marked": "Tekst jest ukryty za ostrzeżeniem",
"compose_form.spoiler.unmarked": "Tekst nie jest ukryty",
"compose_form.spoiler_placeholder": "Wprowadź swoje ostrzeżenie o zawartości",
"confirmation_modal.cancel": "Anuluj",
"confirmations.block.confirm": "Zablokuj",
@@ -219,7 +221,7 @@
"report.target": "Zgłaszanie {target}",
"search.placeholder": "Szukaj",
"search_popout.search_format": "Zaawansowane wyszukiwanie",
"search_popout.tips.full_text": "Simple text returns statuses you have written, favourited, boosted, or have been mentioned in, as well as matching usernames, display names, and hashtags.",
"search_popout.tips.full_text": "Pozwala na wyszukiwanie wpisów które napisałeś, dodałeś do ulubionych, podbiłeś w których o Tobie wspomniano, oraz pasujące nazwy użytkowników, pełne nazwy i hashtagi.",
"search_popout.tips.hashtag": "hashtag",
"search_popout.tips.status": "wpis",
"search_popout.tips.text": "Proste wyszukiwanie pasujących pseudonimów, nazw użytkowników i hashtagów",
@@ -251,8 +253,10 @@
"status.sensitive_toggle": "Naciśnij aby wyświetlić",
"status.sensitive_warning": "Wrażliwa zawartość",
"status.share": "Udostępnij",
"status.show_less": "Pokaż mniej",
"status.show_more": "Pokaż więcej",
"status.show_less": "Zwiń",
"status.show_less_all": "Zwiń wszystkie",
"status.show_more": "Rozwiń",
"status.show_more_all": "Rozwiń wszystkie",
"status.unmute_conversation": "Cofnij wyciszenie konwersacji",
"status.unpin": "Odepnij z profilu",
"tabs_bar.federated_timeline": "Globalne",
@@ -263,7 +267,7 @@
"upload_area.title": "Przeciągnij i upuść aby wysłać",
"upload_button.label": "Dodaj zawartość multimedialną",
"upload_form.description": "Wprowadź opis dla niewidomych i niedowidzących",
"upload_form.focus": "Crop",
"upload_form.focus": "Przytnij",
"upload_form.undo": "Cofnij",
"upload_progress.label": "Wysyłanie",
"video.close": "Zamknij film",

View File

@@ -60,8 +60,10 @@
"compose_form.placeholder": "No que você está pensando?",
"compose_form.publish": "Publicar",
"compose_form.publish_loud": "{publish}!",
"compose_form.sensitive": "Marcar mídia como conteúdo sensível",
"compose_form.spoiler": "Esconder texto com aviso de conteúdo",
"compose_form.sensitive.marked": "Mídia está marcada como sensível",
"compose_form.sensitive.unmarked": "Mídia não está marcada como sensível",
"compose_form.spoiler.marked": "O texto está escondido por um aviso de conteúdo",
"compose_form.spoiler.unmarked": "O texto não está escondido",
"compose_form.spoiler_placeholder": "Aviso de conteúdo",
"confirmation_modal.cancel": "Cancelar",
"confirmations.block.confirm": "Bloquear",
@@ -252,7 +254,9 @@
"status.sensitive_warning": "Conteúdo sensível",
"status.share": "Compartilhar",
"status.show_less": "Mostrar menos",
"status.show_less_all": "Mostrar menos para todas as mensagens",
"status.show_more": "Mostrar mais",
"status.show_more_all": "Mostrar mais para todas as mensagens",
"status.unmute_conversation": "Desativar silêncio desta conversa",
"status.unpin": "Desafixar do perfil",
"tabs_bar.federated_timeline": "Global",

View File

@@ -60,8 +60,10 @@
"compose_form.placeholder": "Em que estás a pensar?",
"compose_form.publish": "Publicar",
"compose_form.publish_loud": "{publish}!",
"compose_form.sensitive": "Marcar media como conteúdo sensível",
"compose_form.spoiler": "Esconder texto com aviso",
"compose_form.sensitive.marked": "Media is marked as sensitive",
"compose_form.sensitive.unmarked": "Media is not marked as sensitive",
"compose_form.spoiler.marked": "Text is hidden behind warning",
"compose_form.spoiler.unmarked": "Text is not hidden",
"compose_form.spoiler_placeholder": "Aviso de conteúdo",
"confirmation_modal.cancel": "Cancelar",
"confirmations.block.confirm": "Block",
@@ -252,7 +254,9 @@
"status.sensitive_warning": "Conteúdo sensível",
"status.share": "Compartilhar",
"status.show_less": "Mostrar menos",
"status.show_less_all": "Show less for all",
"status.show_more": "Mostrar mais",
"status.show_more_all": "Show more for all",
"status.unmute_conversation": "Deixar de silenciar esta conversa",
"status.unpin": "Não fixar no perfil",
"tabs_bar.federated_timeline": "Global",

View File

@@ -60,8 +60,10 @@
"compose_form.placeholder": "О чем Вы думаете?",
"compose_form.publish": "Трубить",
"compose_form.publish_loud": "{publish}!",
"compose_form.sensitive": "Отметить как чувствительный контент",
"compose_form.spoiler": "Скрыть текст за предупреждением",
"compose_form.sensitive.marked": "Media is marked as sensitive",
"compose_form.sensitive.unmarked": "Media is not marked as sensitive",
"compose_form.spoiler.marked": "Text is hidden behind warning",
"compose_form.spoiler.unmarked": "Text is not hidden",
"compose_form.spoiler_placeholder": "Напишите свое предупреждение здесь",
"confirmation_modal.cancel": "Отмена",
"confirmations.block.confirm": "Заблокировать",
@@ -252,7 +254,9 @@
"status.sensitive_warning": "Чувствительный контент",
"status.share": "Поделиться",
"status.show_less": "Свернуть",
"status.show_less_all": "Show less for all",
"status.show_more": "Развернуть",
"status.show_more_all": "Show more for all",
"status.unmute_conversation": "Снять глушение с треда",
"status.unpin": "Открепить от профиля",
"tabs_bar.federated_timeline": "Глобальная",

View File

@@ -18,7 +18,7 @@
"account.muted": "Utíšený/á",
"account.posts": "Hlášky",
"account.posts_with_replies": "Príspevky s odpoveďami",
"account.report": "Nahlás @{name}",
"account.report": "Nahlás @{name}",
"account.requested": "Čaká na schválenie. Kliknite pre zrušenie žiadosti",
"account.share": "Zdieľať @{name} profil",
"account.show_reblogs": "Zobraziť povýšenia od @{name}",
@@ -35,13 +35,13 @@
"bundle_modal_error.close": "Zatvoriť",
"bundle_modal_error.message": "Nastala chyba pri načítaní tohto komponentu.",
"bundle_modal_error.retry": "Skúsiť znova",
"column.blocks": "Blokovaní používatelia",
"column.blocks": "Blokovaní užívatelia",
"column.community": "Lokálna časová os",
"column.favourites": "Obľúbené",
"column.follow_requests": "Žiadosti o sledovaní",
"column.home": "Domov",
"column.lists": "Zoznamy",
"column.mutes": "Ignorovaní používatelia",
"column.mutes": "Ignorovaní užívatelia",
"column.notifications": "Notifikácie",
"column.pins": "Pripnuté toots",
"column.public": "Federovaná časová os",
@@ -50,18 +50,20 @@
"column_header.moveLeft_settings": "Presunúť stĺpec doľava",
"column_header.moveRight_settings": "Presunúť stĺpec doprava",
"column_header.pin": "Pripnúť",
"column_header.show_settings": "Ukázať nastavenia",
"column_header.show_settings": "Ukáž nastavenia",
"column_header.unpin": "Odopnúť",
"column_subheading.navigation": "Navigácia",
"column_subheading.settings": "Nastavenia",
"compose_form.hashtag_warning": "Tento toot nebude zobrazený pod žiadným haštagom lebo nieje listovaný. Iba verejné toots môžu byť nájdené podľa haštagu.",
"compose_form.hashtag_warning": "Tento toot nebude zobrazený pod žiadným haštagom lebo nieje listovaný. Iba verejné tooty môžu byť nájdené podľa haštagu.",
"compose_form.lock_disclaimer": "Váš účet nie je zamknutý. Ktokoľvek ťa môže nasledovať a vidieť tvoje správy pre sledujúcich.",
"compose_form.lock_disclaimer.lock": "zamknutý",
"compose_form.placeholder": "Na čo myslíš?",
"compose_form.publish": "Toot",
"compose_form.publish_loud": "{publish}!",
"compose_form.sensitive": "Označ médiá ako chúlostivé",
"compose_form.spoiler": "Skryť text za varovanie",
"compose_form.sensitive.marked": "Médiálny obsah je označený ako chúlostivý",
"compose_form.sensitive.unmarked": "Médiálny obsah nieje označený ako chúlostivý",
"compose_form.spoiler.marked": "Text je ukrytý za varovaním",
"compose_form.spoiler.unmarked": "Text nieje ukrytý",
"compose_form.spoiler_placeholder": "Sem napíšte vaše varovanie",
"confirmation_modal.cancel": "Zrušiť",
"confirmations.block.confirm": "Blokovať",
@@ -99,14 +101,14 @@
"empty_column.list": "Tento zoznam je ešte prázdny. Keď ale členovia tohoto zoznamu napíšu nové správy, tak tie sa objavia priamo tu.",
"empty_column.notifications": "Nemáte ešte žiadne notifikácie. Napíšte niekomu, následujte niekoho a komunikujte s ostatnými aby diskusia mohla začať.",
"empty_column.public": "Ešte tu nič nie je. Napíšte niečo verejne alebo začnite sledovať používateľov z iných Mastodon serverov aby tu niečo pribudlo",
"follow_request.authorize": "Povoliť prístup",
"follow_request.reject": "Odmietnúť",
"follow_request.authorize": "Povoľ prístup",
"follow_request.reject": "Odmietni",
"getting_started.appsshort": "Aplikácie",
"getting_started.faq": "FAQ",
"getting_started.heading": "Začíname",
"getting_started.faq": "Časté otázky",
"getting_started.heading": "Začni tu",
"getting_started.open_source_notice": "Mastodon má otvorený kód. Nahlásiť chyby, alebo prispievať vlastným kódom môžete na GitHube v {github}.",
"getting_started.userguide": "Používateľská príručka",
"home.column_settings.advanced": "Rozšírené",
"home.column_settings.advanced": "Pokročilé",
"home.column_settings.basic": "Základné",
"home.column_settings.filter_regex": "Filtrovať použitím regulárnych výrazov",
"home.column_settings.show_reblogs": "Zobraziť povýšené",
@@ -145,7 +147,7 @@
"missing_indicator.label": "Nenájdené",
"missing_indicator.sublabel": "Tento zdroj sa nepodarilo nájsť",
"mute_modal.hide_notifications": "Skryť notifikácie od tohoto užívateľa?",
"navigation_bar.blocks": "Blokovaní používatelia",
"navigation_bar.blocks": "Blokovaní užívatelia",
"navigation_bar.community_timeline": "Lokálna časová os",
"navigation_bar.edit_profile": "Upraviť profil",
"navigation_bar.favourites": "Obľúbené",
@@ -154,9 +156,9 @@
"navigation_bar.keyboard_shortcuts": "Klávesové skratky",
"navigation_bar.lists": "Zoznamy",
"navigation_bar.logout": "Odhlásiť",
"navigation_bar.mutes": "Ignorovaní používatelia",
"navigation_bar.mutes": "Ignorovaní užívatelia",
"navigation_bar.pins": "Pripnuté toots",
"navigation_bar.preferences": "Možnosti",
"navigation_bar.preferences": "Voľby",
"navigation_bar.public_timeline": "Federovaná časová os",
"notification.favourite": "{name} sa páči tvoj status",
"notification.follow": "{name} ťa začal/a následovať",
@@ -217,8 +219,8 @@
"report.placeholder": "Ďalšie komentáre",
"report.submit": "Poslať",
"report.target": "Nahlásenie {target}",
"search.placeholder": "Hľadať",
"search_popout.search_format": "Pokročilý formát vyhľadávania",
"search.placeholder": "Hľadaj",
"search_popout.search_format": "Pokročilé vyhľadávanie",
"search_popout.tips.full_text": "Simple text returns statuses you have written, favourited, boosted, or have been mentioned in, as well as matching usernames, display names, and hashtags.",
"search_popout.tips.hashtag": "haštag",
"search_popout.tips.status": "status",
@@ -252,7 +254,9 @@
"status.sensitive_warning": "Chúlostivý obsah",
"status.share": "Zdieľať",
"status.show_less": "Zobraz menej",
"status.show_less_all": "Všetkým ukáž menej",
"status.show_more": "Zobraz viac",
"status.show_more_all": "Všetkým ukáž viac",
"status.unmute_conversation": "Prestať ignorovať konverzáciu",
"status.unpin": "Odopnúť z profilu",
"tabs_bar.federated_timeline": "Federovaná",

View File

@@ -60,8 +60,10 @@
"compose_form.placeholder": "Šta Vam je na umu?",
"compose_form.publish": "Tutni",
"compose_form.publish_loud": "{publish}!",
"compose_form.sensitive": "Obeleži multimediju kao osetljivu",
"compose_form.spoiler": "Sakrij tekst ispod upozorenja",
"compose_form.sensitive.marked": "Media is marked as sensitive",
"compose_form.sensitive.unmarked": "Media is not marked as sensitive",
"compose_form.spoiler.marked": "Text is hidden behind warning",
"compose_form.spoiler.unmarked": "Text is not hidden",
"compose_form.spoiler_placeholder": "Ovde upišite upozorenje",
"confirmation_modal.cancel": "Poništi",
"confirmations.block.confirm": "Blokiraj",
@@ -252,7 +254,9 @@
"status.sensitive_warning": "Osetljiv sadržaj",
"status.share": "Podeli",
"status.show_less": "Prikaži manje",
"status.show_less_all": "Show less for all",
"status.show_more": "Prikaži više",
"status.show_more_all": "Show more for all",
"status.unmute_conversation": "Uključi prepisku",
"status.unpin": "Otkači sa profila",
"tabs_bar.federated_timeline": "Federisano",

View File

@@ -60,8 +60,10 @@
"compose_form.placeholder": "Шта Вам је на уму?",
"compose_form.publish": "Тутни",
"compose_form.publish_loud": "{publish}!",
"compose_form.sensitive": "Обележи мултимедију као осетљиву",
"compose_form.spoiler": "Сакриј текст испод упозорења",
"compose_form.sensitive.marked": "Media is marked as sensitive",
"compose_form.sensitive.unmarked": "Media is not marked as sensitive",
"compose_form.spoiler.marked": "Text is hidden behind warning",
"compose_form.spoiler.unmarked": "Text is not hidden",
"compose_form.spoiler_placeholder": "Овде упишите упозорење",
"confirmation_modal.cancel": "Поништи",
"confirmations.block.confirm": "Блокирај",
@@ -252,7 +254,9 @@
"status.sensitive_warning": "Осетљив садржај",
"status.share": "Подели",
"status.show_less": "Прикажи мање",
"status.show_less_all": "Show less for all",
"status.show_more": "Прикажи више",
"status.show_more_all": "Show more for all",
"status.unmute_conversation": "Укључи преписку",
"status.unpin": "Откачи са профила",
"tabs_bar.federated_timeline": "Федерисано",

View File

@@ -1,9 +1,9 @@
{
"account.block": "Blockera @{name}",
"account.block_domain": "Dölj allt från {domain}",
"account.blocked": "Blocked",
"account.blocked": "Blockerad",
"account.disclaimer_full": "Informationen nedan kan spegla användarens profil ofullständigt.",
"account.domain_blocked": "Domain hidden",
"account.domain_blocked": "Domän gömd",
"account.edit_profile": "Redigera profil",
"account.follow": "Följ",
"account.followers": "Följare",
@@ -15,9 +15,9 @@
"account.moved_to": "{name} har flyttat till:",
"account.mute": "Tysta @{name}",
"account.mute_notifications": "Stäng av notifieringar från @{name}",
"account.muted": "Muted",
"account.muted": "Nertystad",
"account.posts": "Inlägg",
"account.posts_with_replies": "Toots with replies",
"account.posts_with_replies": "Toots med svar",
"account.report": "Rapportera @{name}",
"account.requested": "Inväntar godkännande. Klicka för att avbryta följförfrågan",
"account.share": "Dela @{name}'s profil",
@@ -60,8 +60,10 @@
"compose_form.placeholder": "Vad funderar du på?",
"compose_form.publish": "Toot",
"compose_form.publish_loud": "{publish}!",
"compose_form.sensitive": "Markera media som känslig",
"compose_form.spoiler": "Dölj text bakom varning",
"compose_form.sensitive.marked": "Media har markerats som känsligt",
"compose_form.sensitive.unmarked": "Media har inte markerats som känsligt",
"compose_form.spoiler.marked": "Texten har dolts bakom en varning",
"compose_form.spoiler.unmarked": "Texten är inte dold",
"compose_form.spoiler_placeholder": "Skriv din varning här",
"confirmation_modal.cancel": "Ångra",
"confirmations.block.confirm": "Blockera",
@@ -211,20 +213,20 @@
"relative_time.minutes": "{number}m",
"relative_time.seconds": "{number}s",
"reply_indicator.cancel": "Ångra",
"report.forward": "Forward to {target}",
"report.forward_hint": "The account is from another server. Send an anonymized copy of the report there as well?",
"report.hint": "The report will be sent to your instance moderators. You can provide an explanation of why you are reporting this account below:",
"report.forward": "Vidarebefordra till {target}",
"report.forward_hint": "Kontot är från en annan server. Skicka även en anonymiserad kopia av anmälan dit?",
"report.hint": "Anmälan skickas till din instans moderatorer. Du kan ge en förklaring till varför du har anmält detta konto nedan:",
"report.placeholder": "Ytterligare kommentarer",
"report.submit": "Skicka",
"report.target": "Rapporterar {target}",
"search.placeholder": "Sök",
"search_popout.search_format": "Avancerat sökformat",
"search_popout.tips.full_text": "Simple text returns statuses you have written, favourited, boosted, or have been mentioned in, as well as matching usernames, display names, and hashtags.",
"search_popout.tips.full_text": "Enkel text returnerar statusar där du har skrivit, favoriserat, knuffat eller nämnts samt med matchande användarnamn, visningsnamn och hashtags.",
"search_popout.tips.hashtag": "hashtag",
"search_popout.tips.status": "status",
"search_popout.tips.text": "Enkel text returnerar matchande visningsnamn, användarnamn och hashtags",
"search_popout.tips.user": "användare",
"search_results.accounts": "People",
"search_results.accounts": "Människor",
"search_results.hashtags": "Hashtags",
"search_results.statuses": "Toots",
"search_results.total": "{count, number} {count, plural, ett {result} andra {results}}",
@@ -242,7 +244,7 @@
"status.mute_conversation": "Tysta konversation",
"status.open": "Utvidga denna status",
"status.pin": "Fäst i profil",
"status.pinned": "Pinned toot",
"status.pinned": "Fäst toot",
"status.reblog": "Knuff",
"status.reblogged_by": "{name} knuffade",
"status.reply": "Svara",
@@ -252,7 +254,9 @@
"status.sensitive_warning": "Känsligt innehåll",
"status.share": "Dela",
"status.show_less": "Visa mindre",
"status.show_less_all": "Visa mindre för alla",
"status.show_more": "Visa mer",
"status.show_more_all": "Visa mer för alla",
"status.unmute_conversation": "Öppna konversation",
"status.unpin": "Ångra fäst i profil",
"tabs_bar.federated_timeline": "Förenad",
@@ -263,7 +267,7 @@
"upload_area.title": "Dra & släpp för att ladda upp",
"upload_button.label": "Lägg till media",
"upload_form.description": "Beskriv för synskadade",
"upload_form.focus": "Crop",
"upload_form.focus": "Beskär",
"upload_form.undo": "Ångra",
"upload_progress.label": "Laddar upp...",
"video.close": "Stäng video",

View File

@@ -60,8 +60,10 @@
"compose_form.placeholder": "What is on your mind?",
"compose_form.publish": "Toot",
"compose_form.publish_loud": "{publish}!",
"compose_form.sensitive": "Mark media as sensitive",
"compose_form.spoiler": "Hide text behind warning",
"compose_form.sensitive.marked": "Media is marked as sensitive",
"compose_form.sensitive.unmarked": "Media is not marked as sensitive",
"compose_form.spoiler.marked": "Text is hidden behind warning",
"compose_form.spoiler.unmarked": "Text is not hidden",
"compose_form.spoiler_placeholder": "Content warning",
"confirmation_modal.cancel": "Cancel",
"confirmations.block.confirm": "Block",
@@ -252,7 +254,9 @@
"status.sensitive_warning": "Sensitive content",
"status.share": "Share",
"status.show_less": "Show less",
"status.show_less_all": "Show less for all",
"status.show_more": "Show more",
"status.show_more_all": "Show more for all",
"status.unmute_conversation": "Unmute conversation",
"status.unpin": "Unpin from profile",
"tabs_bar.federated_timeline": "Federated",

View File

@@ -60,8 +60,10 @@
"compose_form.placeholder": "Ne düşünüyorsun?",
"compose_form.publish": "Toot",
"compose_form.publish_loud": "{publish}!",
"compose_form.sensitive": "Görseli hassas olarak işaretle",
"compose_form.spoiler": "Metni uyarı arkasına gizle",
"compose_form.sensitive.marked": "Media is marked as sensitive",
"compose_form.sensitive.unmarked": "Media is not marked as sensitive",
"compose_form.spoiler.marked": "Text is hidden behind warning",
"compose_form.spoiler.unmarked": "Text is not hidden",
"compose_form.spoiler_placeholder": "İçerik uyarısı",
"confirmation_modal.cancel": "İptal",
"confirmations.block.confirm": "Engelle",
@@ -252,7 +254,9 @@
"status.sensitive_warning": "Hassas içerik",
"status.share": "Share",
"status.show_less": "Daha azı",
"status.show_less_all": "Show less for all",
"status.show_more": "Daha fazlası",
"status.show_more_all": "Show more for all",
"status.unmute_conversation": "Unmute conversation",
"status.unpin": "Unpin from profile",
"tabs_bar.federated_timeline": "Federe",

View File

@@ -60,8 +60,10 @@
"compose_form.placeholder": "Що у Вас на думці?",
"compose_form.publish": "Дмухнути",
"compose_form.publish_loud": "{publish}!",
"compose_form.sensitive": "Відмітити як непристойний зміст",
"compose_form.spoiler": "Приховати текст за попередженням",
"compose_form.sensitive.marked": "Media is marked as sensitive",
"compose_form.sensitive.unmarked": "Media is not marked as sensitive",
"compose_form.spoiler.marked": "Text is hidden behind warning",
"compose_form.spoiler.unmarked": "Text is not hidden",
"compose_form.spoiler_placeholder": "Попередження щодо прихованого тексту",
"confirmation_modal.cancel": "Відмінити",
"confirmations.block.confirm": "Заблокувати",
@@ -252,7 +254,9 @@
"status.sensitive_warning": "Непристойний зміст",
"status.share": "Share",
"status.show_less": "Згорнути",
"status.show_less_all": "Show less for all",
"status.show_more": "Розгорнути",
"status.show_more_all": "Show more for all",
"status.unmute_conversation": "Зняти глушення з діалогу",
"status.unpin": "Unpin from profile",
"tabs_bar.federated_timeline": "Глобальна",

View File

@@ -60,8 +60,10 @@
"compose_form.placeholder": "在想啥?",
"compose_form.publish": "嘟嘟",
"compose_form.publish_loud": "{publish}",
"compose_form.sensitive": "将媒体文件标记为敏感内容",
"compose_form.spoiler": "折叠嘟文内容",
"compose_form.sensitive.marked": "Media is marked as sensitive",
"compose_form.sensitive.unmarked": "Media is not marked as sensitive",
"compose_form.spoiler.marked": "Text is hidden behind warning",
"compose_form.spoiler.unmarked": "Text is not hidden",
"compose_form.spoiler_placeholder": "折叠部分的警告消息",
"confirmation_modal.cancel": "取消",
"confirmations.block.confirm": "屏蔽",
@@ -252,7 +254,9 @@
"status.sensitive_warning": "敏感内容",
"status.share": "分享",
"status.show_less": "隐藏内容",
"status.show_less_all": "Show less for all",
"status.show_more": "显示内容",
"status.show_more_all": "Show more for all",
"status.unmute_conversation": "不再隐藏此对话",
"status.unpin": "在个人资料页面取消置顶",
"tabs_bar.federated_timeline": "跨站",

View File

@@ -60,8 +60,10 @@
"compose_form.placeholder": "你在想甚麼?",
"compose_form.publish": "發文",
"compose_form.publish_loud": "{publish}",
"compose_form.sensitive": "將媒體檔案標示為「敏感內容」",
"compose_form.spoiler": "將部份文字藏於警告訊息之後",
"compose_form.sensitive.marked": "Media is marked as sensitive",
"compose_form.sensitive.unmarked": "Media is not marked as sensitive",
"compose_form.spoiler.marked": "Text is hidden behind warning",
"compose_form.spoiler.unmarked": "Text is not hidden",
"compose_form.spoiler_placeholder": "敏感警告訊息",
"confirmation_modal.cancel": "取消",
"confirmations.block.confirm": "封鎖",
@@ -252,7 +254,9 @@
"status.sensitive_warning": "敏感內容",
"status.share": "Share",
"status.show_less": "減少顯示",
"status.show_less_all": "Show less for all",
"status.show_more": "顯示更多",
"status.show_more_all": "Show more for all",
"status.unmute_conversation": "解禁對話",
"status.unpin": "解除置頂",
"tabs_bar.federated_timeline": "跨站",

View File

@@ -60,8 +60,10 @@
"compose_form.placeholder": "在想些什麼?",
"compose_form.publish": "貼掉",
"compose_form.publish_loud": "{publish}",
"compose_form.sensitive": "將此媒體標為敏感",
"compose_form.spoiler": "將訊息隱藏在警告訊息之後",
"compose_form.sensitive.marked": "Media is marked as sensitive",
"compose_form.sensitive.unmarked": "Media is not marked as sensitive",
"compose_form.spoiler.marked": "Text is hidden behind warning",
"compose_form.spoiler.unmarked": "Text is not hidden",
"compose_form.spoiler_placeholder": "內容警告",
"confirmation_modal.cancel": "取消",
"confirmations.block.confirm": "封鎖",
@@ -252,7 +254,9 @@
"status.sensitive_warning": "敏感內容",
"status.share": "Share",
"status.show_less": "看少點",
"status.show_less_all": "Show less for all",
"status.show_more": "看更多",
"status.show_more_all": "Show more for all",
"status.unmute_conversation": "不消音對話",
"status.unpin": "解除置頂",
"tabs_bar.federated_timeline": "聯盟",

View File

@@ -35,6 +35,8 @@ import { Map as ImmutableMap, List as ImmutableList, OrderedSet as ImmutableOrde
import uuid from '../uuid';
import { me } from '../initial_state';
const allowedAroundShortCode = '><\u0085\u0020\u00a0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029\u0009\u000a\u000b\u000c\u000d';
const initialState = ImmutableMap({
mounted: 0,
sensitive: false,
@@ -135,12 +137,14 @@ const updateSuggestionTags = (state, token) => {
};
const insertEmoji = (state, position, emojiData) => {
const emoji = emojiData.native;
const oldText = state.get('text');
const needsSpace = emojiData.custom && position > 0 && !allowedAroundShortCode.includes(oldText[position - 1]);
const emoji = needsSpace ? ' ' + emojiData.native : emojiData.native;
return state.withMutations(map => {
map.update('text', oldText => `${oldText.slice(0, position)}${emoji} ${oldText.slice(position)}`);
map.set('focusDate', new Date());
map.set('idempotencyKey', uuid());
return state.merge({
text: `${oldText.slice(0, position)}${emoji} ${oldText.slice(position)}`,
focusDate: new Date(),
idempotencyKey: uuid(),
});
};

View File

@@ -15,6 +15,8 @@ import {
CONTEXT_FETCH_SUCCESS,
STATUS_MUTE_SUCCESS,
STATUS_UNMUTE_SUCCESS,
STATUS_REVEAL,
STATUS_HIDE,
} from '../actions/statuses';
import {
TIMELINE_REFRESH_SUCCESS,
@@ -54,16 +56,21 @@ const normalizeStatus = (state, status) => {
normalStatus.reblog = status.reblog.id;
}
const searchContent = [status.spoiler_text, status.content].join('\n\n').replace(/<br\s*\/?>/g, '\n').replace(/<\/p><p>/g, '\n\n');
// Only calculate these values when status first encountered
// Otherwise keep the ones already in the reducer
if (!state.has(status.id)) {
const searchContent = [status.spoiler_text, status.content].join('\n\n').replace(/<br\s*\/?>/g, '\n').replace(/<\/p><p>/g, '\n\n');
const emojiMap = normalStatus.emojis.reduce((obj, emoji) => {
obj[`:${emoji.shortcode}:`] = emoji;
return obj;
}, {});
const emojiMap = normalStatus.emojis.reduce((obj, emoji) => {
obj[`:${emoji.shortcode}:`] = emoji;
return obj;
}, {});
normalStatus.search_index = domParser.parseFromString(searchContent, 'text/html').documentElement.textContent;
normalStatus.contentHtml = emojify(normalStatus.content, emojiMap);
normalStatus.spoilerHtml = emojify(escapeTextContentForBrowser(normalStatus.spoiler_text || ''), emojiMap);
normalStatus.search_index = domParser.parseFromString(searchContent, 'text/html').documentElement.textContent;
normalStatus.contentHtml = emojify(normalStatus.content, emojiMap);
normalStatus.spoilerHtml = emojify(escapeTextContentForBrowser(normalStatus.spoiler_text || ''), emojiMap);
normalStatus.hidden = normalStatus.sensitive;
}
return state.update(status.id, ImmutableMap(), map => map.mergeDeep(fromJS(normalStatus)));
};
@@ -111,6 +118,14 @@ export default function statuses(state = initialState, action) {
return state.setIn([action.id, 'muted'], true);
case STATUS_UNMUTE_SUCCESS:
return state.setIn([action.id, 'muted'], false);
case STATUS_REVEAL:
return state.withMutations(map => {
action.ids.forEach(id => map.setIn([id, 'hidden'], false));
});
case STATUS_HIDE:
return state.withMutations(map => {
action.ids.forEach(id => map.setIn([id, 'hidden'], true));
});
case TIMELINE_REFRESH_SUCCESS:
case TIMELINE_EXPAND_SUCCESS:
case CONTEXT_FETCH_SUCCESS:

View File

@@ -1,10 +1,48 @@
import './web_push_notifications';
function openCache() {
return caches.open('mastodon-web');
}
function fetchRoot() {
return fetch('/', { credentials: 'include' });
}
// Cause a new version of a registered Service Worker to replace an existing one
// that is already installed, and replace the currently active worker on open pages.
self.addEventListener('install', function(event) {
event.waitUntil(self.skipWaiting());
event.waitUntil(Promise.all([openCache(), fetchRoot()]).then(([cache, root]) => cache.put('/', root)));
});
self.addEventListener('activate', function(event) {
event.waitUntil(self.clients.claim());
});
self.addEventListener('fetch', function(event) {
const url = new URL(event.request.url);
if (url.pathname.startsWith('/web/')) {
const asyncResponse = fetchRoot();
const asyncCache = openCache();
event.respondWith(asyncResponse.then(async response => {
if (response.ok) {
const cache = await asyncCache;
await cache.put('/', response);
return response.clone();
}
throw null;
}).catch(() => caches.match('/')));
} else if (url.pathname === '/auth/sign_out') {
const asyncResponse = fetch(event.request);
const asyncCache = openCache();
event.respondWith(asyncResponse.then(async response => {
if (response.ok || response.type === 'opaqueredirect') {
const cache = await asyncCache;
await cache.delete('/');
}
return response;
}));
}
});

View File

@@ -440,6 +440,7 @@
text-align: center;
padding: 60px 0;
padding-top: 55px;
margin: 0 auto;
cursor: default;
}

View File

@@ -1842,6 +1842,9 @@
object-position: bottom left;
width: 100%;
height: 100%;
pointer-events: none;
user-drag: none;
user-select: none;
}
}
@@ -2515,6 +2518,10 @@ a.status-card {
flex: 1;
}
& > .column-header__back-button {
color: $ui-highlight-color;
}
&.active {
box-shadow: 0 1px 0 rgba($ui-highlight-color, 0.3);
@@ -3418,8 +3425,12 @@ a.status-card {
img,
canvas,
video {
max-width: 100vw;
max-height: 100vh;
max-width: 100%;
/*
put margins on top and bottom of image to avoid the screen coverd by
image.
*/
max-height: 80%;
width: auto;
height: auto;
margin: auto;
@@ -3431,11 +3442,6 @@ a.status-card {
background: url('../images/void.png') repeat;
object-fit: contain;
}
.react-swipeable-view-container {
width: 100vw;
height: 100%;
}
}
.media-modal__closer {
@@ -4311,18 +4317,16 @@ a.status-card {
display: block;
text-decoration: none;
color: $ui-secondary-color;
height: 100%;
line-height: 0;
&,
img {
height: 100%;
width: 100%;
}
img {
position: relative;
object-fit: cover;
height: auto;
}
}
@@ -5072,6 +5076,12 @@ noscript {
}
}
.focal-point-modal {
max-width: 80vw;
max-height: 80vh;
position: relative;
}
.focal-point {
position: relative;
cursor: pointer;
@@ -5081,6 +5091,14 @@ noscript {
cursor: move;
}
img {
max-width: 80vw;
max-height: 80vh;
width: auto;
height: auto;
margin: auto;
}
&__reticle {
position: absolute;
width: 100px;

View File

@@ -1,6 +1,22 @@
body.rtl {
direction: rtl;
.column-header > button {
text-align: right;
padding-left: 0;
padding-right: 15px;
}
.landing-page__logo {
margin-right: 0;
margin-left: 20px;
}
.landing-page .features-list .features-list__row .visual {
margin-left: 0;
margin-right: 15px;
}
.column-link__icon,
.column-header__icon {
margin-right: 0;

View File

@@ -53,7 +53,7 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
visibility: visibility_from_audience,
thread: replied_to_status,
conversation: conversation_from_uri(@object['conversation']),
media_attachments: process_attachments.take(4),
media_attachment_ids: process_attachments.take(4).map(&:id),
}
end

View File

@@ -45,7 +45,7 @@ class OStatus::Activity::Creation < OStatus::Activity::Base
visibility: visibility_scope,
conversation: find_or_create_conversation,
thread: thread? ? find_status(thread.first) || find_activitypub_status(thread.first, thread.second) : nil,
media_attachments: media_attachments
media_attachment_ids: media_attachments.map(&:id)
)
save_mentions(status)

View File

@@ -351,7 +351,7 @@ class OStatus::AtomSerializer
append_element(entry, 'summary', status.spoiler_text, 'xml:lang': status.language) if status.spoiler_text?
append_element(entry, 'content', Formatter.instance.format(status).to_str, type: 'html', 'xml:lang': status.language)
status.mentions.each do |mentioned|
status.mentions.order(:id).each do |mentioned|
append_element(entry, 'link', nil, rel: :mentioned, 'ostatus:object-type': OStatus::TagManager::TYPES[:person], href: OStatus::TagManager.instance.uri_for(mentioned.account))
end

View File

@@ -94,9 +94,16 @@ class Request
class Socket < TCPSocket
class << self
def open(host, *args)
address = IPSocket.getaddress(host)
raise Mastodon::HostValidationError if PrivateAddressCheck.private_address? IPAddr.new(address)
super address, *args
outer_e = nil
Addrinfo.foreach(host, nil, nil, :SOCK_STREAM) do |address|
begin
raise Mastodon::HostValidationError if PrivateAddressCheck.private_address? IPAddr.new(address.ip_address)
return super address.ip_address, *args
rescue => e
outer_e = e
end
end
raise outer_e if outer_e
end
alias new open

View File

@@ -47,7 +47,8 @@
#
class Account < ApplicationRecord
MENTION_RE = /(?<=^|[^\/[:word:]])@(([a-z0-9_]+)(?:@[a-z0-9\.\-]+[a-z0-9]+)?)/i
USERNAME_RE = /[a-z0-9_]+([a-z0-9_\.]+[a-z0-9_]+)?/i
MENTION_RE = /(?<=^|[^\/[:word:]])@((#{USERNAME_RE})(?:@[a-z0-9\.\-]+[a-z0-9]+)?)/i
include AccountAvatar
include AccountFinderConcern
@@ -68,7 +69,8 @@ class Account < ApplicationRecord
validates :username, uniqueness: { scope: :domain, case_sensitive: true }, if: -> { !local? && will_save_change_to_username? }
# Local user validations
validates :username, format: { with: /\A[a-z0-9_]+\z/i }, uniqueness: { scope: :domain, case_sensitive: false }, length: { maximum: 30 }, if: -> { local? && will_save_change_to_username? }
validates :username, format: { with: /\A[a-z0-9_]+\z/i }, length: { maximum: 30 }, if: -> { local? && will_save_change_to_username? }
validates_with UniqueUsernameValidator, if: -> { local? && will_save_change_to_username? }
validates_with UnreservedUsernameValidator, if: -> { local? && will_save_change_to_username? }
validates :display_name, length: { maximum: 30 }, if: -> { local? && will_save_change_to_display_name? }
validates :note, length: { maximum: 160 }, if: -> { local? && will_save_change_to_note? }

View File

@@ -30,7 +30,7 @@ module AccountFinderConcern
end
def account
scoped_accounts.take
scoped_accounts.order(id: :asc).take
end
private

View File

@@ -38,7 +38,7 @@ module Remotable
send("#{attachment_name}_file_name=", basename + extname)
self[attribute_name] = url if has_attribute?(attribute_name)
rescue HTTP::TimeoutError, HTTP::ConnectionError, OpenSSL::SSL::SSLError, Paperclip::Errors::NotIdentifiedByImageMagickError, Addressable::URI::InvalidURIError => e
rescue HTTP::TimeoutError, HTTP::ConnectionError, OpenSSL::SSL::SSLError, Paperclip::Errors::NotIdentifiedByImageMagickError, Addressable::URI::InvalidURIError, Mastodon::HostValidationError => e
Rails.logger.debug "Error fetching remote #{attachment_name}: #{e}"
nil
end

View File

@@ -12,7 +12,7 @@
class Tag < ApplicationRecord
has_and_belongs_to_many :statuses
HASHTAG_NAME_RE = '[[:word:]_]*[[:alpha:]_][[:word:]_]*'
HASHTAG_NAME_RE = '[[:word:]_]*[[:alpha:]_·][[:word:]_]*'
HASHTAG_RE = /(?:^|[^\/\)\w])#(#{HASHTAG_NAME_RE})/i
validates :name, presence: true, uniqueness: true, format: { with: /\A#{HASHTAG_NAME_RE}\z/i }

View File

@@ -52,6 +52,8 @@ class User < ApplicationRecord
devise :registerable, :recoverable, :rememberable, :trackable, :validatable,
:confirmable
devise :pam_authenticatable if ENV['PAM_ENABLED'] == 'true'
devise :omniauthable
belongs_to :account, inverse_of: :user
@@ -96,7 +98,7 @@ class User < ApplicationRecord
def pam_conflict?
return false unless Devise.pam_authentication
encrypted_password.present? && is_pam_account?
encrypted_password.present? && pam_managed_user?
end
def pam_get_name
@@ -267,22 +269,22 @@ class User < ApplicationRecord
end
def self.pam_get_user(attributes = {})
if attributes[:email]
resource =
if Devise.check_at_sign && !attributes[:email].index('@')
joins(:account).find_by(accounts: { username: attributes[:email] })
else
find_by(email: attributes[:email])
end
if resource.blank?
resource = new(email: attributes[:email])
if Devise.check_at_sign && !resource[:email].index('@')
resource[:email] = "#{attributes[:email]}@#{resource.find_pam_suffix}"
end
return nil unless attributes[:email]
resource =
if Devise.check_at_sign && !attributes[:email].index('@')
joins(:account).find_by(accounts: { username: attributes[:email] })
else
find_by(email: attributes[:email])
end
if resource.blank?
resource = new(email: attributes[:email])
if Devise.check_at_sign && !resource[:email].index('@')
resource[:email] = Rpam2.getenv(resource.find_pam_service, attributes[:email], attributes[:password], 'email', false)
resource[:email] = "#{attributes[:email]}@#{resource.find_pam_suffix}" unless resource[:email]
end
resource
end
resource
end
def self.ldap_get_user(attributes = {})

View File

@@ -57,7 +57,7 @@ class ActivityPub::NoteSerializer < ActiveModel::Serializer
end
def virtual_tags
object.mentions + object.tags + object.emojis
object.mentions.to_a.sort_by(&:id) + object.tags + object.emojis
end
def atom_uri

View File

@@ -15,7 +15,7 @@ class REST::StatusSerializer < ActiveModel::Serializer
belongs_to :account, serializer: REST::AccountSerializer
has_many :media_attachments, serializer: REST::MediaAttachmentSerializer
has_many :mentions
has_many :ordered_mentions, key: :mentions
has_many :tags
has_many :emojis, serializer: REST::CustomEmojiSerializer
@@ -86,6 +86,10 @@ class REST::StatusSerializer < ActiveModel::Serializer
%w(public unlisted).include?(object.visibility)
end
def ordered_mentions
object.mentions.to_a.sort_by(&:id)
end
class ApplicationSerializer < ActiveModel::Serializer
attributes :name, :website
end

View File

@@ -16,7 +16,7 @@ class ActivityPub::ProcessAccountService < BaseService
RedisLock.acquire(lock_options) do |lock|
if lock.acquired?
@account = Account.find_by(uri: @uri)
@account = Account.find_remote(@username, @domain)
@old_public_key = @account&.public_key
@old_protocol = @account&.protocol

View File

@@ -49,7 +49,7 @@ class BackupService < BaseService
end
end
archive_filename = ['archive', Time.now.utc.strftime('%Y%m%d%H%M%S'), SecureRandom.hex(2)].join('-') + '.tar.gz'
archive_filename = ['archive', Time.now.utc.strftime('%Y%m%d%H%M%S'), SecureRandom.hex(16)].join('-') + '.tar.gz'
@backup.dump = ActionDispatch::Http::UploadedFile.new(tempfile: tmp_file, filename: archive_filename)
@backup.processed = true

View File

@@ -0,0 +1,14 @@
# frozen_string_literal: true
class UniqueUsernameValidator < ActiveModel::Validator
def validate(account)
return if account.username.nil?
normalized_username = account.username.downcase.delete('.')
scope = Account.where(domain: nil).where('lower(username) = ?', normalized_username)
scope = scope.where.not(id: account.id) if account.persisted?
account.errors.add(:username, :taken) if scope.exists?
end
end

View File

@@ -50,7 +50,7 @@
%p= @instance_presenter.site_description.html_safe.presence || t('about.generic_description', domain: site_hostname)
.landing-page__call-to-action
.landing-page__call-to-action{ dir: 'ltr' }
.row
.row__information-board
.information-board__section

View File

@@ -1,6 +1,6 @@
= opengraph 'og:url', url
= opengraph 'og:site_name', site_title
= opengraph 'og:title', [yield(:page_title).strip.presence, site_title].compact.join(' - ')
= opengraph 'og:title', yield(:page_title).strip
= opengraph 'og:description', account_description(account)
= opengraph 'og:image', full_asset_url(account.avatar.url(:original))
= opengraph 'og:image:width', '120'

View File

@@ -1,5 +1,5 @@
- content_for :page_title do
= "#{display_name(@account)} (@#{@account.username})"
= "#{display_name(@account)} (@#{@account.local_username_and_domain})"
- content_for :header_tags do
%meta{ name: 'description', content: account_description(@account) }/

View File

@@ -11,7 +11,7 @@
%meta{ name: 'theme-color', content: '#282c37' }/
%meta{ name: 'apple-mobile-web-app-capable', content: 'yes' }/
%title= content_for?(:page_title) ? safe_join([yield(:page_title).chomp, ' - ', title]) : title
%title= content_for?(:page_title) ? safe_join([yield(:page_title).chomp.html_safe, title], ' - ') : title
= stylesheet_pack_tag 'common', media: 'all'
= stylesheet_pack_tag current_theme, media: 'all'

View File

@@ -24,6 +24,11 @@
%bdi= display_name(status.account)
= "@#{status.account.acct}"
- if status.spoiler_text?
%div{ dir: rtl_status?(status) ? 'rtl' : 'ltr' }
%p
= Formatter.instance.format_spoiler(status)
%div{ dir: rtl_status?(status) ? 'rtl' : 'ltr' }
= Formatter.instance.format(status)

View File

@@ -1,3 +1,8 @@
<% if status.spoiler_text? %>
<%= raw status.spoiler_text %>
----
<% end %>
<%= raw Formatter.instance.plaintext(status) %>
<%= raw t('application_mailer.view')%> <%= web_url("statuses/#{status.id}") %>

View File

@@ -1 +1 @@
= opengraph 'og:description', [activity.spoiler_text, activity.text].reject(&:blank?).join("\n\n")
= opengraph 'og:description', status_description(activity)

View File

@@ -1,4 +1,4 @@
- if activity.is_a?(Status) && activity.media_attachments.any?
- if activity.is_a?(Status) && activity.non_sensitive_with_media?
- player_card = false
- activity.media_attachments.each do |media|
- if media.image?

View File

@@ -11,8 +11,8 @@
= opengraph 'og:site_name', site_title
= opengraph 'og:type', 'article'
= opengraph 'og:title', "#{@account.display_name.presence || @account.username} on #{site_hostname}"
= opengraph 'og:url', account_stream_entry_url(@account, @stream_entry)
= opengraph 'og:title', "#{display_name(@account)} (@#{@account.local_username_and_domain})"
= opengraph 'og:url', short_account_status_url(@account, @stream_entry)
= render 'stream_entries/og_description', activity: @stream_entry.activity
= render 'stream_entries/og_image', activity: @stream_entry.activity, account: @account

View File

@@ -38,7 +38,7 @@
%table.input{ align: 'center', cellspacing: 0, cellpadding: 0 }
%tbody
%tr
%td= @resource.unconfirmed_email
%td= @resource.try(:unconfirmed_email) ? @resource.unconfirmed_email : @resource.email
%table.email-table{ cellspacing: 0, cellpadding: 0 }
%tbody

View File

@@ -4,6 +4,6 @@
<%= t 'devise.mailer.email_changed.explanation' %>
<%= @resource.unconfirmed_email %>
<%= @resource.try(:unconfirmed_email) ? @resource.unconfirmed_email : @resource.email %>
<%= t 'devise.mailer.email_changed.extra' %>

View File

@@ -3,7 +3,16 @@
class BackupWorker
include Sidekiq::Worker
sidekiq_options queue: 'pull'
sidekiq_options queue: 'pull', backtrace: true, retry: 5, dead: false
sidekiq_retries_exhausted do |msg|
backup_id = msg['args'].first
ActiveRecord::Base.connection_pool.with_connection do
backup = Backup.find(backup_id)
backup&.destroy
end
end
def perform(backup_id)
backup = Backup.find(backup_id)

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