Merge branch 'master' into federation

This commit is contained in:
Felix Ableitner 2020-03-12 12:34:37 +01:00
commit 063811cb60
99 changed files with 6882 additions and 5102 deletions

3
.dockerignore vendored
View file

@ -3,4 +3,7 @@ server/target/debug
!server/target/debug/lemmy_server !server/target/debug/lemmy_server
server/target/release server/target/release
server/target/debug/incremental server/target/debug/incremental
ui/dist
server/target
docker/dev/volumes
.git .git

2
.gitignore vendored
View file

@ -6,3 +6,5 @@ docker/dev/env_deploy.sh
docker/federation-test/volumes docker/federation-test/volumes
build/ build/
.idea/ .idea/
ui/src/translations
docker/dev/volumes

2
CODE_OF_CONDUCT.md vendored
View file

@ -19,7 +19,7 @@ These are the policies for upholding our communitys standards of conduct. If
1. Remarks that violate the Lemmy standards of conduct, including hateful, hurtful, oppressive, or exclusionary remarks, are not allowed. (Cursing is allowed, but never targeting another user, and never in a hateful manner.) 1. Remarks that violate the Lemmy standards of conduct, including hateful, hurtful, oppressive, or exclusionary remarks, are not allowed. (Cursing is allowed, but never targeting another user, and never in a hateful manner.)
2. Remarks that moderators find inappropriate, whether listed in the code of conduct or not, are also not allowed. 2. Remarks that moderators find inappropriate, whether listed in the code of conduct or not, are also not allowed.
3. Moderators will first respond to such remarks with a warning. 3. Moderators will first respond to such remarks with a warning, at the same time the offending content will likely be removed whenever possible.
4. If the warning is unheeded, the user will be “kicked,” i.e., kicked out of the communication channel to cool off. 4. If the warning is unheeded, the user will be “kicked,” i.e., kicked out of the communication channel to cool off.
5. If the user comes back and continues to make trouble, they will be banned, i.e., indefinitely excluded. 5. If the user comes back and continues to make trouble, they will be banned, i.e., indefinitely excluded.
6. Moderators may choose at their discretion to un-ban the user if it was a first offense and they offer the offended party a genuine apology. 6. Moderators may choose at their discretion to un-ban the user if it was a first offense and they offer the offended party a genuine apology.

32
README.md vendored
View file

@ -4,6 +4,7 @@
[![Build Status](https://travis-ci.org/dessalines/lemmy.svg?branch=master)](https://travis-ci.org/dessalines/lemmy) [![Build Status](https://travis-ci.org/dessalines/lemmy.svg?branch=master)](https://travis-ci.org/dessalines/lemmy)
[![GitHub issues](https://img.shields.io/github/issues-raw/dessalines/lemmy.svg)](https://github.com/dessalines/lemmy/issues) [![GitHub issues](https://img.shields.io/github/issues-raw/dessalines/lemmy.svg)](https://github.com/dessalines/lemmy/issues)
[![Docker Pulls](https://img.shields.io/docker/pulls/dessalines/lemmy.svg)](https://cloud.docker.com/repository/docker/dessalines/lemmy/) [![Docker Pulls](https://img.shields.io/docker/pulls/dessalines/lemmy.svg)](https://cloud.docker.com/repository/docker/dessalines/lemmy/)
[![Translation status](http://weblate.yerbamate.dev/widgets/lemmy/-/lemmy/svg-badge.svg)](http://weblate.yerbamate.dev/engage/lemmy/)
[![License](https://img.shields.io/github/license/dessalines/lemmy.svg)](LICENSE) [![License](https://img.shields.io/github/license/dessalines/lemmy.svg)](LICENSE)
![GitHub stars](https://img.shields.io/github/stars/dessalines/lemmy?style=social) ![GitHub stars](https://img.shields.io/github/stars/dessalines/lemmy?style=social)
</div> </div>
@ -77,6 +78,7 @@ Each lemmy server can set its own moderation policy; appointing site-wide admins
- A post can consist of a title and any combination of self text, a URL, or nothing else. - A post can consist of a title and any combination of self text, a URL, or nothing else.
- Notifications, on comment replies and when you're tagged. - Notifications, on comment replies and when you're tagged.
- Notifications can be sent via email. - Notifications can be sent via email.
- Private messaging support.
- i18n / internationalization support. - i18n / internationalization support.
- RSS / Atom feeds for `All`, `Subscribed`, `Inbox`, `User`, and `Community`. - RSS / Atom feeds for `All`, `Subscribed`, `Inbox`, `User`, and `Community`.
- Cross-posting support. - Cross-posting support.
@ -124,35 +126,7 @@ Lemmy is free, open-source software, meaning no advertising, monetizing, or vent
### Translations ### Translations
If you'd like to add translations, take a look at the [English translation file](ui/src/translations/en.ts). If you want to help with translating, take a look at [Weblate](https://weblate.yerbamate.dev/projects/lemmy/).
- Languages supported: Brazilian Portuguese (`pt-br`), Catalan, (`ca`), Farsi (`fa`), English (`en`), Chinese (`zh`), Dutch (`nl`), Esperanto (`eo`), Finnish (`fi`), French (`fr`), Spanish (`es`), Swedish (`sv`), German (`de`), Russian (`ru`), Italian (`it`).
<!-- translations -->
lang | done | missing
---- | ---- | -------
ca | 97% | cross_posted_to,old,support_on_liberapay,couldnt_get_comments,post_title_too_long,time,action
de | 86% | cross_posted_to,create_private_message,send_secure_message,send_message,message,avatar,upload_avatar,show_avatars,old,docs,message_sent,messages,old_password,matrix_user_id,private_message_disclaimer,send_notifications_to_email,downvotes_disabled,enable_downvotes,open_registration,registration_closed,enable_nsfw,donate_to_lemmy,donate,from,logged_in,couldnt_get_comments,post_title_too_long,email_already_exists,couldnt_create_private_message,no_private_message_edit_allowed,couldnt_update_private_message,time,action
fa | 71% | cross_post,cross_posted_to,subscribed_to_communities,trending_communities,create_private_message,send_secure_message,send_message,message,mod,mods,moderates,remove_as_mod,appoint_as_mod,modlog,stickied,ban,ban_from_site,unban,unban_from_site,banned,number_of_subscribers,subscribers,both,saved,unsubscribe,subscribe,subscribed,old,api,docs,inbox,inbox_for,message_sent,notifications_error,messages,no_email_setup,matrix_user_id,private_message_disclaimer,url,body,copy_suggested_title,community,expand_here,subscribe_to_communities,theme,sponsor_message,support_on_liberapay,general_sponsors,joined,by,to,from,landing_0,logged_in,couldnt_get_comments,community_moderator_already_exists,community_follower_already_exists,community_user_already_banned,post_title_too_long,no_slurs,admin_already_created,couldnt_create_private_message,no_private_message_edit_allowed,couldnt_update_private_message,time,action
eo | 73% | cross_posted_to,number_of_communities,create_private_message,send_secure_message,send_message,message,preview,upload_image,avatar,upload_avatar,show_avatars,formatting_help,view_source,sticky,unsticky,archive_link,stickied,delete_account,delete_account_confirm,banned,creator,number_online,old,docs,replies,mentions,message_sent,messages,old_password,forgot_password,reset_password_mail_sent,password_change,new_password,no_email_setup,matrix_user_id,private_message_disclaimer,send_notifications_to_email,language,browser_default,downvotes_disabled,enable_downvotes,open_registration,registration_closed,enable_nsfw,theme,support_on_liberapay,donate_to_lemmy,donate,from,are_you_sure,yes,no,logged_in,couldnt_get_comments,post_title_too_long,email_already_exists,couldnt_create_private_message,no_private_message_edit_allowed,couldnt_update_private_message,time,action
es | 99% | cross_posted_to,couldnt_get_comments,post_title_too_long
fi | 97% | cross_posted_to,old,support_on_liberapay,couldnt_get_comments,post_title_too_long,time,action
fr | 100% |
it | 82% | cross_posted_to,create_private_message,send_secure_message,send_message,message,avatar,upload_avatar,show_avatars,archive_link,old,docs,message_sent,messages,old_password,forgot_password,reset_password_mail_sent,password_change,new_password,no_email_setup,matrix_user_id,private_message_disclaimer,send_notifications_to_email,language,browser_default,downvotes_disabled,enable_downvotes,open_registration,registration_closed,enable_nsfw,donate_to_lemmy,donate,from,logged_in,couldnt_get_comments,post_title_too_long,email_already_exists,couldnt_create_private_message,no_private_message_edit_allowed,couldnt_update_private_message,time,action
nl | 98% | cross_posted_to,couldnt_get_comments,post_title_too_long,time,action
pt-br | 99% | couldnt_get_comments,post_title_too_long
ru | 70% | cross_posts,cross_post,cross_posted_to,number_of_communities,create_private_message,send_secure_message,send_message,message,preview,upload_image,avatar,upload_avatar,show_avatars,formatting_help,view_source,sticky,unsticky,archive_link,stickied,delete_account,delete_account_confirm,banned,creator,number_online,old,docs,replies,mentions,message_sent,messages,old_password,forgot_password,reset_password_mail_sent,password_change,new_password,no_email_setup,matrix_user_id,private_message_disclaimer,send_notifications_to_email,language,browser_default,downvotes_disabled,enable_downvotes,open_registration,registration_closed,enable_nsfw,recent_comments,theme,support_on_liberapay,donate_to_lemmy,donate,monero,by,to,from,transfer_community,transfer_site,are_you_sure,yes,no,logged_in,couldnt_get_comments,post_title_too_long,email_already_exists,couldnt_create_private_message,no_private_message_edit_allowed,couldnt_update_private_message,time,action
sv | 81% | cross_posted_to,create_private_message,send_secure_message,send_message,message,avatar,upload_avatar,show_avatars,archive_link,old,docs,replies,mentions,message_sent,messages,old_password,forgot_password,reset_password_mail_sent,password_change,new_password,no_email_setup,matrix_user_id,private_message_disclaimer,send_notifications_to_email,language,browser_default,downvotes_disabled,enable_downvotes,open_registration,registration_closed,enable_nsfw,support_on_liberapay,donate_to_lemmy,donate,from,logged_in,couldnt_get_comments,post_title_too_long,email_already_exists,couldnt_create_private_message,no_private_message_edit_allowed,couldnt_update_private_message,time,action
zh | 69% | cross_posts,cross_post,cross_posted_to,users,number_of_communities,create_private_message,send_secure_message,send_message,message,preview,upload_image,avatar,upload_avatar,show_avatars,formatting_help,view_source,sticky,unsticky,archive_link,settings,stickied,delete_account,delete_account_confirm,banned,creator,number_online,old,docs,replies,mentions,message_sent,messages,old_password,forgot_password,reset_password_mail_sent,password_change,new_password,no_email_setup,matrix_user_id,private_message_disclaimer,send_notifications_to_email,language,browser_default,downvotes_disabled,enable_downvotes,open_registration,registration_closed,enable_nsfw,recent_comments,nsfw,show_nsfw,theme,donate_to_lemmy,donate,monero,by,to,from,transfer_community,transfer_site,are_you_sure,yes,no,logged_in,couldnt_get_comments,post_title_too_long,email_already_exists,couldnt_create_private_message,no_private_message_edit_allowed,couldnt_update_private_message,time,action
<!-- translationsstop -->
If you'd like to update this report, run:
```bash
cd ui
ts-node translation_report.ts
```
## Contact ## Contact

2
ansible/VERSION vendored
View file

@ -1 +1 @@
v0.6.25 v0.6.39

View file

@ -1,7 +1,7 @@
{ {
database: { database: {
password: "{{ postgres_password }}" password: "{{ postgres_password }}"
host: "lemmy_db" host: "postgres"
} }
hostname: "{{ domain }}" hostname: "{{ domain }}"
jwt_secret: "{{ jwt_password }}" jwt_secret: "{{ jwt_password }}"

View file

@ -9,31 +9,32 @@ services:
volumes: volumes:
- ./lemmy.hjson:/config/config.hjson:ro - ./lemmy.hjson:/config/config.hjson:ro
depends_on: depends_on:
- lemmy_db - postgres
- lemmy_pictshare - pictshare
- iframely
lemmy_db: postgres:
image: postgres:12-alpine image: postgres:12-alpine
environment: environment:
- POSTGRES_USER=lemmy - POSTGRES_USER=lemmy
- POSTGRES_PASSWORD={{ postgres_password }} - POSTGRES_PASSWORD={{ postgres_password }}
- POSTGRES_DB=lemmy - POSTGRES_DB=lemmy
volumes: volumes:
- lemmy_db:/var/lib/postgresql/data - ./volumes/postgres:/var/lib/postgresql/data
restart: always restart: always
lemmy_pictshare: pictshare:
image: shtripok/pictshare:latest image: shtripok/pictshare:latest
ports: ports:
- "127.0.0.1:8537:80" - "127.0.0.1:8537:80"
volumes: volumes:
- lemmy_pictshare:/usr/share/nginx/html/data - ./volumes/pictshare:/usr/share/nginx/html/data
restart: always restart: always
lemmy_iframely: iframely:
image: dogbin/iframely:latest image: dogbin/iframely:latest
ports: ports:
- "127.0.0.1:8061:8061" - "127.0.0.1:8061:80"
volumes: volumes:
- ./iframely.config.local.js:/iframely/config.local.js:ro - ./iframely.config.local.js:/iframely/config.local.js:ro
restart: always restart: always
@ -43,7 +44,3 @@ services:
environment: environment:
- POSTFIX_myhostname={{ domain }} - POSTFIX_myhostname={{ domain }}
restart: "always" restart: "always"
volumes:
lemmy_db:
lemmy_pictshare:
lemmy_iframely:

17
docker/dev/deploy.sh vendored
View file

@ -1,24 +1,26 @@
#!/bin/sh #!/bin/sh
git checkout master git checkout master
# Import translations
git fetch weblate
git merge weblate/master
# Creating the new tag # Creating the new tag
new_tag="$1" new_tag="$1"
git tag $new_tag
third_semver=$(echo $new_tag | cut -d "." -f 3) third_semver=$(echo $new_tag | cut -d "." -f 3)
# Setting the version on the front end # Setting the version on the front end
cd ../../ cd ../../
echo "export const version: string = '$(git describe --tags)';" > "ui/src/version.ts" echo "export const version: string = '$new_tag';" > "ui/src/version.ts"
git add "ui/src/version.ts" git add "ui/src/version.ts"
# Setting the version on the backend # Setting the version on the backend
echo "pub const VERSION: &str = \"$(git describe --tags)\";" > "server/src/version.rs" echo "pub const VERSION: &str = \"$new_tag\";" > "server/src/version.rs"
git add "server/src/version.rs" git add "server/src/version.rs"
# Setting the version for Ansible # Setting the version for Ansible
git describe --tags > "ansible/VERSION" echo $new_tag > "ansible/VERSION"
git add "ansible/VERSION" git add "ansible/VERSION"
cd docker/dev cd docker/dev || exit
# Changing the docker-compose prod # Changing the docker-compose prod
sed -i "s/dessalines\/lemmy:.*/dessalines\/lemmy:$new_tag/" ../prod/docker-compose.yml sed -i "s/dessalines\/lemmy:.*/dessalines\/lemmy:$new_tag/" ../prod/docker-compose.yml
@ -28,6 +30,7 @@ git add ../../ansible/templates/docker-compose.yml
# The commit # The commit
git commit -m"Version $new_tag" git commit -m"Version $new_tag"
git tag $new_tag
# Rebuilding docker # Rebuilding docker
docker-compose build docker-compose build
@ -69,5 +72,5 @@ git push origin $new_tag
git push git push
# Pushing to any ansible deploys # Pushing to any ansible deploys
cd ../../ansible cd ../../ansible || exit
ansible-playbook lemmy.yml --become ansible-playbook lemmy.yml --become

View file

@ -1,15 +1,16 @@
version: '3.3' version: '3.3'
services: services:
lemmy_db: postgres:
image: postgres:12-alpine image: postgres:12-alpine
environment: environment:
- POSTGRES_USER=lemmy - POSTGRES_USER=lemmy
- POSTGRES_PASSWORD=password - POSTGRES_PASSWORD=password
- POSTGRES_DB=lemmy - POSTGRES_DB=lemmy
volumes: volumes:
- lemmy_db:/var/lib/postgresql/data - ./volumes/postgres:/var/lib/postgresql/data
restart: always restart: always
lemmy: lemmy:
build: build:
context: ../../ context: ../../
@ -20,22 +21,22 @@ services:
volumes: volumes:
- ../lemmy.hjson:/config/config.hjson:ro - ../lemmy.hjson:/config/config.hjson:ro
depends_on: depends_on:
- lemmy_db - postgres
lemmy_pictshare: - pictshare
- iframely
pictshare:
image: shtripok/pictshare:latest image: shtripok/pictshare:latest
ports: ports:
- "127.0.0.1:8537:80" - "127.0.0.1:8537:80"
volumes: volumes:
- lemmy_pictshare:/usr/share/nginx/html/data - ./volumes/pictshare:/usr/share/nginx/html/data
restart: always restart: always
lemmy_iframely:
iframely:
image: dogbin/iframely:latest image: dogbin/iframely:latest
ports: ports:
- "127.0.0.1:8061:8061" - "127.0.0.1:8061:80"
volumes: volumes:
- ../iframely.config.local.js:/iframely/config.local.js:ro - ../iframely.config.local.js:/iframely/config.local.js:ro
restart: always restart: always
volumes:
lemmy_db:
lemmy_pictshare:
lemmy_iframely:

View file

@ -37,7 +37,7 @@
}, },
*/ */
port: 8061, //can be overridden by PORT env var port: 80, //can be overridden by PORT env var
host: '0.0.0.0', // Dockers beware. See https://github.com/itteco/iframely/issues/132#issuecomment-242991246 host: '0.0.0.0', // Dockers beware. See https://github.com/itteco/iframely/issues/132#issuecomment-242991246
//can be overridden by HOST env var //can be overridden by HOST env var

2
docker/lemmy.hjson vendored
View file

@ -5,7 +5,7 @@
# password to connect to postgres # password to connect to postgres
password: "password" password: "password"
# host where postgres is running # host where postgres is running
host: "lemmy_db" host: "postgres"
# port where postgres can be accessed # port where postgres can be accessed
port: 5432 port: 5432
# name of the postgres database for lemmy # name of the postgres database for lemmy

View file

@ -1,39 +1,40 @@
version: '3.3' version: '3.3'
services: services:
lemmy_db: postgres:
image: postgres:12-alpine image: postgres:12-alpine
environment: environment:
- POSTGRES_USER=lemmy - POSTGRES_USER=lemmy
- POSTGRES_PASSWORD=password - POSTGRES_PASSWORD=password
- POSTGRES_DB=lemmy - POSTGRES_DB=lemmy
volumes: volumes:
- lemmy_db:/var/lib/postgresql/data - ./volumes/postgres:/var/lib/postgresql/data
restart: always restart: always
lemmy: lemmy:
image: dessalines/lemmy:v0.6.25 image: dessalines/lemmy:v0.6.39
ports: ports:
- "127.0.0.1:8536:8536" - "127.0.0.1:8536:8536"
restart: always restart: always
volumes: volumes:
- ./lemmy.hjson:/config/config.hjson:ro - ./lemmy.hjson:/config/config.hjson:ro
depends_on: depends_on:
- lemmy_db - postgres
lemmy_pictshare: - pictshare
- iframely
pictshare:
image: shtripok/pictshare:latest image: shtripok/pictshare:latest
ports: ports:
- "127.0.0.1:8537:80" - "127.0.0.1:8537:80"
volumes: volumes:
- lemmy_pictshare:/usr/share/nginx/html/data - ./volumes/pictshare:/usr/share/nginx/html/data
restart: always restart: always
lemmy_iframely:
iframely:
image: dogbin/iframely:latest image: dogbin/iframely:latest
ports: ports:
- "127.0.0.1:8061:8061" - "127.0.0.1:8061:80"
volumes: volumes:
- ./iframely.config.local.js:/iframely/config.local.js:ro - ./iframely.config.local.js:/iframely/config.local.js:ro
restart: always restart: always
volumes:
lemmy_db:
lemmy_pictshare:
lemmy_iframely:

1
docs/src/SUMMARY.md vendored
View file

@ -15,3 +15,4 @@
- [Local Development](contributing_local_development.md) - [Local Development](contributing_local_development.md)
- [Websocket/HTTP API](contributing_websocket_http_api.md) - [Websocket/HTTP API](contributing_websocket_http_api.md)
- [ActivityPub API Outline](contributing_apub_api_outline.md) - [ActivityPub API Outline](contributing_apub_api_outline.md)
- [Lemmy Council](lemmy_council.md)

View file

@ -1,4 +1,5 @@
# Goals # Goals
- Come up with a name / codename. - Come up with a name / codename.
- Must have communities. - Must have communities.
- Must have threaded comments. - Must have threaded comments.
@ -7,6 +8,7 @@
- Use websockets for post / gets to your own instance. - Use websockets for post / gets to your own instance.
# Questions # Questions
- How does voting work? Should we go back to the old way of showing up and downvote counts? Or just a score? - How does voting work? Should we go back to the old way of showing up and downvote counts? Or just a score?
- Decide on tech to be used - Decide on tech to be used
- Backend: Actix, Diesel. - Backend: Actix, Diesel.
@ -17,10 +19,7 @@
- On mobile, allow you to switch between them. Default? - On mobile, allow you to switch between them. Default?
# Resources / Potential Libraries # Resources / Potential Libraries
- Use the [activitypub crate.](https://docs.rs/activitypub/0.1.4/activitypub/)
- https://docs.rs/activitypub/0.1.4/activitypub/
- [Activitypub vocab.](https://www.w3.org/TR/activitystreams-vocabulary/)
- [Activitypub main](https://www.w3.org/TR/activitypub/)
- [Diesel to Postgres data types](https://kotiri.com/2018/01/31/postgresql-diesel-rust-types.html) - [Diesel to Postgres data types](https://kotiri.com/2018/01/31/postgresql-diesel-rust-types.html)
- [helpful diesel examples](http://siciarz.net/24-days-rust-diesel/) - [helpful diesel examples](http://siciarz.net/24-days-rust-diesel/)
- [Recursive query for adjacency list for nested comments](https://stackoverflow.com/questions/192220/what-is-the-most-efficient-elegant-way-to-parse-a-flat-table-into-a-tree/192462#192462) - [Recursive query for adjacency list for nested comments](https://stackoverflow.com/questions/192220/what-is-the-most-efficient-elegant-way-to-parse-a-flat-table-into-a-tree/192462#192462)
@ -36,9 +35,15 @@
- [Temp Icon](https://www.flaticon.com/free-icon/mouse_194242) - [Temp Icon](https://www.flaticon.com/free-icon/mouse_194242)
- [Rust docker build](https://shaneutt.com/blog/rust-fast-small-docker-image-builds/) - [Rust docker build](https://shaneutt.com/blog/rust-fast-small-docker-image-builds/)
- [Zurb mentions](https://github.com/zurb/tribute) - [Zurb mentions](https://github.com/zurb/tribute)
- Activitypub guides - [TippyJS](https://github.com/atomiks/tippyjs)
## Activitypub guides
- https://blog.joinmastodon.org/2018/06/how-to-implement-a-basic-activitypub-server/ - https://blog.joinmastodon.org/2018/06/how-to-implement-a-basic-activitypub-server/
- https://raw.githubusercontent.com/w3c/activitypub/gh-pages/activitypub-tutorial.txt - https://raw.githubusercontent.com/w3c/activitypub/gh-pages/activitypub-tutorial.txt
- https://github.com/tOkeshu/activitypub-example - https://github.com/tOkeshu/activitypub-example
- https://blog.joinmastodon.org/2018/07/how-to-make-friends-and-verify-requests/ - https://blog.joinmastodon.org/2018/07/how-to-make-friends-and-verify-requests/
- Use the [activitypub crate.](https://docs.rs/activitypub/0.1.4/activitypub/)
- https://docs.rs/activitypub/0.1.4/activitypub/
- [Activitypub vocab.](https://www.w3.org/TR/activitystreams-vocabulary/)
- [Activitypub main](https://www.w3.org/TR/activitypub/)

View file

@ -6,6 +6,18 @@ Start typing...
- `#a_community` to get a list of communities. - `#a_community` to get a list of communities.
- `:emoji` to get a list of emojis. - `:emoji` to get a list of emojis.
## Sorting
*Applies to both posts and comments*
Type | Description
--- | ---
Hot | Shows *trending* posts, based on the score, and the most recent comment time.
New | Newest posts.
Top | Shows the highest scoring posts in the given time frame.
For more detail, check the [Post and Comment Ranking details](about_ranking.md).
## Markdown Guide ## Markdown Guide
Type | Or | … to Get Type | Or | … to Get

View file

@ -18,7 +18,7 @@ Score = Upvotes - Downvotes
Time = time since submission (in hours) Time = time since submission (in hours)
Gravity = Decay gravity, 1.8 is default Gravity = Decay gravity, 1.8 is default
``` ```
- For posts, in order to bring up active posts, it uses the latest comment time (limited to a max creation age of a month ago)
- Use Max(1, score) to make sure all comments are affected by time decay. - Use Max(1, score) to make sure all comments are affected by time decay.
- Add 3 to the score, so that everything that has less than 3 downvotes will seem new. Otherwise all new comments would stay at zero, near the bottom. - Add 3 to the score, so that everything that has less than 3 downvotes will seem new. Otherwise all new comments would stay at zero, near the bottom.
- The sign and abs of the score are necessary for dealing with the log of negative scores. - The sign and abs of the score are necessary for dealing with the log of negative scores.

53
docs/src/lemmy_council.md vendored Normal file
View file

@ -0,0 +1,53 @@
# Lemmy Council
- A group of lemmy developers and users that use a well-defined democratic process to steer the project in a positive direction, keep it aligned to community goals, and resolve conflicts.
## Voting / Decision-Making
### Process
- Anything is open for discussion
- Voting done through matrix chat reacts (thumbs up/thumbs down)
- Require a simple majority for votes. (Maybe 2/3rds for more debated decisions).
- Once a decision is reached democratically, the dicision is binding and all group members have to follow it
- All members of the Lemmy council have equal voting power.
- Voting must stay open for at least 2 days.
### What gets voted on
- Membership (joining, removing)
- Coding direction
- Priorities / Emphasis
- Controversial features (For example, an unpopular feature should be removed)
- Communication mediums
- Conflict resolution
- dev.lemmy.ml (domain and server)
- lemmy.ml and subdomains (excluding communism.lemmy.ml)
- git repo including mirrors (on github, gitea, etc)
- Any official accounts of the Lemmy project, for example the Mastodon account or the Liberapay account
- Changes to these rules
## Joining
- We use the following process: anyone who is active around Lemmy can recommend any other active person to join the council. This has to be approved by a majority of the council.
- Active users are defined as those who contribute to Lemmy in some way for at least an hour per week on average, doing things like reporting bugs, discussing rules and features, translating, promoting, developing, or doing other things that aim to improve Lemmy as a whole.
-> people should have joined at least a month ago.
- The member list is public.
- Note: we would like to have a process where community members can elect candidates for the council, but this is not realistic because a single user could easily create multiple accounts and cheat the vote.
- Limit growth to one new member per month at most.
## Removing members
- Inactive members should be removed from the council after a few months of inactivity, and after receiving a notification about this.
- Members that dont follow binding council decisions should be removed.
- Any member can be removed in a vote.
## Goals
- We encourage the membership of groups such as LGBT, religious or ethnic minorities, abuse victims, etc etc, and strive to create a safe space for them to express their opinions. We also support measures to increase participation by the previously mentioned groups.
- The following are banned, and will always be harshly punished: fascism, abuse, racism, sexism, etc etc,
## Communication
- A private Matrix chat for all council members.
- (Once private communities are done) A private community on dev.lemmy.ml for issues.
## Member List / Contact Info
General Contact [@LemmyDev Mastodon](https://mastodon.social/@LemmyDev)
- Dessalines [Matrix](https://matrix.to/#/@happydooby:matrix.org)
- Nutomic [Matrix](https://matrix.to/#/@nutomic:matrix.org), [Mastodon](https://radical.town/@felix)

1213
server/Cargo.lock generated vendored

File diff suppressed because it is too large Load diff

4
server/Cargo.toml vendored
View file

@ -5,7 +5,7 @@ authors = ["Dessalines <happydooby@gmail.com>"]
edition = "2018" edition = "2018"
[dependencies] [dependencies]
diesel = { version = "1.4.2", features = ["postgres","chrono", "r2d2"] } diesel = { version = "1.4.2", features = ["postgres","chrono", "r2d2", "64-column-tables"] }
diesel_migrations = "1.4.0" diesel_migrations = "1.4.0"
dotenv = "0.15.0" dotenv = "0.15.0"
bcrypt = "0.6.1" bcrypt = "0.6.1"
@ -35,3 +35,5 @@ config = "0.10.1"
hjson = "0.8.2" hjson = "0.8.2"
reqwest = "0.9.24" reqwest = "0.9.24"
url = "2.1.1" url = "2.1.1"
percent-encoding = "2.1.0"
chttp = "0.5.5"

View file

@ -0,0 +1,112 @@
-- Adds a newest_activity_time for the post_views, in order to sort by newest comment
drop view post_view;
drop view post_mview;
drop materialized view post_aggregates_mview;
drop view post_aggregates_view;
-- Drop the columns
alter table post drop column embed_title;
alter table post drop column embed_description;
alter table post drop column embed_html;
alter table post drop column thumbnail_url;
-- regen post view
create view post_aggregates_view as
select
p.*,
(select u.banned from user_ u where p.creator_id = u.id) as banned,
(select cb.id::bool from community_user_ban cb where p.creator_id = cb.user_id and p.community_id = cb.community_id) as banned_from_community,
(select name from user_ where p.creator_id = user_.id) as creator_name,
(select avatar from user_ where p.creator_id = user_.id) as creator_avatar,
(select name from community where p.community_id = community.id) as community_name,
(select removed from community c where p.community_id = c.id) as community_removed,
(select deleted from community c where p.community_id = c.id) as community_deleted,
(select nsfw from community c where p.community_id = c.id) as community_nsfw,
(select count(*) from comment where comment.post_id = p.id) as number_of_comments,
coalesce(sum(pl.score), 0) as score,
count (case when pl.score = 1 then 1 else null end) as upvotes,
count (case when pl.score = -1 then 1 else null end) as downvotes,
hot_rank(coalesce(sum(pl.score) , 0),
(
case when (p.published < ('now'::timestamp - '1 month'::interval)) then p.published -- Prevents necro-bumps
else greatest(c.recent_comment_time, p.published)
end
)
) as hot_rank,
(
case when (p.published < ('now'::timestamp - '1 month'::interval)) then p.published -- Prevents necro-bumps
else greatest(c.recent_comment_time, p.published)
end
) as newest_activity_time
from post p
left join post_like pl on p.id = pl.post_id
left join (
select post_id,
max(published) as recent_comment_time
from comment
group by 1
) c on p.id = c.post_id
group by p.id, c.recent_comment_time;
create materialized view post_aggregates_mview as select * from post_aggregates_view;
create unique index idx_post_aggregates_mview_id on post_aggregates_mview (id);
create view post_view as
with all_post as (
select
pa.*
from post_aggregates_view pa
)
select
ap.*,
u.id as user_id,
coalesce(pl.score, 0) as my_vote,
(select cf.id::bool from community_follower cf where u.id = cf.user_id and cf.community_id = ap.community_id) as subscribed,
(select pr.id::bool from post_read pr where u.id = pr.user_id and pr.post_id = ap.id) as read,
(select ps.id::bool from post_saved ps where u.id = ps.user_id and ps.post_id = ap.id) as saved
from user_ u
cross join all_post ap
left join post_like pl on u.id = pl.user_id and ap.id = pl.post_id
union all
select
ap.*,
null as user_id,
null as my_vote,
null as subscribed,
null as read,
null as saved
from all_post ap
;
create view post_mview as
with all_post as (
select
pa.*
from post_aggregates_mview pa
)
select
ap.*,
u.id as user_id,
coalesce(pl.score, 0) as my_vote,
(select cf.id::bool from community_follower cf where u.id = cf.user_id and cf.community_id = ap.community_id) as subscribed,
(select pr.id::bool from post_read pr where u.id = pr.user_id and pr.post_id = ap.id) as read,
(select ps.id::bool from post_saved ps where u.id = ps.user_id and ps.post_id = ap.id) as saved
from user_ u
cross join all_post ap
left join post_like pl on u.id = pl.user_id and ap.id = pl.post_id
union all
select
ap.*,
null as user_id,
null as my_vote,
null as subscribed,
null as read,
null as saved
from all_post ap
;

View file

@ -0,0 +1,115 @@
-- Add the columns
alter table post add column embed_title text;
alter table post add column embed_description text;
alter table post add column embed_html text;
alter table post add column thumbnail_url text;
-- Regenerate the views
-- Adds a newest_activity_time for the post_views, in order to sort by newest comment
drop view post_view;
drop view post_mview;
drop materialized view post_aggregates_mview;
drop view post_aggregates_view;
-- regen post view
create view post_aggregates_view as
select
p.*,
(select u.banned from user_ u where p.creator_id = u.id) as banned,
(select cb.id::bool from community_user_ban cb where p.creator_id = cb.user_id and p.community_id = cb.community_id) as banned_from_community,
(select name from user_ where p.creator_id = user_.id) as creator_name,
(select avatar from user_ where p.creator_id = user_.id) as creator_avatar,
(select name from community where p.community_id = community.id) as community_name,
(select removed from community c where p.community_id = c.id) as community_removed,
(select deleted from community c where p.community_id = c.id) as community_deleted,
(select nsfw from community c where p.community_id = c.id) as community_nsfw,
(select count(*) from comment where comment.post_id = p.id) as number_of_comments,
coalesce(sum(pl.score), 0) as score,
count (case when pl.score = 1 then 1 else null end) as upvotes,
count (case when pl.score = -1 then 1 else null end) as downvotes,
hot_rank(coalesce(sum(pl.score) , 0),
(
case when (p.published < ('now'::timestamp - '1 month'::interval)) then p.published -- Prevents necro-bumps
else greatest(c.recent_comment_time, p.published)
end
)
) as hot_rank,
(
case when (p.published < ('now'::timestamp - '1 month'::interval)) then p.published -- Prevents necro-bumps
else greatest(c.recent_comment_time, p.published)
end
) as newest_activity_time
from post p
left join post_like pl on p.id = pl.post_id
left join (
select post_id,
max(published) as recent_comment_time
from comment
group by 1
) c on p.id = c.post_id
group by p.id, c.recent_comment_time;
create materialized view post_aggregates_mview as select * from post_aggregates_view;
create unique index idx_post_aggregates_mview_id on post_aggregates_mview (id);
create view post_view as
with all_post as (
select
pa.*
from post_aggregates_view pa
)
select
ap.*,
u.id as user_id,
coalesce(pl.score, 0) as my_vote,
(select cf.id::bool from community_follower cf where u.id = cf.user_id and cf.community_id = ap.community_id) as subscribed,
(select pr.id::bool from post_read pr where u.id = pr.user_id and pr.post_id = ap.id) as read,
(select ps.id::bool from post_saved ps where u.id = ps.user_id and ps.post_id = ap.id) as saved
from user_ u
cross join all_post ap
left join post_like pl on u.id = pl.user_id and ap.id = pl.post_id
union all
select
ap.*,
null as user_id,
null as my_vote,
null as subscribed,
null as read,
null as saved
from all_post ap
;
create view post_mview as
with all_post as (
select
pa.*
from post_aggregates_mview pa
)
select
ap.*,
u.id as user_id,
coalesce(pl.score, 0) as my_vote,
(select cf.id::bool from community_follower cf where u.id = cf.user_id and cf.community_id = ap.community_id) as subscribed,
(select pr.id::bool from post_read pr where u.id = pr.user_id and pr.post_id = ap.id) as read,
(select ps.id::bool from post_saved ps where u.id = ps.user_id and ps.post_id = ap.id) as saved
from user_ u
cross join all_post ap
left join post_like pl on u.id = pl.user_id and ap.id = pl.post_id
union all
select
ap.*,
null as user_id,
null as my_vote,
null as subscribed,
null as read,
null as saved
from all_post ap
;

View file

@ -18,7 +18,8 @@ use crate::db::user_mention_view::*;
use crate::db::user_view::*; use crate::db::user_view::*;
use crate::db::*; use crate::db::*;
use crate::{ use crate::{
extract_usernames, naive_from_unix, naive_now, remove_slurs, slur_check, slurs_vec_to_str, extract_usernames, fetch_iframely_and_pictshare_data, naive_from_unix, naive_now, remove_slurs,
slur_check, slurs_vec_to_str,
}; };
use diesel::PgConnection; use diesel::PgConnection;
use failure::Error; use failure::Error;

View file

@ -110,6 +110,10 @@ impl Perform<PostResponse> for Oper<CreatePost> {
return Err(APIError::err("site_ban").into()); return Err(APIError::err("site_ban").into());
} }
// Fetch Iframely and Pictshare cached image
let (iframely_title, iframely_description, iframely_html, pictshare_thumbnail) =
fetch_iframely_and_pictshare_data(data.url.to_owned());
let post_form = PostForm { let post_form = PostForm {
name: data.name.to_owned(), name: data.name.to_owned(),
url: data.url.to_owned(), url: data.url.to_owned(),
@ -122,6 +126,10 @@ impl Perform<PostResponse> for Oper<CreatePost> {
locked: None, locked: None,
stickied: None, stickied: None,
updated: None, updated: None,
embed_title: iframely_title,
embed_description: iframely_description,
embed_html: iframely_html,
thumbnail_url: pictshare_thumbnail,
}; };
let inserted_post = match Post::create(&conn, &post_form) { let inserted_post = match Post::create(&conn, &post_form) {
@ -353,6 +361,10 @@ impl Perform<PostResponse> for Oper<EditPost> {
return Err(APIError::err("site_ban").into()); return Err(APIError::err("site_ban").into());
} }
// Fetch Iframely and Pictshare cached image
let (iframely_title, iframely_description, iframely_html, pictshare_thumbnail) =
fetch_iframely_and_pictshare_data(data.url.to_owned());
let post_form = PostForm { let post_form = PostForm {
name: data.name.to_owned(), name: data.name.to_owned(),
url: data.url.to_owned(), url: data.url.to_owned(),
@ -365,6 +377,10 @@ impl Perform<PostResponse> for Oper<EditPost> {
locked: data.locked.to_owned(), locked: data.locked.to_owned(),
stickied: data.stickied.to_owned(), stickied: data.stickied.to_owned(),
updated: Some(naive_now()), updated: Some(naive_now()),
embed_title: iframely_title,
embed_description: iframely_description,
embed_html: iframely_html,
thumbnail_url: pictshare_thumbnail,
}; };
let _updated_post = match Post::update(&conn, data.edit_id, &post_form) { let _updated_post = match Post::update(&conn, data.edit_id, &post_form) {

View file

@ -466,7 +466,7 @@ impl Perform<GetUserDetailsResponse> for Oper<GetUserDetails> {
} }
}; };
let user_view = UserView::read(&conn, user_details_id)?; let mut user_view = UserView::read(&conn, user_details_id)?;
let mut posts_query = PostQueryBuilder::create(&conn) let mut posts_query = PostQueryBuilder::create(&conn)
.sort(&sort) .sort(&sort)
@ -502,6 +502,15 @@ impl Perform<GetUserDetailsResponse> for Oper<GetUserDetails> {
let creator_user = admins.remove(creator_index); let creator_user = admins.remove(creator_index);
admins.insert(0, creator_user); admins.insert(0, creator_user);
// If its not the same user, remove the email
if let Some(user_id) = user_id {
if user_details_id != user_id {
user_view.email = None;
}
} else {
user_view.email = None;
}
// Return the jwt // Return the jwt
Ok(GetUserDetailsResponse { Ok(GetUserDetailsResponse {
user: user_view, user: user_view,
@ -874,6 +883,10 @@ impl Perform<LoginResponse> for Oper<DeleteAccount> {
locked: None, locked: None,
stickied: None, stickied: None,
updated: Some(naive_now()), updated: Some(naive_now()),
embed_title: None,
embed_description: None,
embed_html: None,
thumbnail_url: None,
}; };
let _updated_post = match Post::update(&conn, post.id, &post_form) { let _updated_post = match Post::update(&conn, post.id, &post_form) {

View file

@ -86,6 +86,10 @@ mod tests {
nsfw: false, nsfw: false,
deleted: false, deleted: false,
updated: None, updated: None,
embed_title: None,
embed_description: None,
embed_html: None,
thumbnail_url: None,
}; };
let page = post.as_page(); let page = post.as_page();

View file

@ -216,6 +216,10 @@ mod tests {
stickied: None, stickied: None,
updated: None, updated: None,
nsfw: false, nsfw: false,
embed_title: None,
embed_description: None,
embed_html: None,
thumbnail_url: None,
}; };
let inserted_post = Post::create(&conn, &new_post).unwrap(); let inserted_post = Post::create(&conn, &new_post).unwrap();

View file

@ -480,6 +480,10 @@ mod tests {
stickied: None, stickied: None,
updated: None, updated: None,
nsfw: false, nsfw: false,
embed_title: None,
embed_description: None,
embed_html: None,
thumbnail_url: None,
}; };
let inserted_post = Post::create(&conn, &new_post).unwrap(); let inserted_post = Post::create(&conn, &new_post).unwrap();

View file

@ -180,7 +180,11 @@ impl<'a> CommunityQueryBuilder<'a> {
let mut query = self.query; let mut query = self.query;
if let Some(search_term) = self.search_term { if let Some(search_term) = self.search_term {
query = query.filter(name.ilike(fuzzy_search(&search_term))); let searcher = fuzzy_search(&search_term);
query = query
.filter(name.ilike(searcher.to_owned()))
.or_filter(title.ilike(searcher.to_owned()))
.or_filter(description.ilike(searcher));
}; };
// The view lets you pass a null user_id, if you're not logged in // The view lets you pass a null user_id, if you're not logged in

View file

@ -506,6 +506,10 @@ mod tests {
stickied: None, stickied: None,
updated: None, updated: None,
nsfw: false, nsfw: false,
embed_title: None,
embed_description: None,
embed_html: None,
thumbnail_url: None,
}; };
let inserted_post = Post::create(&conn, &new_post).unwrap(); let inserted_post = Post::create(&conn, &new_post).unwrap();

View file

@ -17,6 +17,10 @@ pub struct Post {
pub deleted: bool, pub deleted: bool,
pub nsfw: bool, pub nsfw: bool,
pub stickied: bool, pub stickied: bool,
pub embed_title: Option<String>,
pub embed_description: Option<String>,
pub embed_html: Option<String>,
pub thumbnail_url: Option<String>,
} }
#[derive(Insertable, AsChangeset, Clone)] #[derive(Insertable, AsChangeset, Clone)]
@ -33,6 +37,10 @@ pub struct PostForm {
pub deleted: Option<bool>, pub deleted: Option<bool>,
pub nsfw: bool, pub nsfw: bool,
pub stickied: Option<bool>, pub stickied: Option<bool>,
pub embed_title: Option<String>,
pub embed_description: Option<String>,
pub embed_html: Option<String>,
pub thumbnail_url: Option<String>,
} }
impl Crud<PostForm> for Post { impl Crud<PostForm> for Post {
@ -229,6 +237,10 @@ mod tests {
stickied: None, stickied: None,
nsfw: false, nsfw: false,
updated: None, updated: None,
embed_title: None,
embed_description: None,
embed_html: None,
thumbnail_url: None,
}; };
let inserted_post = Post::create(&conn, &new_post).unwrap(); let inserted_post = Post::create(&conn, &new_post).unwrap();
@ -247,6 +259,10 @@ mod tests {
nsfw: false, nsfw: false,
deleted: false, deleted: false,
updated: None, updated: None,
embed_title: None,
embed_description: None,
embed_html: None,
thumbnail_url: None,
}; };
// Post Like // Post Like

View file

@ -17,9 +17,54 @@ table! {
updated -> Nullable<Timestamp>, updated -> Nullable<Timestamp>,
deleted -> Bool, deleted -> Bool,
nsfw -> Bool, nsfw -> Bool,
stickied -> Bool,
embed_title -> Nullable<Text>,
embed_description -> Nullable<Text>,
embed_html -> Nullable<Text>,
thumbnail_url -> Nullable<Text>,
banned -> Bool, banned -> Bool,
banned_from_community -> Bool, banned_from_community -> Bool,
creator_name -> Varchar,
creator_avatar -> Nullable<Text>,
community_name -> Varchar,
community_removed -> Bool,
community_deleted -> Bool,
community_nsfw -> Bool,
number_of_comments -> BigInt,
score -> BigInt,
upvotes -> BigInt,
downvotes -> BigInt,
hot_rank -> Int4,
newest_activity_time -> Timestamp,
user_id -> Nullable<Int4>,
my_vote -> Nullable<Int4>,
subscribed -> Nullable<Bool>,
read -> Nullable<Bool>,
saved -> Nullable<Bool>,
}
}
table! {
post_mview (id) {
id -> Int4,
name -> Varchar,
url -> Nullable<Text>,
body -> Nullable<Text>,
creator_id -> Int4,
community_id -> Int4,
removed -> Bool,
locked -> Bool,
published -> Timestamp,
updated -> Nullable<Timestamp>,
deleted -> Bool,
nsfw -> Bool,
stickied -> Bool, stickied -> Bool,
embed_title -> Nullable<Text>,
embed_description -> Nullable<Text>,
embed_html -> Nullable<Text>,
thumbnail_url -> Nullable<Text>,
banned -> Bool,
banned_from_community -> Bool,
creator_name -> Varchar, creator_name -> Varchar,
creator_avatar -> Nullable<Text>, creator_avatar -> Nullable<Text>,
community_name -> Varchar, community_name -> Varchar,
@ -57,9 +102,13 @@ pub struct PostView {
pub updated: Option<chrono::NaiveDateTime>, pub updated: Option<chrono::NaiveDateTime>,
pub deleted: bool, pub deleted: bool,
pub nsfw: bool, pub nsfw: bool,
pub stickied: bool,
pub embed_title: Option<String>,
pub embed_description: Option<String>,
pub embed_html: Option<String>,
pub thumbnail_url: Option<String>,
pub banned: bool, pub banned: bool,
pub banned_from_community: bool, pub banned_from_community: bool,
pub stickied: bool,
pub creator_name: String, pub creator_name: String,
pub creator_avatar: Option<String>, pub creator_avatar: Option<String>,
pub community_name: String, pub community_name: String,
@ -79,44 +128,6 @@ pub struct PostView {
pub saved: Option<bool>, pub saved: Option<bool>,
} }
// The faked schema since diesel doesn't do views
table! {
post_mview (id) {
id -> Int4,
name -> Varchar,
url -> Nullable<Text>,
body -> Nullable<Text>,
creator_id -> Int4,
community_id -> Int4,
removed -> Bool,
locked -> Bool,
published -> Timestamp,
updated -> Nullable<Timestamp>,
deleted -> Bool,
nsfw -> Bool,
banned -> Bool,
banned_from_community -> Bool,
stickied -> Bool,
creator_name -> Varchar,
creator_avatar -> Nullable<Text>,
community_name -> Varchar,
community_removed -> Bool,
community_deleted -> Bool,
community_nsfw -> Bool,
number_of_comments -> BigInt,
score -> BigInt,
upvotes -> BigInt,
downvotes -> BigInt,
hot_rank -> Int4,
newest_activity_time -> Timestamp,
user_id -> Nullable<Int4>,
my_vote -> Nullable<Int4>,
subscribed -> Nullable<Bool>,
read -> Nullable<Bool>,
saved -> Nullable<Bool>,
}
}
pub struct PostQueryBuilder<'a> { pub struct PostQueryBuilder<'a> {
conn: &'a PgConnection, conn: &'a PgConnection,
query: BoxedQuery<'a, Pg>, query: BoxedQuery<'a, Pg>,
@ -394,6 +405,10 @@ mod tests {
stickied: None, stickied: None,
updated: None, updated: None,
nsfw: false, nsfw: false,
embed_title: None,
embed_description: None,
embed_html: None,
thumbnail_url: None,
}; };
let inserted_post = Post::create(&conn, &new_post).unwrap(); let inserted_post = Post::create(&conn, &new_post).unwrap();
@ -454,6 +469,10 @@ mod tests {
read: None, read: None,
saved: None, saved: None,
nsfw: false, nsfw: false,
embed_title: None,
embed_description: None,
embed_html: None,
thumbnail_url: None,
}; };
let expected_post_listing_with_user = PostView { let expected_post_listing_with_user = PostView {
@ -489,6 +508,10 @@ mod tests {
read: None, read: None,
saved: None, saved: None,
nsfw: false, nsfw: false,
embed_title: None,
embed_description: None,
embed_html: None,
thumbnail_url: None,
}; };
let read_post_listings_with_user = PostQueryBuilder::create(&conn) let read_post_listings_with_user = PostQueryBuilder::create(&conn)

View file

@ -132,6 +132,10 @@ mod tests {
stickied: None, stickied: None,
updated: None, updated: None,
nsfw: false, nsfw: false,
embed_title: None,
embed_description: None,
embed_html: None,
thumbnail_url: None,
}; };
let inserted_post = Post::create(&conn, &new_post).unwrap(); let inserted_post = Post::create(&conn, &new_post).unwrap();

View file

@ -33,14 +33,17 @@ pub mod websocket;
use crate::settings::Settings; use crate::settings::Settings;
use chrono::{DateTime, FixedOffset, Local, NaiveDateTime}; use chrono::{DateTime, FixedOffset, Local, NaiveDateTime};
use chttp::prelude::*;
use lettre::smtp::authentication::{Credentials, Mechanism}; use lettre::smtp::authentication::{Credentials, Mechanism};
use lettre::smtp::extension::ClientId; use lettre::smtp::extension::ClientId;
use lettre::smtp::ConnectionReuseParameters; use lettre::smtp::ConnectionReuseParameters;
use lettre::{ClientSecurity, SmtpClient, Transport}; use lettre::{ClientSecurity, SmtpClient, Transport};
use lettre_email::Email; use lettre_email::Email;
use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC};
use rand::distributions::Alphanumeric; use rand::distributions::Alphanumeric;
use rand::{thread_rng, Rng}; use rand::{thread_rng, Rng};
use regex::{Regex, RegexBuilder}; use regex::{Regex, RegexBuilder};
use serde::Deserialize;
pub fn naive_now() -> NaiveDateTime { pub fn naive_now() -> NaiveDateTime {
chrono::prelude::Utc::now().naive_utc() chrono::prelude::Utc::now().naive_utc()
@ -144,6 +147,77 @@ pub fn send_email(
} }
} }
#[derive(Deserialize, Debug)]
pub struct IframelyResponse {
title: Option<String>,
description: Option<String>,
thumbnail_url: Option<String>,
html: Option<String>,
}
pub fn fetch_iframely(url: &str) -> Result<IframelyResponse, failure::Error> {
let fetch_url = format!("http://iframely/oembed?url={}", url);
let text = chttp::get(&fetch_url)?.text()?;
let res: IframelyResponse = serde_json::from_str(&text)?;
Ok(res)
}
#[derive(Deserialize, Debug)]
pub struct PictshareResponse {
status: String,
url: String,
}
pub fn fetch_pictshare(image_url: &str) -> Result<PictshareResponse, failure::Error> {
let fetch_url = format!(
"http://pictshare/api/geturl.php?url={}",
utf8_percent_encode(image_url, NON_ALPHANUMERIC)
);
let text = chttp::get(&fetch_url)?.text()?;
let res: PictshareResponse = serde_json::from_str(&text)?;
Ok(res)
}
fn fetch_iframely_and_pictshare_data(
url: Option<String>,
) -> (
Option<String>,
Option<String>,
Option<String>,
Option<String>,
) {
// Fetch iframely data
let (iframely_title, iframely_description, iframely_thumbnail_url, iframely_html) = match url {
Some(url) => match fetch_iframely(&url) {
Ok(res) => (res.title, res.description, res.thumbnail_url, res.html),
Err(e) => {
eprintln!("iframely err: {}", e);
(None, None, None, None)
}
},
None => (None, None, None, None),
};
// Fetch pictshare thumbnail
let pictshare_thumbnail = match iframely_thumbnail_url {
Some(iframely_thumbnail_url) => match fetch_pictshare(&iframely_thumbnail_url) {
Ok(res) => Some(res.url),
Err(e) => {
eprintln!("pictshare err: {}", e);
None
}
},
None => None,
};
(
iframely_title,
iframely_description,
iframely_html,
pictshare_thumbnail,
)
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::{extract_usernames, is_email_regex, remove_slurs, slur_check, slurs_vec_to_str}; use crate::{extract_usernames, is_email_regex, remove_slurs, slur_check, slurs_vec_to_str};
@ -189,6 +263,21 @@ mod tests {
assert_eq!(usernames, expected); assert_eq!(usernames, expected);
} }
// These helped with testing
// #[test]
// fn test_iframely() {
// let res = fetch_iframely("https://www.redspark.nu/?p=15341");
// assert!(res.is_ok());
// }
// #[test]
// fn test_pictshare() {
// let res = fetch_pictshare("https://upload.wikimedia.org/wikipedia/en/2/27/The_Mandalorian_logo.jpg");
// assert!(res.is_ok());
// let res_other = fetch_pictshare("https://upload.wikimedia.org/wikipedia/en/2/27/The_Mandalorian_logo.jpgaoeu");
// assert!(res_other.is_err());
// }
// #[test] // #[test]
// fn test_send_email() { // fn test_send_email() {
// let result = send_email("not a subject", "test_email@gmail.com", "ur user", "<h1>HI there</h1>"); // let result = send_email("not a subject", "test_email@gmail.com", "ur user", "<h1>HI there</h1>");

View file

@ -207,6 +207,10 @@ table! {
deleted -> Bool, deleted -> Bool,
nsfw -> Bool, nsfw -> Bool,
stickied -> Bool, stickied -> Bool,
embed_title -> Nullable<Text>,
embed_description -> Nullable<Text>,
embed_html -> Nullable<Text>,
thumbnail_url -> Nullable<Text>,
} }
} }

View file

@ -1 +1 @@
pub const VERSION: &str = "v0.6.25"; pub const VERSION: &str = "v0.6.39";

View file

@ -74,10 +74,6 @@
border-top: 2px solid var(--dark); border-top: 2px solid var(--dark);
} }
.comment-node {
margin-bottom: 10px;
}
.vote-bar { .vote-bar {
margin-top: -6.5px; margin-top: -6.5px;
} }
@ -95,8 +91,17 @@
fill: currentColor; fill: currentColor;
vertical-align: middle; vertical-align: middle;
align-self: center; align-self: center;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
} }
.icon-inline {
margin-bottom: 2px;
}
.spin { .spin {
animation: spins 2s linear infinite; animation: spins 2s linear infinite;
@ -112,7 +117,7 @@
} }
blockquote { blockquote {
border-left: 3px solid #ccc; border-left: 2px solid var(--secondary);
margin: 0.5em 5px; margin: 0.5em 5px;
padding: 0.1em 5px; padding: 0.1em 5px;
} }
@ -131,8 +136,13 @@ blockquote {
} }
.thumbnail { .thumbnail {
max-height: 62px; object-fit: cover;
max-width: 400px; max-height: 80px;
width: 100%;
}
svg.thumbnail {
height: 40px;
} }
.no-s-hows { .no-s-hows {
@ -188,6 +198,18 @@ hr {
border: unset; border: unset;
} }
.mini-overlay {
position: absolute;
top: 0;
right: 0;
padding: 2px;
height: 1.5em;
width: 1.5em;
background: rgba(0,0,0,.4);
border-bottom-left-radius: 0.25rem !important;
border-top-right-radius: 0.25rem !important;
}
.link-overlay:hover { .link-overlay:hover {
transition: .1s; transition: .1s;
opacity: 1; opacity: 1;
@ -208,3 +230,25 @@ hr {
height: 50px; height: 50px;
width: 50px; width: 50px;
} }
.unselectable {
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.list-inline-item-action {
display: inline-block;
}
.list-inline-item-action:not(:last-child) {
margin-right: 1.2rem;
}
pre {
white-space: pre-wrap;
word-break: keep-all;
}

1
ui/assets/css/tippy.css vendored Normal file
View file

@ -0,0 +1 @@
.tippy-box[data-animation=fade][data-state=hidden]{opacity:0}.tippy-iOS{cursor:pointer!important;-webkit-tap-highlight-color:transparent}[data-tippy-root]{max-width:calc(100vw - 10px)}.tippy-box{position:relative;background-color:#333;color:#fff;border-radius:4px;font-size:14px;line-height:1.4;outline:0;transition-property:transform,visibility,opacity}.tippy-box[data-placement^=top]>.tippy-arrow{bottom:0}.tippy-box[data-placement^=top]>.tippy-arrow:before{border-width:8px 8px 0;border-top-color:#333;bottom:-7px;transform-origin:center top}.tippy-box[data-placement^=bottom]>.tippy-arrow{top:0}.tippy-box[data-placement^=bottom]>.tippy-arrow:before{top:-7px;border-width:0 8px 8px;border-bottom-color:#333;transform-origin:center bottom}.tippy-box[data-placement^=left]>.tippy-arrow{right:0}.tippy-box[data-placement^=left]>.tippy-arrow:before{border-width:8px 0 8px 8px;border-left-color:#333;right:-7px;transform-origin:center left}.tippy-box[data-placement^=right]>.tippy-arrow{left:0}.tippy-box[data-placement^=right]>.tippy-arrow:before{left:-7px;border-width:8px 8px 8px 0;border-right-color:#333;transform-origin:center right}.tippy-box[data-inertia][data-state=visible]{transition-timing-function:cubic-bezier(.54,1.5,.38,1.11)}.tippy-arrow{width:16px;height:16px}.tippy-arrow:before{content:"";position:absolute;border-color:transparent;border-style:solid}.tippy-content{position:relative;padding:5px 9px;z-index:1}

25
ui/generate_translations.js vendored Normal file
View file

@ -0,0 +1,25 @@
fs = require('fs');
fs.mkdirSync('src/translations/', { recursive: true });
fs.readdir('translations', (err, files) => {
files.forEach(filename => {
const lang = filename.split('.')[0];
try {
const json = JSON.parse(
fs.readFileSync('translations/' + filename, 'utf8')
);
var data = `export const ${lang} = {\n translation: {`;
for (var key in json) {
if (key in json) {
const value = json[key].replace(/"/g, '\\"');
data = `${data}\n ${key}: "${value}",`;
}
}
data += '\n },\n};';
const target = 'src/translations/' + lang + '.ts';
fs.writeFileSync(target, data);
} catch (err) {
console.error(err);
}
});
});

13
ui/package.json vendored
View file

@ -8,6 +8,8 @@
"scripts": { "scripts": {
"build": "node fuse prod", "build": "node fuse prod",
"lint": "tsc --noEmit && eslint --report-unused-disable-directives --ext .js,.ts,.tsx src", "lint": "tsc --noEmit && eslint --report-unused-disable-directives --ext .js,.ts,.tsx src",
"prebuild": "node generate_translations.js",
"prestart": "node generate_translations.js",
"start": "node fuse dev" "start": "node fuse dev"
}, },
"keywords": [], "keywords": [],
@ -25,9 +27,9 @@
"emoji-short-name": "^1.0.0", "emoji-short-name": "^1.0.0",
"husky": "^4.2.1", "husky": "^4.2.1",
"i18next": "^19.0.3", "i18next": "^19.0.3",
"inferno": "^7.0.1", "inferno": "^7.4.2",
"inferno-i18next": "nimbusec-oss/inferno-i18next", "inferno-i18next": "nimbusec-oss/inferno-i18next",
"inferno-router": "^7.0.1", "inferno-router": "^7.4.2",
"js-cookie": "^2.2.0", "js-cookie": "^2.2.0",
"jwt-decode": "^2.2.0", "jwt-decode": "^2.2.0",
"markdown-it": "^10.0.0", "markdown-it": "^10.0.0",
@ -39,8 +41,9 @@
"reconnecting-websocket": "^4.4.0", "reconnecting-websocket": "^4.4.0",
"rxjs": "^6.4.0", "rxjs": "^6.4.0",
"terser": "^4.6.3", "terser": "^4.6.3",
"tippy.js": "^6.0.0",
"toastify-js": "^1.6.2", "toastify-js": "^1.6.2",
"tributejs": "^4.1.1", "tributejs": "^5.0.0",
"twemoji": "^12.1.2", "twemoji": "^12.1.2",
"ws": "^7.0.0" "ws": "^7.0.0"
}, },
@ -54,7 +57,7 @@
"ts-node": "^8.6.2", "ts-node": "^8.6.2",
"ts-transform-classcat": "^0.0.2", "ts-transform-classcat": "^0.0.2",
"ts-transform-inferno": "^4.0.2", "ts-transform-inferno": "^4.0.2",
"typescript": "^3.7.5" "typescript": "^3.8.3"
}, },
"engines": { "engines": {
"node": ">=8.9.0" "node": ">=8.9.0"
@ -62,7 +65,7 @@
"engineStrict": true, "engineStrict": true,
"husky": { "husky": {
"hooks": { "hooks": {
"pre-commit": "yarn run ts-node translation_report.ts && git add ../README.md && cargo clippy --manifest-path ../server/Cargo.toml --all-targets --all-features -- -D warnings && lint-staged" "pre-commit": "cargo clippy --manifest-path ../server/Cargo.toml --all-targets --all-features -- -D warnings && lint-staged"
} }
}, },
"lint-staged": { "lint-staged": {

View file

@ -1,7 +1,13 @@
import { Component, linkEvent } from 'inferno'; import { Component, linkEvent } from 'inferno';
import { Subscription } from 'rxjs';
import { retryWhen, delay, take } from 'rxjs/operators';
import { Prompt } from 'inferno-router';
import { import {
CommentNode as CommentNodeI, CommentNode as CommentNodeI,
CommentForm as CommentFormI, CommentForm as CommentFormI,
WebSocketJsonResponse,
UserOperation,
CommentResponse,
} from '../interfaces'; } from '../interfaces';
import { import {
capitalizeFirstLetter, capitalizeFirstLetter,
@ -10,6 +16,7 @@ import {
markdownHelpUrl, markdownHelpUrl,
toast, toast,
setupTribute, setupTribute,
wsJsonToRes,
} from '../utils'; } from '../utils';
import { WebSocketService, UserService } from '../services'; import { WebSocketService, UserService } from '../services';
import autosize from 'autosize'; import autosize from 'autosize';
@ -28,12 +35,15 @@ interface CommentFormState {
commentForm: CommentFormI; commentForm: CommentFormI;
buttonTitle: string; buttonTitle: string;
previewMode: boolean; previewMode: boolean;
loading: boolean;
imageLoading: boolean; imageLoading: boolean;
} }
export class CommentForm extends Component<CommentFormProps, CommentFormState> { export class CommentForm extends Component<CommentFormProps, CommentFormState> {
private id = `comment-form-${randomStr()}`; private id = `comment-textarea-${randomStr()}`;
private formId = `comment-form-${randomStr()}`;
private tribute: Tribute; private tribute: Tribute;
private subscription: Subscription;
private emptyState: CommentFormState = { private emptyState: CommentFormState = {
commentForm: { commentForm: {
auth: null, auth: null,
@ -51,6 +61,7 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> {
? capitalizeFirstLetter(i18n.t('edit')) ? capitalizeFirstLetter(i18n.t('edit'))
: capitalizeFirstLetter(i18n.t('reply')), : capitalizeFirstLetter(i18n.t('reply')),
previewMode: false, previewMode: false,
loading: false,
imageLoading: false, imageLoading: false,
}; };
@ -71,6 +82,14 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> {
this.state.commentForm.parent_id = this.props.node.comment.id; this.state.commentForm.parent_id = this.props.node.comment.id;
} }
} }
this.subscription = WebSocketService.Instance.subject
.pipe(retryWhen(errors => errors.pipe(delay(3000), take(10))))
.subscribe(
msg => this.parseMessage(msg),
err => console.error(err),
() => console.log('complete')
);
} }
componentDidMount() { componentDidMount() {
@ -84,10 +103,21 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> {
}); });
} }
componentWillUnmount() {
this.subscription.unsubscribe();
}
render() { render() {
return ( return (
<div class="mb-3"> <div class="mb-3">
<form onSubmit={linkEvent(this, this.handleCommentSubmit)}> <Prompt
when={this.state.commentForm.content}
message={i18n.t('block_leaving')}
/>
<form
id={this.formId}
onSubmit={linkEvent(this, this.handleCommentSubmit)}
>
<div class="form-group row"> <div class="form-group row">
<div className={`col-sm-12`}> <div className={`col-sm-12`}>
<textarea <textarea
@ -118,7 +148,13 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> {
class="btn btn-sm btn-secondary mr-2" class="btn btn-sm btn-secondary mr-2"
disabled={this.props.disabled} disabled={this.props.disabled}
> >
{this.state.buttonTitle} {this.state.loading ? (
<svg class="icon icon-spinner spin">
<use xlinkHref="#icon-spinner"></use>
</svg>
) : (
<span>{this.state.buttonTitle}</span>
)}
</button> </button>
{this.state.commentForm.content && ( {this.state.commentForm.content && (
<button <button
@ -141,16 +177,22 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> {
<a <a
href={markdownHelpUrl} href={markdownHelpUrl}
target="_blank" target="_blank"
class="d-inline-block float-right text-muted small font-weight-bold" class="d-inline-block float-right text-muted font-weight-bold"
title={i18n.t('formatting_help')}
> >
{i18n.t('formatting_help')} <svg class="icon icon-inline">
<use xlinkHref="#icon-help-circle"></use>
</svg>
</a> </a>
<form class="d-inline-block mr-2 float-right text-muted small font-weight-bold"> <form class="d-inline-block mr-3 float-right text-muted font-weight-bold">
<label <label
htmlFor={`file-upload-${this.id}`} htmlFor={`file-upload-${this.id}`}
className={`${UserService.Instance.user && 'pointer'}`} className={`${UserService.Instance.user && 'pointer'}`}
data-tippy-content={i18n.t('upload_image')}
> >
{i18n.t('upload_image')} <svg class="icon icon-inline">
<use xlinkHref="#icon-image"></use>
</svg>
</label> </label>
<input <input
id={`file-upload-${this.id}`} id={`file-upload-${this.id}`}
@ -174,6 +216,20 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> {
); );
} }
handleFinished() {
this.state.previewMode = false;
this.state.loading = false;
this.state.commentForm.content = '';
this.setState(this.state);
let form: any = document.getElementById(this.formId);
form.reset();
if (this.props.node) {
this.props.onReplyCancel();
}
autosize.update(document.querySelector('textarea'));
this.setState(this.state);
}
handleCommentSubmit(i: CommentForm, event: any) { handleCommentSubmit(i: CommentForm, event: any) {
event.preventDefault(); event.preventDefault();
if (i.props.edit) { if (i.props.edit) {
@ -182,15 +238,8 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> {
WebSocketService.Instance.createComment(i.state.commentForm); WebSocketService.Instance.createComment(i.state.commentForm);
} }
i.state.previewMode = false; i.state.loading = true;
i.state.commentForm.content = undefined;
event.target.reset();
i.setState(i.state); i.setState(i.state);
if (i.props.node) {
i.props.onReplyCancel();
}
autosize.update(document.querySelector('textarea'));
} }
handleCommentContentChange(i: CommentForm, event: any) { handleCommentContentChange(i: CommentForm, event: any) {
@ -245,7 +294,7 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> {
i.state.commentForm.content = content; i.state.commentForm.content = content;
i.state.imageLoading = false; i.state.imageLoading = false;
i.setState(i.state); i.setState(i.state);
var textarea: any = document.getElementById(i.id); let textarea: any = document.getElementById(i.id);
autosize.update(textarea); autosize.update(textarea);
}) })
.catch(error => { .catch(error => {
@ -254,4 +303,23 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> {
toast(error, 'danger'); toast(error, 'danger');
}); });
} }
parseMessage(msg: WebSocketJsonResponse) {
let res = wsJsonToRes(msg);
// Only do the showing and hiding if logged in
if (UserService.Instance.user) {
if (res.op == UserOperation.CreateComment) {
let data = res.data as CommentResponse;
if (data.comment.creator_id == UserService.Instance.user.id) {
this.handleFinished();
}
} else if (res.op == UserOperation.EditComment) {
let data = res.data as CommentResponse;
if (data.comment.creator_id == UserService.Instance.user.id) {
this.handleFinished();
}
}
}
}
} }

View file

@ -26,6 +26,8 @@ import {
isMod, isMod,
pictshareAvatarThumbnail, pictshareAvatarThumbnail,
showAvatars, showAvatars,
setupTippy,
colorList,
} from '../utils'; } from '../utils';
import moment from 'moment'; import moment from 'moment';
import { MomentTime } from './moment-time'; import { MomentTime } from './moment-time';
@ -48,10 +50,12 @@ interface CommentNodeState {
showConfirmAppointAsAdmin: boolean; showConfirmAppointAsAdmin: boolean;
collapsed: boolean; collapsed: boolean;
viewSource: boolean; viewSource: boolean;
showAdvanced: boolean;
my_vote: number; my_vote: number;
score: number; score: number;
upvotes: number; upvotes: number;
downvotes: number; downvotes: number;
borderColor: string;
} }
interface CommentNodeProps { interface CommentNodeProps {
@ -81,6 +85,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
banType: BanType.Community, banType: BanType.Community,
collapsed: false, collapsed: false,
viewSource: false, viewSource: false,
showAdvanced: false,
showConfirmTransferSite: false, showConfirmTransferSite: false,
showConfirmTransferCommunity: false, showConfirmTransferCommunity: false,
showConfirmAppointAsMod: false, showConfirmAppointAsMod: false,
@ -89,6 +94,9 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
score: this.props.node.comment.score, score: this.props.node.comment.score,
upvotes: this.props.node.comment.upvotes, upvotes: this.props.node.comment.upvotes,
downvotes: this.props.node.comment.downvotes, downvotes: this.props.node.comment.downvotes,
borderColor: this.props.node.comment.depth
? colorList[this.props.node.comment.depth % colorList.length]
: colorList[0],
}; };
constructor(props: any, context: any) { constructor(props: any, context: any) {
@ -113,56 +121,44 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
return ( return (
<div <div
className={`comment ${ className={`comment ${
node.comment.parent_id && !this.props.noIndent ? 'ml-4' : '' node.comment.parent_id && !this.props.noIndent ? 'ml-2' : ''
}`} }`}
> >
{!this.state.collapsed && ( {!node.comment.parent_id && !this.props.noIndent && (
<div <>
className={`vote-bar mr-2 float-left small text-center ${this.props <hr class="d-sm-none my-2" />
.viewOnly && 'no-click'}`} <div class="d-none d-sm-block d-sm-none my-3" />
> </>
<button
className={`vote-animate btn btn-link p-0 ${
this.state.my_vote == 1 ? 'text-info' : 'text-muted'
}`}
onClick={linkEvent(node, this.handleCommentUpvote)}
>
<svg class="icon upvote">
<use xlinkHref="#icon-arrow-up"></use>
</svg>
</button>
<div class={`font-weight-bold text-muted`}>{this.state.score}</div>
{WebSocketService.Instance.site.enable_downvotes && (
<button
className={`vote-animate btn btn-link p-0 ${
this.state.my_vote == -1 ? 'text-danger' : 'text-muted'
}`}
onClick={linkEvent(node, this.handleCommentDownvote)}
>
<svg class="icon downvote">
<use xlinkHref="#icon-arrow-down"></use>
</svg>
</button>
)}
</div>
)} )}
<div <div
id={`comment-${node.comment.id}`} id={`comment-${node.comment.id}`}
className={`details comment-node ml-4 ${ className={`details comment-node mb-1 ${
this.isCommentNew ? 'mark' : '' this.isCommentNew ? 'mark' : ''
}`} }`}
style={
!this.props.noIndent &&
this.props.node.comment.parent_id &&
`border-left: 2px ${this.state.borderColor} solid !important`
}
> >
<ul class="list-inline mb-0 text-muted small"> <div
class={`${!this.props.noIndent &&
this.props.node.comment.parent_id &&
'ml-2'}`}
>
<ul class="list-inline mb-1 text-muted small">
<li className="list-inline-item"> <li className="list-inline-item">
<Link <Link
className="text-info" className="text-body font-weight-bold"
to={`/u/${node.comment.creator_name}`} to={`/u/${node.comment.creator_name}`}
> >
{node.comment.creator_avatar && showAvatars() && ( {node.comment.creator_avatar && showAvatars() && (
<img <img
height="32" height="32"
width="32" width="32"
src={pictshareAvatarThumbnail(node.comment.creator_avatar)} src={pictshareAvatarThumbnail(
node.comment.creator_avatar
)}
class="rounded-circle mr-1" class="rounded-circle mr-1"
/> />
)} )}
@ -189,14 +185,6 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
{i18n.t('banned')} {i18n.t('banned')}
</li> </li>
)} )}
<li className="list-inline-item">
<span>
(<span className="text-info">+{this.state.upvotes}</span>
<span> | </span>
<span className="text-danger">-{this.state.downvotes}</span>
<span>) </span>
</span>
</li>
{this.props.showCommunity && ( {this.props.showCommunity && (
<li className="list-inline-item"> <li className="list-inline-item">
<span> {i18n.t('to')} </span> <span> {i18n.t('to')} </span>
@ -205,6 +193,22 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
</Link> </Link>
</li> </li>
)} )}
<li className="list-inline-item"></li>
<li className="list-inline-item">
<span
className={`unselectable pointer ${this.scoreColor}`}
onClick={linkEvent(node, this.handleCommentUpvote)}
data-tippy-content={i18n.t('number_of_points', {
count: this.state.score,
})}
>
<svg class="icon icon-inline mr-1">
<use xlinkHref="#icon-zap"></use>
</svg>
{this.state.score}
</span>
</li>
<li className="list-inline-item"></li>
<li className="list-inline-item"> <li className="list-inline-item">
<span> <span>
<MomentTime data={node.comment} /> <MomentTime data={node.comment} />
@ -212,10 +216,18 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
</li> </li>
<li className="list-inline-item"> <li className="list-inline-item">
<div <div
className="pointer text-monospace" className="unselectable pointer text-monospace"
onClick={linkEvent(this, this.handleCommentCollapse)} onClick={linkEvent(this, this.handleCommentCollapse)}
> >
{this.state.collapsed ? '[+]' : '[-]'} {this.state.collapsed ? (
<svg class="icon icon-inline">
<use xlinkHref="#icon-plus-square"></use>
</svg>
) : (
<svg class="icon icon-inline">
<use xlinkHref="#icon-minus-square"></use>
</svg>
)}
</div> </div>
</li> </li>
</ul> </ul>
@ -234,94 +246,201 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
) : ( ) : (
<div <div
className="md-div" className="md-div"
dangerouslySetInnerHTML={mdToHtml(this.commentUnlessRemoved)} dangerouslySetInnerHTML={mdToHtml(
this.commentUnlessRemoved
)}
/> />
)} )}
<ul class="list-inline mb-1 text-muted small font-weight-bold"> <ul class="list-inline mb-0 text-muted font-weight-bold h5">
{this.props.markable && ( {this.props.markable && (
<li className="list-inline-item"> <li className="list-inline-item-action">
<span <span
class="pointer" class="pointer"
onClick={linkEvent(this, this.handleMarkRead)} onClick={linkEvent(this, this.handleMarkRead)}
> data-tippy-content={
{node.comment.read node.comment.read
? i18n.t('mark_as_unread') ? i18n.t('mark_as_unread')
: i18n.t('mark_as_read')} : i18n.t('mark_as_read')
}
>
<svg
class={`icon icon-inline ${node.comment.read &&
'text-success'}`}
>
<use xlinkHref="#icon-check"></use>
</svg>
</span> </span>
</li> </li>
)} )}
{UserService.Instance.user && !this.props.viewOnly && ( {UserService.Instance.user && !this.props.viewOnly && (
<> <>
<li className="list-inline-item"> <li className="list-inline-item-action">
<button
className={`vote-animate btn btn-link p-0 mb-1 ${
this.state.my_vote == 1 ? 'text-info' : 'text-muted'
}`}
onClick={linkEvent(node, this.handleCommentUpvote)}
data-tippy-content={i18n.t('upvote')}
>
<svg class="icon icon-inline">
<use xlinkHref="#icon-arrow-up"></use>
</svg>
{this.state.upvotes !== this.state.score && (
<span class="ml-1">{this.state.upvotes}</span>
)}
</button>
</li>
{WebSocketService.Instance.site.enable_downvotes && (
<li className="list-inline-item-action">
<button
className={`vote-animate btn btn-link p-0 mb-1 ${
this.state.my_vote == -1
? 'text-danger'
: 'text-muted'
}`}
onClick={linkEvent(
node,
this.handleCommentDownvote
)}
data-tippy-content={i18n.t('downvote')}
>
<svg class="icon icon-inline">
<use xlinkHref="#icon-arrow-down"></use>
</svg>
{this.state.upvotes !== this.state.score && (
<span class="ml-1">{this.state.downvotes}</span>
)}
</button>
</li>
)}
<li className="list-inline-item-action">
<span <span
class="pointer" class="pointer"
onClick={linkEvent(this, this.handleReplyClick)} onClick={linkEvent(this, this.handleReplyClick)}
data-tippy-content={i18n.t('reply')}
> >
{i18n.t('reply')} <svg class="icon icon-inline">
<use xlinkHref="#icon-reply1"></use>
</svg>
</span> </span>
</li> </li>
<li className="list-inline-item mr-2"> <li className="list-inline-item-action">
<Link
className="text-muted"
to={`/post/${node.comment.post_id}/comment/${node.comment.id}`}
title={i18n.t('link')}
>
<svg class="icon icon-inline">
<use xlinkHref="#icon-link"></use>
</svg>
</Link>
</li>
{!this.state.showAdvanced ? (
<li className="list-inline-item-action">
<span
className="unselectable pointer"
onClick={linkEvent(this, this.handleShowAdvanced)}
data-tippy-content={i18n.t('more')}
>
<svg class="icon icon-inline">
<use xlinkHref="#icon-more-vertical"></use>
</svg>
</span>
</li>
) : (
<>
{!this.myComment && (
<li className="list-inline-item-action">
<Link
class="text-muted"
to={`/create_private_message?recipient_id=${node.comment.creator_id}`}
title={i18n.t('message').toLowerCase()}
>
<svg class="icon">
<use xlinkHref="#icon-mail"></use>
</svg>
</Link>
</li>
)}
<li className="list-inline-item-action">
<span <span
class="pointer" class="pointer"
onClick={linkEvent(this, this.handleSaveCommentClick)} onClick={linkEvent(
this,
this.handleSaveCommentClick
)}
data-tippy-content={
node.comment.saved
? i18n.t('unsave')
: i18n.t('save')
}
> >
{node.comment.saved ? i18n.t('unsave') : i18n.t('save')} <svg
class={`icon icon-inline ${node.comment.saved &&
'text-warning'}`}
>
<use xlinkHref="#icon-star"></use>
</svg>
</span>
</li>
<li className="list-inline-item-action">
<span
className="pointer"
onClick={linkEvent(this, this.handleViewSource)}
data-tippy-content={i18n.t('view_source')}
>
<svg
class={`icon icon-inline ${this.state
.viewSource && 'text-success'}`}
>
<use xlinkHref="#icon-file-text"></use>
</svg>
</span> </span>
</li> </li>
{this.myComment && ( {this.myComment && (
<> <>
<li className="list-inline-item"> <li className="list-inline-item-action"></li>
<li className="list-inline-item-action">
<span <span
class="pointer" class="pointer"
onClick={linkEvent(this, this.handleEditClick)} onClick={linkEvent(
this,
this.handleEditClick
)}
data-tippy-content={i18n.t('edit')}
> >
{i18n.t('edit')} <svg class="icon icon-inline">
<use xlinkHref="#icon-edit"></use>
</svg>
</span> </span>
</li> </li>
<li className="list-inline-item"> <li className="list-inline-item-action">
<span <span
class="pointer" class="pointer"
onClick={linkEvent(this, this.handleDeleteClick)} onClick={linkEvent(
> this,
{!node.comment.deleted this.handleDeleteClick
)}
data-tippy-content={
!node.comment.deleted
? i18n.t('delete') ? i18n.t('delete')
: i18n.t('restore')} : i18n.t('restore')
}
>
<svg
class={`icon icon-inline ${node.comment
.deleted && 'text-danger'}`}
>
<use xlinkHref="#icon-trash"></use>
</svg>
</span> </span>
</li> </li>
</> </>
)} )}
{!this.myComment && (
<li className="list-inline-item">
<Link
class="text-muted"
to={`/create_private_message?recipient_id=${node.comment.creator_id}`}
>
{i18n.t('message').toLowerCase()}
</Link>
</li>
)}
<li className="list-inline-item"></li>
<li className="list-inline-item">
<span
className="pointer"
onClick={linkEvent(this, this.handleViewSource)}
>
{i18n.t('view_source')}
</span>
</li>
<li className="list-inline-item">
<Link
className="text-muted"
to={`/post/${node.comment.post_id}/comment/${node.comment.id}`}
>
{i18n.t('link')}
</Link>
</li>
{/* Admins and mods can remove comments */} {/* Admins and mods can remove comments */}
{(this.canMod || this.canAdmin) && ( {(this.canMod || this.canAdmin) && (
<> <>
<li className="list-inline-item"></li> <li className="list-inline-item-action">
<li className="list-inline-item">
{!node.comment.removed ? ( {!node.comment.removed ? (
<span <span
class="pointer" class="pointer"
@ -350,7 +469,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
{this.canMod && ( {this.canMod && (
<> <>
{!this.isMod && ( {!this.isMod && (
<li className="list-inline-item"> <li className="list-inline-item-action">
{!node.comment.banned_from_community ? ( {!node.comment.banned_from_community ? (
<span <span
class="pointer" class="pointer"
@ -375,7 +494,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
</li> </li>
)} )}
{!node.comment.banned_from_community && ( {!node.comment.banned_from_community && (
<li className="list-inline-item"> <li className="list-inline-item-action">
{!this.state.showConfirmAppointAsMod ? ( {!this.state.showConfirmAppointAsMod ? (
<span <span
class="pointer" class="pointer"
@ -418,8 +537,9 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
</> </>
)} )}
{/* Community creators and admins can transfer community to another mod */} {/* Community creators and admins can transfer community to another mod */}
{(this.amCommunityCreator || this.canAdmin) && this.isMod && ( {(this.amCommunityCreator || this.canAdmin) &&
<li className="list-inline-item"> this.isMod && (
<li className="list-inline-item-action">
{!this.state.showConfirmTransferCommunity ? ( {!this.state.showConfirmTransferCommunity ? (
<span <span
class="pointer" class="pointer"
@ -448,7 +568,8 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
class="pointer d-inline-block" class="pointer d-inline-block"
onClick={linkEvent( onClick={linkEvent(
this, this,
this.handleCancelShowConfirmTransferCommunity this
.handleCancelShowConfirmTransferCommunity
)} )}
> >
{i18n.t('no')} {i18n.t('no')}
@ -461,11 +582,14 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
{this.canAdmin && ( {this.canAdmin && (
<> <>
{!this.isAdmin && ( {!this.isAdmin && (
<li className="list-inline-item"> <li className="list-inline-item-action">
{!node.comment.banned ? ( {!node.comment.banned ? (
<span <span
class="pointer" class="pointer"
onClick={linkEvent(this, this.handleModBanShow)} onClick={linkEvent(
this,
this.handleModBanShow
)}
> >
{i18n.t('ban_from_site')} {i18n.t('ban_from_site')}
</span> </span>
@ -483,7 +607,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
</li> </li>
)} )}
{!node.comment.banned && ( {!node.comment.banned && (
<li className="list-inline-item"> <li className="list-inline-item-action">
{!this.state.showConfirmAppointAsAdmin ? ( {!this.state.showConfirmAppointAsAdmin ? (
<span <span
class="pointer" class="pointer"
@ -503,7 +627,10 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
</span> </span>
<span <span
class="pointer d-inline-block mr-1" class="pointer d-inline-block mr-1"
onClick={linkEvent(this, this.handleAddAdmin)} onClick={linkEvent(
this,
this.handleAddAdmin
)}
> >
{i18n.t('yes')} {i18n.t('yes')}
</span> </span>
@ -524,7 +651,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
)} )}
{/* Site Creator can transfer to another admin */} {/* Site Creator can transfer to another admin */}
{this.amSiteCreator && this.isAdmin && ( {this.amSiteCreator && this.isAdmin && (
<li className="list-inline-item"> <li className="list-inline-item-action">
{!this.state.showConfirmTransferSite ? ( {!this.state.showConfirmTransferSite ? (
<span <span
class="pointer" class="pointer"
@ -542,7 +669,10 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
</span> </span>
<span <span
class="pointer d-inline-block mr-1" class="pointer d-inline-block mr-1"
onClick={linkEvent(this, this.handleTransferSite)} onClick={linkEvent(
this,
this.handleTransferSite
)}
> >
{i18n.t('yes')} {i18n.t('yes')}
</span> </span>
@ -561,10 +691,14 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
)} )}
</> </>
)} )}
</>
)}
</ul> </ul>
</div> </div>
)} )}
</div> </div>
</div>
{/* end of details */}
{this.state.showRemoveDialog && ( {this.state.showRemoveDialog && (
<form <form
class="form-inline" class="form-inline"
@ -1016,4 +1150,20 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
i.state.viewSource = !i.state.viewSource; i.state.viewSource = !i.state.viewSource;
i.setState(i.state); i.setState(i.state);
} }
handleShowAdvanced(i: CommentNode) {
i.state.showAdvanced = !i.state.showAdvanced;
i.setState(i.state);
setupTippy();
}
get scoreColor() {
if (this.state.my_vote == 1) {
return 'text-info';
} else if (this.state.my_vote == -1) {
return 'text-danger';
} else {
return 'text-muted';
}
}
} }

View file

@ -38,6 +38,7 @@ export class CommentNodes extends Component<
<div className="comments"> <div className="comments">
{this.sorter().map(node => ( {this.sorter().map(node => (
<CommentNode <CommentNode
key={node.comment.id}
node={node} node={node}
noIndent={this.props.noIndent} noIndent={this.props.noIndent}
viewOnly={this.props.viewOnly} viewOnly={this.props.viewOnly}

View file

@ -1,4 +1,5 @@
import { Component, linkEvent } from 'inferno'; import { Component, linkEvent } from 'inferno';
import { Prompt } from 'inferno-router';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
import { retryWhen, delay, take } from 'rxjs/operators'; import { retryWhen, delay, take } from 'rxjs/operators';
import { import {
@ -105,6 +106,16 @@ export class CommunityForm extends Component<
render() { render() {
return ( return (
<>
<Prompt
when={
!this.state.loading &&
(this.state.communityForm.name ||
this.state.communityForm.title ||
this.state.communityForm.description)
}
message={i18n.t('block_leaving')}
/>
<form onSubmit={linkEvent(this, this.handleCreateCommunitySubmit)}> <form onSubmit={linkEvent(this, this.handleCreateCommunitySubmit)}>
<div class="form-group row"> <div class="form-group row">
<label class="col-12 col-form-label" htmlFor="community-name"> <label class="col-12 col-form-label" htmlFor="community-name">
@ -219,6 +230,7 @@ export class CommunityForm extends Component<
</div> </div>
</div> </div>
</form> </form>
</>
); );
} }

View file

@ -43,6 +43,7 @@ import {
createPostLikeFindRes, createPostLikeFindRes,
editPostFindRes, editPostFindRes,
commentsToFlatNodes, commentsToFlatNodes,
setupTippy,
} from '../utils'; } from '../utils';
import { i18n } from '../i18next'; import { i18n } from '../i18next';
@ -194,13 +195,14 @@ export class Community extends Component<any, State> {
selects() { selects() {
return ( return (
<div class="mb-2"> <div class="mb-3">
<span class="mr-3">
<DataTypeSelect <DataTypeSelect
type_={this.state.dataType} type_={this.state.dataType}
onChange={this.handleDataTypeChange} onChange={this.handleDataTypeChange}
/> />
</span>
<span class="mx-3"> <span class="mr-2">
<SortSelect sort={this.state.sort} onChange={this.handleSortChange} /> <SortSelect sort={this.state.sort} onChange={this.handleSortChange} />
</span> </span>
<a <a
@ -208,6 +210,7 @@ export class Community extends Component<any, State> {
SortType[this.state.sort] SortType[this.state.sort]
}`} }`}
target="_blank" target="_blank"
title="RSS"
> >
<svg class="icon text-muted small"> <svg class="icon text-muted small">
<use xlinkHref="#icon-rss">#</use> <use xlinkHref="#icon-rss">#</use>
@ -339,6 +342,7 @@ export class Community extends Component<any, State> {
this.state.posts = data.posts; this.state.posts = data.posts;
this.state.loading = false; this.state.loading = false;
this.setState(this.state); this.setState(this.state);
setupTippy();
} else if (res.op == UserOperation.EditPost) { } else if (res.op == UserOperation.EditPost) {
let data = res.data as PostResponse; let data = res.data as PostResponse;
editPostFindRes(data, this.state.posts); editPostFindRes(data, this.state.posts);

View file

@ -1,9 +1,10 @@
import { Component, linkEvent } from 'inferno'; import { Component, linkEvent } from 'inferno';
import { FramelyData } from '../interfaces'; import { Post } from '../interfaces';
import { mdToHtml } from '../utils'; import { mdToHtml } from '../utils';
import { i18n } from '../i18next';
interface FramelyCardProps { interface FramelyCardProps {
iframely: FramelyData; post: Post;
} }
interface FramelyCardState { interface FramelyCardState {
@ -24,45 +25,56 @@ export class IFramelyCard extends Component<
} }
render() { render() {
let iframely = this.props.iframely; let post = this.props.post;
return ( return (
<> <>
{iframely.title && !this.state.expanded && ( {post.embed_title && !this.state.expanded && (
<div class="card mt-3 mb-2"> <div class="card mt-3 mb-2">
<div class="row"> <div class="row">
<div class="col-12"> <div class="col-12">
<div class="card-body"> <div class="card-body">
<h5 class="card-title d-inline"> <h5 class="card-title d-inline">
{post.embed_html ? (
<span
class="unselectable pointer"
onClick={linkEvent(this, this.handleIframeExpand)}
data-tippy-content={i18n.t('expand_here')}
>
{post.embed_title}
</span>
) : (
<span> <span>
<a class="text-body" target="_blank" href={iframely.url}> <a class="text-body" target="_blank" href={post.url}>
{iframely.title} {post.embed_title}
</a> </a>
</span> </span>
)}
</h5> </h5>
<span class="d-inline-block ml-2 mb-2 small text-muted"> <span class="d-inline-block ml-2 mb-2 small text-muted">
<a <a
class="text-muted font-italic" class="text-muted font-italic"
target="_blank" target="_blank"
href={iframely.url} href={post.url}
> >
{new URL(iframely.url).hostname} {new URL(post.url).hostname}
<svg class="ml-1 icon"> <svg class="ml-1 icon">
<use xlinkHref="#icon-external-link"></use> <use xlinkHref="#icon-external-link"></use>
</svg> </svg>
</a> </a>
{iframely.html && ( {post.embed_html && (
<span <span
class="ml-2 pointer text-monospace" class="ml-2 pointer text-monospace"
onClick={linkEvent(this, this.handleIframeExpand)} onClick={linkEvent(this, this.handleIframeExpand)}
data-tippy-content={i18n.t('expand_here')}
> >
{this.state.expanded ? '[-]' : '[+]'} {this.state.expanded ? '[-]' : '[+]'}
</span> </span>
)} )}
</span> </span>
{iframely.description && ( {post.embed_description && (
<div <div
className="card-text small text-muted md-div" className="card-text small text-muted md-div"
dangerouslySetInnerHTML={mdToHtml(iframely.description)} dangerouslySetInnerHTML={mdToHtml(post.embed_description)}
/> />
)} )}
</div> </div>
@ -73,7 +85,7 @@ export class IFramelyCard extends Component<
{this.state.expanded && ( {this.state.expanded && (
<div <div
class="mt-3 mb-2" class="mt-3 mb-2"
dangerouslySetInnerHTML={{ __html: iframely.html }} dangerouslySetInnerHTML={{ __html: post.embed_html }}
/> />
)} )}
</> </>

View file

@ -28,6 +28,7 @@ import {
saveCommentRes, saveCommentRes,
createCommentLikeRes, createCommentLikeRes,
commentsToFlatNodes, commentsToFlatNodes,
setupTippy,
} from '../utils'; } from '../utils';
import { CommentNodes } from './comment-nodes'; import { CommentNodes } from './comment-nodes';
import { PrivateMessage } from './private-message'; import { PrivateMessage } from './private-message';
@ -116,6 +117,7 @@ export class Inbox extends Component<any, InboxState> {
<a <a
href={`/feeds/inbox/${UserService.Instance.auth}.xml`} href={`/feeds/inbox/${UserService.Instance.auth}.xml`}
target="_blank" target="_blank"
title="RSS"
> >
<svg class="icon mx-2 text-muted small"> <svg class="icon mx-2 text-muted small">
<use xlinkHref="#icon-rss">#</use> <use xlinkHref="#icon-rss">#</use>
@ -332,18 +334,21 @@ export class Inbox extends Component<any, InboxState> {
this.sendUnreadCount(); this.sendUnreadCount();
window.scrollTo(0, 0); window.scrollTo(0, 0);
this.setState(this.state); this.setState(this.state);
setupTippy();
} else if (res.op == UserOperation.GetUserMentions) { } else if (res.op == UserOperation.GetUserMentions) {
let data = res.data as GetUserMentionsResponse; let data = res.data as GetUserMentionsResponse;
this.state.mentions = data.mentions; this.state.mentions = data.mentions;
this.sendUnreadCount(); this.sendUnreadCount();
window.scrollTo(0, 0); window.scrollTo(0, 0);
this.setState(this.state); this.setState(this.state);
setupTippy();
} else if (res.op == UserOperation.GetPrivateMessages) { } else if (res.op == UserOperation.GetPrivateMessages) {
let data = res.data as PrivateMessagesResponse; let data = res.data as PrivateMessagesResponse;
this.state.messages = data.messages; this.state.messages = data.messages;
this.sendUnreadCount(); this.sendUnreadCount();
window.scrollTo(0, 0); window.scrollTo(0, 0);
this.setState(this.state); this.setState(this.state);
setupTippy();
} else if (res.op == UserOperation.EditPrivateMessage) { } else if (res.op == UserOperation.EditPrivateMessage) {
let data = res.data as PrivateMessageResponse; let data = res.data as PrivateMessageResponse;
let found: PrivateMessageI = this.state.messages.find( let found: PrivateMessageI = this.state.messages.find(
@ -364,6 +369,7 @@ export class Inbox extends Component<any, InboxState> {
this.sendUnreadCount(); this.sendUnreadCount();
window.scrollTo(0, 0); window.scrollTo(0, 0);
this.setState(this.state); this.setState(this.state);
setupTippy();
} else if (res.op == UserOperation.MarkAllAsRead) { } else if (res.op == UserOperation.MarkAllAsRead) {
this.state.replies = []; this.state.replies = [];
this.state.mentions = []; this.state.mentions = [];
@ -386,6 +392,7 @@ export class Inbox extends Component<any, InboxState> {
} }
this.sendUnreadCount(); this.sendUnreadCount();
this.setState(this.state); this.setState(this.state);
setupTippy();
} else if (res.op == UserOperation.EditUserMention) { } else if (res.op == UserOperation.EditUserMention) {
let data = res.data as UserMentionResponse; let data = res.data as UserMentionResponse;
@ -429,6 +436,7 @@ export class Inbox extends Component<any, InboxState> {
let data = res.data as CommentResponse; let data = res.data as CommentResponse;
saveCommentRes(data, this.state.replies); saveCommentRes(data, this.state.replies);
this.setState(this.state); this.setState(this.state);
setupTippy();
} else if (res.op == UserOperation.CreateCommentLike) { } else if (res.op == UserOperation.CreateCommentLike) {
let data = res.data as CommentResponse; let data = res.data as CommentResponse;
createCommentLikeRes(data, this.state.replies); createCommentLikeRes(data, this.state.replies);

View file

@ -51,7 +51,7 @@ import {
createPostLikeFindRes, createPostLikeFindRes,
editPostFindRes, editPostFindRes,
commentsToFlatNodes, commentsToFlatNodes,
commentSortSortType, setupTippy,
} from '../utils'; } from '../utils';
import { i18n } from '../i18next'; import { i18n } from '../i18next';
import { T } from 'inferno-i18next'; import { T } from 'inferno-i18next';
@ -183,7 +183,7 @@ export class Main extends Component<any, MainState> {
<h5> <h5>
<T i18nKey="subscribed_to_communities"> <T i18nKey="subscribed_to_communities">
# #
<Link class="text-white" to="/communities"> <Link class="text-body" to="/communities">
# #
</Link> </Link>
</T> </T>
@ -221,7 +221,7 @@ export class Main extends Component<any, MainState> {
<h5> <h5>
<T i18nKey="trending_communities"> <T i18nKey="trending_communities">
# #
<Link class="text-white" to="/communities"> <Link class="text-body" to="/communities">
# #
</Link> </Link>
</T> </T>
@ -268,13 +268,16 @@ export class Main extends Component<any, MainState> {
<div class="card-body"> <div class="card-body">
<h5 class="mb-0">{`${this.state.siteRes.site.name}`}</h5> <h5 class="mb-0">{`${this.state.siteRes.site.name}`}</h5>
{this.canAdmin && ( {this.canAdmin && (
<ul class="list-inline mb-1 text-muted small font-weight-bold"> <ul class="list-inline mb-1 text-muted font-weight-bold">
<li className="list-inline-item"> <li className="list-inline-item-action">
<span <span
class="pointer" class="pointer"
onClick={linkEvent(this, this.handleEditClick)} onClick={linkEvent(this, this.handleEditClick)}
data-tippy-content={i18n.t('edit')}
> >
{i18n.t('edit')} <svg class="icon icon-inline">
<use xlinkHref="#icon-edit"></use>
</svg>
</span> </span>
</li> </li>
</ul> </ul>
@ -313,7 +316,10 @@ export class Main extends Component<any, MainState> {
<li class="list-inline-item">{i18n.t('admins')}:</li> <li class="list-inline-item">{i18n.t('admins')}:</li>
{this.state.siteRes.admins.map(admin => ( {this.state.siteRes.admins.map(admin => (
<li class="list-inline-item"> <li class="list-inline-item">
<Link class="text-info" to={`/u/${admin.name}`}> <Link
class="text-body font-weight-bold"
to={`/u/${admin.name}`}
>
{admin.avatar && showAvatars() && ( {admin.avatar && showAvatars() && (
<img <img
height="32" height="32"
@ -424,11 +430,13 @@ export class Main extends Component<any, MainState> {
selects() { selects() {
return ( return (
<div className="mb-3"> <div className="mb-3">
<span class="mr-3">
<DataTypeSelect <DataTypeSelect
type_={this.state.dataType} type_={this.state.dataType}
onChange={this.handleDataTypeChange} onChange={this.handleDataTypeChange}
/> />
<span class="mx-3"> </span>
<span class="mr-3">
<ListingTypeSelect <ListingTypeSelect
type_={this.state.listingType} type_={this.state.listingType}
onChange={this.handleListingTypeChange} onChange={this.handleListingTypeChange}
@ -441,8 +449,9 @@ export class Main extends Component<any, MainState> {
<a <a
href={`/feeds/all.xml?sort=${SortType[this.state.sort]}`} href={`/feeds/all.xml?sort=${SortType[this.state.sort]}`}
target="_blank" target="_blank"
title="RSS"
> >
<svg class="icon mx-1 text-muted small"> <svg class="icon text-muted small">
<use xlinkHref="#icon-rss">#</use> <use xlinkHref="#icon-rss">#</use>
</svg> </svg>
</a> </a>
@ -454,8 +463,9 @@ export class Main extends Component<any, MainState> {
SortType[this.state.sort] SortType[this.state.sort]
}`} }`}
target="_blank" target="_blank"
title="RSS"
> >
<svg class="icon mx-1 text-muted small"> <svg class="icon text-muted small">
<use xlinkHref="#icon-rss">#</use> <use xlinkHref="#icon-rss">#</use>
</svg> </svg>
</a> </a>
@ -613,6 +623,7 @@ export class Main extends Component<any, MainState> {
this.state.posts = data.posts; this.state.posts = data.posts;
this.state.loading = false; this.state.loading = false;
this.setState(this.state); this.setState(this.state);
setupTippy();
} else if (res.op == UserOperation.CreatePost) { } else if (res.op == UserOperation.CreatePost) {
let data = res.data as PostResponse; let data = res.data as PostResponse;
@ -626,9 +637,19 @@ export class Main extends Component<any, MainState> {
this.state.posts.unshift(data.post); this.state.posts.unshift(data.post);
} }
} else { } else {
// NSFW posts
let nsfw = data.post.nsfw || data.post.community_nsfw;
// Don't push the post if its nsfw, and don't have that setting on
if (
!nsfw ||
(nsfw &&
UserService.Instance.user &&
UserService.Instance.user.show_nsfw)
) {
this.state.posts.unshift(data.post); this.state.posts.unshift(data.post);
} }
}
this.setState(this.state); this.setState(this.state);
} else if (res.op == UserOperation.EditPost) { } else if (res.op == UserOperation.EditPost) {
let data = res.data as PostResponse; let data = res.data as PostResponse;

View file

@ -354,7 +354,7 @@ export class Modlog extends Component<any, ModlogState> {
<h5> <h5>
{this.state.communityName && ( {this.state.communityName && (
<Link <Link
className="text-white" className="text-body"
to={`/c/${this.state.communityName}`} to={`/c/${this.state.communityName}`}
> >
/c/{this.state.communityName}{' '} /c/{this.state.communityName}{' '}

View file

@ -1,6 +1,6 @@
import { Component } from 'inferno'; import { Component } from 'inferno';
import moment from 'moment'; import moment from 'moment';
import { getMomentLanguage } from '../utils'; import { getMomentLanguage, capitalizeFirstLetter } from '../utils';
import { i18n } from '../i18next'; import { i18n } from '../i18next';
interface MomentTimeProps { interface MomentTimeProps {
@ -9,6 +9,7 @@ interface MomentTimeProps {
when_?: string; when_?: string;
updated?: string; updated?: string;
}; };
showAgo?: boolean;
} }
export class MomentTime extends Component<MomentTimeProps, any> { export class MomentTime extends Component<MomentTimeProps, any> {
@ -23,13 +24,35 @@ export class MomentTime extends Component<MomentTimeProps, any> {
render() { render() {
if (this.props.data.updated) { if (this.props.data.updated) {
return ( return (
<span title={this.props.data.updated} className="font-italics"> <span
{i18n.t('modified')} {moment.utc(this.props.data.updated).fromNow()} data-tippy-content={`${capitalizeFirstLetter(
i18n.t('modified')
)} ${this.format(this.props.data.updated)}`}
className="font-italics pointer unselectable"
>
<svg class="icon icon-inline mr-1">
<use xlinkHref="#icon-edit-2"></use>
</svg>
{moment.utc(this.props.data.updated).fromNow(!this.props.showAgo)}
</span> </span>
); );
} else { } else {
let str = this.props.data.published || this.props.data.when_; let str = this.props.data.published || this.props.data.when_;
return <span title={str}>{moment.utc(str).fromNow()}</span>; return (
<span
className="pointer unselectable"
data-tippy-content={this.format(str)}
>
{moment.utc(str).fromNow(!this.props.showAgo)}
</span>
);
} }
} }
format(input: string): string {
return moment
.utc(input)
.local()
.format('LLLL');
}
} }

View file

@ -105,6 +105,7 @@ export class Navbar extends Component<any, NavbarState> {
type="button" type="button"
aria-label="menu" aria-label="menu"
onClick={linkEvent(this, this.expandNavbar)} onClick={linkEvent(this, this.expandNavbar)}
data-tippy-content={i18n.t('expand_here')}
> >
<span class="navbar-toggler-icon"></span> <span class="navbar-toggler-icon"></span>
</button> </button>
@ -113,12 +114,16 @@ export class Navbar extends Component<any, NavbarState> {
> >
<ul class="navbar-nav mr-auto"> <ul class="navbar-nav mr-auto">
<li class="nav-item"> <li class="nav-item">
<Link class="nav-link" to="/communities"> <Link
class="nav-link"
to="/communities"
title={i18n.t('communities')}
>
{i18n.t('communities')} {i18n.t('communities')}
</Link> </Link>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<Link class="nav-link" to="/search"> <Link class="nav-link" to="/search" title={i18n.t('search')}>
{i18n.t('search')} {i18n.t('search')}
</Link> </Link>
</li> </li>
@ -129,12 +134,17 @@ export class Navbar extends Component<any, NavbarState> {
pathname: '/create_post', pathname: '/create_post',
state: { prevPath: this.currentLocation }, state: { prevPath: this.currentLocation },
}} }}
title={i18n.t('create_post')}
> >
{i18n.t('create_post')} {i18n.t('create_post')}
</Link> </Link>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<Link class="nav-link" to="/create_community"> <Link
class="nav-link"
to="/create_community"
title={i18n.t('create_community')}
>
{i18n.t('create_community')} {i18n.t('create_community')}
</Link> </Link>
</li> </li>
@ -154,9 +164,9 @@ export class Navbar extends Component<any, NavbarState> {
{this.state.isLoggedIn ? ( {this.state.isLoggedIn ? (
<> <>
<li className="nav-item mt-1"> <li className="nav-item mt-1">
<Link class="nav-link" to="/inbox"> <Link class="nav-link" to="/inbox" title={i18n.t('inbox')}>
<svg class="icon"> <svg class="icon">
<use xlinkHref="#icon-mail"></use> <use xlinkHref="#icon-bell"></use>
</svg> </svg>
{this.state.unreadCount > 0 && ( {this.state.unreadCount > 0 && (
<span class="ml-1 badge badge-light"> <span class="ml-1 badge badge-light">
@ -169,6 +179,7 @@ export class Navbar extends Component<any, NavbarState> {
<Link <Link
class="nav-link" class="nav-link"
to={`/u/${UserService.Instance.user.username}`} to={`/u/${UserService.Instance.user.username}`}
title={i18n.t('settings')}
> >
<span> <span>
{UserService.Instance.user.avatar && showAvatars() && ( {UserService.Instance.user.avatar && showAvatars() && (
@ -187,7 +198,11 @@ export class Navbar extends Component<any, NavbarState> {
</li> </li>
</> </>
) : ( ) : (
<Link class="nav-link" to="/login"> <Link
class="nav-link"
to="/login"
title={i18n.t('login_sign_up')}
>
{i18n.t('login_sign_up')} {i18n.t('login_sign_up')}
</Link> </Link>
)} )}
@ -263,7 +278,7 @@ export class Navbar extends Component<any, NavbarState> {
} else if (res.op == UserOperation.GetSite) { } else if (res.op == UserOperation.GetSite) {
let data = res.data as GetSiteResponse; let data = res.data as GetSiteResponse;
if (data.site) { if (data.site && !this.state.siteName) {
this.state.siteName = data.site.name; this.state.siteName = data.site.name;
WebSocketService.Instance.site = data.site; WebSocketService.Instance.site = data.site;
this.setState(this.state); this.setState(this.state);

View file

@ -1,4 +1,5 @@
import { Component, linkEvent } from 'inferno'; import { Component, linkEvent } from 'inferno';
import { Prompt } from 'inferno-router';
import { PostListings } from './post-listings'; import { PostListings } from './post-listings';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
import { retryWhen, delay, take } from 'rxjs/operators'; import { retryWhen, delay, take } from 'rxjs/operators';
@ -32,6 +33,7 @@ import {
toast, toast,
randomStr, randomStr,
setupTribute, setupTribute,
setupTippy,
} from '../utils'; } from '../utils';
import autosize from 'autosize'; import autosize from 'autosize';
import Tribute from 'tributejs/src/Tribute.js'; import Tribute from 'tributejs/src/Tribute.js';
@ -142,6 +144,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
this.setState(this.state); this.setState(this.state);
autosize.update(textarea); autosize.update(textarea);
}); });
setupTippy();
} }
componentWillUnmount() { componentWillUnmount() {
@ -151,6 +154,15 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
render() { render() {
return ( return (
<div> <div>
<Prompt
when={
!this.state.loading &&
(this.state.postForm.name ||
this.state.postForm.url ||
this.state.postForm.body)
}
message={i18n.t('block_leaving')}
/>
<form onSubmit={linkEvent(this, this.handlePostSubmit)}> <form onSubmit={linkEvent(this, this.handlePostSubmit)}>
<div class="form-group row"> <div class="form-group row">
<label class="col-sm-2 col-form-label" htmlFor="post-url"> <label class="col-sm-2 col-form-label" htmlFor="post-url">
@ -179,9 +191,12 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
<label <label
htmlFor="file-upload" htmlFor="file-upload"
className={`${UserService.Instance.user && className={`${UserService.Instance.user &&
'pointer'} d-inline-block mr-2 float-right text-muted small font-weight-bold`} 'pointer'} d-inline-block float-right text-muted h6 font-weight-bold`}
data-tippy-content={i18n.t('upload_image')}
> >
{i18n.t('upload_image')} <svg class="icon icon-inline">
<use xlinkHref="#icon-image"></use>
</svg>
</label> </label>
<input <input
id="file-upload" id="file-upload"
@ -279,9 +294,12 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
<a <a
href={markdownHelpUrl} href={markdownHelpUrl}
target="_blank" target="_blank"
class="d-inline-block float-right text-muted small font-weight-bold" class="d-inline-block float-right text-muted h6 font-weight-bold"
title={i18n.t('formatting_help')}
> >
{i18n.t('formatting_help')} <svg class="icon icon-inline">
<use xlinkHref="#icon-help-circle"></use>
</svg>
</a> </a>
</div> </div>
</div> </div>
@ -479,7 +497,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
}) })
.then(res => res.json()) .then(res => res.json())
.then(res => { .then(res => {
let url = `${window.location.origin}/pictshare/${res.url}`; let url = `${window.location.origin}/pictshare/${encodeURI(res.url)}`;
if (res.filetype == 'mp4') { if (res.filetype == 'mp4') {
url += '/raw'; url += '/raw';
} }

View file

@ -15,7 +15,6 @@ import {
AddAdminForm, AddAdminForm,
TransferSiteForm, TransferSiteForm,
TransferCommunityForm, TransferCommunityForm,
FramelyData,
} from '../interfaces'; } from '../interfaces';
import { MomentTime } from './moment-time'; import { MomentTime } from './moment-time';
import { PostForm } from './post-form'; import { PostForm } from './post-form';
@ -29,7 +28,8 @@ import {
getUnixTime, getUnixTime,
pictshareAvatarThumbnail, pictshareAvatarThumbnail,
showAvatars, showAvatars,
imageThumbnailer, pictshareImage,
setupTippy,
} from '../utils'; } from '../utils';
import { i18n } from '../i18next'; import { i18n } from '../i18next';
@ -45,13 +45,11 @@ interface PostListingState {
showConfirmTransferCommunity: boolean; showConfirmTransferCommunity: boolean;
imageExpanded: boolean; imageExpanded: boolean;
viewSource: boolean; viewSource: boolean;
showAdvanced: boolean;
my_vote: number; my_vote: number;
score: number; score: number;
upvotes: number; upvotes: number;
downvotes: number; downvotes: number;
url: string;
iframely: FramelyData;
thumbnail: string;
} }
interface PostListingProps { interface PostListingProps {
@ -75,13 +73,11 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
showConfirmTransferCommunity: false, showConfirmTransferCommunity: false,
imageExpanded: false, imageExpanded: false,
viewSource: false, viewSource: false,
showAdvanced: false,
my_vote: this.props.post.my_vote, my_vote: this.props.post.my_vote,
score: this.props.post.score, score: this.props.post.score,
upvotes: this.props.post.upvotes, upvotes: this.props.post.upvotes,
downvotes: this.props.post.downvotes, downvotes: this.props.post.downvotes,
url: this.props.post.url,
iframely: null,
thumbnail: null,
}; };
constructor(props: any, context: any) { constructor(props: any, context: any) {
@ -92,11 +88,6 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
this.handlePostDisLike = this.handlePostDisLike.bind(this); this.handlePostDisLike = this.handlePostDisLike.bind(this);
this.handleEditPost = this.handleEditPost.bind(this); this.handleEditPost = this.handleEditPost.bind(this);
this.handleEditCancel = this.handleEditCancel.bind(this); this.handleEditCancel = this.handleEditCancel.bind(this);
if (this.state.url) {
this.setThumbnail();
this.fetchIframely();
}
} }
componentWillReceiveProps(nextProps: PostListingProps) { componentWillReceiveProps(nextProps: PostListingProps) {
@ -104,26 +95,17 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
this.state.upvotes = nextProps.post.upvotes; this.state.upvotes = nextProps.post.upvotes;
this.state.downvotes = nextProps.post.downvotes; this.state.downvotes = nextProps.post.downvotes;
this.state.score = nextProps.post.score; this.state.score = nextProps.post.score;
if (nextProps.post.url !== this.state.url) {
this.state.url = nextProps.post.url;
if (this.state.url) {
this.setThumbnail();
this.fetchIframely();
} else {
this.state.iframely = null;
this.state.thumbnail = null;
}
}
this.setState(this.state); this.setState(this.state);
} }
render() { render() {
return ( return (
<div class="row"> <div class="">
{!this.state.showEdit ? ( {!this.state.showEdit ? (
this.listing() <>
{this.listing()}
{this.body()}
</>
) : ( ) : (
<div class="col-12"> <div class="col-12">
<PostForm <PostForm
@ -137,40 +119,162 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
); );
} }
imgThumbnail() { body() {
return (
<div class="row">
<div class="col-12">
{this.props.post.url &&
this.props.showBody &&
this.props.post.embed_title && (
<IFramelyCard post={this.props.post} />
)}
{this.props.showBody && this.props.post.body && (
<>
{this.state.viewSource ? (
<pre>{this.props.post.body}</pre>
) : (
<div
className="md-div"
dangerouslySetInnerHTML={mdToHtml(this.props.post.body)}
/>
)}
</>
)}
</div>
</div>
);
}
imgThumb(src: string) {
let post = this.props.post; let post = this.props.post;
return ( return (
<object <img
className={`img-fluid thumbnail rounded ${(post.nsfw || className={`img-fluid thumbnail rounded ${(post.nsfw ||
post.community_nsfw) && post.community_nsfw) &&
'img-blur'}`} 'img-blur'}`}
data={imageThumbnailer(this.state.thumbnail)} src={src}
></object> />
); );
} }
getImage(thumbnail: boolean = false) {
let post = this.props.post;
if (isImage(post.url)) {
if (post.url.includes('pictshare')) {
return pictshareImage(post.url, thumbnail);
} else {
return post.url;
}
} else if (post.thumbnail_url) {
return pictshareImage(post.thumbnail_url, thumbnail);
}
}
thumbnail() {
let post = this.props.post;
if (isImage(post.url)) {
return (
<span
class="text-body pointer"
data-tippy-content={i18n.t('expand_here')}
onClick={linkEvent(this, this.handleImageExpandClick)}
>
{this.imgThumb(this.getImage(true))}
<svg class="icon mini-overlay">
<use xlinkHref="#icon-image"></use>
</svg>
</span>
);
} else if (post.thumbnail_url) {
return (
<a
className="text-body"
href={post.url}
target="_blank"
title={post.url}
>
{this.imgThumb(this.getImage(true))}
<svg class="icon mini-overlay">
<use xlinkHref="#icon-external-link"></use>
</svg>
</a>
);
} else if (post.url) {
if (isVideo(post.url)) {
return (
<div class="embed-responsive embed-responsive-16by9">
<video
playsinline
muted
loop
controls
class="embed-responsive-item"
>
<source src={post.url} type="video/mp4" />
</video>
</div>
);
} else {
return (
<a
className="text-body"
href={post.url}
target="_blank"
title={post.url}
>
<svg class="icon thumbnail">
<use xlinkHref="#icon-external-link"></use>
</svg>
</a>
);
}
} else {
return (
<Link
className="text-body"
to={`/post/${post.id}`}
title={i18n.t('comments')}
>
<svg class="icon thumbnail">
<use xlinkHref="#icon-message-square"></use>
</svg>
</Link>
);
}
}
listing() { listing() {
let post = this.props.post; let post = this.props.post;
return ( return (
<div class="listing col-12"> <div class="row">
<div className={`vote-bar mr-2 float-left small text-center`}> <div className={`vote-bar col-1 pr-0 small text-center`}>
<button <button
className={`vote-animate btn btn-link p-0 ${ className={`vote-animate btn btn-link p-0 ${
this.state.my_vote == 1 ? 'text-info' : 'text-muted' this.state.my_vote == 1 ? 'text-info' : 'text-muted'
}`} }`}
onClick={linkEvent(this, this.handlePostLike)} onClick={linkEvent(this, this.handlePostLike)}
data-tippy-content={i18n.t('upvote')}
> >
<svg class="icon upvote"> <svg class="icon upvote">
<use xlinkHref="#icon-arrow-up"></use> <use xlinkHref="#icon-arrow-up"></use>
</svg> </svg>
</button> </button>
<div class={`font-weight-bold text-muted`}>{this.state.score}</div> <div
class={`unselectable pointer font-weight-bold text-muted px-1`}
data-tippy-content={i18n.t('number_of_points', {
count: this.state.score,
})}
>
{this.state.score}
</div>
{WebSocketService.Instance.site.enable_downvotes && ( {WebSocketService.Instance.site.enable_downvotes && (
<button <button
className={`vote-animate btn btn-link p-0 ${ className={`vote-animate btn btn-link p-0 ${
this.state.my_vote == -1 ? 'text-danger' : 'text-muted' this.state.my_vote == -1 ? 'text-danger' : 'text-muted'
}`} }`}
onClick={linkEvent(this, this.handlePostDisLike)} onClick={linkEvent(this, this.handlePostDisLike)}
data-tippy-content={i18n.t('downvote')}
> >
<svg class="icon downvote"> <svg class="icon downvote">
<use xlinkHref="#icon-arrow-down"></use> <use xlinkHref="#icon-arrow-down"></use>
@ -178,56 +282,24 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
</button> </button>
)} )}
</div> </div>
{this.state.thumbnail && !this.state.imageExpanded && ( {!this.state.imageExpanded && (
<div class="mx-2 mt-1 float-left position-relative"> <div class="col-3 col-sm-2 pr-0 mt-1">
{isImage(this.state.url) ? ( <div class="position-relative">{this.thumbnail()}</div>
<span
class="text-body pointer"
title={i18n.t('expand_here')}
onClick={linkEvent(this, this.handleImageExpandClick)}
>
{this.imgThumbnail()}
<svg class="icon rounded link-overlay hover-link">
<use xlinkHref="#icon-image"></use>
</svg>
</span>
) : (
<a
className="text-body"
href={this.state.url}
target="_blank"
title={this.state.url}
>
{this.imgThumbnail()}
<svg class="icon rounded link-overlay hover-link">
<use xlinkHref="#icon-external-link"></use>
</svg>
</a>
)}
</div> </div>
)} )}
{this.state.url && isVideo(this.state.url) && ( <div
<video class={`${this.state.imageExpanded ? 'col-12' : 'col-8 col-sm-9'}`}
playsinline
muted
loop
controls
class="mx-2 mt-1 float-left"
height="100"
width="150"
> >
<source src={this.state.url} type="video/mp4" /> <div class="row">
</video> <div className="col-12">
)}
<div className="ml-4">
<div className="post-title"> <div className="post-title">
<h5 className="mb-0 d-inline"> <h5 className="mb-0 d-inline">
{this.props.showBody && this.state.url ? ( {this.props.showBody && post.url ? (
<a <a
className="text-body" className="text-body"
href={this.state.url} href={post.url}
target="_blank" target="_blank"
title={this.state.url} title={post.url}
> >
{post.name} {post.name}
</a> </a>
@ -241,55 +313,56 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
</Link> </Link>
)} )}
</h5> </h5>
{this.state.url && {post.url &&
!( !(new URL(post.url).hostname == window.location.hostname) && (
new URL(this.state.url).hostname == window.location.hostname
) && (
<small class="d-inline-block"> <small class="d-inline-block">
<a <a
className="ml-2 text-muted font-italic" className="ml-2 text-muted font-italic"
href={this.state.url} href={post.url}
target="_blank" target="_blank"
title={this.state.url} title={post.url}
> >
{new URL(this.state.url).hostname} {new URL(post.url).hostname}
<svg class="ml-1 icon"> <svg class="ml-1 icon icon-inline">
<use xlinkHref="#icon-external-link"></use> <use xlinkHref="#icon-external-link"></use>
</svg> </svg>
</a> </a>
</small> </small>
)} )}
{this.state.thumbnail && ( {(isImage(post.url) || this.props.post.thumbnail_url) && (
<> <>
{!this.state.imageExpanded ? ( {!this.state.imageExpanded ? (
<span <span
class="text-monospace pointer ml-2 text-muted small" class="text-monospace unselectable pointer ml-2 text-muted small"
title={i18n.t('expand_here')} data-tippy-content={i18n.t('expand_here')}
onClick={linkEvent(this, this.handleImageExpandClick)} onClick={linkEvent(this, this.handleImageExpandClick)}
> >
[+] <svg class="icon icon-inline">
<use xlinkHref="#icon-plus-square"></use>
</svg>
</span> </span>
) : ( ) : (
<span> <span>
<span <span
class="text-monospace pointer ml-2 text-muted small" class="text-monospace unselectable pointer ml-2 text-muted small"
onClick={linkEvent(this, this.handleImageExpandClick)} onClick={linkEvent(this, this.handleImageExpandClick)}
> >
[-] <svg class="icon icon-inline">
<use xlinkHref="#icon-minus-square"></use>
</svg>
</span> </span>
<div> <div>
<span <span
class="pointer" class="pointer"
onClick={linkEvent(this, this.handleImageExpandClick)} onClick={linkEvent(
this,
this.handleImageExpandClick
)}
> >
<object <img
class="img-fluid img-expanded" class="img-fluid img-expanded"
data={this.state.thumbnail} src={this.getImage()}
> />
<svg class="icon rounded placeholder">
<use xlinkHref="#icon-external-link"></use>
</svg>
</object>
</span> </span>
</div> </div>
</span> </span>
@ -302,18 +375,33 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
</small> </small>
)} )}
{post.deleted && ( {post.deleted && (
<small className="ml-2 text-muted font-italic"> <small
{i18n.t('deleted')} className="unselectable pointer ml-2 text-muted font-italic"
data-tippy-content={i18n.t('deleted')}
>
<svg class={`icon icon-inline text-danger`}>
<use xlinkHref="#icon-trash"></use>
</svg>
</small> </small>
)} )}
{post.locked && ( {post.locked && (
<small className="ml-2 text-muted font-italic"> <small
{i18n.t('locked')} className="unselectable pointer ml-2 text-muted font-italic"
data-tippy-content={i18n.t('locked')}
>
<svg class={`icon icon-inline text-danger`}>
<use xlinkHref="#icon-lock"></use>
</svg>
</small> </small>
)} )}
{post.stickied && ( {post.stickied && (
<small className="ml-2 text-muted font-italic"> <small
{i18n.t('stickied')} className="unselectable pointer ml-2 text-muted font-italic"
data-tippy-content={i18n.t('stickied')}
>
<svg class={`icon icon-inline text-success`}>
<use xlinkHref="#icon-pin"></use>
</svg>
</small> </small>
)} )}
{post.nsfw && ( {post.nsfw && (
@ -323,11 +411,16 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
)} )}
</div> </div>
</div> </div>
<div className="details ml-4"> </div>
<div class="row">
<div className="details col-12">
<ul class="list-inline mb-0 text-muted small"> <ul class="list-inline mb-0 text-muted small">
<li className="list-inline-item"> <li className="list-inline-item">
<span>{i18n.t('by')} </span> <span>{i18n.t('by')} </span>
<Link className="text-info" to={`/u/${post.creator_name}`}> <Link
className="text-body font-weight-bold"
to={`/u/${post.creator_name}`}
>
{post.creator_avatar && showAvatars() && ( {post.creator_avatar && showAvatars() && (
<img <img
height="32" height="32"
@ -339,7 +432,9 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
<span>{post.creator_name}</span> <span>{post.creator_name}</span>
</Link> </Link>
{this.isMod && ( {this.isMod && (
<span className="mx-1 badge badge-light">{i18n.t('mod')}</span> <span className="mx-1 badge badge-light">
{i18n.t('mod')}
</span>
)} )}
{this.isAdmin && ( {this.isAdmin && (
<span className="mx-1 badge badge-light"> <span className="mx-1 badge badge-light">
@ -360,28 +455,57 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
</span> </span>
)} )}
</li> </li>
<li className="list-inline-item"></li>
<li className="list-inline-item"> <li className="list-inline-item">
<span> <span>
<MomentTime data={post} /> <MomentTime data={post} />
</span> </span>
</li> </li>
<li className="list-inline-item"></li>
{this.state.upvotes !== this.state.score && (
<>
<span
class="unselectable pointer mr-2"
data-tippy-content={i18n.t('number_of_points', {
count: this.state.score,
})}
>
<li className="list-inline-item"> <li className="list-inline-item">
<span> <span className="text-muted">
(<span className="text-info">+{this.state.upvotes}</span> <svg class="small icon icon-inline mr-1">
<span> | </span> <use xlinkHref="#icon-arrow-up"></use>
<span className="text-danger">-{this.state.downvotes}</span> </svg>
<span>) </span> {this.state.upvotes}
</span> </span>
</li> </li>
<li className="list-inline-item"> <li className="list-inline-item">
<Link className="text-muted" to={`/post/${post.id}`}> <span className="text-muted">
{i18n.t('number_of_comments', { <svg class="small icon icon-inline mr-1">
<use xlinkHref="#icon-arrow-down"></use>
</svg>
{this.state.downvotes}
</span>
</li>
</span>
<li className="list-inline-item"></li>
</>
)}
<li className="list-inline-item">
<Link
className="text-muted"
title={i18n.t('number_of_comments', {
count: post.number_of_comments, count: post.number_of_comments,
})} })}
to={`/post/${post.id}`}
>
<svg class="mr-1 icon icon-inline">
<use xlinkHref="#icon-message-square"></use>
</svg>
{post.number_of_comments}
</Link> </Link>
</li> </li>
</ul> </ul>
<ul class="list-inline mb-1 text-muted small"> <ul class="list-inline mb-1 small text-muted">
{this.props.post.duplicates && ( {this.props.post.duplicates && (
<> <>
<li className="list-inline-item mr-2"> <li className="list-inline-item mr-2">
@ -389,71 +513,148 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
</li> </li>
{this.props.post.duplicates.map(post => ( {this.props.post.duplicates.map(post => (
<li className="list-inline-item mr-2"> <li className="list-inline-item mr-2">
<Link to={`/post/${post.id}`}>{post.community_name}</Link> <Link to={`/post/${post.id}`}>
{post.community_name}
</Link>
</li> </li>
))} ))}
</> </>
)} )}
</ul> </ul>
<ul class="list-inline mb-1 text-muted small font-weight-bold"> <ul class="list-inline mb-1 text-muted h5 font-weight-bold">
{UserService.Instance.user && ( {UserService.Instance.user && (
<> <>
{this.props.showBody && ( {this.props.showBody && (
<> <>
<li className="list-inline-item mr-2"> <li className="list-inline-item-action">
<span <span
class="pointer" class="pointer"
onClick={linkEvent(this, this.handleSavePostClick)} onClick={linkEvent(this, this.handleSavePostClick)}
data-tippy-content={
post.saved ? i18n.t('unsave') : i18n.t('save')
}
> >
{post.saved ? i18n.t('unsave') : i18n.t('save')} <svg
class={`icon icon-inline ${post.saved &&
'text-warning'}`}
>
<use xlinkHref="#icon-star"></use>
</svg>
</span> </span>
</li> </li>
<li className="list-inline-item mr-2"> <li className="list-inline-item-action">
<Link <Link
className="text-muted" className="text-muted"
to={`/create_post${this.crossPostParams}`} to={`/create_post${this.crossPostParams}`}
title={i18n.t('cross_post')}
> >
{i18n.t('cross_post')} <svg class="icon icon-inline">
<use xlinkHref="#icon-copy"></use>
</svg>
</Link> </Link>
</li> </li>
</> </>
)} )}
{this.myPost && this.props.showBody && ( {this.myPost && this.props.showBody && (
<> <>
<li className="list-inline-item"> <li className="list-inline-item-action">
<span <span
class="pointer" class="pointer"
onClick={linkEvent(this, this.handleEditClick)} onClick={linkEvent(this, this.handleEditClick)}
data-tippy-content={i18n.t('edit')}
> >
{i18n.t('edit')} <svg class="icon icon-inline">
<use xlinkHref="#icon-edit"></use>
</svg>
</span> </span>
</li> </li>
<li className="list-inline-item mr-2"> <li className="list-inline-item-action">
<span <span
class="pointer" class="pointer"
onClick={linkEvent(this, this.handleDeleteClick)} onClick={linkEvent(this, this.handleDeleteClick)}
data-tippy-content={
!post.deleted
? i18n.t('delete')
: i18n.t('restore')
}
> >
{!post.deleted ? i18n.t('delete') : i18n.t('restore')} <svg
class={`icon icon-inline ${post.deleted &&
'text-danger'}`}
>
<use xlinkHref="#icon-trash"></use>
</svg>
</span> </span>
</li> </li>
</> </>
)} )}
{!this.state.showAdvanced && this.props.showBody ? (
<li className="list-inline-item-action">
<span
className="pointer"
onClick={linkEvent(this, this.handleShowAdvanced)}
data-tippy-content={i18n.t('more')}
>
<svg class="icon icon-inline">
<use xlinkHref="#icon-more-vertical"></use>
</svg>
</span>
</li>
) : (
<>
{this.props.showBody && post.body && (
<li className="list-inline-item-action">
<span
className="pointer"
onClick={linkEvent(this, this.handleViewSource)}
data-tippy-content={i18n.t('view_source')}
>
<svg
class={`icon icon-inline ${this.state
.viewSource && 'text-success'}`}
>
<use xlinkHref="#icon-file-text"></use>
</svg>
</span>
</li>
)}
{this.canModOnSelf && ( {this.canModOnSelf && (
<> <>
<li className="list-inline-item"> <li className="list-inline-item-action">
<span <span
class="pointer" class="pointer"
onClick={linkEvent(this, this.handleModLock)} onClick={linkEvent(this, this.handleModLock)}
data-tippy-content={
post.locked
? i18n.t('unlock')
: i18n.t('lock')
}
> >
{post.locked ? i18n.t('unlock') : i18n.t('lock')} <svg
class={`icon icon-inline ${post.locked &&
'text-danger'}`}
>
<use xlinkHref="#icon-lock"></use>
</svg>
</span> </span>
</li> </li>
<li className="list-inline-item"> <li className="list-inline-item-action">
<span <span
class="pointer" class="pointer"
onClick={linkEvent(this, this.handleModSticky)} onClick={linkEvent(this, this.handleModSticky)}
data-tippy-content={
post.stickied
? i18n.t('unsticky')
: i18n.t('sticky')
}
> >
{post.stickied ? i18n.t('unsticky') : i18n.t('sticky')} <svg
class={`icon icon-inline ${post.stickied &&
'text-success'}`}
>
<use xlinkHref="#icon-pin"></use>
</svg>
</span> </span>
</li> </li>
</> </>
@ -464,14 +665,20 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
{!post.removed ? ( {!post.removed ? (
<span <span
class="pointer" class="pointer"
onClick={linkEvent(this, this.handleModRemoveShow)} onClick={linkEvent(
this,
this.handleModRemoveShow
)}
> >
{i18n.t('remove')} {i18n.t('remove')}
</span> </span>
) : ( ) : (
<span <span
class="pointer" class="pointer"
onClick={linkEvent(this, this.handleModRemoveSubmit)} onClick={linkEvent(
this,
this.handleModRemoveSubmit
)}
> >
{i18n.t('restore')} {i18n.t('restore')}
</span> </span>
@ -523,7 +730,8 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
</> </>
)} )}
{/* Community creators and admins can transfer community to another mod */} {/* Community creators and admins can transfer community to another mod */}
{(this.amCommunityCreator || this.canAdmin) && this.isMod && ( {(this.amCommunityCreator || this.canAdmin) &&
this.isMod && (
<li className="list-inline-item"> <li className="list-inline-item">
{!this.state.showConfirmTransferCommunity ? ( {!this.state.showConfirmTransferCommunity ? (
<span <span
@ -553,7 +761,8 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
class="pointer d-inline-block" class="pointer d-inline-block"
onClick={linkEvent( onClick={linkEvent(
this, this,
this.handleCancelShowConfirmTransferCommunity this
.handleCancelShowConfirmTransferCommunity
)} )}
> >
{i18n.t('no')} {i18n.t('no')}
@ -570,14 +779,20 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
{!post.banned ? ( {!post.banned ? (
<span <span
class="pointer" class="pointer"
onClick={linkEvent(this, this.handleModBanShow)} onClick={linkEvent(
this,
this.handleModBanShow
)}
> >
{i18n.t('ban_from_site')} {i18n.t('ban_from_site')}
</span> </span>
) : ( ) : (
<span <span
class="pointer" class="pointer"
onClick={linkEvent(this, this.handleModBanSubmit)} onClick={linkEvent(
this,
this.handleModBanSubmit
)}
> >
{i18n.t('unban_from_site')} {i18n.t('unban_from_site')}
</span> </span>
@ -618,7 +833,10 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
</span> </span>
<span <span
class="pointer d-inline-block mr-1" class="pointer d-inline-block mr-1"
onClick={linkEvent(this, this.handleTransferSite)} onClick={linkEvent(
this,
this.handleTransferSite
)}
> >
{i18n.t('yes')} {i18n.t('yes')}
</span> </span>
@ -637,20 +855,9 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
)} )}
</> </>
)} )}
{this.props.showBody && post.body && ( </>
<li className="list-inline-item">
<span
className="pointer"
onClick={linkEvent(this, this.handleViewSource)}
>
{i18n.t('view_source')}
</span>
</li>
)} )}
</ul> </ul>
{this.state.url && this.props.showBody && this.state.iframely && (
<IFramelyCard iframely={this.state.iframely} />
)}
{this.state.showRemoveDialog && ( {this.state.showRemoveDialog && (
<form <form
class="form-inline" class="form-inline"
@ -695,18 +902,8 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
</div> </div>
</form> </form>
)} )}
{this.props.showBody && post.body && ( </div>
<> </div>
{this.state.viewSource ? (
<pre>{post.body}</pre>
) : (
<div
className="md-div"
dangerouslySetInnerHTML={mdToHtml(post.body)}
/>
)}
</>
)}
</div> </div>
</div> </div>
); );
@ -801,47 +998,6 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
); );
} }
fetchIframely() {
fetch(`/iframely/oembed?url=${this.state.url}`)
.then(res => res.json())
.then(res => {
this.state.iframely = res;
this.setState(this.state);
// Store and fetch the image in pictshare
if (
this.state.iframely.thumbnail_url &&
isImage(this.state.iframely.thumbnail_url)
) {
fetch(
`/pictshare/api/geturl.php?url=${this.state.iframely.thumbnail_url}`
)
.then(res => res.json())
.then(res => {
let url = `${window.location.origin}/pictshare/${res.url}`;
if (res.filetype == 'mp4') {
url += '/raw';
}
this.state.thumbnail = url;
this.setState(this.state);
});
}
})
.catch(error => {
console.error(`Iframely service not set up properly. ${error}`);
});
}
setThumbnail() {
let simpleImg = isImage(this.state.url);
if (simpleImg) {
this.state.thumbnail = this.state.url;
} else {
this.state.thumbnail = null;
}
this.setState(this.state);
}
handlePostLike(i: PostListing) { handlePostLike(i: PostListing) {
let new_vote = i.state.my_vote == 1 ? 0 : 1; let new_vote = i.state.my_vote == 1 ? 0 : 1;
@ -937,8 +1093,10 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
get crossPostParams(): string { get crossPostParams(): string {
let params = `?title=${this.props.post.name}`; let params = `?title=${this.props.post.name}`;
if (this.state.url) { let post = this.props.post;
params += `&url=${this.state.url}`;
if (post.url) {
params += `&url=${post.url}`;
} }
if (this.props.post.body) { if (this.props.post.body) {
params += `&body=${this.props.post.body}`; params += `&body=${this.props.post.body}`;
@ -1127,4 +1285,10 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
i.state.viewSource = !i.state.viewSource; i.state.viewSource = !i.state.viewSource;
i.setState(i.state); i.setState(i.state);
} }
handleShowAdvanced(i: PostListing) {
i.state.showAdvanced = !i.state.showAdvanced;
i.setState(i.state);
setupTippy();
}
} }

View file

@ -53,7 +53,7 @@ export class PostListings extends Component<PostListingsProps, any> {
} }
if (this.props.sort !== undefined) { if (this.props.sort !== undefined) {
postSort(out, this.props.sort); postSort(out, this.props.sort, this.props.showCommunity == undefined);
} }
return out; return out;

View file

@ -37,6 +37,7 @@ import {
createCommentLikeRes, createCommentLikeRes,
createPostLikeRes, createPostLikeRes,
commentsToFlatNodes, commentsToFlatNodes,
setupTippy,
} from '../utils'; } from '../utils';
import { PostListing } from './post-listing'; import { PostListing } from './post-listing';
import { PostListings } from './post-listings'; import { PostListings } from './post-listings';
@ -210,7 +211,7 @@ export class Post extends Component<any, PostState> {
sortRadios() { sortRadios() {
return ( return (
<div class="btn-group btn-group-toggle mb-3"> <div class="btn-group btn-group-toggle">
<label <label
className={`btn btn-sm btn-secondary pointer ${this.state className={`btn btn-sm btn-secondary pointer ${this.state
.commentSort === CommentSortType.Hot && 'active'}`} .commentSort === CommentSortType.Hot && 'active'}`}
@ -299,7 +300,7 @@ export class Post extends Component<any, PostState> {
i.setState(i.state); i.setState(i.state);
} }
private buildCommentsTree(): Array<CommentNodeI> { buildCommentsTree(): Array<CommentNodeI> {
let map = new Map<number, CommentNodeI>(); let map = new Map<number, CommentNodeI>();
for (let comment of this.state.comments) { for (let comment of this.state.comments) {
let node: CommentNodeI = { let node: CommentNodeI = {
@ -310,16 +311,27 @@ export class Post extends Component<any, PostState> {
} }
let tree: Array<CommentNodeI> = []; let tree: Array<CommentNodeI> = [];
for (let comment of this.state.comments) { for (let comment of this.state.comments) {
let child = map.get(comment.id);
if (comment.parent_id) { if (comment.parent_id) {
map.get(comment.parent_id).children.push(map.get(comment.id)); let parent_ = map.get(comment.parent_id);
parent_.children.push(child);
} else { } else {
tree.push(map.get(comment.id)); tree.push(child);
} }
this.setDepth(child);
} }
return tree; return tree;
} }
setDepth(node: CommentNodeI, i: number = 0): void {
for (let child of node.children) {
child.comment.depth = i;
this.setDepth(child, i + 1);
}
}
commentsTree() { commentsTree() {
let nodes = this.buildCommentsTree(); let nodes = this.buildCommentsTree();
return ( return (
@ -370,6 +382,7 @@ export class Post extends Component<any, PostState> {
} }
this.setState(this.state); this.setState(this.state);
setupTippy();
} else if (res.op == UserOperation.CreateComment) { } else if (res.op == UserOperation.CreateComment) {
let data = res.data as CommentResponse; let data = res.data as CommentResponse;
@ -386,6 +399,7 @@ export class Post extends Component<any, PostState> {
let data = res.data as CommentResponse; let data = res.data as CommentResponse;
saveCommentRes(data, this.state.comments); saveCommentRes(data, this.state.comments);
this.setState(this.state); this.setState(this.state);
setupTippy();
} else if (res.op == UserOperation.CreateCommentLike) { } else if (res.op == UserOperation.CreateCommentLike) {
let data = res.data as CommentResponse; let data = res.data as CommentResponse;
createCommentLikeRes(data, this.state.comments); createCommentLikeRes(data, this.state.comments);
@ -398,10 +412,12 @@ export class Post extends Component<any, PostState> {
let data = res.data as PostResponse; let data = res.data as PostResponse;
this.state.post = data.post; this.state.post = data.post;
this.setState(this.state); this.setState(this.state);
setupTippy();
} else if (res.op == UserOperation.SavePost) { } else if (res.op == UserOperation.SavePost) {
let data = res.data as PostResponse; let data = res.data as PostResponse;
this.state.post = data.post; this.state.post = data.post;
this.setState(this.state); this.setState(this.state);
setupTippy();
} else if (res.op == UserOperation.EditCommunity) { } else if (res.op == UserOperation.EditCommunity) {
let data = res.data as CommunityResponse; let data = res.data as CommunityResponse;
this.state.community = data.community; this.state.community = data.community;

View file

@ -1,4 +1,5 @@
import { Component, linkEvent } from 'inferno'; import { Component, linkEvent } from 'inferno';
import { Prompt } from 'inferno-router';
import { Link } from 'inferno-router'; import { Link } from 'inferno-router';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
import { retryWhen, delay, take } from 'rxjs/operators'; import { retryWhen, delay, take } from 'rxjs/operators';
@ -26,6 +27,7 @@ import {
toast, toast,
randomStr, randomStr,
setupTribute, setupTribute,
setupTippy,
} from '../utils'; } from '../utils';
import Tribute from 'tributejs/src/Tribute.js'; import Tribute from 'tributejs/src/Tribute.js';
import autosize from 'autosize'; import autosize from 'autosize';
@ -107,6 +109,7 @@ export class PrivateMessageForm extends Component<
this.setState(this.state); this.setState(this.state);
autosize.update(textarea); autosize.update(textarea);
}); });
setupTippy();
} }
componentWillUnmount() { componentWillUnmount() {
@ -116,6 +119,10 @@ export class PrivateMessageForm extends Component<
render() { render() {
return ( return (
<div> <div>
<Prompt
when={!this.state.loading && this.state.privateMessageForm.content}
message={i18n.t('block_leaving')}
/>
<form onSubmit={linkEvent(this, this.handlePrivateMessageSubmit)}> <form onSubmit={linkEvent(this, this.handlePrivateMessageSubmit)}>
{!this.props.privateMessage && ( {!this.props.privateMessage && (
<div class="form-group row"> <div class="form-group row">
@ -126,7 +133,7 @@ export class PrivateMessageForm extends Component<
{this.state.recipient && ( {this.state.recipient && (
<div class="col-sm-10 form-control-plaintext"> <div class="col-sm-10 form-control-plaintext">
<Link <Link
className="text-info" className="text-body font-weight-bold"
to={`/u/${this.state.recipient.name}`} to={`/u/${this.state.recipient.name}`}
> >
{this.state.recipient.avatar && showAvatars() && ( {this.state.recipient.avatar && showAvatars() && (
@ -165,18 +172,28 @@ export class PrivateMessageForm extends Component<
/> />
)} )}
<ul class="float-right list-inline mb-1 text-muted small font-weight-bold"> <ul class="float-right list-inline mb-1 text-muted font-weight-bold">
<li class="list-inline-item"> <li class="list-inline-item">
<span <span
onClick={linkEvent(this, this.handleShowDisclaimer)} onClick={linkEvent(this, this.handleShowDisclaimer)}
class="pointer" class="pointer"
data-tippy-content={i18n.t('disclaimer')}
> >
{i18n.t('disclaimer')} <svg class={`icon icon-inline`}>
<use xlinkHref="#icon-alert-triangle"></use>
</svg>
</span> </span>
</li> </li>
<li class="list-inline-item"> <li class="list-inline-item">
<a href={markdownHelpUrl} target="_blank" class="text-muted"> <a
{i18n.t('formatting_help')} href={markdownHelpUrl}
target="_blank"
class="text-muted"
title={i18n.t('formatting_help')}
>
<svg class="icon icon-inline">
<use xlinkHref="#icon-help-circle"></use>
</svg>
</a> </a>
</li> </li>
</ul> </ul>

View file

@ -63,7 +63,7 @@ export class PrivateMessage extends Component<
</li> </li>
<li className="list-inline-item"> <li className="list-inline-item">
<Link <Link
className="text-info" className="text-body font-weight-bold"
to={ to={
this.mine this.mine
? `/u/${message.recipient_name}` ? `/u/${message.recipient_name}`
@ -100,7 +100,15 @@ export class PrivateMessage extends Component<
className="pointer text-monospace" className="pointer text-monospace"
onClick={linkEvent(this, this.handleMessageCollapse)} onClick={linkEvent(this, this.handleMessageCollapse)}
> >
{this.state.collapsed ? '[+]' : '[-]'} {this.state.collapsed ? (
<svg class="icon icon-inline">
<use xlinkHref="#icon-plus-square"></use>
</svg>
) : (
<svg class="icon icon-inline">
<use xlinkHref="#icon-minus-square"></use>
</svg>
)}
</div> </div>
</li> </li>
</ul> </ul>
@ -121,58 +129,85 @@ export class PrivateMessage extends Component<
dangerouslySetInnerHTML={mdToHtml(this.messageUnlessRemoved)} dangerouslySetInnerHTML={mdToHtml(this.messageUnlessRemoved)}
/> />
)} )}
<ul class="list-inline mb-1 text-muted small font-weight-bold"> <ul class="list-inline mb-1 text-muted h5 font-weight-bold">
{!this.mine && ( {!this.mine && (
<> <>
<li className="list-inline-item"> <li className="list-inline-item-action">
<span <span
class="pointer" class="pointer"
onClick={linkEvent(this, this.handleMarkRead)} onClick={linkEvent(this, this.handleMarkRead)}
> data-tippy-content={
{message.read message.read
? i18n.t('mark_as_unread') ? i18n.t('mark_as_unread')
: i18n.t('mark_as_read')} : i18n.t('mark_as_read')
}
>
<svg
class={`icon icon-inline ${message.read &&
'text-success'}`}
>
<use xlinkHref="#icon-check"></use>
</svg>
</span> </span>
</li> </li>
<li className="list-inline-item"> <li className="list-inline-item-action">
<span <span
class="pointer" class="pointer"
onClick={linkEvent(this, this.handleReplyClick)} onClick={linkEvent(this, this.handleReplyClick)}
data-tippy-content={i18n.t('reply')}
> >
{i18n.t('reply')} <svg class="icon icon-inline">
<use xlinkHref="#icon-reply1"></use>
</svg>
</span> </span>
</li> </li>
</> </>
)} )}
{this.mine && ( {this.mine && (
<> <>
<li className="list-inline-item"> <li className="list-inline-item-action">
<span <span
class="pointer" class="pointer"
onClick={linkEvent(this, this.handleEditClick)} onClick={linkEvent(this, this.handleEditClick)}
data-tippy-content={i18n.t('edit')}
> >
{i18n.t('edit')} <svg class="icon icon-inline">
<use xlinkHref="#icon-edit"></use>
</svg>
</span> </span>
</li> </li>
<li className="list-inline-item"> <li className="list-inline-item-action">
<span <span
class="pointer" class="pointer"
onClick={linkEvent(this, this.handleDeleteClick)} onClick={linkEvent(this, this.handleDeleteClick)}
> data-tippy-content={
{!message.deleted !message.deleted
? i18n.t('delete') ? i18n.t('delete')
: i18n.t('restore')} : i18n.t('restore')
}
>
<svg
class={`icon icon-inline ${message.deleted &&
'text-danger'}`}
>
<use xlinkHref="#icon-trash"></use>
</svg>
</span> </span>
</li> </li>
</> </>
)} )}
<li className="list-inline-item"></li> <li className="list-inline-item-action">
<li className="list-inline-item">
<span <span
className="pointer" className="pointer"
onClick={linkEvent(this, this.handleViewSource)} onClick={linkEvent(this, this.handleViewSource)}
data-tippy-content={i18n.t('view_source')}
> >
{i18n.t('view_source')} <svg
class={`icon icon-inline ${this.state.viewSource &&
'text-success'}`}
>
<use xlinkHref="#icon-file-text"></use>
</svg>
</span> </span>
</li> </li>
</ul> </ul>

View file

@ -84,26 +84,37 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
<Link className="text-muted" to={`/c/${community.name}`}> <Link className="text-muted" to={`/c/${community.name}`}>
/c/{community.name} /c/{community.name}
</Link> </Link>
<ul class="list-inline mb-1 text-muted small font-weight-bold"> <ul class="list-inline mb-1 text-muted font-weight-bold">
{this.canMod && ( {this.canMod && (
<> <>
<li className="list-inline-item"> <li className="list-inline-item-action">
<span <span
class="pointer" class="pointer"
onClick={linkEvent(this, this.handleEditClick)} onClick={linkEvent(this, this.handleEditClick)}
data-tippy-content={i18n.t('edit')}
> >
{i18n.t('edit')} <svg class="icon icon-inline">
<use xlinkHref="#icon-edit"></use>
</svg>
</span> </span>
</li> </li>
{this.amCreator && ( {this.amCreator && (
<li className="list-inline-item"> <li className="list-inline-item-action">
<span <span
class="pointer" class="pointer"
onClick={linkEvent(this, this.handleDeleteClick)} onClick={linkEvent(this, this.handleDeleteClick)}
> data-tippy-content={
{!community.deleted !community.deleted
? i18n.t('delete') ? i18n.t('delete')
: i18n.t('restore')} : i18n.t('restore')
}
>
<svg
class={`icon icon-inline ${community.deleted &&
'text-danger'}`}
>
<use xlinkHref="#icon-trash"></use>
</svg>
</span> </span>
</li> </li>
)} )}
@ -193,7 +204,10 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
<li class="list-inline-item">{i18n.t('mods')}: </li> <li class="list-inline-item">{i18n.t('mods')}: </li>
{this.props.moderators.map(mod => ( {this.props.moderators.map(mod => (
<li class="list-inline-item"> <li class="list-inline-item">
<Link class="text-info" to={`/u/${mod.user_name}`}> <Link
class="text-body font-weight-bold"
to={`/u/${mod.user_name}`}
>
{mod.avatar && showAvatars() && ( {mod.avatar && showAvatars() && (
<img <img
height="32" height="32"

View file

@ -1,4 +1,5 @@
import { Component, linkEvent } from 'inferno'; import { Component, linkEvent } from 'inferno';
import { Prompt } from 'inferno-router';
import { Site, SiteForm as SiteFormI } from '../interfaces'; import { Site, SiteForm as SiteFormI } from '../interfaces';
import { WebSocketService } from '../services'; import { WebSocketService } from '../services';
import { capitalizeFirstLetter, randomStr, setupTribute } from '../utils'; import { capitalizeFirstLetter, randomStr, setupTribute } from '../utils';
@ -59,6 +60,14 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
render() { render() {
return ( return (
<>
<Prompt
when={
!this.state.loading &&
(this.state.siteForm.name || this.state.siteForm.description)
}
message={i18n.t('block_leaving')}
/>
<form onSubmit={linkEvent(this, this.handleCreateSiteSubmit)}> <form onSubmit={linkEvent(this, this.handleCreateSiteSubmit)}>
<h5>{`${ <h5>{`${
this.props.site this.props.site
@ -105,7 +114,10 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
id="create-site-downvotes" id="create-site-downvotes"
type="checkbox" type="checkbox"
checked={this.state.siteForm.enable_downvotes} checked={this.state.siteForm.enable_downvotes}
onChange={linkEvent(this, this.handleSiteEnableDownvotesChange)} onChange={linkEvent(
this,
this.handleSiteEnableDownvotesChange
)}
/> />
<label class="form-check-label" htmlFor="create-site-downvotes"> <label class="form-check-label" htmlFor="create-site-downvotes">
{i18n.t('enable_downvotes')} {i18n.t('enable_downvotes')}
@ -123,7 +135,10 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
checked={this.state.siteForm.enable_nsfw} checked={this.state.siteForm.enable_nsfw}
onChange={linkEvent(this, this.handleSiteEnableNsfwChange)} onChange={linkEvent(this, this.handleSiteEnableNsfwChange)}
/> />
<label class="form-check-label" htmlFor="create-site-enable-nsfw"> <label
class="form-check-label"
htmlFor="create-site-enable-nsfw"
>
{i18n.t('enable_nsfw')} {i18n.t('enable_nsfw')}
</label> </label>
</div> </div>
@ -176,6 +191,7 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
</div> </div>
</div> </div>
</form> </form>
</>
); );
} }

View file

@ -1,5 +1,6 @@
import { Component, linkEvent } from 'inferno'; import { Component, linkEvent } from 'inferno';
import { SortType } from '../interfaces'; import { SortType } from '../interfaces';
import { sortingHelpUrl } from '../utils';
import { i18n } from '../i18next'; import { i18n } from '../i18next';
interface SortSelectProps { interface SortSelectProps {
@ -24,10 +25,11 @@ export class SortSelect extends Component<SortSelectProps, SortSelectState> {
render() { render() {
return ( return (
<>
<select <select
value={this.state.sort} value={this.state.sort}
onChange={linkEvent(this, this.handleSortChange)} onChange={linkEvent(this, this.handleSortChange)}
class="custom-select custom-select-sm w-auto" class="custom-select custom-select-sm w-auto mr-2"
> >
<option disabled>{i18n.t('sort_type')}</option> <option disabled>{i18n.t('sort_type')}</option>
{!this.props.hideHot && ( {!this.props.hideHot && (
@ -41,6 +43,17 @@ export class SortSelect extends Component<SortSelectProps, SortSelectState> {
<option value={SortType.TopYear}>{i18n.t('year')}</option> <option value={SortType.TopYear}>{i18n.t('year')}</option>
<option value={SortType.TopAll}>{i18n.t('all')}</option> <option value={SortType.TopAll}>{i18n.t('all')}</option>
</select> </select>
<a
className="text-muted"
href={sortingHelpUrl}
target="_blank"
title={i18n.t('sorting_help')}
>
<svg class={`icon icon-inline`}>
<use xlinkHref="#icon-help-circle"></use>
</svg>
</a>
</>
); );
} }

View file

@ -15,36 +15,90 @@ export class Symbols extends Component<any, any> {
xmlnsXlink="http://www.w3.org/1999/xlink" xmlnsXlink="http://www.w3.org/1999/xlink"
> >
<defs> <defs>
<symbol id="icon-image" viewBox="0 0 32 32"> <symbol id="icon-alert-triangle" viewBox="0 0 24 24">
<title>image</title> <path d="M11.148 4.374c0.073-0.123 0.185-0.242 0.334-0.332 0.236-0.143 0.506-0.178 0.756-0.116s0.474 0.216 0.614 0.448l8.466 14.133c0.070 0.12 0.119 0.268 0.128 0.434-0.015 0.368-0.119 0.591-0.283 0.759-0.18 0.184-0.427 0.298-0.693 0.301l-16.937-0.001c-0.152-0.001-0.321-0.041-0.481-0.134-0.239-0.138-0.399-0.359-0.466-0.607s-0.038-0.519 0.092-0.745zM9.432 3.346l-8.47 14.14c-0.422 0.731-0.506 1.55-0.308 2.29s0.68 1.408 1.398 1.822c0.464 0.268 0.976 0.4 1.475 0.402h16.943c0.839-0.009 1.587-0.354 2.123-0.902s0.864-1.303 0.855-2.131c-0.006-0.536-0.153-1.044-0.406-1.474l-8.474-14.147c-0.432-0.713-1.11-1.181-1.854-1.363s-1.561-0.081-2.269 0.349c-0.429 0.26-0.775 0.615-1.012 1.014zM11 9v4c0 0.552 0.448 1 1 1s1-0.448 1-1v-4c0-0.552-0.448-1-1-1s-1 0.448-1 1zM12 18c0.552 0 1-0.448 1-1s-0.448-1-1-1-1 0.448-1 1 0.448 1 1 1z"></path>
<path d="M29.996 4c0.001 0.001 0.003 0.002 0.004 0.004v23.993c-0.001 0.001-0.002 0.003-0.004 0.004h-27.993c-0.001-0.001-0.003-0.002-0.004-0.004v-23.993c0.001-0.001 0.002-0.003 0.004-0.004h27.993zM30 2h-28c-1.1 0-2 0.9-2 2v24c0 1.1 0.9 2 2 2h28c1.1 0 2-0.9 2-2v-24c0-1.1-0.9-2-2-2v0z"></path> </symbol>
<path d="M26 9c0 1.657-1.343 3-3 3s-3-1.343-3-3 1.343-3 3-3 3 1.343 3 3z"></path> <symbol id="icon-zap" viewBox="0 0 24 24">
<path d="M28 26h-24v-4l7-12 8 10h2l7-6z"></path> <path d="M11.585 5.26l-0.577 4.616c0.033 0.716 0.465 1.124 0.992 1.124h6.865l-6.45 7.74 0.577-4.616c-0.033-0.716-0.465-1.124-0.992-1.124h-6.865zM12.232 1.36l-10 12c-0.354 0.424-0.296 1.055 0.128 1.408 0.187 0.157 0.415 0.233 0.64 0.232h7.867l-0.859 6.876c-0.069 0.548 0.32 1.048 0.868 1.116 0.349 0.044 0.678-0.098 0.892-0.352l10-12c0.354-0.424 0.296-1.055-0.128-1.408-0.187-0.157-0.415-0.233-0.64-0.232h-7.867l0.859-6.876c0.069-0.548-0.32-1.048-0.868-1.116-0.349-0.044-0.678 0.098-0.892 0.352z"></path>
</symbol>
<symbol id="icon-heart" viewBox="0 0 24 24">
<path d="M20.133 5.317c0.88 0.881 1.319 2.031 1.319 3.184s-0.44 2.303-1.319 3.182l-8.133 8.133-8.133-8.133c-0.879-0.879-1.318-2.029-1.318-3.183s0.439-2.304 1.318-3.183 2.029-1.318 3.183-1.318 2.304 0.439 3.183 1.318l1.060 1.060c0.391 0.391 1.024 0.391 1.414 0l1.062-1.062c0.879-0.879 2.029-1.318 3.182-1.317s2.303 0.44 3.182 1.319zM21.547 3.903c-1.269-1.269-2.934-1.904-4.596-1.905s-3.327 0.634-4.597 1.903l-0.354 0.355-0.353-0.353c-1.269-1.269-2.935-1.904-4.597-1.904s-3.328 0.635-4.597 1.904-1.904 2.935-1.904 4.597 0.635 3.328 1.904 4.597l8.84 8.84c0.391 0.391 1.024 0.391 1.414 0l8.84-8.84c1.269-1.269 1.904-2.934 1.905-4.596s-0.634-3.327-1.905-4.598z"></path>
</symbol>
<symbol id="icon-link" viewBox="0 0 24 24">
<path d="M9.199 13.599c0.992 1.327 2.43 2.126 3.948 2.345s3.123-0.142 4.45-1.134c0.239-0.179 0.465-0.375 0.655-0.568l2.995-2.995c1.163-1.204 1.722-2.751 1.696-4.285s-0.639-3.061-1.831-4.211c-1.172-1.132-2.688-1.692-4.199-1.683-1.492 0.008-2.984 0.571-4.137 1.683l-1.731 1.721c-0.392 0.389-0.394 1.023-0.004 1.414s1.023 0.394 1.414 0.004l1.709-1.699c0.77-0.742 1.763-1.117 2.76-1.123 1.009-0.006 2.016 0.367 2.798 1.122 0.795 0.768 1.203 1.783 1.221 2.808s-0.355 2.054-1.11 2.836l-3.005 3.005c-0.114 0.116-0.263 0.247-0.428 0.37-0.885 0.662-1.952 0.902-2.967 0.756s-1.971-0.678-2.632-1.563c-0.331-0.442-0.957-0.533-1.4-0.202s-0.533 0.957-0.202 1.4zM14.801 10.401c-0.992-1.327-2.43-2.126-3.948-2.345s-3.124 0.142-4.451 1.134c-0.239 0.179-0.464 0.375-0.655 0.568l-2.995 2.995c-1.163 1.204-1.722 2.751-1.696 4.285s0.639 3.061 1.831 4.211c1.172 1.132 2.688 1.692 4.199 1.683 1.492-0.008 2.984-0.571 4.137-1.683l1.723-1.723c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-1.696 1.698c-0.77 0.742-1.763 1.117-2.76 1.123-1.009 0.006-2.016-0.367-2.798-1.122-0.795-0.768-1.203-1.783-1.221-2.808s0.355-2.054 1.11-2.836l3.005-3.005c0.114-0.116 0.263-0.247 0.428-0.37 0.885-0.662 1.952-0.902 2.967-0.756s1.971 0.678 2.632 1.563c0.331 0.442 0.957 0.533 1.4 0.202s0.533-0.957 0.202-1.4z"></path>
</symbol>
<symbol id="icon-minus-square" viewBox="0 0 24 24">
<path d="M5 2c-0.828 0-1.58 0.337-2.121 0.879s-0.879 1.293-0.879 2.121v14c0 0.828 0.337 1.58 0.879 2.121s1.293 0.879 2.121 0.879h14c0.828 0 1.58-0.337 2.121-0.879s0.879-1.293 0.879-2.121v-14c0-0.828-0.337-1.58-0.879-2.121s-1.293-0.879-2.121-0.879zM5 4h14c0.276 0 0.525 0.111 0.707 0.293s0.293 0.431 0.293 0.707v14c0 0.276-0.111 0.525-0.293 0.707s-0.431 0.293-0.707 0.293h-14c-0.276 0-0.525-0.111-0.707-0.293s-0.293-0.431-0.293-0.707v-14c0-0.276 0.111-0.525 0.293-0.707s0.431-0.293 0.707-0.293zM8 13h8c0.552 0 1-0.448 1-1s-0.448-1-1-1h-8c-0.552 0-1 0.448-1 1s0.448 1 1 1z"></path>
</symbol>
<symbol id="icon-plus-square" viewBox="0 0 24 24">
<path d="M5 2c-0.828 0-1.58 0.337-2.121 0.879s-0.879 1.293-0.879 2.121v14c0 0.828 0.337 1.58 0.879 2.121s1.293 0.879 2.121 0.879h14c0.828 0 1.58-0.337 2.121-0.879s0.879-1.293 0.879-2.121v-14c0-0.828-0.337-1.58-0.879-2.121s-1.293-0.879-2.121-0.879zM5 4h14c0.276 0 0.525 0.111 0.707 0.293s0.293 0.431 0.293 0.707v14c0 0.276-0.111 0.525-0.293 0.707s-0.431 0.293-0.707 0.293h-14c-0.276 0-0.525-0.111-0.707-0.293s-0.293-0.431-0.293-0.707v-14c0-0.276 0.111-0.525 0.293-0.707s0.431-0.293 0.707-0.293zM8 13h3v3c0 0.552 0.448 1 1 1s1-0.448 1-1v-3h3c0.552 0 1-0.448 1-1s-0.448-1-1-1h-3v-3c0-0.552-0.448-1-1-1s-1 0.448-1 1v3h-3c-0.552 0-1 0.448-1 1s0.448 1 1 1z"></path>
</symbol>
<symbol id="icon-help-circle" viewBox="0 0 24 24">
<path d="M23 12c0-3.037-1.232-5.789-3.222-7.778s-4.741-3.222-7.778-3.222-5.789 1.232-7.778 3.222-3.222 4.741-3.222 7.778 1.232 5.789 3.222 7.778 4.741 3.222 7.778 3.222 5.789-1.232 7.778-3.222 3.222-4.741 3.222-7.778zM21 12c0 2.486-1.006 4.734-2.636 6.364s-3.878 2.636-6.364 2.636-4.734-1.006-6.364-2.636-2.636-3.878-2.636-6.364 1.006-4.734 2.636-6.364 3.878-2.636 6.364-2.636 4.734 1.006 6.364 2.636 2.636 3.878 2.636 6.364zM10.033 9.332c0.183-0.521 0.559-0.918 1.022-1.14s1.007-0.267 1.528-0.083c0.458 0.161 0.819 0.47 1.050 0.859 0.183 0.307 0.284 0.665 0.286 1.037 0 0.155-0.039 0.309-0.117 0.464-0.080 0.16-0.203 0.325-0.368 0.49-0.709 0.709-1.831 1.092-1.831 1.092-0.524 0.175-0.807 0.741-0.632 1.265s0.741 0.807 1.265 0.632c0 0 1.544-0.506 2.613-1.575 0.279-0.279 0.545-0.614 0.743-1.010 0.2-0.4 0.328-0.858 0.328-1.369-0.004-0.731-0.204-1.437-0.567-2.049-0.463-0.778-1.19-1.402-2.105-1.724-1.042-0.366-2.135-0.275-3.057 0.167s-1.678 1.238-2.044 2.28c-0.184 0.521 0.090 1.092 0.611 1.275s1.092-0.091 1.275-0.611zM12 18c0.552 0 1-0.448 1-1s-0.448-1-1-1-1 0.448-1 1 0.448 1 1 1z"></path>
</symbol>
<symbol id="icon-pin" viewBox="0 0 18 18">
<path d="M15 2v-1h-12v1c0 0.552 0.448 1 1 1v8c-0.552 0-1 0.448-1 1v1h5v3c0 0.552 0.448 1 1 1s1-0.448 1-1v-3h5v-1c0-0.552-0.448-1-1-1v-8c0.552 0 1-0.448 1-1zM12 11h-6v-8h6v8z"></path>
</symbol>
<symbol id="icon-lock" viewBox="0 0 24 24">
<path d="M5 12h14c0.276 0 0.525 0.111 0.707 0.293s0.293 0.431 0.293 0.707v7c0 0.276-0.111 0.525-0.293 0.707s-0.431 0.293-0.707 0.293h-14c-0.276 0-0.525-0.111-0.707-0.293s-0.293-0.431-0.293-0.707v-7c0-0.276 0.111-0.525 0.293-0.707s0.431-0.293 0.707-0.293zM18 10v-3c0-1.657-0.673-3.158-1.757-4.243s-2.586-1.757-4.243-1.757-3.158 0.673-4.243 1.757-1.757 2.586-1.757 4.243v3h-1c-0.828 0-1.58 0.337-2.121 0.879s-0.879 1.293-0.879 2.121v7c0 0.828 0.337 1.58 0.879 2.121s1.293 0.879 2.121 0.879h14c0.828 0 1.58-0.337 2.121-0.879s0.879-1.293 0.879-2.121v-7c0-0.828-0.337-1.58-0.879-2.121s-1.293-0.879-2.121-0.879zM8 10v-3c0-1.105 0.447-2.103 1.172-2.828s1.723-1.172 2.828-1.172 2.103 0.447 2.828 1.172 1.172 1.723 1.172 2.828v3z"></path>
</symbol>
<symbol id="icon-check" viewBox="0 0 24 24">
<path d="M19.293 5.293l-10.293 10.293-4.293-4.293c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414l5 5c0.391 0.391 1.024 0.391 1.414 0l11-11c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0z"></path>
</symbol>
<symbol id="icon-copy" viewBox="0 0 24 24">
<path d="M11 8c-0.828 0-1.58 0.337-2.121 0.879s-0.879 1.293-0.879 2.121v9c0 0.828 0.337 1.58 0.879 2.121s1.293 0.879 2.121 0.879h9c0.828 0 1.58-0.337 2.121-0.879s0.879-1.293 0.879-2.121v-9c0-0.828-0.337-1.58-0.879-2.121s-1.293-0.879-2.121-0.879zM11 10h9c0.276 0 0.525 0.111 0.707 0.293s0.293 0.431 0.293 0.707v9c0 0.276-0.111 0.525-0.293 0.707s-0.431 0.293-0.707 0.293h-9c-0.276 0-0.525-0.111-0.707-0.293s-0.293-0.431-0.293-0.707v-9c0-0.276 0.111-0.525 0.293-0.707s0.431-0.293 0.707-0.293zM5 14h-1c-0.276 0-0.525-0.111-0.707-0.293s-0.293-0.431-0.293-0.707v-9c0-0.276 0.111-0.525 0.293-0.707s0.431-0.293 0.707-0.293h9c0.276 0 0.525 0.111 0.707 0.293s0.293 0.431 0.293 0.707v1c0 0.552 0.448 1 1 1s1-0.448 1-1v-1c0-0.828-0.337-1.58-0.879-2.121s-1.293-0.879-2.121-0.879h-9c-0.828 0-1.58 0.337-2.121 0.879s-0.879 1.293-0.879 2.121v9c0 0.828 0.337 1.58 0.879 2.121s1.293 0.879 2.121 0.879h1c0.552 0 1-0.448 1-1s-0.448-1-1-1z"></path>
</symbol>
<symbol id="icon-more-vertical" viewBox="0 0 24 24">
<path d="M14 12c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM14 5c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414zM14 19c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414z"></path>
</symbol>
<symbol id="icon-bell" viewBox="0 0 24 24">
<path d="M17 8c0 4.011 0.947 6.52 1.851 8h-13.702c0.904-1.48 1.851-3.989 1.851-8 0-1.381 0.559-2.63 1.464-3.536s2.155-1.464 3.536-1.464 2.63 0.559 3.536 1.464 1.464 2.155 1.464 3.536zM19 8c0-1.933-0.785-3.684-2.050-4.95s-3.017-2.050-4.95-2.050-3.684 0.785-4.95 2.050-2.050 3.017-2.050 4.95c0 6.127-2.393 8.047-2.563 8.174-0.453 0.308-0.573 0.924-0.269 1.381 0.192 0.287 0.506 0.443 0.832 0.445h18c0.552 0 1-0.448 1-1 0-0.339-0.168-0.638-0.429-0.821-0.176-0.13-2.571-2.050-2.571-8.179zM12.865 20.498c-0.139 0.239-0.359 0.399-0.608 0.465s-0.52 0.037-0.759-0.101c-0.162-0.094-0.283-0.222-0.359-0.357-0.274-0.48-0.884-0.647-1.364-0.373s-0.647 0.884-0.373 1.364c0.25 0.439 0.623 0.823 1.093 1.096 0.716 0.416 1.535 0.501 2.276 0.304s1.409-0.678 1.824-1.394c0.277-0.478 0.114-1.090-0.363-1.367s-1.090-0.114-1.367 0.363z"></path>
</symbol>
<symbol id="icon-file-text" viewBox="0 0 24 24">
<path d="M17.586 7h-2.586v-2.586zM20.707 7.293l-6-6c-0.092-0.092-0.202-0.166-0.324-0.217s-0.253-0.076-0.383-0.076h-8c-0.828 0-1.58 0.337-2.121 0.879s-0.879 1.293-0.879 2.121v16c0 0.828 0.337 1.58 0.879 2.121s1.293 0.879 2.121 0.879h12c0.828 0 1.58-0.337 2.121-0.879s0.879-1.293 0.879-2.121v-12c0-0.276-0.112-0.526-0.293-0.707zM13 3v5c0 0.552 0.448 1 1 1h5v11c0 0.276-0.111 0.525-0.293 0.707s-0.431 0.293-0.707 0.293h-12c-0.276 0-0.525-0.111-0.707-0.293s-0.293-0.431-0.293-0.707v-16c0-0.276 0.111-0.525 0.293-0.707s0.431-0.293 0.707-0.293zM16 12h-8c-0.552 0-1 0.448-1 1s0.448 1 1 1h8c0.552 0 1-0.448 1-1s-0.448-1-1-1zM16 16h-8c-0.552 0-1 0.448-1 1s0.448 1 1 1h8c0.552 0 1-0.448 1-1s-0.448-1-1-1zM10 8h-2c-0.552 0-1 0.448-1 1s0.448 1 1 1h2c0.552 0 1-0.448 1-1s-0.448-1-1-1z"></path>
</symbol>
<symbol id="icon-eye" viewBox="0 0 24 24">
<path d="M0.106 11.553c-0.136 0.274-0.146 0.603 0 0.894 0 0 0.396 0.789 1.12 1.843 0.451 0.656 1.038 1.432 1.757 2.218 0.894 0.979 2.004 1.987 3.319 2.8 1.595 0.986 3.506 1.692 5.698 1.692s4.103-0.706 5.698-1.692c1.315-0.813 2.425-1.821 3.319-2.8 0.718-0.786 1.306-1.562 1.757-2.218 0.724-1.054 1.12-1.843 1.12-1.843 0.136-0.274 0.146-0.603 0-0.894 0 0-0.396-0.789-1.12-1.843-0.451-0.656-1.038-1.432-1.757-2.218-0.894-0.979-2.004-1.987-3.319-2.8-1.595-0.986-3.506-1.692-5.698-1.692s-4.103 0.706-5.698 1.692c-1.315 0.813-2.425 1.821-3.319 2.8-0.719 0.786-1.306 1.561-1.757 2.218-0.724 1.054-1.12 1.843-1.12 1.843zM2.14 12c0.163-0.281 0.407-0.681 0.734-1.158 0.41-0.596 0.94-1.296 1.585-2.001 0.805-0.881 1.775-1.756 2.894-2.448 1.35-0.834 2.901-1.393 4.647-1.393s3.297 0.559 4.646 1.393c1.119 0.692 2.089 1.567 2.894 2.448 0.644 0.705 1.175 1.405 1.585 2.001 0.328 0.477 0.572 0.876 0.734 1.158-0.163 0.281-0.407 0.681-0.734 1.158-0.41 0.596-0.94 1.296-1.585 2.001-0.805 0.881-1.775 1.756-2.894 2.448-1.349 0.834-2.9 1.393-4.646 1.393s-3.297-0.559-4.646-1.393c-1.119-0.692-2.089-1.567-2.894-2.448-0.644-0.705-1.175-1.405-1.585-2.001-0.328-0.477-0.572-0.877-0.735-1.158zM16 12c0-1.104-0.449-2.106-1.172-2.828s-1.724-1.172-2.828-1.172-2.106 0.449-2.828 1.172-1.172 1.724-1.172 2.828 0.449 2.106 1.172 2.828 1.724 1.172 2.828 1.172 2.106-0.449 2.828-1.172 1.172-1.724 1.172-2.828zM14 12c0 0.553-0.223 1.051-0.586 1.414s-0.861 0.586-1.414 0.586-1.051-0.223-1.414-0.586-0.586-0.861-0.586-1.414 0.223-1.051 0.586-1.414 0.861-0.586 1.414-0.586 1.051 0.223 1.414 0.586 0.586 0.861 0.586 1.414z"></path>
</symbol>
<symbol id="icon-edit" viewBox="0 0 24 24">
<path d="M11 3h-7c-0.828 0-1.58 0.337-2.121 0.879s-0.879 1.293-0.879 2.121v14c0 0.828 0.337 1.58 0.879 2.121s1.293 0.879 2.121 0.879h14c0.828 0 1.58-0.337 2.121-0.879s0.879-1.293 0.879-2.121v-7c0-0.552-0.448-1-1-1s-1 0.448-1 1v7c0 0.276-0.111 0.525-0.293 0.707s-0.431 0.293-0.707 0.293h-14c-0.276 0-0.525-0.111-0.707-0.293s-0.293-0.431-0.293-0.707v-14c0-0.276 0.111-0.525 0.293-0.707s0.431-0.293 0.707-0.293h7c0.552 0 1-0.448 1-1s-0.448-1-1-1zM17.793 1.793l-9.5 9.5c-0.122 0.121-0.217 0.28-0.263 0.465l-1 4c-0.039 0.15-0.042 0.318 0 0.485 0.134 0.536 0.677 0.862 1.213 0.728l4-1c0.167-0.041 0.33-0.129 0.465-0.263l9.5-9.5c0.609-0.609 0.914-1.41 0.914-2.207s-0.305-1.598-0.914-2.207-1.411-0.915-2.208-0.915-1.598 0.305-2.207 0.914zM19.207 3.207c0.219-0.219 0.504-0.328 0.793-0.328s0.574 0.109 0.793 0.328 0.328 0.504 0.328 0.793-0.109 0.574-0.328 0.793l-9.304 9.304-2.114 0.529 0.529-2.114z"></path>
</symbol>
<symbol id="icon-edit-2" viewBox="0 0 24 24">
<path d="M16.293 2.293l-13.5 13.5c-0.117 0.116-0.21 0.268-0.258 0.444l-1.5 5.5c-0.046 0.163-0.049 0.346 0 0.526 0.145 0.533 0.695 0.847 1.228 0.702l5.5-1.5c0.159-0.042 0.315-0.129 0.444-0.258l13.5-13.5c0.747-0.747 1.121-1.729 1.121-2.707s-0.374-1.96-1.121-2.707-1.729-1.121-2.707-1.121-1.96 0.374-2.707 1.121zM17.707 3.707c0.357-0.357 0.824-0.535 1.293-0.535s0.936 0.178 1.293 0.536 0.535 0.823 0.535 1.292-0.178 0.936-0.535 1.293l-13.312 13.312-3.556 0.97 0.97-3.555z"></path>
</symbol>
<symbol id="icon-trash" viewBox="0 0 24 24">
<path d="M18 7v13c0 0.276-0.111 0.525-0.293 0.707s-0.431 0.293-0.707 0.293h-10c-0.276 0-0.525-0.111-0.707-0.293s-0.293-0.431-0.293-0.707v-13zM17 5v-1c0-0.828-0.337-1.58-0.879-2.121s-1.293-0.879-2.121-0.879h-4c-0.828 0-1.58 0.337-2.121 0.879s-0.879 1.293-0.879 2.121v1h-4c-0.552 0-1 0.448-1 1s0.448 1 1 1h1v13c0 0.828 0.337 1.58 0.879 2.121s1.293 0.879 2.121 0.879h10c0.828 0 1.58-0.337 2.121-0.879s0.879-1.293 0.879-2.121v-13h1c0.552 0 1-0.448 1-1s-0.448-1-1-1zM9 5v-1c0-0.276 0.111-0.525 0.293-0.707s0.431-0.293 0.707-0.293h4c0.276 0 0.525 0.111 0.707 0.293s0.293 0.431 0.293 0.707v1z"></path>
</symbol>
<symbol id="icon-reply1" viewBox="0 0 20 20">
<path d="M19 16.685c0 0-2.225-9.732-11-9.732v-3.984l-7 6.573 7 6.69v-4.357c4.763-0.001 8.516 0.421 11 4.81z"></path>
</symbol>
<symbol id="icon-star" viewBox="0 0 24 24">
<path d="M12.897 1.557c-0.092-0.189-0.248-0.352-0.454-0.454-0.495-0.244-1.095-0.041-1.339 0.454l-2.858 5.789-6.391 0.935c-0.208 0.029-0.411 0.127-0.571 0.291-0.386 0.396-0.377 1.029 0.018 1.414l4.623 4.503-1.091 6.362c-0.036 0.207-0.006 0.431 0.101 0.634 0.257 0.489 0.862 0.677 1.351 0.42l5.714-3.005 5.715 3.005c0.186 0.099 0.408 0.139 0.634 0.101 0.544-0.093 0.91-0.61 0.817-1.155l-1.091-6.362 4.623-4.503c0.151-0.146 0.259-0.344 0.292-0.572 0.080-0.546-0.298-1.054-0.845-1.134l-6.39-0.934zM12 4.259l2.193 4.444c0.151 0.305 0.436 0.499 0.752 0.547l4.906 0.717-3.549 3.457c-0.244 0.238-0.341 0.569-0.288 0.885l0.837 4.883-4.386-2.307c-0.301-0.158-0.647-0.148-0.931 0l-4.386 2.307 0.837-4.883c0.058-0.336-0.059-0.661-0.288-0.885l-3.549-3.457 4.907-0.718c0.336-0.049 0.609-0.26 0.752-0.546z"></path>
</symbol>
<symbol id="icon-message-square" viewBox="0 0 24 24">
<path d="M22 15v-10c0-0.828-0.337-1.58-0.879-2.121s-1.293-0.879-2.121-0.879h-14c-0.828 0-1.58 0.337-2.121 0.879s-0.879 1.293-0.879 2.121v16c0 0.256 0.098 0.512 0.293 0.707 0.391 0.391 1.024 0.391 1.414 0l3.707-3.707h11.586c0.828 0 1.58-0.337 2.121-0.879s0.879-1.293 0.879-2.121zM20 15c0 0.276-0.111 0.525-0.293 0.707s-0.431 0.293-0.707 0.293h-12c-0.276 0-0.526 0.112-0.707 0.293l-2.293 2.293v-13.586c0-0.276 0.111-0.525 0.293-0.707s0.431-0.293 0.707-0.293h14c0.276 0 0.525 0.111 0.707 0.293s0.293 0.431 0.293 0.707z"></path>
</symbol>
<symbol id="icon-image" viewBox="0 0 24 24">
<path d="M5 2c-0.828 0-1.58 0.337-2.121 0.879s-0.879 1.293-0.879 2.121v14c0 0.828 0.337 1.58 0.879 2.121s1.293 0.879 2.121 0.879h14c0.828 0 1.58-0.337 2.121-0.879s0.879-1.293 0.879-2.121v-14c0-0.828-0.337-1.58-0.879-2.121s-1.293-0.879-2.121-0.879zM11 8.5c0-0.69-0.281-1.316-0.732-1.768s-1.078-0.732-1.768-0.732-1.316 0.281-1.768 0.732-0.732 1.078-0.732 1.768 0.281 1.316 0.732 1.768 1.078 0.732 1.768 0.732 1.316-0.281 1.768-0.732 0.732-1.078 0.732-1.768zM9 8.5c0 0.138-0.055 0.262-0.146 0.354s-0.216 0.146-0.354 0.146-0.262-0.055-0.354-0.146-0.146-0.216-0.146-0.354 0.055-0.262 0.146-0.354 0.216-0.146 0.354-0.146 0.262 0.055 0.354 0.146 0.146 0.216 0.146 0.354zM7.414 20l8.586-8.586 4 4v3.586c0 0.276-0.111 0.525-0.293 0.707s-0.431 0.293-0.707 0.293zM20 12.586l-3.293-3.293c-0.391-0.391-1.024-0.391-1.414 0l-10.644 10.644c-0.135-0.050-0.255-0.129-0.356-0.23-0.182-0.182-0.293-0.431-0.293-0.707v-14c0-0.276 0.111-0.525 0.293-0.707s0.431-0.293 0.707-0.293h14c0.276 0 0.525 0.111 0.707 0.293s0.293 0.431 0.293 0.707z"></path>
</symbol> </symbol>
<symbol id="icon-external-link" viewBox="0 0 24 24"> <symbol id="icon-external-link" viewBox="0 0 24 24">
<title>external-link</title>
<path d="M17 13v6c0 0.276-0.111 0.525-0.293 0.707s-0.431 0.293-0.707 0.293h-11c-0.276 0-0.525-0.111-0.707-0.293s-0.293-0.431-0.293-0.707v-11c0-0.276 0.111-0.525 0.293-0.707s0.431-0.293 0.707-0.293h6c0.552 0 1-0.448 1-1s-0.448-1-1-1h-6c-0.828 0-1.58 0.337-2.121 0.879s-0.879 1.293-0.879 2.121v11c0 0.828 0.337 1.58 0.879 2.121s1.293 0.879 2.121 0.879h11c0.828 0 1.58-0.337 2.121-0.879s0.879-1.293 0.879-2.121v-6c0-0.552-0.448-1-1-1s-1 0.448-1 1zM10.707 14.707l9.293-9.293v3.586c0 0.552 0.448 1 1 1s1-0.448 1-1v-6c0-0.136-0.027-0.265-0.076-0.383s-0.121-0.228-0.216-0.323c-0.001-0.001-0.001-0.001-0.002-0.002-0.092-0.092-0.202-0.166-0.323-0.216-0.118-0.049-0.247-0.076-0.383-0.076h-6c-0.552 0-1 0.448-1 1s0.448 1 1 1h3.586l-9.293 9.293c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0z"></path> <path d="M17 13v6c0 0.276-0.111 0.525-0.293 0.707s-0.431 0.293-0.707 0.293h-11c-0.276 0-0.525-0.111-0.707-0.293s-0.293-0.431-0.293-0.707v-11c0-0.276 0.111-0.525 0.293-0.707s0.431-0.293 0.707-0.293h6c0.552 0 1-0.448 1-1s-0.448-1-1-1h-6c-0.828 0-1.58 0.337-2.121 0.879s-0.879 1.293-0.879 2.121v11c0 0.828 0.337 1.58 0.879 2.121s1.293 0.879 2.121 0.879h11c0.828 0 1.58-0.337 2.121-0.879s0.879-1.293 0.879-2.121v-6c0-0.552-0.448-1-1-1s-1 0.448-1 1zM10.707 14.707l9.293-9.293v3.586c0 0.552 0.448 1 1 1s1-0.448 1-1v-6c0-0.136-0.027-0.265-0.076-0.383s-0.121-0.228-0.216-0.323c-0.001-0.001-0.001-0.001-0.002-0.002-0.092-0.092-0.202-0.166-0.323-0.216-0.118-0.049-0.247-0.076-0.383-0.076h-6c-0.552 0-1 0.448-1 1s0.448 1 1 1h3.586l-9.293 9.293c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0z"></path>
</symbol> </symbol>
<symbol id="icon-coffee" viewBox="0 0 24 24"> <symbol id="icon-coffee" viewBox="0 0 24 24">
<title>coffee1</title>
<path d="M17 19h-12c-0.553 0-1-0.447-1-1s0.447-1 1-1h12c0.553 0 1 0.447 1 1s-0.447 1-1 1z"></path> <path d="M17 19h-12c-0.553 0-1-0.447-1-1s0.447-1 1-1h12c0.553 0 1 0.447 1 1s-0.447 1-1 1z"></path>
<path d="M17.5 5h-12.5v9c0 1.1 0.9 2 2 2h8c1.1 0 2-0.9 2-2v-2h0.5c1.93 0 3.5-1.57 3.5-3.5s-1.57-3.5-3.5-3.5zM15 14h-8v-7h8v7zM17.5 10h-1.5v-3h1.5c0.827 0 1.5 0.673 1.5 1.5s-0.673 1.5-1.5 1.5z"></path> <path d="M17.5 5h-12.5v9c0 1.1 0.9 2 2 2h8c1.1 0 2-0.9 2-2v-2h0.5c1.93 0 3.5-1.57 3.5-3.5s-1.57-3.5-3.5-3.5zM15 14h-8v-7h8v7zM17.5 10h-1.5v-3h1.5c0.827 0 1.5 0.673 1.5 1.5s-0.673 1.5-1.5 1.5z"></path>
</symbol> </symbol>
<symbol id="icon-rss" viewBox="0 0 32 32"> <symbol id="icon-rss" viewBox="0 0 32 32">
<title>rss</title>
<path d="M4.259 23.467c-2.35 0-4.259 1.917-4.259 4.252 0 2.349 1.909 4.244 4.259 4.244 2.358 0 4.265-1.895 4.265-4.244-0-2.336-1.907-4.252-4.265-4.252zM0.005 10.873v6.133c3.993 0 7.749 1.562 10.577 4.391 2.825 2.822 4.384 6.595 4.384 10.603h6.16c-0-11.651-9.478-21.127-21.121-21.127zM0.012 0v6.136c14.243 0 25.836 11.604 25.836 25.864h6.152c0-17.64-14.352-32-31.988-32z"></path> <path d="M4.259 23.467c-2.35 0-4.259 1.917-4.259 4.252 0 2.349 1.909 4.244 4.259 4.244 2.358 0 4.265-1.895 4.265-4.244-0-2.336-1.907-4.252-4.265-4.252zM0.005 10.873v6.133c3.993 0 7.749 1.562 10.577 4.391 2.825 2.822 4.384 6.595 4.384 10.603h6.16c-0-11.651-9.478-21.127-21.121-21.127zM0.012 0v6.136c14.243 0 25.836 11.604 25.836 25.864h6.152c0-17.64-14.352-32-31.988-32z"></path>
</symbol> </symbol>
<symbol id="icon-arrow-down" viewBox="0 0 26 28"> <symbol id="icon-arrow-down" viewBox="0 0 26 28">
<title>arrow-down</title>
<path d="M25.172 13c0 0.531-0.219 1.047-0.578 1.406l-10.172 10.187c-0.375 0.359-0.891 0.578-1.422 0.578s-1.047-0.219-1.406-0.578l-10.172-10.187c-0.375-0.359-0.594-0.875-0.594-1.406s0.219-1.047 0.594-1.422l1.156-1.172c0.375-0.359 0.891-0.578 1.422-0.578s1.047 0.219 1.406 0.578l4.594 4.594v-11c0-1.094 0.906-2 2-2h2c1.094 0 2 0.906 2 2v11l4.594-4.594c0.359-0.359 0.875-0.578 1.406-0.578s1.047 0.219 1.422 0.578l1.172 1.172c0.359 0.375 0.578 0.891 0.578 1.422z"></path> <path d="M25.172 13c0 0.531-0.219 1.047-0.578 1.406l-10.172 10.187c-0.375 0.359-0.891 0.578-1.422 0.578s-1.047-0.219-1.406-0.578l-10.172-10.187c-0.375-0.359-0.594-0.875-0.594-1.406s0.219-1.047 0.594-1.422l1.156-1.172c0.375-0.359 0.891-0.578 1.422-0.578s1.047 0.219 1.406 0.578l4.594 4.594v-11c0-1.094 0.906-2 2-2h2c1.094 0 2 0.906 2 2v11l4.594-4.594c0.359-0.359 0.875-0.578 1.406-0.578s1.047 0.219 1.422 0.578l1.172 1.172c0.359 0.375 0.578 0.891 0.578 1.422z"></path>
</symbol> </symbol>
<symbol id="icon-arrow-up" viewBox="0 0 26 28"> <symbol id="icon-arrow-up" viewBox="0 0 26 28">
<title>arrow-up</title>
<path d="M25.172 15.172c0 0.531-0.219 1.031-0.578 1.406l-1.172 1.172c-0.375 0.375-0.891 0.594-1.422 0.594s-1.047-0.219-1.406-0.594l-4.594-4.578v11c0 1.125-0.938 1.828-2 1.828h-2c-1.062 0-2-0.703-2-1.828v-11l-4.594 4.578c-0.359 0.375-0.875 0.594-1.406 0.594s-1.047-0.219-1.406-0.594l-1.172-1.172c-0.375-0.375-0.594-0.875-0.594-1.406s0.219-1.047 0.594-1.422l10.172-10.172c0.359-0.375 0.875-0.578 1.406-0.578s1.047 0.203 1.422 0.578l10.172 10.172c0.359 0.375 0.578 0.891 0.578 1.422z"></path> <path d="M25.172 15.172c0 0.531-0.219 1.031-0.578 1.406l-1.172 1.172c-0.375 0.375-0.891 0.594-1.422 0.594s-1.047-0.219-1.406-0.594l-4.594-4.578v11c0 1.125-0.938 1.828-2 1.828h-2c-1.062 0-2-0.703-2-1.828v-11l-4.594 4.578c-0.359 0.375-0.875 0.594-1.406 0.594s-1.047-0.219-1.406-0.594l-1.172-1.172c-0.375-0.375-0.594-0.875-0.594-1.406s0.219-1.047 0.594-1.422l10.172-10.172c0.359-0.375 0.875-0.578 1.406-0.578s1.047 0.203 1.422 0.578l10.172 10.172c0.359 0.375 0.578 0.891 0.578 1.422z"></path>
</symbol> </symbol>
<symbol id="icon-mail" viewBox="0 0 32 32"> <symbol id="icon-mail" viewBox="0 0 24 24">
<title>mail</title> <path d="M3 7.921l8.427 5.899c0.34 0.235 0.795 0.246 1.147 0l8.426-5.899v10.079c0 0.272-0.11 0.521-0.295 0.705s-0.433 0.295-0.705 0.295h-16c-0.272 0-0.521-0.11-0.705-0.295s-0.295-0.433-0.295-0.705zM1 5.983c0 0.010 0 0.020 0 0.030v11.987c0 0.828 0.34 1.579 0.88 2.12s1.292 0.88 2.12 0.88h16c0.828 0 1.579-0.34 2.12-0.88s0.88-1.292 0.88-2.12v-11.988c0-0.010 0-0.020 0-0.030-0.005-0.821-0.343-1.565-0.88-2.102-0.541-0.54-1.292-0.88-2.12-0.88h-16c-0.828 0-1.579 0.34-2.12 0.88-0.537 0.537-0.875 1.281-0.88 2.103zM20.894 5.554l-8.894 6.225-8.894-6.225c0.048-0.096 0.112-0.183 0.188-0.259 0.185-0.185 0.434-0.295 0.706-0.295h16c0.272 0 0.521 0.11 0.705 0.295 0.076 0.076 0.14 0.164 0.188 0.259z"></path>
<path d="M28 5h-24c-2.209 0-4 1.792-4 4v13c0 2.209 1.791 4 4 4h24c2.209 0 4-1.791 4-4v-13c0-2.208-1.791-4-4-4zM2 10.25l6.999 5.25-6.999 5.25v-10.5zM30 22c0 1.104-0.898 2-2 2h-24c-1.103 0-2-0.896-2-2l7.832-5.875 4.368 3.277c0.533 0.398 1.166 0.6 1.8 0.6 0.633 0 1.266-0.201 1.799-0.6l4.369-3.277 7.832 5.875zM30 20.75l-7-5.25 7-5.25v10.5zM17.199 18.602c-0.349 0.262-0.763 0.4-1.199 0.4s-0.851-0.139-1.2-0.4l-12.8-9.602c0-1.103 0.897-2 2-2h24c1.102 0 2 0.897 2 2l-12.801 9.602z"></path>
</symbol> </symbol>
<symbol <symbol
id="icon-mouse" id="icon-mouse"
@ -91,15 +145,12 @@ export class Symbols extends Component<any, any> {
</g> </g>
</symbol> </symbol>
<symbol id="icon-search" viewBox="0 0 32 32"> <symbol id="icon-search" viewBox="0 0 32 32">
<title>search</title>
<path d="M31.008 27.231l-7.58-6.447c-0.784-0.705-1.622-1.029-2.299-0.998 1.789-2.096 2.87-4.815 2.87-7.787 0-6.627-5.373-12-12-12s-12 5.373-12 12 5.373 12 12 12c2.972 0 5.691-1.081 7.787-2.87-0.031 0.677 0.293 1.515 0.998 2.299l6.447 7.58c1.104 1.226 2.907 1.33 4.007 0.23s0.997-2.903-0.23-4.007zM12 20c-4.418 0-8-3.582-8-8s3.582-8 8-8 8 3.582 8 8-3.582 8-8 8z"></path> <path d="M31.008 27.231l-7.58-6.447c-0.784-0.705-1.622-1.029-2.299-0.998 1.789-2.096 2.87-4.815 2.87-7.787 0-6.627-5.373-12-12-12s-12 5.373-12 12 5.373 12 12 12c2.972 0 5.691-1.081 7.787-2.87-0.031 0.677 0.293 1.515 0.998 2.299l6.447 7.58c1.104 1.226 2.907 1.33 4.007 0.23s0.997-2.903-0.23-4.007zM12 20c-4.418 0-8-3.582-8-8s3.582-8 8-8 8 3.582 8 8-3.582 8-8 8z"></path>
</symbol> </symbol>
<symbol id="icon-github" viewBox="0 0 32 32"> <symbol id="icon-github" viewBox="0 0 32 32">
<title>github</title>
<path d="M16 0.395c-8.836 0-16 7.163-16 16 0 7.069 4.585 13.067 10.942 15.182 0.8 0.148 1.094-0.347 1.094-0.77 0-0.381-0.015-1.642-0.022-2.979-4.452 0.968-5.391-1.888-5.391-1.888-0.728-1.849-1.776-2.341-1.776-2.341-1.452-0.993 0.11-0.973 0.11-0.973 1.606 0.113 2.452 1.649 2.452 1.649 1.427 2.446 3.743 1.739 4.656 1.33 0.143-1.034 0.558-1.74 1.016-2.14-3.554-0.404-7.29-1.777-7.29-7.907 0-1.747 0.625-3.174 1.649-4.295-0.166-0.403-0.714-2.030 0.155-4.234 0 0 1.344-0.43 4.401 1.64 1.276-0.355 2.645-0.532 4.005-0.539 1.359 0.006 2.729 0.184 4.008 0.539 3.054-2.070 4.395-1.64 4.395-1.64 0.871 2.204 0.323 3.831 0.157 4.234 1.026 1.12 1.647 2.548 1.647 4.295 0 6.145-3.743 7.498-7.306 7.895 0.574 0.497 1.085 1.47 1.085 2.963 0 2.141-0.019 3.864-0.019 4.391 0 0.426 0.288 0.925 1.099 0.768 6.354-2.118 10.933-8.113 10.933-15.18 0-8.837-7.164-16-16-16z"></path> <path d="M16 0.395c-8.836 0-16 7.163-16 16 0 7.069 4.585 13.067 10.942 15.182 0.8 0.148 1.094-0.347 1.094-0.77 0-0.381-0.015-1.642-0.022-2.979-4.452 0.968-5.391-1.888-5.391-1.888-0.728-1.849-1.776-2.341-1.776-2.341-1.452-0.993 0.11-0.973 0.11-0.973 1.606 0.113 2.452 1.649 2.452 1.649 1.427 2.446 3.743 1.739 4.656 1.33 0.143-1.034 0.558-1.74 1.016-2.14-3.554-0.404-7.29-1.777-7.29-7.907 0-1.747 0.625-3.174 1.649-4.295-0.166-0.403-0.714-2.030 0.155-4.234 0 0 1.344-0.43 4.401 1.64 1.276-0.355 2.645-0.532 4.005-0.539 1.359 0.006 2.729 0.184 4.008 0.539 3.054-2.070 4.395-1.64 4.395-1.64 0.871 2.204 0.323 3.831 0.157 4.234 1.026 1.12 1.647 2.548 1.647 4.295 0 6.145-3.743 7.498-7.306 7.895 0.574 0.497 1.085 1.47 1.085 2.963 0 2.141-0.019 3.864-0.019 4.391 0 0.426 0.288 0.925 1.099 0.768 6.354-2.118 10.933-8.113 10.933-15.18 0-8.837-7.164-16-16-16z"></path>
</symbol> </symbol>
<symbol id="icon-spinner" viewBox="0 0 32 32"> <symbol id="icon-spinner" viewBox="0 0 32 32">
<title>spinner</title>
<path d="M16 32c-4.274 0-8.292-1.664-11.314-4.686s-4.686-7.040-4.686-11.314c0-3.026 0.849-5.973 2.456-8.522 1.563-2.478 3.771-4.48 6.386-5.791l1.344 2.682c-2.126 1.065-3.922 2.693-5.192 4.708-1.305 2.069-1.994 4.462-1.994 6.922 0 7.168 5.832 13 13 13s13-5.832 13-13c0-2.459-0.69-4.853-1.994-6.922-1.271-2.015-3.066-3.643-5.192-4.708l1.344-2.682c2.615 1.31 4.824 3.313 6.386 5.791 1.607 2.549 2.456 5.495 2.456 8.522 0 4.274-1.664 8.292-4.686 11.314s-7.040 4.686-11.314 4.686z"></path> <path d="M16 32c-4.274 0-8.292-1.664-11.314-4.686s-4.686-7.040-4.686-11.314c0-3.026 0.849-5.973 2.456-8.522 1.563-2.478 3.771-4.48 6.386-5.791l1.344 2.682c-2.126 1.065-3.922 2.693-5.192 4.708-1.305 2.069-1.994 4.462-1.994 6.922 0 7.168 5.832 13 13 13s13-5.832 13-13c0-2.459-0.69-4.853-1.994-6.922-1.271-2.015-3.066-3.643-5.192-4.708l1.344-2.682c2.615 1.31 4.824 3.313 6.386 5.791 1.607 2.549 2.456 5.495 2.456 8.522 0 4.274-1.664 8.292-4.686 11.314s-7.040 4.686-11.314 4.686z"></path>
</symbol> </symbol>
</defs> </defs>

View file

@ -37,6 +37,7 @@ import {
createCommentLikeRes, createCommentLikeRes,
createPostLikeFindRes, createPostLikeFindRes,
commentsToFlatNodes, commentsToFlatNodes,
setupTippy,
} from '../utils'; } from '../utils';
import { PostListing } from './post-listing'; import { PostListing } from './post-listing';
import { SortSelect } from './sort-select'; import { SortSelect } from './sort-select';
@ -267,6 +268,7 @@ export class User extends Component<any, UserState> {
SortType[this.state.sort] SortType[this.state.sort]
}`} }`}
target="_blank" target="_blank"
title="RSS"
> >
<svg class="icon mx-2 text-muted small"> <svg class="icon mx-2 text-muted small">
<use xlinkHref="#icon-rss">#</use> <use xlinkHref="#icon-rss">#</use>
@ -357,10 +359,11 @@ export class User extends Component<any, UserState> {
</ul> </ul>
</h5> </h5>
<div> <div>
{i18n.t('joined')} <MomentTime data={user} /> {i18n.t('joined')} <MomentTime data={user} showAgo />
</div> </div>
<div class="table-responsive mt-1"> <div class="table-responsive mt-1">
<table class="table table-bordered table-sm mt-2 mb-0"> <table class="table table-bordered table-sm mt-2 mb-0">
{/*
<tr> <tr>
<td class="text-center" colSpan={2}> <td class="text-center" colSpan={2}>
{i18n.t('number_of_points', { {i18n.t('number_of_points', {
@ -368,18 +371,23 @@ export class User extends Component<any, UserState> {
})} })}
</td> </td>
</tr> </tr>
*/}
<tr> <tr>
{/*
<td> <td>
{i18n.t('number_of_points', { count: user.post_score })} {i18n.t('number_of_points', { count: user.post_score })}
</td> </td>
*/}
<td> <td>
{i18n.t('number_of_posts', { count: user.number_of_posts })} {i18n.t('number_of_posts', { count: user.number_of_posts })}
</td> </td>
{/*
</tr> </tr>
<tr> <tr>
<td> <td>
{i18n.t('number_of_points', { count: user.comment_score })} {i18n.t('number_of_points', { count: user.comment_score })}
</td> </td>
*/}
<td> <td>
{i18n.t('number_of_comments', { {i18n.t('number_of_comments', {
count: user.number_of_comments, count: user.number_of_comments,
@ -1033,6 +1041,7 @@ export class User extends Component<any, UserState> {
document.title = `/u/${this.state.user.name} - ${WebSocketService.Instance.site.name}`; document.title = `/u/${this.state.user.name} - ${WebSocketService.Instance.site.name}`;
window.scrollTo(0, 0); window.scrollTo(0, 0);
this.setState(this.state); this.setState(this.state);
setupTippy();
} else if (res.op == UserOperation.EditComment) { } else if (res.op == UserOperation.EditComment) {
let data = res.data as CommentResponse; let data = res.data as CommentResponse;
editCommentRes(data, this.state.comments); editCommentRes(data, this.state.comments);

4
ui/src/i18next.ts vendored
View file

@ -13,7 +13,8 @@ import { it } from './translations/it';
import { fi } from './translations/fi'; import { fi } from './translations/fi';
import { ca } from './translations/ca'; import { ca } from './translations/ca';
import { fa } from './translations/fa'; import { fa } from './translations/fa';
import { pt_BR } from './translations/pt_br'; import { pt_BR } from './translations/pt_BR';
import { ja } from './translations/ja';
// https://github.com/nimbusec-oss/inferno-i18next/blob/master/tests/T.test.js#L66 // https://github.com/nimbusec-oss/inferno-i18next/blob/master/tests/T.test.js#L66
const resources = { const resources = {
@ -31,6 +32,7 @@ const resources = {
ca, ca,
fa, fa,
pt_BR, pt_BR,
ja,
}; };
function format(value: any, format: any, lng: any): any { function format(value: any, format: any, lng: any): any {

1
ui/src/index.html vendored
View file

@ -14,6 +14,7 @@
<link rel="stylesheet" type="text/css" href="/static/assets/css/tribute.css" /> <link rel="stylesheet" type="text/css" href="/static/assets/css/tribute.css" />
<link rel="stylesheet" type="text/css" href="/static/assets/css/toastify.css" /> <link rel="stylesheet" type="text/css" href="/static/assets/css/toastify.css" />
<link rel="stylesheet" type="text/css" href="/static/assets/css/selectr.min.css" /> <link rel="stylesheet" type="text/css" href="/static/assets/css/selectr.min.css" />
<link rel="stylesheet" type="text/css" href="/static/assets/css/tippy.css" />
<link rel="stylesheet" type="text/css" href="/static/assets/css/themes/darkly.min.css" id="darkly" /> <link rel="stylesheet" type="text/css" href="/static/assets/css/themes/darkly.min.css" id="darkly" />
<link rel="stylesheet" type="text/css" href="/static/assets/css/main.css" /> <link rel="stylesheet" type="text/css" href="/static/assets/css/main.css" />

20
ui/src/interfaces.ts vendored
View file

@ -156,6 +156,10 @@ export interface Post {
deleted: boolean; deleted: boolean;
locked: boolean; locked: boolean;
stickied: boolean; stickied: boolean;
embed_title?: string;
embed_description?: string;
embed_html?: string;
thumbnail_url?: string;
nsfw: boolean; nsfw: boolean;
banned: boolean; banned: boolean;
banned_from_community: boolean; banned_from_community: boolean;
@ -208,6 +212,7 @@ export interface Comment {
saved?: boolean; saved?: boolean;
user_mention_id?: number; // For mention type user_mention_id?: number; // For mention type
recipient_id?: number; recipient_id?: number;
depth?: number;
} }
export interface Category { export interface Category {
@ -876,18 +881,3 @@ export interface WebSocketJsonResponse {
error?: string; error?: string;
reconnect?: boolean; reconnect?: boolean;
} }
export interface FramelyData {
url: string;
type: string;
version?: string;
title: string;
author?: string;
author_url?: string;
provider_name?: string;
thumbnail_url?: string;
thumbnail_width?: number;
thumbnail_height?: number;
description?: string;
html?: string;
}

View file

@ -61,6 +61,7 @@ export class WebSocketService {
private constructor() { private constructor() {
this.ws = new ReconnectingWebSocket(wsUri); this.ws = new ReconnectingWebSocket(wsUri);
let firstConnect = true;
this.subject = Observable.create((obs: any) => { this.subject = Observable.create((obs: any) => {
this.ws.onmessage = e => { this.ws.onmessage = e => {
@ -68,13 +69,19 @@ export class WebSocketService {
}; };
this.ws.onopen = () => { this.ws.onopen = () => {
console.log(`Connected to ${wsUri}`); console.log(`Connected to ${wsUri}`);
if (UserService.Instance.user) { if (UserService.Instance.user) {
this.userJoin(); this.userJoin();
} }
if (!firstConnect) {
let res: WebSocketJsonResponse = { let res: WebSocketJsonResponse = {
reconnect: true, reconnect: true,
}; };
obs.next(res); obs.next(res);
}
firstConnect = false;
}; };
}).pipe(share()); }).pipe(share());
} }

View file

@ -1,239 +0,0 @@
export const ca = {
translation: {
post: 'Publicar',
remove_post: 'Eliminar publicació',
no_posts: 'Sense publicacions.',
create_a_post: 'Crear una publicació',
create_post: 'Crear Publicació',
number_of_posts: '{{count}} Publicacions',
posts: 'Publicacions',
related_posts: 'Aquestes publicacions podrien estar relacionades',
cross_posts: 'Aquest link també ha sigut publicat en:',
cross_post: 'cross-post',
comments: 'Comentaris',
number_of_comments: '{{count}} Comentaris',
remove_comment: 'Eliminar Comentaris',
communities: 'Comunitats',
users: 'Usuaris',
create_a_community: 'Crear una comunitat',
create_community: 'Crear Comunitat',
remove_community: 'Eliminar Comunitat',
subscribed_to_communities: 'Subscrit a <1>comunitats</1>',
trending_communities: '<1>Comunitats</1> en tendència',
list_of_communities: 'Llista de comunitats',
number_of_communities: '{{count}} Comunitats',
community_reqs: 'minúscules, guió baix, i sense espais.',
create_private_message: 'Crear Missatge Privat',
send_secure_message: 'Enviar Missatge Segur',
send_message: 'Enviar Missatge',
message: 'Missatge',
edit: 'editar',
reply: 'respondre',
cancel: 'Cancelar',
preview: 'Previsualitzar',
upload_image: 'pujar imatge',
avatar: 'Avatar',
upload_avatar: 'Pujar Avatar',
show_avatars: 'Veure Avatares',
formatting_help: 'Ajuda de format',
view_source: 'veure font',
unlock: 'desbloquejar',
lock: 'bloquejar',
sticky: 'fijat',
unsticky: 'no fijat',
link: 'link',
archive_link: 'arxivar link',
mod: 'moderador',
mods: 'moderadores',
moderates: 'Modera',
settings: 'Configuració',
remove_as_mod: 'eliminar com moderador',
appoint_as_mod: 'designar com moderador',
modlog: 'Historial de moderació',
admin: 'administrador',
admins: 'administradors',
remove_as_admin: 'eliminar com administrador',
appoint_as_admin: 'designar com administrador',
remove: 'eliminar',
removed: 'eliminat',
locked: 'bloquejat',
stickied: 'fijat',
reason: 'Raó',
mark_as_read: 'marcar com llegit',
mark_as_unread: 'marcar com no llegit',
delete: 'eliminar',
deleted: 'eliminat',
delete_account: 'Eliminar Compte',
delete_account_confirm:
'Avís: aquesta acció eliminarà permanentment la teva informació. Introdueix la teva contrasenya per a continuar',
restore: 'restaurar',
ban: 'expulsar',
ban_from_site: 'expulsar del lloc',
unban: 'admetre',
unban_from_site: 'admetre al lloc',
banned: 'expulsat',
save: 'guardar',
unsave: 'descartar',
create: 'crear',
creator: 'creador',
username: "Nom d'Usuari",
email_or_username: 'Correu o Usuari',
number_of_users: '{{count}} Usuaris',
number_of_subscribers: '{{count}} Subscriptors',
number_of_points: '{{count}} Punts',
number_online: '{{count}} Usauris En Línia',
name: 'Nom',
title: 'Titol',
category: 'Categoria',
subscribers: 'Suscriptors',
both: 'Ambdos',
saved: 'Guardat',
unsubscribe: "Desubscriure's",
subscribe: "Subscriure's",
subscribed: 'Subscrit',
prev: 'Anterior',
next: 'Següent',
sidebar: 'Descripció de la comunitat',
sort_type: "Tipus d'orden",
hot: 'Popular',
new: 'Nou',
top_day: 'El millor del dia',
week: 'Setmana',
month: 'Mes',
year: 'Any',
all: 'Tot',
top: 'Millor',
api: 'API',
docs: 'Docs',
inbox: "Bústia d'entrada",
inbox_for: "Bústia d'entrada per a <1>{{user}}</1>",
mark_all_as_read: 'marcar tot com llegit',
type: 'Tipus',
unread: 'No llegit',
replies: 'Respostes',
mentions: 'Menciones',
reply_sent: 'Resposta enviada',
message_sent: 'Missatge enviado',
search: 'Buscar',
overview: 'Resum',
view: 'Vista',
logout: 'Tancar sessió',
login_sign_up: 'Iniciar sessió / Crear compte',
login: 'Iniciar sessió',
sign_up: 'Crear compte',
notifications_error:
"Notificacions d'escriptori no disponibles al teu navegador. Prova amb Firefox o Chrome.",
unread_messages: 'Missatges no llegits',
messages: 'Missatges',
password: 'Contrasenya',
verify_password: 'Verificar Contrasenya',
old_password: 'Antiga Contrasenya',
forgot_password: 'oblidí la meva contrasenya',
reset_password_mail_sent: 'Enviar correu per a restablir la contrasenya.',
password_change: 'Canvi de Contrasenya',
new_password: 'Nueva Contrasenya',
no_email_setup: 'Aquest servidor no ha activat correctament el correu.',
email: 'Correu electrònic',
matrix_user_id: 'Usuari Matricial',
private_message_disclaimer:
'Avís: Els missatges privats en Lemmy no són segurs. Sisplau creu un compte en <1>Riot.im</1> per a mensajeria segura.',
send_notifications_to_email: 'Enviar notificacions al correu',
optional: 'Opcional',
expires: 'Expira',
language: 'Llenguatge',
browser_default: 'Per defecte del navegador',
downvotes_disabled: 'Vots negatius deshabilitats',
enable_downvotes: 'Habilitar vots negatius',
open_registration: 'Obrir registre',
registration_closed: 'Registre tancat',
enable_nsfw: 'Habilitar NSFW',
url: 'URL',
body: 'Descripció',
copy_suggested_title: 'Copiar el títol sugerido: {{title}}',
community: 'Comunitat',
expand_here: 'Expandir ací',
subscribe_to_communities: "Subscriure's a algunes <1>comunitats</1>.",
chat: 'Chat',
recent_comments: 'Comentaris recients',
no_results: 'Sense resultats.',
setup: 'Configurar',
lemmy_instance_setup: "Configuració d'instancia de Lemmy",
setup_admin: 'Configurar administrador del Lloc',
your_site: 'el teu lloc',
modified: 'modificat',
nsfw: 'NSFW',
show_nsfw: 'Mostrar contingut NSFW',
theme: 'Tema',
sponsors: 'Patrocinadors',
sponsors_of_lemmy: 'Patrocinadors de Lemmy',
sponsor_message:
'Lemmy és programari lliure i de <1>codi obert</1>, la qual cosa significa que no tindrà publicitats, monetització, ni capitals emprenedors, mai. Les teves donacions secunden directament el desenvolupament a temps complet del projecte. Moltes gràcies a les següents persones:',
support_on_patreon: 'Suport a Patreon',
donate_to_lemmy: 'Donar a Lemmy',
donate: 'Donar',
general_sponsors:
'Los Patrocinadores Generales son aquellos que señaron entre $10 y $39 a Lemmy.',
crypto: 'Crypto',
bitcoin: 'Bitcoin',
ethereum: 'Ethereum',
monero: 'Monero',
code: 'Codi',
joined: 'Es va unir',
by: 'per',
to: 'a',
from: 'des de',
transfer_community: 'transferir comunitat',
transfer_site: 'transferir lloc',
are_you_sure: 'Ets segur?',
yes: 'sí',
no: 'no',
powered_by: 'Impulsat per',
landing_0:
'Lemmy és un <1>agregador de links</1> / alternativa a reddit, amb la intenció de funcionar al <2>fedivers</2>.<3></3>És allotjable per un mateix (sense necessitat de grans companyies), té actualització en directe de cadenes de comentaris, i és petit (<4>~80kB</4>). Federar amb el sistema de xarxes ActivityPub forma part dels objectius del projecte. <5></5>Aquesta és una <6>versió beta molt prematura</6>, i actualment moltes de les característiques són trencades o falten. <7></7>Suggereix noves característiques o reporta errors <8>aquí</8>.<9></9>Fet amb <10>Rust</10>, <11>Actix</11>, <12>Inferno</12>, <13>Typescript</13>.',
not_logged_in: 'No has iniciat sessió.',
logged_in: 'Has iniciat sessió.',
community_ban: "Has sigut expulsat d'aquesta comunitat.",
site_ban: "Has sigut expulsat d'aquest lloc.",
couldnt_create_comment: "No s'ha pogut crear el comentari.",
couldnt_like_comment: "No s'ha pogut donar m'agrada al comentari.",
couldnt_update_comment: "No s'ha pogut actualitzar el comentari.",
couldnt_save_comment: "No s'ha pogut guardar el comentari.",
no_comment_edit_allowed: 'No tens permisos per a editar el comentari.',
no_post_edit_allowed: 'No tens permisos per a editar la publicació.',
no_community_edit_allowed: 'No tens permisos per a editar la comunitat.',
couldnt_find_community: "No s'ha pogut trobar la comunitat.",
couldnt_update_community: "No s'ha pogut actualitzar la comunitat.",
community_already_exists: 'Aquesta comunitat ja existeix.',
community_moderator_already_exists:
'Aquest moderador de la comunitat ja existeix.',
community_follower_already_exists:
'Aquest seguidor de la comunitat ja existeix.',
community_user_already_banned:
'Aquest usuari de la comunitat ja fou expulsat.',
couldnt_create_post: "No s'ha pogut crear la publicació.",
couldnt_like_post: "No s'ha pogut donar m'agrada a la publicació.",
couldnt_find_post: "No s'ha pogut trobar la publicació.",
couldnt_get_posts: "No s'han pogut obtindre les publicacions.",
couldnt_update_post: "No s'ha pogut actualitzar la publicació.",
couldnt_save_post: "No s'ha pogut guardar la publicació.",
no_slurs: 'Prohibit insultar.',
not_an_admin: 'No és un administrador.',
site_already_exists: 'El lloc ja existeix.',
couldnt_update_site: "No s'ha pogut actualitzar el lloc.",
couldnt_find_that_username_or_email:
"No s'ha pogut trobar aquest nom de usuari o correu electrònic.",
password_incorrect: 'Contrasenya incorrecta.',
passwords_dont_match: 'Les contrasenyes no coincideixen.',
admin_already_created: 'Ho sentim, ja hi ha un adminisitrador.',
user_already_exists: "L'usuari ja existeix.",
email_already_exists: 'El correu ja és en ús.',
couldnt_update_user: "No s'ha pogut actualitzar l'usuari.",
system_err_login:
'Error del sistema. Intenti tancar sessió i ingressar de nou.',
couldnt_create_private_message: "No s'ha pogut crear el missatge privat.",
no_private_message_edit_allowed:
'Sense permisos per a editar el missatge privat.',
couldnt_update_private_message:
"No s'ha pogut actualitzar el missatge privat.",
},
};

View file

@ -1,210 +0,0 @@
export const de = {
translation: {
post: 'post',
remove_post: 'Beitrag löschen',
no_posts: 'Keine Beiträge.',
create_a_post: 'Einen Beitrag anlegen',
create_post: 'Beitrag anlegen',
number_of_posts: '{{count}} Beiträge',
posts: 'Beiträge',
related_posts: 'Diese Beiträge könnten verwandt sein',
cross_posts: 'Dieser Link wurde auch veröffentlicht unter:',
cross_post: 'Crosspost',
comments: 'Kommentare',
number_of_comments: '{{count}} Kommentare',
remove_comment: 'Kommentar löschen',
communities: 'Communities',
users: 'Benutzer',
create_a_community: 'Eine Gemeinschaft anlegen',
create_community: 'Gemeinschaft anlegen',
remove_community: 'Gemeinschaft entfernen',
subscribed_to_communities: 'Abonnierte <1>communities</1>',
trending_communities: 'Trending <1>communities</1>',
list_of_communities: 'Liste von communities',
number_of_communities: '{{count}} Communities',
community_reqs: 'Kleinbuchstaben, Großbuchstaben und keine Leerzeichen.',
edit: 'editieren',
reply: 'antworten',
cancel: 'Abbrechen',
preview: 'Vorschau',
upload_image: 'Bild hochladen',
formatting_help: 'Formatierungshilfe',
view_source: 'Quelle anzeigen',
unlock: 'entsperren',
lock: 'sperren',
sticky: 'haftend',
unsticky: 'nicht haftend',
link: 'link',
archive_link: 'Archiv-Link',
mod: 'Moderator',
mods: 'Moderatoren',
moderates: 'Moderiert',
settings: 'Einstellungen',
remove_as_mod: 'Als Moderator entfernen',
appoint_as_mod: 'Zum Moderator ernennen',
modlog: 'Modlog',
admin: 'Administrator',
admins: 'Administratoren',
remove_as_admin: 'Als Administrator entfernen',
appoint_as_admin: 'Zum Administrator ernennen',
remove: 'entfernen',
removed: 'entfernt',
locked: 'gesperrt',
stickied: 'angeheftet',
reason: 'Grund',
mark_as_read: 'als gelesen markieren',
mark_as_unread: 'als ungelesen markieren',
delete: 'löschen',
deleted: 'gelöscht',
delete_account: 'Konto löschen',
delete_account_confirm:
'Achtung: Dadurch werden alle Ihre Daten dauerhaft gelöscht. Geben Sie zur Bestätigung Ihr Passwort ein.',
restore: 'wiederherstellen',
ban: 'bannen',
ban_from_site: 'Von der Seite bannen',
unban: 'entbannen',
unban_from_site: 'Von der Seite entbannen',
banned: 'gesperrt',
save: 'speichern',
unsave: 'nicht speichern',
create: 'anlegen',
creator: 'Ersteller',
username: 'Benutzername',
email_or_username: 'E-mail oder Username',
number_of_users: '{{count}} Benutzer',
number_of_subscribers: '{{count}} Abonnenten',
number_of_points: '{{count}} Punkte',
number_online: '{{count}} Benutzer online',
name: 'Name',
title: 'Titel',
category: 'Kategorie',
subscribers: 'Abonnenten',
both: 'Beide',
saved: 'Gespeichert',
unsubscribe: 'Abbestellen',
subscribe: 'Abonnieren',
subscribed: 'Abonniert',
prev: 'Zurück',
next: 'Weiter',
sidebar: 'Seitenleiste',
sort_type: 'Sortieren nach',
hot: 'Hot',
new: 'Neu',
top_day: 'Top täglich',
week: 'Woche',
month: 'Monat',
year: 'Jahr',
all: 'Alle',
top: 'Top',
api: 'API',
inbox: 'Posteingang',
inbox_for: 'Posteingang für <1>{{user}}</1>',
mark_all_as_read: 'Alle als gelesen markieren',
type: 'Typ',
unread: 'Ungelesen',
replies: 'Antworten',
mentions: 'Erwähnung',
reply_sent: 'Antwort gesendet',
search: 'Suchen',
overview: 'Übersicht',
view: 'Ansicht',
logout: 'Ausloggen',
login_sign_up: 'Einloggen / Registrieren',
notifications_error:
'Desktop-Benachrichtigungen sind in deinem browser nicht verfügbar. Versuche Firefox oder Chrome.',
unread_messages: 'Ungelesene Nachrichten',
password: 'Passwort',
verify_password: 'Passwort überprüfen',
forgot_password: 'Passwort vergessen',
reset_password_mail_sent:
'Eine E-Mail wurde geschickt, um dein Passwort zurückzusetzen.',
password_change: 'Passwort geändert',
new_password: 'neues Passwort',
no_email_setup: 'Dieser Server hat E-Mails nicht korrekt eingerichtet.',
login: 'Einloggen',
sign_up: 'Registrieren',
email: 'E-Mail',
optional: 'optional',
expires: 'Ablaufdatum',
language: 'Sprache',
browser_default: 'Standard-Browser',
url: 'URL',
body: 'Text',
copy_suggested_title: 'Vorgeschlagenen Titel übernehmen: {{title}}',
community: 'Gemeinschaft',
expand_here: 'hier erweitern',
subscribe_to_communities: 'Abonniere ein paar <1>communities</1>.',
chat: 'Chat',
recent_comments: 'Neueste Kommentare',
no_results: 'Keine Ergebnisse.',
setup: 'Einrichten',
lemmy_instance_setup: 'Lemmy Instanz Einrichten',
setup_admin: 'Seiten Administrator konfigurieren',
your_site: 'deine Seite',
modified: 'verändert',
nsfw: 'NSFW',
show_nsfw: 'NSFW-Inhalte anzeigen',
theme: 'Aussehen',
sponsors: 'Sponsoren',
sponsors_of_lemmy: 'Sponsoren von Lemmy',
sponsor_message:
'Lemmy ist freie <1>Open-Source</1> Software, also ohne Werbung, Monetarisierung oder Venturekapital, Punkt. Deine Spenden gehen direkt an die Vollzeit Entwicklung des Projekts. Vielen Dank an die folgenden Personen:',
support_on_patreon: 'Auf Patreon unterstützen',
support_on_liberapay: 'Auf Liberapay unterstützen',
general_sponsors:
'Allgemeine Sponsoren sind die, die zwischen $10 und $39 zu Lemmy beitragen.',
crypto: 'Kryptowährung',
bitcoin: 'Bitcoin',
ethereum: 'Ethereum',
monero: 'Monero',
code: 'Code',
joined: 'beigetreten',
by: 'von',
to: 'bis',
transfer_community: 'Gemeinschaft übertragen',
transfer_site: 'Transferseite',
are_you_sure: 'Bist du sicher?',
yes: 'Ja',
no: 'Nein',
powered_by: 'Bereitgestellt durch',
landing_0:
'Lemmy ist ein <1>Link-Aggregator</1> / Reddit Alternative im <2>Fediverse</2>.<3></3>Es ist selbst-hostbar, hat live-updates von Kommentar-threads und ist winzig (<4>~80kB</4>). Federation in das ActivityPub Netzwerk ist geplant. <5></5>Dies ist eine <6>sehr frühe Beta Version</6>, und viele Features funktionieren zurzeit nicht richtig oder fehlen. <7></7>Schlage neue Features vor oder melde Bugs <8>hier.</8><9></9>Gebaut mit <10>Rust</10>, <11>Actix</11>, <12>Inferno</12>, <13>Typescript</13>.',
not_logged_in: 'Nicht eingeloggt.',
community_ban: 'Du wurdest von dieser Gemeinschaft gebannt.',
site_ban: 'Du wurdest von dieser Seite gebannt',
couldnt_create_comment: 'Konnte Kommentar nicht anlegen.',
couldnt_like_comment: 'Konnte nicht liken.',
couldnt_update_comment: 'Konnte Kommentar nicht aktualisieren.',
couldnt_save_comment: 'Konnte Kommentar nicht speichern.',
no_comment_edit_allowed: 'Keine Erlaubnis Kommentar zu editieren.',
no_post_edit_allowed: 'Keine Erlaubnis Beitrag zu editieren.',
no_community_edit_allowed: 'Keine Erlaubnis Gemeinschaft zu editieren.',
couldnt_find_community: 'Konnte Gemeinschaft nicht finden.',
couldnt_update_community: 'Konnte Gemeinschaft nicht aktualisieren.',
community_already_exists: 'Gemeinschaft existiert bereits.',
community_moderator_already_exists:
'Gemeinschaft Moderator existiert bereits.',
community_follower_already_exists:
'Gemeinschaft Follower existiert bereits.',
community_user_already_banned: 'Gemeinschaft Nutzer schon gebannt.',
couldnt_create_post: 'Konnte Beitrag nicht anlegen.',
couldnt_like_post: 'Konnte Beitrag nicht liken.',
couldnt_find_post: 'Konnte Beitrag nicht finden.',
couldnt_get_posts: 'Konnte Beiträge nicht holen.',
couldnt_update_post: 'Konnte Beitrag nicht aktualisieren.',
couldnt_save_post: 'Konnte Beitrag nicht speichern.',
no_slurs: 'Keine Beleidigungen.',
not_an_admin: 'Kein Administrator.',
site_already_exists: 'Seite existiert bereits.',
couldnt_update_site: 'Konnte Seite nicht aktualisieren.',
couldnt_find_that_username_or_email:
'Konnte Username oder E-Mail nicht finden.',
password_incorrect: 'Passwort falsch.',
passwords_dont_match: 'Passwörter stimmen nicht überein.',
admin_already_created: 'Entschuldigung, es gibt schon einen Administrator.',
user_already_exists: 'Nutzer existiert bereits.',
couldnt_update_user: 'Konnte Nutzer nicht aktualisieren',
system_err_login:
'Systemfehler. Versuche dich aus- und wieder einzuloggen.',
},
};

View file

@ -1,240 +0,0 @@
export const en = {
translation: {
post: 'post',
remove_post: 'Remove Post',
no_posts: 'No Posts.',
create_a_post: 'Create a post',
create_post: 'Create Post',
number_of_posts: '{{count}} Posts',
posts: 'Posts',
related_posts: 'These posts might be related',
cross_posts: 'This link has also been posted to:',
cross_post: 'cross-post',
cross_posted_to: 'cross-posted to: ',
comments: 'Comments',
number_of_comments: '{{count}} Comments',
remove_comment: 'Remove Comment',
communities: 'Communities',
users: 'Users',
create_a_community: 'Create a community',
create_community: 'Create Community',
remove_community: 'Remove Community',
subscribed_to_communities: 'Subscribed to <1>communities</1>',
trending_communities: 'Trending <1>communities</1>',
list_of_communities: 'List of communities',
number_of_communities: '{{count}} Communities',
community_reqs: 'lowercase, underscores, and no spaces.',
create_private_message: 'Create Private Message',
send_secure_message: 'Send Secure Message',
send_message: 'Send Message',
message: 'Message',
edit: 'edit',
reply: 'reply',
cancel: 'Cancel',
preview: 'Preview',
upload_image: 'upload image',
avatar: 'Avatar',
upload_avatar: 'Upload Avatar',
show_avatars: 'Show Avatars',
formatting_help: 'formatting help',
view_source: 'view source',
unlock: 'unlock',
lock: 'lock',
sticky: 'sticky',
unsticky: 'unsticky',
link: 'link',
archive_link: 'archive link',
mod: 'mod',
mods: 'mods',
moderates: 'Moderates',
settings: 'Settings',
remove_as_mod: 'remove as mod',
appoint_as_mod: 'appoint as mod',
modlog: 'Modlog',
admin: 'admin',
admins: 'admins',
remove_as_admin: 'remove as admin',
appoint_as_admin: 'appoint as admin',
remove: 'remove',
removed: 'removed',
locked: 'locked',
stickied: 'stickied',
reason: 'Reason',
mark_as_read: 'mark as read',
mark_as_unread: 'mark as unread',
delete: 'delete',
deleted: 'deleted',
delete_account: 'Delete Account',
delete_account_confirm:
'Warning: this will permanently delete all your data. Enter your password to confirm.',
restore: 'restore',
ban: 'ban',
ban_from_site: 'ban from site',
unban: 'unban',
unban_from_site: 'unban from site',
banned: 'banned',
save: 'save',
unsave: 'unsave',
create: 'create',
creator: 'creator',
username: 'Username',
email_or_username: 'Email or Username',
number_of_users: '{{count}} Users',
number_of_subscribers: '{{count}} Subscribers',
number_of_points: '{{count}} Points',
number_online: '{{count}} Users Online',
name: 'Name',
title: 'Title',
category: 'Category',
subscribers: 'Subscribers',
both: 'Both',
saved: 'Saved',
unsubscribe: 'Unsubscribe',
subscribe: 'Subscribe',
subscribed: 'Subscribed',
prev: 'Prev',
next: 'Next',
sidebar: 'Sidebar',
sort_type: 'Sort type',
hot: 'Hot',
new: 'New',
old: 'Old',
top_day: 'Top day',
week: 'Week',
month: 'Month',
year: 'Year',
all: 'All',
top: 'Top',
api: 'API',
docs: 'Docs',
inbox: 'Inbox',
inbox_for: 'Inbox for <1>{{user}}</1>',
mark_all_as_read: 'mark all as read',
type: 'Type',
unread: 'Unread',
replies: 'Replies',
mentions: 'Mentions',
reply_sent: 'Reply sent',
message_sent: 'Message sent',
search: 'Search',
overview: 'Overview',
view: 'View',
logout: 'Logout',
login_sign_up: 'Login / Sign up',
login: 'Login',
sign_up: 'Sign Up',
notifications_error:
'Desktop notifications not available in your browser. Try Firefox or Chrome.',
unread_messages: 'Unread Messages',
messages: 'Messages',
password: 'Password',
verify_password: 'Verify Password',
old_password: 'Old Password',
forgot_password: 'forgot password',
reset_password_mail_sent: 'Sent an Email to reset your password.',
password_change: 'Password Change',
new_password: 'New Password',
no_email_setup: "This server hasn't correctly set up email.",
email: 'Email',
matrix_user_id: 'Matrix User',
private_message_disclaimer:
'Warning: Private messages in Lemmy are not secure. Please create an account on <1>Riot.im</1> for secure messaging.',
send_notifications_to_email: 'Send notifications to Email',
optional: 'Optional',
expires: 'Expires',
language: 'Language',
browser_default: 'Browser Default',
downvotes_disabled: 'Downvotes disabled',
enable_downvotes: 'Enable Downvotes',
open_registration: 'Open Registration',
registration_closed: 'Registration closed',
enable_nsfw: 'Enable NSFW',
url: 'URL',
body: 'Body',
copy_suggested_title: 'copy suggested title: {{title}}',
community: 'Community',
expand_here: 'Expand here',
subscribe_to_communities: 'Subscribe to some <1>communities</1>.',
chat: 'Chat',
recent_comments: 'Recent Comments',
no_results: 'No results.',
setup: 'Setup',
lemmy_instance_setup: 'Lemmy Instance Setup',
setup_admin: 'Set Up Site Administrator',
your_site: 'your site',
modified: 'modified',
nsfw: 'NSFW',
show_nsfw: 'Show NSFW content',
theme: 'Theme',
sponsors: 'Sponsors',
sponsors_of_lemmy: 'Sponsors of Lemmy',
sponsor_message:
'Lemmy is free, <1>open-source</1> software, meaning no advertising, monetizing, or venture capital, ever. Your donations directly support full-time development of the project. Thank you to the following people:',
support_on_patreon: 'Support on Patreon',
support_on_liberapay: 'Support on Liberapay',
donate_to_lemmy: 'Donate to Lemmy',
donate: 'Donate',
general_sponsors:
'General Sponsors are those that pledged $10 to $39 to Lemmy.',
crypto: 'Crypto',
bitcoin: 'Bitcoin',
ethereum: 'Ethereum',
monero: 'Monero',
code: 'Code',
joined: 'Joined',
by: 'by',
to: 'to',
from: 'from',
transfer_community: 'transfer community',
transfer_site: 'transfer site',
are_you_sure: 'are you sure?',
yes: 'yes',
no: 'no',
powered_by: 'Powered by',
landing_0:
"Lemmy is a <1>link aggregator</1> / reddit alternative, intended to work in the <2>fediverse</2>.<3></3>It's self-hostable, has live-updating comment threads, and is tiny (<4>~80kB</4>). Federation into the ActivityPub network is on the roadmap. <5></5>This is a <6>very early beta version</6>, and a lot of features are currently broken or missing. <7></7>Suggest new features or report bugs <8>here.</8><9></9>Made with <10>Rust</10>, <11>Actix</11>, <12>Inferno</12>, <13>Typescript</13>.",
not_logged_in: 'Not logged in.',
logged_in: 'Logged in.',
community_ban: 'You have been banned from this community.',
site_ban: 'You have been banned from the site',
couldnt_create_comment: "Couldn't create comment.",
couldnt_like_comment: "Couldn't like comment.",
couldnt_update_comment: "Couldn't update comment.",
couldnt_save_comment: "Couldn't save comment.",
couldnt_get_comments: "Couldn't get comments.",
no_comment_edit_allowed: 'Not allowed to edit comment.',
no_post_edit_allowed: 'Not allowed to edit post.',
no_community_edit_allowed: 'Not allowed to edit community.',
couldnt_find_community: "Couldn't find community.",
couldnt_update_community: "Couldn't update Community.",
community_already_exists: 'Community already exists.',
community_moderator_already_exists: 'Community moderator already exists.',
community_follower_already_exists: 'Community follower already exists.',
community_user_already_banned: 'Community user already banned.',
couldnt_create_post: "Couldn't create post.",
post_title_too_long: 'Post title too long.',
couldnt_like_post: "Couldn't like post.",
couldnt_find_post: "Couldn't find post.",
couldnt_get_posts: "Couldn't get posts",
couldnt_update_post: "Couldn't update post",
couldnt_save_post: "Couldn't save post.",
no_slurs: 'No slurs.',
not_an_admin: 'Not an admin.',
site_already_exists: 'Site already exists.',
couldnt_update_site: "Couldn't update site.",
couldnt_find_that_username_or_email:
"Couldn't find that username or email.",
password_incorrect: 'Password incorrect.',
passwords_dont_match: 'Passwords do not match.',
admin_already_created: "Sorry, there's already an admin.",
user_already_exists: 'User already exists.',
email_already_exists: 'Email already exists.',
couldnt_update_user: "Couldn't update user.",
system_err_login: 'System error. Try logging out and back in.',
couldnt_create_private_message: "Couldn't create private message.",
no_private_message_edit_allowed: 'Not allowed to edit private message.',
couldnt_update_private_message: "Couldn't update private message.",
time: 'Time',
action: 'Action',
},
};

View file

@ -1,177 +0,0 @@
export const eo = {
translation: {
post: 'Poŝti',
remove_post: 'Fortiri Poŝton',
no_posts: 'Ne Poŝtoj.',
create_a_post: 'Verki Poŝton',
create_post: 'Verki Poŝton',
number_of_posts: '{{count}} Poŝtoj',
posts: 'Poŝtoj',
related_posts: 'Tiuj poŝtoj eble rilatas',
cross_posts: 'Tiuj ligilo ankaŭ estas poŝtinta al:',
cross_post: 'laŭapoŝto',
comments: 'Komentoj',
number_of_comments: '{{count}} Komentoj',
remove_comment: 'Fortiri Komentojn',
communities: 'Komunumoj',
users: 'Uzantoj',
create_a_community: 'Krei komunumon',
create_community: 'Krei Komunumon',
remove_community: 'Forigi Komunumon',
subscribed_to_communities: 'Abonita al <1>komunumoj</1>',
trending_communities: 'Furora <1>komunumoj</1>',
list_of_communities: 'Listo de komunumoj',
community_reqs: 'minusklaj leteroj, substrekoj, kaj ne spacetoj.',
edit: 'redakti',
reply: 'repliki',
cancel: 'nuligi',
unlock: 'malŝlosi',
lock: 'ŝlosi',
link: 'ligi',
mod: 'moderanto',
mods: 'moderantoj',
moderates: 'Moderigas',
settings: 'Agordoj',
remove_as_mod: 'forigi per moderanto',
appoint_as_mod: 'nomumi per moderanto',
modlog: 'Moderlogo',
admin: 'administranto',
admins: 'administrantoj',
remove_as_admin: 'forigi per administranto',
appoint_as_admin: 'nomumi per administranto',
remove: 'fortiri',
removed: 'fortirita',
locked: 'ŝlosita',
reason: 'Kialo',
mark_as_read: 'marki kiel legita',
mark_as_unread: 'marki kiel nelegita',
delete: 'forigi',
deleted: 'forigita',
restore: 'restaŭri',
ban: 'forbari',
ban_from_site: 'forbari de retejo',
unban: 'malforbari',
unban_from_site: 'malforbari de retejo',
save: 'konservi',
unsave: 'malkonservi',
create: 'krei',
username: 'Uzantnomo',
email_or_username: 'Retadreso aŭ Uzantnomo',
number_of_users: '{{count}} Uzantoj',
number_of_subscribers: '{{count}} Abonantoj',
number_of_points: '{{count}} Voĉdonoj',
name: 'Nomo',
title: 'Titolo',
category: 'Kategorio',
subscribers: 'Abonantoj',
both: 'Ambaŭ',
saved: 'Konservita',
unsubscribe: 'Malaboni',
subscribe: 'Aboni',
subscribed: 'Abonita',
prev: 'Antaŭe',
next: 'Poste',
sidebar: 'Flankstango',
sort_type: 'Klasi per kia',
hot: 'Varmaj',
new: 'Novaj',
top_day: 'Supraj tagaj',
week: 'Semajno',
month: 'Monato',
year: 'Jaro',
all: 'Ĉiam',
top: 'Supraj',
api: 'API',
inbox: 'Ricevujo',
inbox_for: 'Ricevujo de <1>{{user}}</1>',
mark_all_as_read: 'marki ĉiujn kiel legitaj',
type: 'Tipo',
unread: 'Nelegitaj',
reply_sent: 'Repliko sendis',
search: 'Serĉi',
overview: 'Resumo',
view: 'Rigardi',
logout: 'Elsaluti',
login_sign_up: 'Ensaluti / Registriĝi',
login: 'Ensaluti',
sign_up: 'Registriĝi',
notifications_error:
'Labortablaj avizoj estas nehavebla en via retumilo. Provu Firefox-on aŭ Chrome-on.',
unread_messages: 'Nelegitaj Mesaĝoj',
password: 'Pasvorto',
verify_password: 'Konfirmu Vian Pasvorton',
email: 'Retadreso',
optional: 'Fakultativa',
expires: 'Finiĝos',
url: 'URL',
body: 'Ĉefparto',
copy_suggested_title: 'kopii la sugestiitan titolon: {{title}}',
community: 'Komunumo',
expand_here: 'Ekspansii ĉi tie',
subscribe_to_communities: 'Aboni al iuj <1>komunumoj</1>.',
chat: 'Babilo',
recent_comments: 'Freŝaj Komentoj',
no_results: 'Ne rezultoj.',
setup: 'Agordi',
lemmy_instance_setup: 'Agordi Instancon de Lemmy',
setup_admin: 'Agordi Retejan Administranton',
your_site: 'via retejo',
modified: 'modifita',
nsfw: 'NSFW',
show_nsfw: 'Vidigi NSFW-an enhavon',
sponsors: 'Subtenantoj',
sponsors_of_lemmy: 'Subtenantoj de Lemmy',
sponsor_message:
'Lemmy estas senpaga, <1>liberkoda</1> programaro. Tio signifas ne reklami, pagigi, aŭ riska kapitalo, ĉiam. Viaj donacoj rekte subtenas plentempan evoluon de la projekto. Dankon al tiuj homoj:',
support_on_patreon: 'Subteni per Patreon',
general_sponsors:
'Ĝeneralaj Subtenantoj estas tiuj ke donacis inter $10 kaj $39 al Lemmy.',
crypto: 'Crypto',
bitcoin: 'Bitcoin',
ethereum: 'Ethereum',
monero: 'Monero',
code: 'Kodo',
joined: 'Unuiĝis',
by: 'de',
to: 'al',
transfer_community: 'transdoni la komunumon',
transfer_site: 'transdoni la retejon',
powered_by: 'Konstruis per',
landing_0:
'Lemmy estas <1>ligila agregatilo</1> / Reddit anstataŭo ke intenciĝas funkci en la <2>federacio-universo</2>.<3></3>ĝi estas mem-gastigebla, havas nuna-ĝisdatigajn komentarojn, kaj estas malgrandega (<4>~80kB</4>). Federacio en la ActivityPub-an reton estas planizita. <5></5>Estas <6>fruega beta versio</6>, kaj multaj trajtoj estas nune difektaj aŭ mankaj. <7></7>Sugestias novajn trajtojn aŭ raportas cimojn <8>ĉi tie.</8><9></9>Faris per <10>Rust</10>, <11>Actix</11>, <12>Inferno</12>, <13>Typescript</13>.',
not_logged_in: 'Ne estas ensalutinta.',
community_ban: 'Vi estas forbarita de la komunumo.',
site_ban: 'Vi estas forbarita de la retejo',
couldnt_create_comment: 'Ne povis krei la komenton.',
couldnt_like_comment: 'Ne povis ŝati la komenton.',
couldnt_update_comment: 'Ne povis ĝisdatigi komenton.',
couldnt_save_comment: 'Ne povis konservi komenton.',
no_comment_edit_allowed: 'Ne rajtas redakti la komenton.',
no_post_edit_allowed: 'Ne rajtas redakti la poŝton.',
no_community_edit_allowed: 'Ne rajtas redakti la komunumon.',
couldnt_find_community: 'Ne povis trovi la komunumon.',
couldnt_update_community: 'Ne povis ĝisdatigi la komunumon.',
community_already_exists: 'Komunumo jam ekzistas.',
community_moderator_already_exists: 'Komunuma moderanto jam ekzistas.',
community_follower_already_exists: 'Komunuma sekvanto.',
community_user_already_banned: 'Komunuma uzanto jam estas forbarita.',
couldnt_create_post: 'Ne povis krei la poŝton.',
couldnt_like_post: 'Ne povis ŝati la poŝton.',
couldnt_find_post: 'Ne povis trovi la poŝton.',
couldnt_get_posts: 'Ne povis irpreni poŝtojn',
couldnt_update_post: 'Ne povis ĝisdatigi la poŝton',
couldnt_save_post: 'Ne povis konservi la poŝton.',
no_slurs: 'Ne bigotaj vortoj.',
not_an_admin: 'Ne estas administranto.',
site_already_exists: 'Retejo jam ekzistas.',
couldnt_update_site: 'Ne povis ĝisdatigi la retejon.',
couldnt_find_that_username_or_email:
'Ne povis trovi tiun uzantnomon aŭ retadreson.',
password_incorrect: 'Pasvorto malĝustas.',
passwords_dont_match: 'Pasvortoj ne samas.',
admin_already_created: 'Pardonu, jam estas administranto.',
user_already_exists: 'Uzanto jam ekzistas.',
couldnt_update_user: 'Ne povis ĝisdatigi la uzanton.',
system_err_login: 'Sistema eraro. Provu elsaluti kaj ensaluti.',
},
};

View file

@ -1,242 +0,0 @@
export const es = {
translation: {
post: 'Publicar',
remove_post: 'Eliminar publicación',
no_posts: 'Sin publicaciones.',
create_a_post: 'Crear una publicación',
create_post: 'Crear Publicación',
number_of_posts: '{{count}} Publicaciones',
posts: 'Publicaciones',
related_posts: 'Estas publicaciones podrían estar relacionadas',
cross_posts: 'Este link también ha sido publicado en:',
cross_post: 'cross-post',
comments: 'Comentarios',
number_of_comments: '{{count}} Comentarios',
remove_comment: 'Eliminar Comentarios',
communities: 'Comunidades',
users: 'Usuarios',
create_a_community: 'Crear una comunidad',
create_community: 'Crear Comunidad',
remove_community: 'Eliminar Comunidad',
subscribed_to_communities: 'Suscrito a <1>comunidades</1>',
trending_communities: '<1>Comunidades</1> en tendencia',
list_of_communities: 'Lista de comunidades',
number_of_communities: '{{count}} Comunidades',
community_reqs: 'minúsculas, guión bajo, y sin espacios.',
create_private_message: 'Crear Mensaje Privado',
send_secure_message: 'Enviar Mensaje Seguro',
send_message: 'Enviar Mensaje',
message: 'Mensaje',
edit: 'editar',
reply: 'responder',
cancel: 'Cancelar',
preview: 'Previsualizar',
upload_image: 'subir imagen',
avatar: 'Avatar',
upload_avatar: 'Subir Avatar',
show_avatars: 'Ver Avatares',
formatting_help: 'Ayuda de formato',
view_source: 'ver fuente',
unlock: 'desbloquear',
lock: 'bloquear',
sticky: 'fijado',
unsticky: 'no fijado',
link: 'link',
archive_link: 'archivar link',
mod: 'moderador',
mods: 'moderadores',
moderates: 'Modera',
settings: 'Configuración',
remove_as_mod: 'eliminar como moderador',
appoint_as_mod: 'designar como moderador',
modlog: 'Historial de moderación',
admin: 'administrador',
admins: 'administradores',
remove_as_admin: 'eliminar como administrador',
appoint_as_admin: 'designar como administrador',
remove: 'eliminar',
removed: 'eliminado',
locked: 'bloqueado',
stickied: 'fijado',
reason: 'Razón',
mark_as_read: 'marcar como leído',
mark_as_unread: 'marcar como no leído',
delete: 'eliminar',
deleted: 'eliminado',
delete_account: 'Eliminar Cuenta',
delete_account_confirm:
'Aviso: esta acción eliminará permanentemente tu información. Introduce tu contraseña para continuar',
restore: 'restaurar',
ban: 'expulsar',
ban_from_site: 'expulsar del sitio',
unban: 'admitir',
unban_from_site: 'admitir en el sitio',
banned: 'expulsado',
save: 'guardar',
unsave: 'descartar',
create: 'crear',
creator: 'creador',
username: 'Nombre de Usuario',
email_or_username: 'Correo o Usuario',
number_of_users: '{{count}} Usuarios',
number_of_subscribers: '{{count}} Suscriptores',
number_of_points: '{{count}} Puntos',
number_online: '{{count}} Usuarios En Línea',
name: 'Nombre',
title: 'Titulo',
category: 'Categoría',
subscribers: 'Suscriptores',
both: 'Ambos',
saved: 'Guardado',
unsubscribe: 'Desuscribirse',
subscribe: 'Suscribirse',
subscribed: 'Suscrito',
prev: 'Anterior',
next: 'Siguiente',
sidebar: 'Descripción de la comunidad',
sort_type: 'Tipo de orden',
hot: 'Popular',
new: 'Nuevo',
top_day: 'Lo mejor del día',
week: 'Semana',
month: 'Mes',
year: 'Año',
all: 'Todo',
top: 'Mejor',
api: 'API',
docs: 'Docs',
inbox: 'Buzón de entrada',
inbox_for: 'Buzón de entrada para <1>{{user}}</1>',
mark_all_as_read: 'marcar todo como leído',
type: 'Tipo',
unread: 'No leído',
replies: 'Respuestas',
mentions: 'Menciones',
reply_sent: 'Respuesta enviada',
message_sent: 'Mensaje enviado',
search: 'Buscar',
overview: 'Resumen',
view: 'Vista',
logout: 'Cerrar sesión',
login_sign_up: 'Iniciar sesión / Crear cuenta',
login: 'Iniciar sesión',
sign_up: 'Crear cuenta',
notifications_error:
'Notificaciones de escritorio no disponibles en tu navegador. Prueba Firefox o Chrome.',
unread_messages: 'Mensajes no leídos',
messages: 'Mensajes',
password: 'Contraseña',
verify_password: 'Verificar contraseña',
old_password: 'Antigua Contraseña',
forgot_password: 'olvidé mi contraseña',
reset_password_mail_sent: 'Enviar correo para reestablecer la contraseña.',
password_change: 'Cambio de Contraseña',
new_password: 'Nueva Contraseña',
no_email_setup: 'Este servidor no ha activado correctamente el correo.',
email: 'Correo electrónico',
matrix_user_id: 'Usuario Matricial',
private_message_disclaimer:
'Aviso: Los mensajes privados en Lemmy no son seguros. Por favor cree una cuenta en <1>Riot.im</1> para mensajeria segura.',
send_notifications_to_email: 'Enviar notificaciones al correo',
optional: 'Opcional',
expires: 'Expira',
language: 'Idioma',
browser_default: 'Por defecto del navegador',
downvotes_disabled: 'Votos negativos deshabilitados',
enable_downvotes: 'Habilitar votos negativos',
open_registration: 'Abrir registro',
registration_closed: 'Registro cerrado',
enable_nsfw: 'Habilitar NSFW',
url: 'URL',
body: 'Descripción',
copy_suggested_title: 'Copiar el título sugerido: {{title}}',
community: 'Comunidad',
expand_here: 'Expandir aquí',
subscribe_to_communities: 'Suscribirse a algunas <1>comunidades</1>.',
chat: 'Chat',
recent_comments: 'Comentarios recientes',
no_results: 'Sin resultados.',
setup: 'Configurar',
lemmy_instance_setup: 'Configuración de instancia de Lemmy',
setup_admin: 'Configurar administrador del Sitio',
your_site: 'tu sitio',
modified: 'modificado',
nsfw: 'NSFW',
show_nsfw: 'Mostrar contenido NSFW',
theme: 'Tema',
sponsors: 'Patrocinadores',
sponsors_of_lemmy: 'Patrocinadores de Lemmy',
sponsor_message:
'Lemmy es software libre y de <1>código abierto</1>, lo que significa que no tendrá publicidades, monetización, ni capitales emprendedores, nunca. Tus donaciones apoyan directamente el desarrollo a tiempo completo del proyecto. Muchas gracias a las siguientes personas:',
support_on_patreon: 'Apoyo en Patreon',
support_on_liberapay: 'Apoyo en Liberapay',
donate_to_lemmy: 'Donar a Lemmy',
donate: 'Donar',
general_sponsors:
'Los Patrocinadores Generales son aquellos que señaron entre $10 y $39 a Lemmy.',
crypto: 'Crypto',
bitcoin: 'Bitcoin',
ethereum: 'Ethereum',
monero: 'Monero',
code: 'Código',
joined: 'Se unió',
by: 'por',
to: 'a',
from: 'desde',
transfer_community: 'transferir comunidad',
transfer_site: 'transferir sitio',
are_you_sure: '¿Estás seguro?',
yes: 'sí',
no: 'no',
powered_by: 'Impulsado por',
landing_0:
'Lemmy es un <1>agregador de links</1> / alternativa a reddit, con la intención de funcionar en el <2>fediverso</2>.<3></3>Es alojable por uno mismo (sin necesidad de grandes compañías), tiene actualización en vivo de cadenas de comentarios, y es pequeño (<4>~80kB</4>). Federar con el sistema de redes ActivityPub forma parte de los objetivos del proyecto. <5></5>Esta es una <6>version beta muy prematura</6>, y actualmente muchas de las características están rotas o faltan. <7></7>Sugiere nuevas características o reporta errores <8>aquí</8>.<9></9>Hecho con <10>Rust</10>, <11>Actix</11>, <12>Inferno</12>, <13>Typescript</13>.',
not_logged_in: 'No has iniciado sesión.',
logged_in: 'Has iniciado sesión.',
community_ban: 'Has sido expulsado de esta comunidad.',
site_ban: 'Has sido expulsado del sitio',
couldnt_create_comment: 'No se pudo crear el comentario.',
couldnt_like_comment: 'No se pudo dar me gusta al comentario.',
couldnt_update_comment: 'No se pudo actualizar el comentario.',
couldnt_save_comment: 'No se pudo guardar el comentario.',
no_comment_edit_allowed: 'No tiene permisos para editar el comentario.',
no_post_edit_allowed: 'No tiene permisos para editar la publicación.',
no_community_edit_allowed: 'No tiene permisos para editar la comunidad.',
couldnt_find_community: 'No se pudo encontrar la comunidad.',
couldnt_update_community: 'No se pudo actualizar la comunidad.',
community_already_exists: 'Esta comunidad ya existe.',
community_moderator_already_exists:
'Este moderador de la comunidad ya existe.',
community_follower_already_exists:
'Este seguidor de la comunidad ya existe.',
community_user_already_banned:
'Este usuario de la comunidad ya fue expulsado.',
couldnt_create_post: 'No se pudo crear la publicación.',
couldnt_like_post: 'No se pudo gustar la publicación.',
couldnt_find_post: 'No se pudo encontrar la publicación.',
couldnt_get_posts: 'No se pudo obtener las publicaciones',
couldnt_update_post: 'No se pudo actualizar la publicación',
couldnt_save_post: 'No se pudo guardar la publicación.',
no_slurs: 'Prohibido insultar.',
not_an_admin: 'No es un administrador.',
site_already_exists: 'El sitio ya existe.',
couldnt_update_site: 'No se pudo actualizar el sitio.',
couldnt_find_that_username_or_email:
'No se pudo encontrar ese nombre de usuario o correo electrónico.',
password_incorrect: 'Contraseña incorrecta.',
passwords_dont_match: 'Las contraseñas no coinciden.',
admin_already_created: 'Lo sentimos, ya hay un adminisitrador.',
user_already_exists: 'El usuario ya existe.',
email_already_exists: 'El correo ya está en uso.',
couldnt_update_user: 'No se pudo actualizar el usuario.',
system_err_login:
'Error del sistema. Intente cerrar sesión e ingresar de nuevo.',
couldnt_create_private_message: 'No se pudo crear el mensaje privado.',
no_private_message_edit_allowed:
'Sin permisos para editar el mensaje privado.',
couldnt_update_private_message: 'No se pudo actualizar el mensaje privado.',
old: 'Antiguo',
time: 'Tiempo',
action: 'Acción',
},
};

View file

@ -1,169 +0,0 @@
export const fa = {
translation: {
post: 'مطلب',
remove_post: 'حذف مطلب',
no_posts: 'بدون مطلب.',
create_a_post: 'ایجاد یک مطلب',
create_post: 'ایجاد مطلب',
number_of_posts: '{{count}} مطلب',
posts: 'مطالب',
related_posts: 'این مطالب ممکن است مرتبط باشند',
cross_posts: 'این پیوند در اینجا هم منتشر شده:',
comments: 'نظرات',
number_of_comments: '{{count}} نظر',
remove_comment: 'حذف نظر',
communities: 'جوامع',
users: 'کاربران',
create_a_community: 'ایجاد یک جامعه جدید',
create_community: 'ایجاد جامعه',
remove_community: 'حذف جامعه',
list_of_communities: 'فهرست جوامع',
number_of_communities: '{{count}} جامعه',
community_reqs: 'حروف کوچک, زیرخط, و بدون فاصله.',
edit: 'ویرایش',
reply: 'پاسخ',
cancel: 'لغو',
preview: 'پیش‌نمایش',
upload_image: 'بارگذاری تصویر',
avatar: 'آواتار',
upload_avatar: 'بارگذاری آواتار',
show_avatars: 'نمایش آواتارها',
formatting_help: 'راهنمای قالب‌بندی',
view_source: 'نمایش منبع',
unlock: 'بازکردن قفل',
lock: 'قفل کردن',
sticky: 'چسبان',
unsticky: 'غیرچسبان',
link: 'پیوند',
archive_link: 'بایگاهی پیوند',
settings: 'تنظیمات',
admin: 'مدیر',
admins: 'مدیران',
remove_as_admin: 'حذف به عنوان مدیر',
appoint_as_admin: 'انتصاب به عنوان مدیر',
remove: 'حذف',
removed: 'حذف شد',
locked: 'قفل شد',
reason: 'دلیل',
mark_as_read: 'علامت‌گذاری به عنوان خوانده شده',
mark_as_unread: 'علامت‌گذاری به عنوان خوانده نشده',
delete: 'پاک کردن',
deleted: 'پاک شد',
delete_account: 'پاک کردن حساب',
delete_account_confirm:
'هشدار: این کنش، تمام اطلاعات شما را برای همیشه پاک می‌کند. برای تایید، گذرواژه خود را وارد کنید.',
restore: 'بازگردانی',
save: 'ذخیره',
unsave: 'عدم ذخیره',
create: 'ایجاد',
creator: 'سازنده',
username: 'نام‌کاربری',
email_or_username: 'رایانامه یا نام‌کاربری',
number_of_users: '{{count}} کاربر',
number_of_points: '{{count}} امتیاز',
number_online: '{{count}} کاربر برخط',
name: 'نام',
title: 'عنوان',
category: 'دسته‌بندی',
prev: 'پیش',
next: 'بعد',
sidebar: 'نوار کناری',
sort_type: 'نوع ترتیب',
hot: 'داغ',
new: 'تازه',
top_day: 'بهترین‌های روز',
week: 'هفته',
month: 'ماه',
year: 'سال',
all: 'همه',
top: 'بالاترین',
mark_all_as_read: 'علامت زدن همه به عنوان خوانده شده',
type: 'نوع',
unread: 'خوانده‌نشده',
replies: 'پاسخ‌ها',
mentions: 'اشاره‌ها',
reply_sent: 'پاسخ فرستاده شد',
search: 'جستجو',
overview: 'دید کلی',
view: 'نما',
logout: 'خروج',
login_sign_up: 'ورود / نام‌نویسی',
login: 'ورود',
sign_up: 'نام‌نویسی',
unread_messages: 'پیام‌های خوانده نشده',
password: 'گذرواژه',
verify_password: 'تایید گذرواژه',
old_password: 'پسورد پیشین',
forgot_password: 'گذرواژه را فراموش کرده‌ام',
reset_password_mail_sent: 'رایانامه‌ای برای بازنشانی گذرواژه فرستاده شد.',
password_change: 'تغییر گذرواژه',
new_password: 'گذرواژه جدید',
email: 'رایانامه',
send_notifications_to_email: 'فرستادن اعلانات به رایانامه',
optional: 'انتخابی',
expires: 'منقضی شود',
language: 'زبان',
browser_default: 'پیش‌فرض مرورگر',
downvotes_disabled: 'رای پایین غیرفعال است',
enable_downvotes: 'فعال‌سازی رای پایین',
open_registration: 'باز کردن نام‌نویسی',
registration_closed: 'نام‌نویسی بسته است',
enable_nsfw: 'فعال‌سازی NSFW',
chat: 'گپ',
recent_comments: 'نظرات اخیر',
no_results: 'بدون نتیجه.',
setup: 'نصب',
lemmy_instance_setup: 'نصب نمونهٔ لمی',
setup_admin: 'نصب مدیریت پایگاه',
your_site: 'پایگاه شما',
modified: 'تغییر یافت',
nsfw: 'NSFW',
show_nsfw: 'نمایش محتوای NSFW',
sponsors: 'حامیان',
sponsors_of_lemmy: 'حامیان لمی',
support_on_patreon: 'حمایت روی Patreon',
donate_to_lemmy: 'اعطای اعانه به لمی',
donate: 'اعانه',
crypto: 'رمزارز',
bitcoin: 'بیت‌کوین',
ethereum: 'اتریوم',
monero: 'مونرو',
code: 'کد',
transfer_community: 'انتقال جامعه',
transfer_site: 'انتقال پایگاه',
are_you_sure: 'مطمئنید؟',
yes: 'بله',
no: 'خیر',
powered_by: 'نیرو گرفته از',
not_logged_in: 'وارد نشده‌اید.',
community_ban: 'فعالیت شما در این جامعه ممنوع شده است.',
site_ban: 'فعالیت شما در این پایگاه ممنوع شده است',
couldnt_create_comment: 'ناتوانی در ایجاد نظر.',
couldnt_like_comment: 'ناتوانی در پسنیدن نظر.',
couldnt_update_comment: 'ناتوانی در به‌روزرسانی نظر.',
couldnt_save_comment: 'ناتوانی در ذخیره نظر.',
no_comment_edit_allowed: 'مجاز به ویرایش نظر نیستید.',
no_post_edit_allowed: 'مجاز به ویرایش مطلب نیستید.',
no_community_edit_allowed: 'مجاز به ویرایش جامعه نیستید.',
couldnt_find_community: 'ناتوانی در یافتن جامعه.',
couldnt_update_community: 'ناتوانی در به‌روزرسانی جامعه.',
community_already_exists: 'این جامعه از قبل وجود داشته است.',
couldnt_create_post: 'ناتوانی در ایجاد مطلب.',
couldnt_like_post: 'ناتوانی در پسندیدن مطلب.',
couldnt_find_post: 'ناتوانی در یافتن مطلب.',
couldnt_get_posts: 'ناتوانی در دریافت مطالب',
couldnt_update_post: 'ناتوای در به‌روزرسانی مطلب',
couldnt_save_post: 'ناتوانی در ذخیره مطلب.',
not_an_admin: 'مدیر نیستید.',
site_already_exists: 'این پایگاه از قبل وجود داشته است.',
couldnt_update_site: 'ناتوانی در به‌روزرسانی پایگاه.',
couldnt_find_that_username_or_email:
'ناتوانی در یافتن این نام کاربری یا رایانامه.',
password_incorrect: 'گذرواژه نادرست.',
passwords_dont_match: 'گذرواژه‌ها با هم منطبق نیستند.',
user_already_exists: 'این کاربر از قبل وجود دارد.',
email_already_exists: 'این رایانامه از قبل وجود دارد.',
couldnt_update_user: 'ناتوانی در به‌روزرسانی کاربر.',
system_err_login: 'خطای سامانه. سعی کنید خارج شده و دوباره وارد شوید.',
},
};

View file

@ -1,236 +0,0 @@
export const fi = {
translation: {
post: 'viesti',
remove_post: 'Poista viesti',
no_posts: 'Ei viestjä.',
create_a_post: 'Luo viesti',
create_post: 'Luo viesti',
number_of_posts: '{{count}} viestiä',
posts: 'Viestit',
related_posts: 'Nämä viestit voivat liittyä toisiinsa',
cross_posts: 'Tämä linkki on jaettu:',
cross_post: 'jaa ristiin',
comments: 'Kommentit',
number_of_comments: '{{count}} kommenttia',
remove_comment: 'Poista kommentti',
communities: 'Yhteisöt',
users: 'Käyttäjät',
create_a_community: 'Luo yhteisö',
create_community: 'Luo yhteisö',
remove_community: 'Poista yhteisö',
subscribed_to_communities: 'Tilatut <1>yhteisöt</1>',
trending_communities: 'Nousevat <1>yhteisöt</1>',
list_of_communities: 'Lista yhteisöistä',
number_of_communities: '{{count}} yhteisöä',
community_reqs:
'pienillä kirjaimilla, alleviivauksella, eikä välilyöntejä.',
create_private_message: 'Luo yksityisviesti',
send_secure_message: 'Lähetä suojattu viesti',
send_message: 'Lähetä viesti',
message: 'Viesti',
edit: 'muokkaa',
reply: 'vastaa',
cancel: 'Peru',
preview: 'Esikatselu',
upload_image: 'lataa kuva',
avatar: 'avatar',
upload_avatar: 'Lähetä avatar',
show_avatars: 'Näytä avatarit',
formatting_help: 'apua muotoiluun',
view_source: 'näytä lähde',
unlock: 'avaa',
lock: 'lukitse',
sticky: 'kiinnitä',
unsticky: 'poista kiinnitys',
link: 'linkitä',
archive_link: 'arkistoi linkki',
mod: 'moderaattori',
mods: 'moderaattorit',
moderates: 'Moderoi',
settings: 'Asetukset',
remove_as_mod: 'Poista moderaattorina',
appoint_as_mod: 'Nimitä moderaattoriksi',
modlog: 'Moderoinnin loki',
admin: 'Ylläpitäjä',
admins: 'ylläpitäjät',
remove_as_admin: 'poista ylläpitäjänä',
appoint_as_admin: 'nimitä ylläpitäjäksi',
remove: 'poista',
removed: 'poistettu',
locked: 'lukittu',
stickied: 'kiinnitetty',
reason: 'Syy',
mark_as_read: 'merkitse luetuksi',
mark_as_unread: 'merkitse lukemattomaksi',
delete: 'poista',
deleted: 'deleted',
delete_account: 'Poista tili',
delete_account_confirm:
'Varoitus: tämä poistaa pysyvästi kaiken datasi. Anna salasanasi varmistukseksi.',
restore: 'palauta',
ban: 'porttikielto',
ban_from_site: 'aseta porttikielto sivulle',
unban: 'poista porttikielto',
unban_from_site: 'poista porttikielto sivulta',
banned: 'asetettu porttikieltoon',
save: 'tallenna',
unsave: 'jätä tallentamatta',
create: 'luo',
creator: 'luoja',
username: 'Käyttäjänimi',
email_or_username: 'Sähköposti tai käyttäjätunnus',
number_of_users: '{{count}} käyttäjää',
number_of_subscribers: '{{count}} tilaajaa',
number_of_points: '{{count}} pistettä',
number_online: '{{count}} käyttäjää aktiivisena',
name: 'Nimi',
title: 'Kuvaus',
category: 'Luokka',
subscribers: 'Tilaajat',
both: 'Molemmat',
saved: 'Tallennettu',
unsubscribe: 'Poista tilaus',
subscribe: 'Tilaa',
subscribed: 'Tilattu',
prev: 'Edellinen',
next: 'Seuraava',
sidebar: 'Sivupalkki',
sort_type: 'Lajittele tyypin mukaan',
hot: 'Kuumat',
new: 'Uudet',
top_day: 'Päivän parhaimmat',
week: 'Viikko',
month: 'Kuukausi',
year: 'Vuosi',
all: 'Kaikki',
top: 'Parhaimmat',
api: 'API',
docs: 'Dokumentaatio',
inbox: 'Postilaatikko',
inbox_for: 'Postilaatikko käyttäjällä <1>{{user}}</1>',
mark_all_as_read: 'aseta kaikki luetuiksi',
type: 'Tyyppi',
unread: 'Lukematon',
replies: 'Vastaukset',
mentions: 'Maininnat',
reply_sent: 'Vastaus lähetetty',
message_sent: 'Viesti lähetetty',
search: 'Etsi',
overview: 'Yleiskatsaus',
view: 'Katso',
logout: 'Kirjaudu ulos',
login_sign_up: 'Kirjaudu sisään / Rekisteröidy',
login: 'Kirjaudu sisään',
sign_up: 'Rekisteröidy',
notifications_error:
'Työpöydän ilmoitukset eivät ole saatavilla selaimellesi. Yritä Firefoxia tai Chromea.',
unread_messages: 'Lukemattomat viestit',
messages: 'Viestit',
password: 'Salasana',
verify_password: 'Vahvista salasana',
old_password: 'Vanha salasana',
forgot_password: 'unohdin salasanani',
reset_password_mail_sent: 'Sähköposti lähetettiin salasanan nollaamiseksi.',
password_change: 'Salasanan muutos',
new_password: 'Uusi salasana',
no_email_setup: 'Tämä palvelin ei ole asettanut sähköpostia oikein.',
email: 'Sähköposti',
matrix_user_id: ' Matrix-käyttäjä',
private_message_disclaimer:
'Varoitus: Yksityisviestit Lemmyssä eivät ole turvallisia. Luo tili <1>Riot.im</1> -palveluun turvallista viestintää varten.',
send_notifications_to_email: 'Lähetä ilmoitukset sähköpostiin',
optional: 'Valinnainen',
expires: 'Umpeutuu',
language: 'Kieli',
browser_default: 'Selaimen oletus',
downvotes_disabled: 'Alaäänet otettu pois päältä',
enable_downvotes: 'Salli alaäänet',
open_registration: 'Avaa rekisteröityminen',
registration_closed: 'Rekisteröityminen suljettu',
enable_nsfw: 'Salli NSFW',
url: 'URL',
body: 'Body',
copy_suggested_title: 'kopioi ehdotettu otsikko: {{title}}',
community: 'Yhteisö',
expand_here: 'Laajenna tässä',
subscribe_to_communities: 'Tilaa joitakin <1>yhteisöjä</1>.',
chat: 'Chat',
recent_comments: 'Viimeaikaiset kommentit',
no_results: 'Ei tuloksia.',
setup: 'Asetus',
lemmy_instance_setup: 'Lemmy-instanssin asetus',
setup_admin: 'Aseta sivuston ylläpitäjä',
your_site: 'sivustosi',
modified: 'muokattu',
nsfw: 'NSFW',
show_nsfw: 'Näytä NSFW-sisältö',
theme: 'Teema',
sponsors: 'Sponsorit',
sponsors_of_lemmy: 'Lemmy-sponsorit',
sponsor_message:
'Lemmy on vapaa, <1>avoimen lähdekoodin</1> -ohjelmisto, eli mainontaa, rahantekemistä, tai pääomasijoitusta täällä ei tule ikinä olemaan. Lahjoituksesi tukevat suoraan projektin täysipäiväistä kehitystä. Kiitokset seuraaville ihmisille:',
support_on_patreon: 'Tue Patreonissa',
donate_to_lemmy: 'Lahjoita Lemmylle',
donate: 'Lahjoita',
general_sponsors:
'Yleisiä sponsoreja ovat he, jotka lupaavat 10-39 dollaria Lemmylle.',
crypto: 'Crypto',
bitcoin: 'Bitcoin',
ethereum: 'Ethereum',
monero: 'Monero',
code: 'Code',
joined: 'Liittyi',
by: 'käyttäjältä',
to: 'yhteisössä',
from: 'paikasta',
transfer_community: 'siirron yhteisö',
transfer_site: 'siirron määrä',
are_you_sure: 'oletko varma?',
yes: 'kyllä',
no: 'ei',
powered_by: 'Vauhdittajana',
landing_0:
'Lemmy on <1>linkinkerääjä</1> / Reddit-vaihtoehto, tarkoitettu toimimaan <2>fediversessä</2>.<3></3>Sitä voi isännöidä itse, siinä on tosiaikaisesti päivittyvät kommenttiketjut, ja se on pieni (<4>~80 kilotavua</4>). Federointi ActivityPub-verkkoon on suunnittelun alla. <5></5>Tämä on <6>hyvin varhainen betaversio</6>, ja monet ominaisuudet ovat toistaiseksi rikki tai poissa. <7></7>Ehdota uusia ominaisuuksia tai raportoi bugeja <8>tänne.</8><9></9>Tehty teknologioilla <10>Rust</10>, <11>Actix</11>, <12>Inferno</12>, <13>Typescript</13>.',
not_logged_in: 'Ei kirjautunut sisään.',
logged_in: 'Kirjautunut sisään.',
community_ban: 'Sinulle on asetettu porttikielto tähän yhteisöön.',
site_ban: 'Sinut on asetettu porttikieltoon tältä sivustolta',
couldnt_create_comment: 'Kommenttia ei pystytty luomaan.',
couldnt_like_comment: 'Kommentista ei voitu tykätä.',
couldnt_update_comment: 'Kommenttia ei voitu päivittää.',
couldnt_save_comment: 'Kommenttia ei voitu tallentaa.',
no_comment_edit_allowed: 'Et ole sallittu muokkaamaan kommenttia.',
no_post_edit_allowed: 'Et ole sallittu muokkaamaan viestiä.',
no_community_edit_allowed: 'Et ole sallittu muokkaamaan yhteisöä.',
couldnt_find_community: 'Yhteisöä ei voitu löytää.',
couldnt_update_community: 'Yhteisöä ei voitu päivittää.',
community_already_exists: 'Yhteisö on jo olemassa.',
community_moderator_already_exists: 'Yhteisön moderaattori on jo olemassa.',
community_follower_already_exists: 'Yhteisön seuraaja on jo olemassa.',
community_user_already_banned: 'Yhteisön käyttäjä on jo porttikiellossa.',
couldnt_create_post: 'Ei voitu luoda viestiä.',
couldnt_like_post: 'Viestistä ei voitu tykätä.',
couldnt_find_post: 'Viestiä ei löytynyt.',
couldnt_get_posts: 'Viestejä ei saatu',
couldnt_update_post: 'Viestiä ei voitu päivittää',
couldnt_save_post: 'Viestiä ei voitu tallentaa.',
no_slurs: 'Ei loukkauksia.',
not_an_admin: 'Ei ole ylläpitäjä.',
site_already_exists: 'Sivusto on jo olemassa.',
couldnt_update_site: 'Sivustoa ei voitu päivittää.',
couldnt_find_that_username_or_email:
'Käyttäjänimeä tai sähköpostia ei onnistuttu löytämään.',
password_incorrect: 'Salasana on väärin.',
passwords_dont_match: 'Salasanat eivät täsmää.',
admin_already_created: 'Anteeksi, mutta täällä on jo ylläpitäjä.',
user_already_exists: 'Käyttäjä on jo olemassa.',
email_already_exists: 'Sähköposti on jo olemassa.',
couldnt_update_user: 'Käyttäjää ei voitu päivittää.',
system_err_login:
'Järjestelmävirhe. Yritä kirjautua ulos ja kirjautua uudestaan sisään.',
couldnt_create_private_message: 'Yksityisviestiä ei voitu luoda.',
no_private_message_edit_allowed:
'Et ole sallittu muokkaamaan yksityisviestiä.',
couldnt_update_private_message: 'Yksityisviestiä ei voitu päivittää.',
},
};

View file

@ -1,242 +0,0 @@
export const fr = {
translation: {
post: 'publication',
remove_post: 'Supprimer la publication',
no_posts: 'Pas de publications.',
create_a_post: 'Créer une publication',
create_post: 'Créer la publication',
number_of_posts: '{{count}} Publications',
posts: 'Publications',
related_posts: 'Ces sujets peuvent être corrélés',
cross_posts: 'Ce sujet a également été posté sur :',
cross_post: 'publication croisée',
cross_posted_to: 'publication croisée à',
comments: 'Commentaires',
number_of_comments: '{{count}} Commentaires',
remove_comment: 'Supprimer le commentaire',
communities: 'Communautés',
users: 'Utilisateurs',
create_a_community: 'Créer une communauté',
create_community: 'Créer la communauté',
remove_community: 'Supprimer la Communauté',
subscribed_to_communities: 'Abonné à ces <1>communautés</1>',
trending_communities: '<1>Communautés</1> appréciées',
list_of_communities: 'Liste des communautés',
number_of_communities: '{{count}} communautés',
community_reqs: 'en minuscule, sans espace et avec tiret du bas.',
create_private_message: 'Créer un message privé',
send_secure_message: 'Envoyer le message sécurisé',
send_message: 'Enovyer le message',
message: 'Message',
edit: 'éditer',
reply: 'répondre',
cancel: 'Annuler',
preview: 'prévisualiser',
upload_image: 'envoyer une image',
avatar: 'Avatar',
upload_avatar: 'Télécharger une avatar',
show_avatars: 'Afficher les avatars',
formatting_help: 'aide au formattage',
view_source: 'voir la source',
unlock: 'débloquer',
lock: 'bloquer',
sticky: 'épingler',
unsticky: 'décrocher',
link: 'lien',
archive_link: 'archiver le lien',
mod: 'modérateur',
mods: 'modérateurs',
moderates: 'Modérer',
settings: 'Paramètres',
remove_as_mod: 'Supprimer comme modérateur',
appoint_as_mod: 'Nommer comme modérateur',
modlog: 'Historique de modération',
admin: 'admin',
admins: 'admins',
remove_as_admin: 'Supprimer comme admin',
appoint_as_admin: 'Nommer comme admin',
remove: 'retirer',
removed: 'retiré',
locked: 'bloqué',
stickied: 'épinglé',
reason: 'Raison',
mark_as_read: 'marquer comme lu',
mark_as_unread: 'marquer comme non-lu',
delete: 'supprimer',
deleted: 'supprimé',
delete_account: 'Supprimer le compte',
delete_account_confirm:
'Attention: cette action supprime toutes vos données de façons permanente ! Entrez votre mot de passe pour confirmer.',
restore: 'restaurer',
ban: 'bannir',
ban_from_site: 'bannir du site',
unban: 'pardon',
unban_from_site: 'faire revenir sur le site',
banned: 'banni',
save: 'sauvegarder',
unsave: 'retirer',
create: 'créer',
creator: 'createur',
username: "Nom d'utilisateur",
email_or_username: "Email ou Nom d'utilisateur",
number_of_users: '{{count}} Utilisateurs',
number_of_subscribers: '{{count}} Abonnés',
number_of_points: '{{count}} Points',
number_online: '{{count}} Utilisateurs en ligne',
name: 'Nom',
title: 'Titre',
category: 'Catégorie',
subscribers: 'Abonnés',
both: 'Les deux',
saved: 'Sauvegardé',
unsubscribe: 'Se désabonner',
subscribe: "S'abonner",
subscribed: 'Abonnés',
prev: 'Précédent',
next: 'Suivant',
sidebar: 'Texte latéral',
sort_type: 'Trier',
hot: 'Tendances',
new: 'Nouveaux',
old: 'Ancien',
top_day: 'Top du jour',
week: 'Semaine',
month: 'Mois',
year: 'Année',
all: 'Tout',
top: 'Top',
api: 'API',
docs: 'Documentations',
inbox: 'Boîte de réception',
inbox_for: 'Boîte de réception de <1>{{user}}</1>',
mark_all_as_read: 'Tout marquer comme lu',
type: 'Type',
unread: 'Non-lu',
replies: 'Réponses',
mentions: 'Mentions',
reply_sent: 'Réponse envoyée',
message_sent: 'Message envoyé',
search: 'Rechercher',
overview: 'Général',
view: 'Voir',
logout: 'Se déconnecter',
login_sign_up: "Se connecter / S'inscrire",
login: 'Se connecter',
sign_up: "S'inscrire",
notifications_error:
'Les notifications de bureau ne sont pas discponibles sur votre navigateur. Essayez Firefox ou Chrome.',
unread_messages: 'Messages non-lu',
messages: 'Messages',
password: 'Mot de passe',
verify_password: 'Vérifiez le mot de passe',
old_password: 'Ancien mot de passe',
forgot_password: 'Mot de passe oublié',
reset_password_mail_sent: 'Un email a été envoyé pour réinitialiser votre mot de passe.',
password_change: 'Changement de mot de passe',
new_password: 'Nouveau mot de passe',
no_email_setup: "Ce serveur n'a pas correctement configuré la messagerie de email.",
email: 'Email',
matrix_user_id: 'Utilisateur Matrix',
private_message_disclaimer:
"Attention: les messages privés en Matrix ne sont pas sécurisés. S'il vous plait, créer un compte de <1>Riot.im</1> pour des messages sécurisés.",
send_notifications_to_email: 'Envoyer des notifications par email',
optional: 'Optionnel',
expires: 'Expire',
language: 'Langue',
browser_default: 'Défaut pour le navigateur',
downvotes_disabled: 'Votes négatifs désactivés',
enable_downvotes: 'Votes négatifs activés',
open_registration: 'Ouvrir la regestration',
registration_closed: 'Régestration fermée',
enable_nsfw: 'Activer NSFW',
url: 'URL',
body: 'Texte',
copy_suggested_title: 'Ajouter le titre suggéré: {{title}}',
community: 'Communauté',
expand_here: 'Développer ici',
subscribe_to_communities: "S'abonner à quelques <1>communautés</1>.",
chat: 'Chat',
recent_comments: 'Commentaires récents',
no_results: 'Pas de résultats.',
setup: 'Installation',
lemmy_instance_setup: "Installation d'une instance Lemmy",
setup_admin: 'Créer un administrateur',
your_site: 'votre site',
modified: 'modifié',
nsfw: 'Pas sûr pour le travail',
show_nsfw: 'Afficher le contenu NSFW',
theme: 'Thème',
sponsors: 'Sponsors',
sponsors_of_lemmy: 'Sponsors de Lemmy',
sponsor_message:
"Lemmy est gratuit et <1>open-source</1>, c'est à dire sans publicité et sans monétisation. Pour toujours. Vos dons soutiennent directement le développement du projet. Merci à nos soutiens.",
support_on_patreon: 'Soutenir sur Patreon',
support_on_liberapay: 'Soutenir sur Liberapay',
donate_to_lemmy: 'Faire un don à Lemmy',
donate: 'Faire un don',
general_sponsors: 'Les sponsors généraux sont ceux garantissant de 10 à 39$.',
crypto: 'Cryptomonnaies',
bitcoin: 'Bitcoin',
ethereum: 'Ethereum',
monero: 'Monero',
code: 'Code',
joined: 'Membre depuis',
by: 'par',
to: 'vers',
from: 'de',
transfer_community: 'transférer la communauté',
transfer_site: 'transférer le site',
are_you_sure: 'Êtes-vous sûr ?',
yes: 'oui',
no: 'non',
powered_by: 'Propulsé par',
landing_0:
'Lemmy est un <1>aggrégateur de lien</1>, similaire à reddit et conçu pour fonctionner sur le <2>fédiverse</2>.<3></3>Il est auto-hébergeable, se met à jour en direct et est léger (<4>~80kB</4>). La fédération via Activitypub est prévue. <5></5>Lemmy est une <6>version beta très précoce</6>, et de nombreuses fonctionnalités sont manquantes ou non fonctionnelles. <7></7>Vous pouvez rapporter des bugs et suggérez de nouvelles fonctionnalités <8>ici.</8><9></9>Crée avec <10>Rust</10>, <11>Actix</11>, <12>Inferno</12>, <13>Typescript</13>.',
not_logged_in: "Vous n'êtes pas connecté.",
logged_in: 'Vous êtes connecté.',
community_ban: 'Vous avez été banni de cette communauté.',
site_ban: 'Vous avez été banni du site',
couldnt_create_comment: 'Impossible de poster le commentaire.',
couldnt_like_comment: "Impossible d'aimer le commentaire.",
couldnt_update_comment: 'Impossible de mettre à jour le commentaire.',
couldnt_save_comment: 'Impossible de sauvegarder le commentaire.',
couldnt_get_comments: 'Impossible de obtenir les commentaires.',
no_comment_edit_allowed:
"Vous n'êtes pas autorisé à éditer ce commentaire.",
no_post_edit_allowed: "Vous n'êtes pas autorisé à éditer sujet.",
no_community_edit_allowed:
"Vous n'êtes pas autorisé à éditer cette communauté.",
couldnt_find_community: 'Impossible de trouver cette communauté.',
couldnt_update_community: "Impossible d'éditer cette communauté.",
community_already_exists: 'Cette communauté existe déjà.',
community_moderator_already_exists: 'Ce membre est déjà modérateur.',
community_follower_already_exists: 'Ce membre est déjà abonné.',
community_user_already_banned: 'Ce membre est déjà banni.',
couldnt_create_post: 'Impossible de créer le sujet.',
post_title_too_long: 'Sujet titre trop long.',
couldnt_like_post: "Impossible d'aimer le sujet.",
couldnt_find_post: 'Impossible de trouver le sujet.',
couldnt_get_posts: "Impossible d'obtenir les sujets",
couldnt_update_post: 'Impossible de mettre à jour le sujet',
couldnt_save_post: 'Impossible de sauvegarder le sujet.',
no_slurs: "Pas d'insultes.",
not_an_admin: 'Pas administrateur.',
site_already_exists: 'Le site existe déjà.',
couldnt_update_site: 'Impossible de mettre à jour le site.',
couldnt_find_that_username_or_email:
'Impossible de trouver cet utilisateur ou cet email.',
password_incorrect: 'Mot de passe incorrect.',
passwords_dont_match: 'Les mots de passes ne correspondent pas..',
admin_already_created: 'Désolé, il y a déjà un admin.',
user_already_exists: "L'utilisateur existe déjà.",
email_already_exists: "L'email existe déjà",
couldnt_update_user: "Impossible de mettre à jour l'utilisateur.",
system_err_login:
'Erreur système. Essayez de vous déconneter puis de vous reconnecter.',
couldnt_create_private_message: 'Impossible de créer un message privé.',
no_private_message_edit_allowed: 'Pas autorisé à modifier un message privé.',
couldnt_update_private_message: 'Impossible de modifier un message privé.',
time: 'Temps',
action: 'Action',
},
};

View file

@ -1,192 +0,0 @@
export const it = {
translation: {
post: 'post',
remove_post: 'Rimuovi Post',
no_posts: 'Nessun Post.',
create_a_post: 'Crea un post',
create_post: 'Crea Post',
number_of_posts: '{{count}} Posts',
posts: 'Posts',
related_posts: 'Questi post potrebbero essere correlati',
cross_posts: 'Questo link è stato postato anche in:',
cross_post: 'cross-post',
comments: 'Commenti',
number_of_comments: '{{count}} Commenti',
remove_comment: 'Rimuovi Commento',
communities: 'Comunità',
users: 'Utenti',
create_a_community: 'Crea una Comunità',
create_community: 'Crea Comunità',
remove_community: 'Rimuovi Comunità',
subscribed_to_communities: 'Iscritto alle <1>comunità</1>',
trending_communities: '<1>Comunità</1> in crescita',
list_of_communities: 'Lista di comunità',
number_of_communities: '{{count}} Comunità',
community_reqs: 'minuscole, trattini bassi e nessuno spazio.',
edit: 'modifica',
reply: 'rispondi',
cancel: 'Annulla',
preview: 'Anteprima',
upload_image: 'carica immagine',
formatting_help: 'aiuto formattazione',
view_source: 'visualizza sorgente',
unlock: 'sblocca',
lock: 'blocca',
sticky: 'evidenzia',
unsticky: 'rimuovi evidenza',
link: 'link',
mod: 'moderatore',
mods: 'moderatori',
moderates: 'Moderatore di',
settings: 'Impostazioni',
remove_as_mod: 'rimuovi come moderatore',
appoint_as_mod: 'nomina come moderatore',
modlog: 'Registro di moderazione',
admin: 'amministratore',
admins: 'amministratori',
remove_as_admin: 'rimuovi come amministratore',
appoint_as_admin: 'nomina come amministratore',
remove: 'rimuovi',
removed: 'rimosso',
locked: 'bloccato',
stickied: 'evidenziato',
reason: 'Ragione',
mark_as_read: 'segna come letto',
mark_as_unread: 'segna come non letto',
delete: 'cancella',
deleted: 'cancellato',
delete_account: 'Cancella Account',
delete_account_confirm: 'Attenzione: stai per cancellare permanentemente tutti i tuoi dati. Sei sicuro?',
restore: 'ripristina',
ban: 'ban',
ban_from_site: 'banna dal sito',
unban: 'rimuovi ban',
unban_from_site: 'rimuove il ban dal sito',
banned: 'bannato',
save: 'salva',
unsave: 'rimuovi',
create: 'crea',
creator: 'autore',
username: 'Username',
email_or_username: 'Email o Username',
number_of_users: '{{count}} Utenti',
number_of_subscribers: '{{count}} Iscritti',
number_of_points: '{{count}} Punti',
number_online: '{{count}} Utenti Online',
name: 'Nome',
title: 'Titolo',
category: 'Categoria',
subscribers: 'Iscritti',
both: 'Entrambi',
saved: 'Salvato',
unsubscribe: 'Disiscriviti',
subscribe: 'Iscriviti',
subscribed: 'Iscritto',
prev: 'Precedente',
next: 'Prossima',
sidebar: 'Barra laterale',
sort_type: 'Ordina per',
hot: 'Popolari',
new: 'Nuovi',
top_day: 'Migliori della giornata',
week: 'Settimana',
month: 'Mese',
year: 'Anno',
all: 'Tutti',
top: 'Migliori',
api: 'API',
inbox: 'Posta in arrivo',
inbox_for: 'Posta di <1>{{user}}</1>',
mark_all_as_read: 'segna tutti come letti',
type: 'Tipo',
unread: 'Non letti',
replies: 'Risposte',
mentions: 'Menzioni',
reply_sent: 'Risposta inviata',
search: 'Cerca',
overview: 'Panoramica',
view: 'Visualizza',
logout: 'Logout',
login_sign_up: 'Login / Iscriviti',
login: 'Login',
sign_up: 'Iscriviti',
notifications_error: 'Le notifiche desktop non sono supportate sul tuo browser. Prova Firefox o Chrome.',
unread_messages: 'Messaggi Non Letti',
password: 'Password',
verify_password: 'Verifica Password',
email: 'Email',
optional: 'Opzionale',
expires: 'Scade',
url: 'URL',
body: 'Contenuto',
copy_suggested_title: 'copia titolo suggerito: {{title}}',
community: 'Comunità',
expand_here: 'Visualizza qui',
subscribe_to_communities: 'Iscriviti ad una <1>comunità</1>.',
chat: 'Chat',
recent_comments: 'Commenti Recenti',
no_results: 'Nessun risultato.',
setup: 'Setup',
lemmy_instance_setup: 'Setup dell\'istanza di Lemmy',
setup_admin: 'Imposta Amministratore del Sito',
your_site: 'il tuo sito',
modified: 'modificato',
nsfw: 'NSFW',
show_nsfw: 'Mostra contenuto NSFW',
theme: 'Tema',
sponsors: 'Sponsors',
sponsors_of_lemmy: 'Sponsors di Lemmy',
sponsor_message: 'Lemmy è un software gratuito e <1>open-source</1>, il che significa nessuna pubblicità, monetizzazione o investitori esterni, per sempre. Le tue donazioni supportano direttamente lo sviluppo full-time del progetto. Si ringraziano le seguenti persone:',
support_on_patreon: 'Supporta su Patreon',
support_on_liberapay: 'Supporta su Liberapay',
general_sponsors: 'I "General Sponsors" sono quelli che hanno investito dai 10$ ai 39$ su Lemmy.',
crypto: 'Crypto',
bitcoin: 'Bitcoin',
ethereum: 'Ethereum',
monero: 'Monero',
code: 'Code',
joined: 'Iscritto da',
by: 'di',
to: 'su',
transfer_community: 'trasferisci comunità',
transfer_site: 'trasferisci sito',
are_you_sure: 'sei sicuro?',
yes: 'si',
no: 'no',
powered_by: 'Powered by',
landing_0: 'Lemmy è un <1>aggregatore di link</1> / alternativa a reddit, creato per integrarsi con il <2>fediverse</2>. <3></3>È self-hosted, i commenti sono aggiornati in tempo reale ed è molto piccolo (<4>~80kB</4>). La Federazione con la rete ActivityPub sarà implementata nel futuro. <5></5>Questa versione è una <6>beta molto giovane</6> e molte funzionalità sono incomplete o mancanti. <7></7>Suggerisci nuove funzionalità o segnala errori a <8>questa pagina.</8><9></9>Sviluppato con <10>Rust</10>, <11>Actix</11>, <12>Inferno</12>, <13>Typescript</13>.',
not_logged_in: 'Non hai effettuato l\'accesso.',
community_ban: 'Sei stato bannato da questa comunità.',
site_ban: 'Sei stato bannato dal sito',
couldnt_create_comment: 'Impossibile creare il commento.',
couldnt_like_comment: 'Impossibile mettere \'Mi piace\' al commento.',
couldnt_update_comment: 'Impossibile aggiornare il commento.',
couldnt_save_comment: 'Impossibile salvare il commento.',
no_comment_edit_allowed: 'Non sei autorizzato a modificare il commento.',
no_post_edit_allowed: 'Non sei autorizzato a modificare il post.',
no_community_edit_allowed: 'Non sei autorizzato a modificare la comunità.',
couldnt_find_community: 'Impossibile trovare la comunità.',
couldnt_update_community: 'Impossibile aggiornare la comunità.',
community_already_exists: 'La comunità esiste già.',
community_moderator_already_exists: 'Questo utente è già moderatore della comunità.',
community_follower_already_exists: 'Questo utente è già moderatore della comunità.',
community_user_already_banned: 'L\'utente della comunità è già stato bannato.',
couldnt_create_post: 'Impossibile creare il post.',
couldnt_like_post: 'Impossibile mettere \'Mi piace\' post.',
couldnt_find_post: 'Impossibile trovare il post.',
couldnt_get_posts: 'Impossibile recuperare i post',
couldnt_update_post: 'Impossibile aggiornare il post',
couldnt_save_post: 'Impossibile salvare il post.',
no_slurs: 'Niente offese.',
not_an_admin: 'Non un amministratore.',
site_already_exists: 'Il sito esiste già.',
couldnt_update_site: 'Impossibile aggiornare il sito.',
couldnt_find_that_username_or_email: 'L\'username o la email non sono stati trovati.',
password_incorrect: 'Password non corretta.',
passwords_dont_match: 'Le password non corrispondono.',
admin_already_created: 'Spiacente, esiste già un amministratore.',
user_already_exists: 'L\'utente esiste già.',
couldnt_update_user: 'Impossibile aggiornare l\'utente.',
system_err_login: 'Si è verificato un errore. Prova ad effettuare nuovamente il login.',
},
}

View file

@ -1,234 +0,0 @@
export const nl = {
translation: {
post: 'post',
remove_post: 'Verwijder post',
no_posts: 'Geen posts.',
create_a_post: 'Plaats een post',
create_post: 'Plaats post',
number_of_posts: '{{count}} posts',
posts: 'posts',
related_posts: 'Deze posts kunnen gerelateerd zijn',
cross_posts: 'Deze link is ook geplaatst in:',
cross_post: 'cross-post',
comments: 'Reacties',
number_of_comments: '{{count}} reacties',
remove_comment: 'Verwijder reactie',
communities: 'Communities',
users: 'Gebruikers',
create_a_community: 'Maak een community',
create_community: 'Maak community',
remove_community: 'Verwijder community',
subscribed_to_communities: 'Geabonneerd op <1>communities</1>',
trending_communities: 'Populaire <1>communities</1>',
list_of_communities: 'Lijst van communities',
number_of_communities: '{{count}} communities',
community_reqs: 'kleine letters, onderstrepingsteken en geen spaties',
edit: 'bewerk',
reply: 'reageer',
cancel: 'Annuleer',
unlock: 'ontsluiten',
lock: 'sluiten',
link: 'link',
mod: 'moderator',
mods: 'moderators',
moderates: 'Modereert',
settings: 'Instellingen',
remove_as_mod: 'Verwijder als moderator',
appoint_as_mod: 'Benoemen tot moderator',
modlog: 'Moderatorlog',
admin: 'beheerder',
admins: 'beheerders',
remove_as_admin: 'verwijder als beheerder',
appoint_as_admin: 'benoemen tot beheerder',
remove: 'weghalen',
removed: 'weggehaald',
locked: 'gesloten',
reason: 'Reden',
mark_as_read: 'markeer als gelezen',
mark_as_unread: 'markeer als ongelezen',
delete: 'verwijder',
deleted: 'verwijderd',
restore: 'herstellen',
ban: 'verban',
ban_from_site: 'verban van site',
unban: 'verbanning opzeggen',
unban_from_site: 'verbanning van site opzeggen',
save: 'opslaan',
unsave: 'unsave',
create: 'maak',
username: 'Gebruikersnaam',
email_or_username: 'E-mail of gebruikersnaam',
number_of_users: '{{count}} gebruikers',
number_of_subscribers: '{{count}} abonnees',
number_of_points: '{{count}} punten',
name: 'Naam',
title: 'Titel',
category: 'Categorie',
subscribers: 'Abonnees',
both: 'Beide',
saved: 'Opgeslagen',
unsubscribe: 'Afmelden',
subscribe: 'Abonneren',
subscribed: 'Geabonneerd',
prev: 'Vorige',
next: 'Volgende',
sidebar: 'Zijbalk',
sort_type: 'Sorteertype',
hot: 'Populair',
new: 'Nieuw',
top_day: 'Dagelijkse top',
week: 'Week',
month: 'Maand',
year: 'Jaar',
all: 'Alle',
top: 'Top',
api: 'API',
inbox: 'Postvak-in',
inbox_for: 'Postvak-in voor <1>{{user}}</1>',
mark_all_as_read: 'markeer alle als gelezen',
type: 'Type',
unread: 'Ongelezen',
reply_sent: 'Reactie gestuurd',
search: 'Zoek',
overview: 'Overzicht',
view: 'Beeld',
logout: 'Log uit',
login_sign_up: 'Log in / Aanmelden',
login: 'Log in',
sign_up: 'Aanmelden',
notifications_error:
'Bureabladberichten niet beschikbaar in je browser. Probeer Firefox of Chrome.',
unread_messages: 'Ongelezen berichten',
password: 'Wachtwoord',
verify_password: 'Herhaal wachtwoord',
email: 'E-mail',
optional: 'Optioneel',
expires: 'Verloopt',
url: 'url',
body: 'Tekst',
copy_suggested_title: 'neem voorgestelde titel over: {{title}}',
community: 'Community',
expand_here: 'Breid hier uit',
subscribe_to_communities: 'Abonneer je op een paar <1>communities</1>.',
chat: 'Praat',
recent_comments: 'Recente reacties',
no_results: 'Geen resultaten',
setup: 'Installatie',
lemmy_instance_setup: 'Installatie van Lemmy-instantie',
setup_admin: 'Maak een administrator',
your_site: 'jouw site',
modified: 'bewerkt',
nsfw: 'NSFW',
show_nsfw: 'Laat NSFW-inhoud zien',
sponsors: 'Sponsoren',
sponsors_of_lemmy: 'Sponsoren van Lemmy',
sponsor_message:
'Lemmy is vrije, <1>open-source</1> software, dus zonder reclame, winstoogmerk en durfkapitaal, punt. Jouw donaties gaan direct naar de full-time-ontwikkeling van het project. Met veel dank aan de volgende mensen:',
support_on_patreon: 'Ondersteun op Patreon',
support_on_liberapay: 'Ondersteun op Liberapay',
general_sponsors:
'Algemene sponsors zijn sponsors die tussen de $10 en $39 hebben gegeven aan Lemmy.',
crypto: 'Cryptovaluta',
bitcoin: 'Bitcoin',
ethereum: 'Ethereum',
monero: 'Monero',
code: 'Code',
joined: 'toegetreden',
by: 'door',
to: 'aan',
transfer_community: 'community overplaatsen',
transfer_site: 'site overplaatsen',
are_you_sure: 'weet je het zeker?',
yes: 'ja',
no: 'nee',
powered_by: 'Mogelijk gemaakt door',
landing_0:
'Lemmy is een <1>linkverzameler</1> / reddit-alternatief, bedoeld om in de <2>fediverse</2> te werken.<3></3>Lemmy kan door om het even wie gehost worden, heeft live-bijgewerkte reacties en is superklein (<4>ca. 80 kB</4>). Federatie in hte ActivityPub-netwerk is gepland. <5></5>Dit is een <6>erg vroege bèta-versie</6>, en een hoop functies zijn stuk of afwezig. <7></7>Stel nieuwe functies voor of meldt fouten <8>hier</8>.<9></9>Gemaakt met <10>Rust</10>, <11>Actix</11>, <12>Inferno</12> en <13>Typescript</13>.',
not_logged_in: 'Niet ingelogd.',
community_ban: 'Je bent verbannen uit deze community.',
site_ban: 'Je bent verbannen van deze site.',
couldnt_create_comment: 'Kon reactie niet maken.',
couldnt_like_comment: 'Kon reactie niet leuk vinden.',
couldnt_update_comment: 'Kon reactie niet bijwerken.',
couldnt_save_comment: 'Kon reactie niet opslaan.',
no_comment_edit_allowed: 'Niet toegestaan om reactie te bewerken.',
no_post_edit_allowed: 'Niet toegestaan om posts te bewerken.',
no_community_edit_allowed: 'Niet toegestaan om community te bewerken.',
couldnt_find_community: 'Kon community niet vinden.',
couldnt_update_community: 'Kon community niet bijwerken.',
community_already_exists: 'Community bestaat al.',
community_moderator_already_exists: 'Community-moderator bestaat al.',
community_follower_already_exists: 'Community-volger bestaat al.',
community_user_already_banned: 'Community-gebruiker reeds verbannen.',
couldnt_create_post: 'Kon post niet maken.',
couldnt_like_post: 'Kon post niet leuk vinden.',
couldnt_find_post: 'Kon post niet vinden.',
couldnt_get_posts: 'Kon posts niet ophalen.',
couldnt_update_post: 'Kon post niet bijwerken.',
couldnt_save_post: 'Kon post niet opslaan.',
no_slurs: 'Geen beledigingen.',
not_an_admin: 'Niet een beheerder.',
site_already_exists: 'Site bestaat al.',
couldnt_update_site: 'Kon site niet bijwerken.',
couldnt_find_that_username_or_email:
'Kon gebruikersnaam of e-mailadres niet vinden.',
password_incorrect: 'Wachtwoord incorrect.',
passwords_dont_match: 'Wachtwoorden zijn niet gelijk.',
admin_already_created: 'Sorry, er is al een beheerder.',
user_already_exists: 'Gebruiker bestaat al.',
couldnt_update_user: 'Kon gebruiker niet bijwerken.',
system_err_login:
'Systeemfout. Probeer uit te loggen en weer in te loggen.',
preview: 'voorbeeld',
upload_image: 'Afbeelding uploaden',
avatar: 'Avatar',
upload_avatar: 'Avatar uploaden',
show_avatars: 'Toon avatars',
formatting_help: 'Opmaak hulp',
view_source: 'bekijk bron',
sticky: 'vastplakken',
unsticky: 'loshalen',
archive_link: 'Archiveer link',
stickied: 'vastgeplakt',
delete_account: 'Verwijder account',
delete_account_confirm: 'Waarschuwing: dit zal al uw data voorgoed verwijderen, vul uw wachtwoord in om te bevestigen.',
banned: 'verbannen',
creator: 'auteur',
number_online: '{{count}} gebruikers online',
docs: 'Documentatie',
replies: 'Reacties',
mentions: 'vermeldingen',
old_password: 'Oud wachtwoord',
forgot_password: 'wachtwoord vergeten',
reset_password_mail_sent: 'Stuur een email om uw wachtwoord te resetten',
password_change: 'Wachtwoord aanpassen',
new_password: 'Nieuw wachtwoord',
no_email_setup: 'Deze server heeft email niet correct opgezet',
send_notifications_to_email: 'Stuur meldingen naar je email',
language: 'Taal',
browser_default: 'Browser standaard',
downvotes_disabled: 'Downvotes geblokkeerd',
enable_downvotes: 'Downvotes toestaan',
open_registration: 'Open registratie',
registration_closed: 'Registratie gesloten',
enable_nsfw: 'NSFW toestaan',
theme: 'Thema',
create_private_message: 'Maak een beveiligd bericht',
send_secure_message: 'Verstuur beveiligd bericht',
send_message: 'Verstuur bericht',
message: 'Bericht',
old: 'Oud',
message_sent: 'Bericht verstuurd',
messages: 'Berichten',
matrix_user_id: 'Matrix gebruikers-id',
private_message_disclaimer: 'Waarschuwing: Privé berichten in Lemmy zijn niet beveiligd. Maak een account aan op <1>Riot.im</1> om veilig te communiceren',
donate_to_lemmy: 'Doneer aan Lemmy',
donate: 'Doneer',
from: 'van',
logged_in: 'Ingelogd',
email_already_exists: 'Email bestaat al',
couldnt_create_private_message: 'Kan beveiligd bericht niet maken',
no_private_message_edit_allowed: 'Niet toegestaan om privé berichten te wijzigen',
couldnt_update_private_message: 'Kan beveiligd bericht niet bijwerken'
},
};

View file

@ -1,241 +0,0 @@
export const pt_BR = {
translation: {
post: 'publicação',
remove_post: 'Apagar publicação',
no_posts: 'Sem publicações.',
create_a_post: 'Criar uma publicação',
create_post: 'Criar publicação',
number_of_posts: '{{count}} publicações',
posts: 'Publicações',
related_posts: 'Essas publicações podem estar relacionadas',
cross_posts: 'Esse link também foi publicado em:',
cross_post: 're-publicar',
cross_posted_to: 'Publicado também em: ',
comments: 'Comentários',
number_of_comments: '{{count}} comentários',
remove_comment: 'Apagar comentário',
communities: 'Comunidades',
users: 'Usuários',
create_a_community: 'Criar uma comunidade',
create_community: 'Criar comunidade',
remove_community: 'Apagar comunidade',
subscribed_to_communities: 'Inscrito em <1>comunidades</1>',
trending_communities: '<1>Comunidades</1> em tendência',
list_of_communities: 'Lista de comunidades',
number_of_communities: '{{count}} comunidades',
community_reqs: 'minúsculas, sublinhados e sem espaços.',
create_private_message: 'Criar mensagem privada',
send_secure_message: 'Enviar mensagem segura',
send_message: 'Enviar mensagem',
message: 'Mensagem',
edit: 'editar',
reply: 'responder',
cancel: 'Cancelar',
preview: 'Pré-visualização',
upload_image: 'fazer upload de imagem',
avatar: 'Avatar',
upload_avatar: 'Fazer upload de avatar',
show_avatars: 'Mostrar Avatars',
formatting_help: 'ajuda de formatação',
view_source: 'ver fonte',
unlock: 'desbloquear',
lock: 'bloquear',
sticky: 'fixar',
unsticky: 'desafixar',
link: 'link',
archive_link: 'arquivar link',
mod: 'moderador',
mods: 'moderadores',
moderates: 'Modera',
settings: 'Configurações',
remove_as_mod: 'remover como moderador',
appoint_as_mod: 'designar como moderador',
modlog: 'Registro de moderação',
admin: 'administrador',
admins: 'administradores',
remove_as_admin: 'remover como administrador',
appoint_as_admin: 'designar como administrador',
remove: 'remover',
removed: 'removido',
locked: 'trancado',
stickied: 'fixado',
reason: 'Motivo',
mark_as_read: 'marcar como lido',
mark_as_unread: 'marcar como não lido',
delete: 'apagar',
deleted: 'apagado',
delete_account: 'Apagar conta',
delete_account_confirm:
'Aviso: isso vai apagar seus dados de forma permanente. Escreva sua senha para confirmar.',
restore: 'restaurar',
ban: 'banir',
ban_from_site: 'banido do site',
unban: 'readmitido',
unban_from_site: 'readmitido ao site',
banned: 'banido',
save: 'guardar',
unsave: 'descartar',
create: 'criar',
creator: 'criador',
username: 'nome de usuário',
email_or_username: 'E-mail ou nome de usuário',
number_of_users: '{{count}} usuários',
number_of_subscribers: '{{count}} inscritos',
number_of_points: '{{count}} pontos',
number_online: '{{count}} usuários online',
name: 'Nome',
title: 'Título',
category: 'Categoria',
subscribers: 'Inscritos',
both: 'Ambos',
saved: 'Guardado',
unsubscribe: 'Cancelar inscrição',
subscribe: 'Inscrever-se',
subscribed: 'Inscrito',
prev: 'Anterior',
next: 'Próximo',
sidebar: 'Barra lateral',
sort_type: 'Ordenação',
hot: 'Popular',
new: 'Novo',
old: 'Velho',
top_day: 'Top do dia',
week: 'Semana',
month: 'Mês',
year: 'Ano',
all: 'Tudo',
top: 'Top',
api: 'API',
docs: 'Docs',
inbox: 'Caixa de entrada',
inbox_for: 'Caixa de entrada de <1>{{user}}</1>',
mark_all_as_read: 'marcar tudo como lido',
type: 'Tipo',
unread: 'Não lido',
replies: 'Respostas',
mentions: 'Menções',
reply_sent: 'Resposta enviada',
message_sent: 'Mensagem enviada',
search: 'Busca',
overview: 'Visão geral',
view: 'Visualização',
logout: 'Sair',
login_sign_up: 'Entrar / Inscrever-se',
login: 'Entrar',
sign_up: 'Inscrever-se',
notifications_error:
'Seu navegador não oferece notificações para a área de trabalho. Tente o Firefox ou o Chrome.',
unread_messages: 'Mensagens não lidas',
messages: 'Mensagens',
password: 'Senha',
verify_password: 'Verifique a senha',
old_password: 'Senha antiga',
forgot_password: 'esqueci a senha',
reset_password_mail_sent: 'Enviado um e-mail para a alteração da senha.',
password_change: 'Alteração de senha',
new_password: 'Nova senha',
no_email_setup: 'Esse servidor não configurou corretamente o e-mail.',
email: 'E-mail',
matrix_user_id: 'Usuário Matrix',
private_message_disclaimer:
'Aviso: mensagens privadas no Lemmy não são seguras. Crie uma conta em <1>Riot.im</1> para troca segura de mensagens.',
send_notifications_to_email: 'Enviar notificações para o e-mail',
optional: 'Opcional',
expires: 'Expira',
language: 'Idioma',
browser_default: 'Padrão do navegador',
downvotes_disabled: 'Votos negativos desativados',
enable_downvotes: 'Permitir votos negativos',
open_registration: 'Permitir registro',
registration_closed: 'Registros desativados',
enable_nsfw: 'Permitir NSFW',
url: 'URL',
body: 'Conteúdo',
copy_suggested_title: 'copiar título sugerido: {{title}}',
community: 'Comunidade',
expand_here: 'Expandir aqui',
subscribe_to_communities: 'Inscreva-se em algumas <1>comunidades</1>.',
chat: 'Chat',
recent_comments: 'Últimos comentários',
no_results: 'Nenhum resultado.',
setup: 'Instalação',
lemmy_instance_setup: 'Criação de instância Lemmy',
setup_admin: 'Configurar administrador do site',
your_site: 'seu site',
modified: 'modificado',
nsfw: 'NSFW',
show_nsfw: 'Mostrar conteúdo NSFW',
theme: 'Tema',
sponsors: 'Patrocinadores',
sponsors_of_lemmy: 'Patrocinadores do Lemmy',
sponsor_message:
'Lemmy é um programa livre e de código aberto, o que significa que não haverá publicidade, monetização ou capital de risco, jamais. Suas doações apoiam de forma direta o desenvolvimento em tempo integral do projeto. Muitos agradecimentos às sequintes pessoas:',
support_on_patreon: 'Colabore no Patreon',
support_on_liberapay: 'Colabore no Liberapay',
donate_to_lemmy: 'Faça uma doação ao Lemmy',
donate: 'Doar',
general_sponsors:
'Patrocinadores são aqueles que doaram entre $10 e $39 ao Lemmy.',
crypto: 'Crypto',
bitcoin: 'Bitcoin',
ethereum: 'Ethereum',
monero: 'Monero',
code: 'Code',
joined: 'Entrou',
by: 'por',
to: 'para',
from: 'de',
transfer_community: 'transferir comunidade',
transfer_site: 'transferir site',
are_you_sure: 'tem certeza?',
yes: 'sim',
no: 'não',
powered_by: 'Powered by',
landing_0:
'Lemmy é um <1>agregador de links</1> / alternativa ao reddit, com a intenção de funcionar junto ao <2>fediverso</2>.<3></3>Pode ser hospedado em servidor próprio, tem atualização de comentários em tempo real e é minúsculo (<4>~80kB</4>). A federação com a rede ActivityPub está no roteiro do projeto. <5></5>Esta é uma <6>versão beta bastante antecipada</6>, e muitas funcionalidades ainda estão quebradas ou ausentes. <7></7>Sugira novas funcionalidades ou reporte erros <8>aqui.</8><9></9>Feito com <10>Rust</10>, <11>Actix</11>, <12>Inferno</12>, <13>Typescript</13>.',
not_logged_in: 'Não autenticado.',
logged_in: 'Autenticado.',
community_ban: 'Você foi banido desta comunidade.',
site_ban: 'Você foi banido do site',
couldnt_create_comment: 'Não foi possível criar o comentário.',
couldnt_like_comment: 'Não foi possível curtir o comentário.',
couldnt_update_comment: 'Não foi possível atualizar o comentário.',
couldnt_save_comment: 'Não foi possível guardar o comentário.',
no_comment_edit_allowed: 'Sem permissão para editar de comentário.',
no_post_edit_allowed: 'Sem permissão para editar publicação.',
no_community_edit_allowed: 'Sem permissão para editar comunidade.',
couldnt_find_community: 'Não foi possível encontrar a comunidade.',
couldnt_update_community: 'Não foi possível atualizar a comunidade.',
community_already_exists: 'Esta comunidade já existe.',
community_moderator_already_exists:
'Este moderador da comunidade já existe.',
community_follower_already_exists: 'Este seguidor da comunidade já existe.',
community_user_already_banned: 'Este usuário da comunidade já foi banido.',
couldnt_create_post: 'Não foi possível criar a publicação.',
couldnt_like_post: 'Não foi possível curtir a publicação.',
couldnt_find_post: 'Não foi possível encontrar a publicação.',
couldnt_get_posts: 'Não foi possível obter as publicações',
couldnt_update_post: 'Não foi possível atualizar a publicação',
couldnt_save_post: 'Não foi possível guardar a publicação.',
no_slurs: 'Sem insultos.',
not_an_admin: 'Não é administrador.',
site_already_exists: 'O site já existe.',
couldnt_update_site: 'Não foi possível atualizar o site.',
couldnt_find_that_username_or_email:
'Não foi possível encontrar esse usuário ou e-mail.',
password_incorrect: 'Senha incorreta.',
passwords_dont_match: 'As senhas não são iguais.',
admin_already_created: 'Desculpe, já há um administrador.',
user_already_exists: 'Este usuário já existe.',
email_already_exists: 'Este e-mail já existe.',
couldnt_update_user: 'Não foi possível atualizar o usuário.',
system_err_login: 'Erro no sistema. Tente sair e autenticar-se outra vez.',
couldnt_create_private_message: 'Não foi possível criar mensagem privada.',
no_private_message_edit_allowed:
'Sem permissão para editar mensagem privada.',
couldnt_update_private_message:
'Não foi possível atualizar a mensagem privada.',
time: 'Tempo',
action: 'Ação',
},
};

View file

@ -1,170 +0,0 @@
export const ru = {
translation: {
post: 'запись',
remove_post: 'Удалить запись',
no_posts: 'Нет записей.',
create_a_post: 'Создать запись',
create_post: 'Создать запись',
number_of_posts: '{{count}} записей',
posts: 'Записи',
related_posts: 'Эти записи могут быть связаны',
comments: 'Комментарии',
number_of_comments: '{{count}} комментариев',
remove_comment: 'Удалить комментарий',
communities: 'Сообщества',
users: 'Пользователи',
create_a_community: 'Создать сообщество',
create_community: 'Создать сообщество',
remove_community: 'Удалить сообщество',
subscribed_to_communities: 'Подписаны на <1>сообщества</1>',
trending_communities: '<1>Сообщества</1> в тренде',
list_of_communities: 'Список сообществ',
community_reqs: 'строчными буквами, подчеркиваниями и без пробелов.',
edit: 'редактировать',
reply: 'ответить',
cancel: 'Отмена',
unlock: 'разблокировать',
lock: 'заблокировать',
link: 'ссылка',
mod: 'модератор',
mods: 'модераторы',
moderates: 'Модерация',
settings: 'Настройки',
remove_as_mod: 'снять из модераторов',
appoint_as_mod: 'назначить модератором',
modlog: 'Модлог',
admin: 'администратор',
admins: 'администраторы',
remove_as_admin: 'снять из администраторов',
appoint_as_admin: 'назначить администратором',
remove: 'убрать',
removed: 'убрано',
locked: 'заблокировано',
reason: 'Причина',
mark_as_read: 'пометить как прочитанное',
mark_as_unread: 'пометить как непрочитанное',
delete: 'удалить',
deleted: 'удалено',
restore: 'восстановить',
ban: 'заблокировать',
ban_from_site: 'заблокировать на сайте',
unban: 'разблокировать',
unban_from_site: 'разблокировать на сайте',
save: 'сохранить',
unsave: 'не сохранять',
create: 'создать',
username: 'Имя пользователя',
email_or_username: 'Электронная почта или имя пользователя',
number_of_users: '{{count}} пользователей',
number_of_subscribers: '{{count}} подписчиков',
number_of_points: '{{count}} баллов',
name: 'Имя',
title: 'Название',
category: 'Категория',
subscribers: 'Подписчики',
both: 'Оба',
saved: 'Сохранено',
unsubscribe: 'Отписаться',
subscribe: 'Подписаться',
subscribed: 'Подписаны',
prev: 'Назад',
next: 'Далее',
sidebar: 'Боковая панель',
sort_type: 'Тип сортировки',
hot: 'Популярно',
new: 'Новое',
top_day: 'Лучшее за день',
week: 'Неделя',
month: 'Месяц',
year: 'Год',
all: 'Всё',
top: 'Лучшее',
api: 'API',
inbox: 'Входящие',
inbox_for: 'Входящие сообщения для <1>{{user}}</1>',
mark_all_as_read: 'пометить все как прочитанные',
type: 'Тип',
unread: 'Не прочитано',
reply_sent: 'Ответ отправлен',
search: 'Поиск',
overview: 'Обзор',
view: 'Просмотр',
logout: 'Выйти',
login_sign_up: 'Войти / Регистрация',
login: 'Авторизация',
sign_up: 'Регистрация',
notifications_error:
'Уведомления на рабочем столе недоступны в вашем браузере. Попробуйте Firefox или Chrome.',
unread_messages: 'Непрочитанные сообщения',
password: 'Пароль',
verify_password: 'Повторите пароль',
email: 'Электронная почта',
optional: 'Необязательно',
expires: 'Истёк',
url: 'URL',
body: 'Тело',
copy_suggested_title: 'предложенное название: {{title}}',
community: 'Сообщество',
expand_here: 'Расширить здесь',
subscribe_to_communities: 'Подпишитесь на некоторые <1>сообщества</1>.',
chat: 'Чат',
no_results: 'Нет результатов.',
setup: 'Установка',
lemmy_instance_setup: 'Установка инстанции Lemmy',
setup_admin: 'Настройка администратора сайта',
your_site: 'ваш сайт',
modified: 'изменено',
nsfw: 'NSFW',
show_nsfw: 'Показывать NSFW-контент',
sponsors: 'Спонсоры',
sponsors_of_lemmy: 'Спонсоры Lemmy',
sponsor_message:
'Lemmy это бесплатное, <1>открытое</1> программное обеспечение, что означает отсутствие рекламы, монетизации или венчурного капитала, никогда. Ваши пожертвования напрямую поддерживают развитие проекта. Спасибо нижеуказанным людям:',
support_on_patreon: 'Поддержать на Patreon',
general_sponsors:
'Генеральные спонсоры - это те, кто пообещал Lemmy от $10 до $39.',
crypto: 'Крипто',
bitcoin: 'Bitcoin',
ethereum: 'Ethereum',
code: 'Код',
joined: 'Присоединился',
powered_by: 'Работает на',
landing_0:
'Lemmy - это <1>агрегатор ссылок</1> / альтернатива reddit, предназначенный для работы в <2>федиверсе</2>.<3></3>Это самодостаточная система, с обновляемыми комментариями, и эта система крошечная (<4>~80 Кб</4>). Федерация в сети ActivityPub находится в разработке. <5></5>Это <6>очень ранняя бета-версия</6>, и многие функции в настоящее время сломаны или отсутствуют. <7></7>Предлагать новые функции или сообщать об ошибках можно <8>здесь.</8><9></9>Сделано на <10>Rust</10>, <11>Actix</11>, <12>Inferno</12>, <13>Typescript</13>.',
not_logged_in: 'Не авторизованы.',
community_ban: 'Вы были заблокированы на данном сообществе.',
site_ban: 'Вы были заблокированы на данном сайте',
couldnt_create_comment: 'Не получилось создать комментарий.',
couldnt_like_comment: 'Не получилось лайкнуть комментарий.',
couldnt_update_comment: 'Не получилось обновить комментарий.',
couldnt_save_comment: 'Не получилось сохранить комментарий.',
no_comment_edit_allowed: 'Невозможно отредактировать комментарий.',
no_post_edit_allowed: 'Невозможно отредактировать запись.',
no_community_edit_allowed: 'Невозможно отредактировать сообщество.',
couldnt_find_community: 'Не получилось найти сообщество.',
couldnt_update_community: 'Не получилось обновить сообщество.',
community_already_exists: 'Сообщество уже существует.',
community_moderator_already_exists: 'Модератор сообщества уже существует.',
community_follower_already_exists: 'Подписчик сообщества уже существует.',
community_user_already_banned: 'Пользователь сообщества уже заблокирован.',
couldnt_create_post: 'Не получилось создать запись.',
couldnt_like_post: 'Не получилось лайкнуть запись.',
couldnt_find_post: 'Не получилось найти запись.',
couldnt_get_posts: 'Не получилось найти записи',
couldnt_update_post: 'Не получилось обновить запись',
couldnt_save_post: 'Не получилось сохранить запись.',
no_slurs: 'Без оскорблений.',
not_an_admin: 'Не администратор.',
site_already_exists: 'Сайт уже существует.',
couldnt_update_site: 'Не получилось обновить сайт.',
couldnt_find_that_username_or_email:
'Не получилось найти данное имя пользователя или электронную почту.',
password_incorrect: 'Неверный пароль.',
passwords_dont_match: 'Пароли не совпадают.',
admin_already_created: 'Извините, уже есть администратор.',
user_already_exists: 'Пользователь уже существует.',
couldnt_update_user: 'Не получилось обновить пользователя.',
system_err_login:
'Системная ошибка. Попробуйте выйти из системы и вернуться обратно.',
},
};

View file

@ -1,195 +0,0 @@
export const sv = {
translation: {
post: 'inlägg',
remove_post: 'Radera inlägg',
no_posts: 'Inga inlägg.',
create_a_post: 'Skriv ett inlägg',
create_post: 'Skapa inlägg',
number_of_posts: '{{count}} inlägg',
posts: 'Inlägg',
related_posts: 'Dessa inlägg kan vara relaterade',
cross_posts: 'Den här länken har även publicerats i:',
cross_post: 'tvärinlägg',
comments: 'Kommentarer',
number_of_comments: '{{count}} kommentarer',
remove_comment: 'Radera kommentar',
communities: 'Gemenskaper',
users: 'Användare',
create_a_community: 'Skapa en gemenskap',
create_community: 'Skapa gemenskap',
remove_community: 'Radera gemenskap',
subscribed_to_communities: 'Prenumererar på <1>gemenskaper</1>',
trending_communities: 'Populära <1>gemenskaper</1>',
list_of_communities: 'Lista över gemenskaper',
number_of_communities: '{{count}} gemenskaper',
community_reqs: 'gemener, understreck och inga blanksteg.',
edit: 'redigera',
reply: 'svara',
cancel: 'Avbryt',
preview: 'Förhandsgranskning',
upload_image: 'ladda upp bild',
formatting_help: 'formateringshjälp',
view_source: 'visa källkod',
unlock: 'lås upp',
lock: 'lås',
sticky: 'fastnålad',
unsticky: 'inte fastnålad',
link: 'länk',
mod: 'moderator',
mods: 'moderatorer',
moderates: 'Modererar',
settings: 'Inställningar',
remove_as_mod: 'tag bort som moderator',
appoint_as_mod: 'lägg till som moderator',
modlog: 'Moderationslogg',
admin: 'administratör',
admins: 'administratörer',
remove_as_admin: 'tag bort som administratör',
appoint_as_admin: 'lägg till som administratör',
remove: 'ta bort',
removed: 'borttagen',
locked: 'låst',
stickied: 'fastnålad',
reason: 'Anledning',
mark_as_read: 'markera som läst',
mark_as_unread: 'markera som oläst',
delete: 'radera',
deleted: 'raderad',
delete_account: 'Ta bort konto',
delete_account_confirm:
'Varning: den här åtgärden kommer radera alla dina data permanent. Är du säker?',
restore: 'återställ',
ban: 'blockera',
ban_from_site: 'blockera från webbplats',
unban: 'ta bort blockering',
unban_from_site: 'ta bort blockering från webbplats',
banned: 'blocerad',
save: 'spara',
unsave: 'förkasta',
create: 'skapa',
creator: 'skapare',
username: 'Användarnamn',
email_or_username: 'E-postadress eller användarnamn',
number_of_users: '{{count}} användare',
number_of_subscribers: '{{count}} prenumeranter',
number_of_points: '{{count}} poäng',
number_online: '{{count}} användare inloggade',
name: 'Namn',
title: 'Titel',
category: 'Kategori',
subscribers: 'Prenumeranter',
both: 'Båda',
saved: 'Sparade',
unsubscribe: 'Avbryt prenumeration',
subscribe: 'Prenumerera',
subscribed: 'Prenumererar',
prev: 'Föregående',
next: 'Nästa',
sidebar: 'Sidlist',
sort_type: 'Sorteringstyp',
hot: 'Hett',
new: 'Nytt',
top_day: 'Dagstoppen',
week: 'Vecka',
month: 'Månad',
year: 'År',
all: 'Samtliga',
top: 'Topp',
api: 'API',
inbox: 'Inkorg',
inbox_for: 'Inkorg tillhörande <1>{{user}}</1>',
mark_all_as_read: 'markera alla som lästa',
type: 'Typ',
unread: 'Oläst',
reply_sent: 'Svar skickat',
search: 'Sök',
overview: 'Översikt',
view: 'Vy',
logout: 'Logga ut',
login_sign_up: 'Logga in eller skapa konto',
login: 'Logga in',
sign_up: 'Skapa konto',
notifications_error:
'Din webbläsare har inte stöd för skrivbordsaviseringar. Testa Firefox eller Chrome.',
unread_messages: 'Olästa meddelanden',
password: 'Lösenord',
verify_password: 'Bekräfta lösenord',
email: 'E-postadress',
optional: 'Valfritt',
expires: 'Går ut',
url: 'URL',
body: 'Text',
copy_suggested_title: 'kopiera föreslagen titel: {{title}}',
community: 'Gemenskap',
expand_here: 'Utvidga här',
subscribe_to_communities: 'Prenumerera på några <1>gemenskaper</1>.',
chat: 'Chatta',
recent_comments: 'Senaste kommentarer',
no_results: 'Inga resultat.',
setup: 'Installering',
lemmy_instance_setup: 'Installering av Lemmy-instans',
setup_admin: 'Skapa en administratör',
your_site: 'din webbplats',
modified: 'ändrades',
nsfw: 'Känsligt eller oförbehållsamt innehåll',
show_nsfw: 'Visa känsligt eller oförbehållsamt innehåll',
theme: 'Utseende',
sponsors: 'Sponsorer',
sponsors_of_lemmy: 'Lemmys sponsorer',
sponsor_message:
'Lemmy är fri mjukvara med <1>öppen källkod</1>, vilket innebär att ingen reklam, vinstindrivning eller venturekapital förekommer, någonsin. Dina donationer går direkt till att stöda utvecklingen av projektet. Stort tack till följande personer:',
support_on_patreon: 'Stöd på Patreon',
general_sponsors:
'Allmänna sponsorer är dem som givit mellan 10 och 39\u00a0dollar till Lemmy.',
crypto: 'Kryptovaluta',
bitcoin: 'Bitcoin',
ethereum: 'Ethereum',
monero: 'Monero',
code: 'Kod',
joined: 'Gick med',
by: 'av',
to: 'till',
transfer_community: 'flytta gemenskap',
transfer_site: 'flytta webbplats',
are_you_sure: 'är du säker?',
yes: 'ja',
no: 'nej',
powered_by: 'Drivs av',
landing_0:
'Lemmy är en <1>länksamlare</1> och alternativ till reddit, ämnad att fungera i <2>Fediversumet</2>.<3></3>Lemmy kan drivas av vem som helst, har kommentarstrådar som updateras i realid och är mycket liten (<4>ca 80\u00a0kB</4>). Federering med ActivityPub-nätverket är planerat. <5></5>Detta är en <6>väldigt tidig betaversion</6> och många funktioner saknas därför eller är trasiga.<7></7>Föreslå nya funktioner eller anmäl buggar <8>här</8>.<9></9>Skapad i <10>Rust</10>, <11>Actix</11>, <12>Inferno</12> och <13>Typescript</13>.',
not_logged_in: 'Inte inloggad.',
community_ban: 'Du har blockerats från den här gemenskapen.',
site_ban: 'Du har blockerats från webbplatsen.',
couldnt_create_comment: 'Kunde inte skapa kommentar.',
couldnt_like_comment: 'Kunde inte gilla kommentar.',
couldnt_update_comment: 'Kunde inte uppdatera kommentar.',
couldnt_save_comment: 'Kunde inte spara kommentar.',
no_comment_edit_allowed: 'Har inte behörighet att redigera komentar.',
no_post_edit_allowed: 'Har inte behörighet att redigera inlägg.',
no_community_edit_allowed: 'Har inte behörighet att redigera gemenskap.',
couldnt_find_community: 'Kunde inte hitta gemenskap.',
couldnt_update_community: 'Kunde inte uppdatera gemenskap.',
community_already_exists: 'Gemenskapen finns redan.',
community_moderator_already_exists: 'Gemenskapsmoderatorn finns redan.',
community_follower_already_exists: 'Gemenskapsföljaren finns redan.',
community_user_already_banned: 'Gemenskapsanvändaren redan blockerad.',
couldnt_create_post: 'Kunde inte skapa inlägg.',
couldnt_like_post: 'Kunde inte gilla inlägg.',
couldnt_find_post: 'Kunde inte hitta inlägg.',
couldnt_get_posts: 'Kunde inte hämta inlägg.',
couldnt_update_post: 'Kunde inte uppdatera inlägg.',
couldnt_save_post: 'Kunde inte spara inlägg.',
no_slurs: 'Inga förolämpningar.',
not_an_admin: 'Inte en administratör.',
site_already_exists: 'Webbplatsen finns redan.',
couldnt_update_site: 'Kunde inte uppdatera webbplats.',
couldnt_find_that_username_or_email:
'Kunde inte hitta det användarnamnet eller e-postadressen.',
password_incorrect: 'Ogiltigt lösenord.',
passwords_dont_match: 'Lösenorden stämmer inte överens.',
admin_already_created: 'Beklagar, men det finns redan en administratör.',
user_already_exists: 'Användaren finns redan.',
couldnt_update_user: 'Kunde inte uppdatera användare.',
system_err_login: 'Systemfel. Försök att logga ut och sedan in igen.',
},
};

View file

@ -1,164 +0,0 @@
export const zh = {
translation: {
post: '帖子',
remove_post: '移除帖子',
no_posts: '没有帖子.',
create_a_post: '创建新帖子',
create_post: '创建帖子',
number_of_posts: '{{count}} 帖子',
posts: '帖子',
related_posts: '相关的帖子',
comments: '评论',
number_of_comments: '{{count}} 评论',
remove_comment: '移除评论',
communities: '节点',
create_a_community: '创建新节点',
create_community: '创建节点',
remove_community: '移除节点',
subscribed_to_communities: '订阅新 <1>节点</1>',
trending_communities: '<1>节点</1>趋势',
list_of_communities: '节点列表',
community_reqs: '包含小写与下划线且没有空格的字符串.',
edit: '编辑',
reply: '回应',
cancel: '取消',
unlock: '解锁',
lock: '加锁',
link: '链接',
mod: '监管人',
mods: '监管人',
moderates: '监管',
remove_as_mod: '添加监管人',
appoint_as_mod: '移除监管人',
modlog: '监管记录',
admin: '管理权限',
admins: '管理权限',
remove_as_admin: '移除管理权限',
appoint_as_admin: '添加管理权限',
remove: '移除',
removed: '已移除',
locked: '已加锁',
reason: '原因',
mark_as_read: '标记未读',
mark_as_unread: '标记已读',
delete: '删除',
deleted: '已删除',
restore: '恢复',
ban: '禁止',
ban_from_site: '禁止此站点',
unban: '取消',
unban_from_site: '取消禁止',
save: '保存',
unsave: '取消保存',
create: '创建',
username: '用户名',
email_or_username: '邮箱或用户名',
number_of_users: '{{count}} 用户',
number_of_subscribers: '{{count}} 订阅',
number_of_points: '{{count}} 分',
name: '名字',
title: '标题',
category: '分类',
subscribers: '订阅',
both: '全部',
saved: '保存',
unsubscribe: '取消订阅',
subscribe: '订阅',
subscribed: '已订阅',
prev: '上一页',
next: '下一页',
sidebar: '侧边栏',
sort_type: '排序方式',
hot: '最热',
new: '最新',
top_day: '今日',
week: '周',
month: '月',
year: '年',
all: '所有',
top: '最热',
api: '应用程式介面',
inbox: '收件箱',
inbox_for: '<1>{{user}}</1> 收件箱',
mark_all_as_read: '标记所有已读',
type: '类型',
unread: '未读',
reply_sent: '回复发送',
search: '搜索',
overview: '个人中心',
view: '查看',
logout: '注销',
login_sign_up: '登录/注册',
login: '登录',
sign_up: '注册',
notifications_error: '你的浏览器不支持桌面通知,尝试 Firefox 或 Chrome',
unread_messages: '未读消息',
password: '密码',
verify_password: '确认密码',
email: '邮箱',
optional: '选项',
expires: '过期',
url: '网址',
body: '内容',
copy_suggested_title: '复制建议的标题: {{title}}',
community: '节点',
expand_here: '展开',
subscribe_to_communities: '订阅一些 <1>节点</1>.',
chat: '聊天',
no_results: '没有结果.',
setup: '设置',
lemmy_instance_setup: 'Lemmy Instance Setup',
setup_admin: '设置管理员',
your_site: '你的站点',
modified: '修改',
sponsors: '发起人',
sponsors_of_lemmy: 'Lemmy 的发起人',
sponsor_message:
'Lemmy is free, <1>open-source</1> software, meaning no advertising, monetizing, or venture capital, ever. Your donations directly support full-time development of the project. Thank you to the following people:',
support_on_patreon: '在 Patreon 赞助',
support_on_liberapay: '在 on 赞助',
general_sponsors:
'General Sponsors are those that pledged $10 to $39 to Lemmy.',
crypto: '加密',
bitcoin: '比特币',
ethereum: '以太币',
code: '代码',
joined: '已加入',
powered_by: '保留所有权利',
landing_0:
"Lemmy is a <1>link aggregator</1> / reddit alternative, intended to work in the <2>fediverse</2>.<3></3>It's self-hostable, has live-updating comment threads, and is tiny (<4>~80kB</4>). Federation into the ActivityPub network is on the roadmap. <5></5>This is a <6>very early beta version</6>, and a lot of features are currently broken or missing. <7></7>Suggest new features or report bugs <8>here.</8><9></9>Made with <10>Rust</10>, <11>Actix</11>, <12>Inferno</12>, <13>Typescript</13>.",
not_logged_in: '未登录.',
community_ban: '你被此节点禁止.',
site_ban: '你被此站点禁止',
couldnt_create_comment: '不能创建评论.',
couldnt_like_comment: '不能收藏评论.',
couldnt_update_comment: '不能更新评论.',
couldnt_save_comment: '不能保存评论.',
no_comment_edit_allowed: '不允许编辑评论.',
no_post_edit_allowed: '不运行编辑帖子.',
no_community_edit_allowed: '不允许编辑节点.',
couldnt_find_community: '不能找到节点.',
couldnt_update_community: '不能更新节点.',
community_already_exists: '节点已存在.',
community_moderator_already_exists: '节点监管人已存在.',
community_follower_already_exists: '节点追随者已存在.',
community_user_already_banned: '节点用户已禁止.',
couldnt_create_post: '不能创建帖子.',
couldnt_like_post: '不能收藏帖子.',
couldnt_find_post: '不能搜寻帖子.',
couldnt_get_posts: '不能获取帖子',
couldnt_update_post: '不能更新帖子',
couldnt_save_post: '不能保持帖子.',
no_slurs: '和谐.',
not_an_admin: '不是管理员.',
site_already_exists: '站点已存在.',
couldnt_update_site: '不能更新站点.',
couldnt_find_that_username_or_email: '用户名/邮箱不存在.',
password_incorrect: '密码不正确.',
passwords_dont_match: '密码不匹配.',
admin_already_created: '抱歉,管理员已存在.',
user_already_exists: '用户已存在.',
couldnt_update_user: '不可以更新用户.',
system_err_login: '系统错误. 尝试注销再登录',
},
};

82
ui/src/utils.ts vendored
View file

@ -11,6 +11,7 @@ import 'moment/locale/fi';
import 'moment/locale/ca'; import 'moment/locale/ca';
import 'moment/locale/fa'; import 'moment/locale/fa';
import 'moment/locale/pt-br'; import 'moment/locale/pt-br';
import 'moment/locale/ja';
import { import {
UserOperation, UserOperation,
@ -40,9 +41,12 @@ import markdown_it_container from 'markdown-it-container';
import twemoji from 'twemoji'; import twemoji from 'twemoji';
import emojiShortName from 'emoji-short-name'; import emojiShortName from 'emoji-short-name';
import Toastify from 'toastify-js'; import Toastify from 'toastify-js';
import tippy from 'tippy.js';
export const repoUrl = 'https://github.com/dessalines/lemmy'; export const repoUrl = 'https://github.com/dessalines/lemmy';
export const markdownHelpUrl = '/docs/about_guide.html'; export const helpGuideUrl = '/docs/about_guide.html';
export const markdownHelpUrl = `${helpGuideUrl}#markdown-guide`;
export const sortingHelpUrl = `${helpGuideUrl}#sorting`;
export const archiveUrl = 'https://archive.is'; export const archiveUrl = 'https://archive.is';
export const postRefetchSeconds: number = 60 * 1000; export const postRefetchSeconds: number = 60 * 1000;
@ -159,10 +163,10 @@ export function isMod(modIds: Array<number>, creator_id: number): boolean {
return modIds.includes(creator_id); return modIds.includes(creator_id);
} }
var imageRegex = new RegExp( const imageRegex = new RegExp(
`(http)?s?:?(\/\/[^"']*\.(?:png|jpg|jpeg|gif|png|svg))` /(http)?s?:?(\/\/[^"']*\.(?:jpg|jpeg|gif|png|svg))/
); );
var videoRegex = new RegExp(`(http)?s?:?(\/\/[^"']*\.(?:mp4))`); const videoRegex = new RegExp(`(http)?s?:?(\/\/[^"']*\.(?:mp4))`);
export function isImage(url: string) { export function isImage(url: string) {
return imageRegex.test(url); return imageRegex.test(url);
@ -278,6 +282,7 @@ export const languages = [
{ code: 'es', name: 'Español' }, { code: 'es', name: 'Español' },
{ code: 'de', name: 'Deutsch' }, { code: 'de', name: 'Deutsch' },
{ code: 'fa', name: 'فارسی' }, { code: 'fa', name: 'فارسی' },
{ code: 'ja', name: '日本語' },
{ code: 'pt_BR', name: 'Português Brasileiro' }, { code: 'pt_BR', name: 'Português Brasileiro' },
{ code: 'zh', name: '中文' }, { code: 'zh', name: '中文' },
{ code: 'fi', name: 'Suomi' }, { code: 'fi', name: 'Suomi' },
@ -331,6 +336,8 @@ export function getMomentLanguage(): string {
lang = 'fa'; lang = 'fa';
} else if (lang.startsWith('pt')) { } else if (lang.startsWith('pt')) {
lang = 'pt-br'; lang = 'pt-br';
} else if (lang.startsWith('ja')) {
lang = 'ja';
} else { } else {
lang = 'en'; lang = 'en';
} }
@ -397,15 +404,22 @@ export function showAvatars(): boolean {
); );
} }
/// Converts to image thumbnail (only supports pictshare currently) // Converts to image thumbnail
export function imageThumbnailer(url: string): string { export function pictshareImage(
let split = url.split('pictshare'); hash: string,
if (split.length > 1) { thumbnail: boolean = false
let out = `${split[0]}pictshare/192${split[1]}`; ): string {
return out; let root = `/pictshare`;
} else {
return url; // Necessary for other servers / domains
if (hash.includes('pictshare')) {
let split = hash.split('/pictshare/');
root = `${split[0]}/pictshare`;
hash = split[1];
} }
let out = `${root}/${thumbnail ? '192/' : ''}${hash}`;
return out;
} }
export function isCommentType(item: Comment | PrivateMessage): item is Comment { export function isCommentType(item: Comment | PrivateMessage): item is Comment {
@ -441,6 +455,7 @@ export function setupTribute(): Tribute {
allowSpaces: false, allowSpaces: false,
autocompleteMode: true, autocompleteMode: true,
menuItemLimit: mentionDropdownFetchLimit, menuItemLimit: mentionDropdownFetchLimit,
menuShowMinLength: 2,
}, },
// Users // Users
{ {
@ -454,6 +469,7 @@ export function setupTribute(): Tribute {
allowSpaces: false, allowSpaces: false,
autocompleteMode: true, autocompleteMode: true,
menuItemLimit: mentionDropdownFetchLimit, menuItemLimit: mentionDropdownFetchLimit,
menuShowMinLength: 2,
}, },
// Communities // Communities
@ -468,11 +484,23 @@ export function setupTribute(): Tribute {
allowSpaces: false, allowSpaces: false,
autocompleteMode: true, autocompleteMode: true,
menuItemLimit: mentionDropdownFetchLimit, menuItemLimit: mentionDropdownFetchLimit,
menuShowMinLength: 2,
}, },
], ],
}); });
} }
let tippyInstance = tippy('[data-tippy-content]');
export function setupTippy() {
tippyInstance.forEach(e => e.destroy());
tippyInstance = tippy('[data-tippy-content]', {
delay: [500, 0],
// Display on "long press"
touch: ['hold', 500],
});
}
function userSearch(text: string, cb: any) { function userSearch(text: string, cb: any) {
if (text) { if (text) {
let form: SearchForm = { let form: SearchForm = {
@ -710,7 +738,11 @@ function convertCommentSortType(sort: SortType): CommentSortType {
} }
} }
export function postSort(posts: Array<Post>, sort: SortType) { export function postSort(
posts: Array<Post>,
sort: SortType,
communityType: boolean
) {
// First, put removed and deleted comments at the bottom, then do your other sorts // First, put removed and deleted comments at the bottom, then do your other sorts
if ( if (
sort == SortType.TopAll || sort == SortType.TopAll ||
@ -721,13 +753,17 @@ export function postSort(posts: Array<Post>, sort: SortType) {
) { ) {
posts.sort( posts.sort(
(a, b) => (a, b) =>
+a.removed - +b.removed || +a.deleted - +b.deleted || b.score - a.score +a.removed - +b.removed ||
+a.deleted - +b.deleted ||
(communityType && +b.stickied - +a.stickied) ||
b.score - a.score
); );
} else if (sort == SortType.New) { } else if (sort == SortType.New) {
posts.sort( posts.sort(
(a, b) => (a, b) =>
+a.removed - +b.removed || +a.removed - +b.removed ||
+a.deleted - +b.deleted || +a.deleted - +b.deleted ||
(communityType && +b.stickied - +a.stickied) ||
b.published.localeCompare(a.published) b.published.localeCompare(a.published)
); );
} else if (sort == SortType.Hot) { } else if (sort == SortType.Hot) {
@ -735,7 +771,25 @@ export function postSort(posts: Array<Post>, sort: SortType) {
(a, b) => (a, b) =>
+a.removed - +b.removed || +a.removed - +b.removed ||
+a.deleted - +b.deleted || +a.deleted - +b.deleted ||
(communityType && +b.stickied - +a.stickied) ||
hotRankPost(b) - hotRankPost(a) hotRankPost(b) - hotRankPost(a)
); );
} }
} }
export const colorList: Array<string> = [
hsl(0),
hsl(100),
hsl(150),
hsl(200),
hsl(250),
hsl(300),
];
function hsl(num: number) {
return `hsla(${num}, 35%, 50%, 1)`;
}
function randomHsl() {
return `hsla(${Math.random() * 360}, 100%, 50%, 1)`;
}

2
ui/src/version.ts vendored
View file

@ -1 +1 @@
export const version: string = 'v0.6.25'; export const version: string = 'v0.6.39';

View file

@ -1,62 +0,0 @@
import { en } from './src/translations/en';
import { eo } from './src/translations/eo';
import { es } from './src/translations/es';
import { de } from './src/translations/de';
import { fa } from './src/translations/fa';
import { zh } from './src/translations/zh';
import { fr } from './src/translations/fr';
import { sv } from './src/translations/sv';
import { ru } from './src/translations/ru';
import { nl } from './src/translations/nl';
import { it } from './src/translations/it';
import { fi } from './src/translations/fi';
import { ca } from './src/translations/ca';
import { pt_BR } from './src/translations/pt_br';
import fs from 'fs';
const files = [
{ t: ca, n: 'ca' },
{ t: de, n: 'de' },
{ t: fa, n: 'fa' },
{ t: eo, n: 'eo' },
{ t: es, n: 'es' },
{ t: fi, n: 'fi' },
{ t: fr, n: 'fr' },
{ t: it, n: 'it' },
{ t: nl, n: 'nl' },
{ t: pt_BR, n: 'pt-br' },
{ t: ru, n: 'ru' },
{ t: sv, n: 'sv' },
{ t: zh, n: 'zh' },
];
const masterKeys = Object.keys(en.translation);
const readmePath = '../README.md';
const open = '<!-- translations -->';
const close = '<!-- translationsstop -->';
const readmeTxt = fs.readFileSync(readmePath, { encoding: 'utf8' });
const before = readmeTxt.split(open)[0];
const after = readmeTxt.split(close)[1];
function difference(a: Array<string>, b: Array<string>): Array<string> {
return a.filter(x => !b.includes(x));
}
const report =
'lang | done | missing\n' +
'---- | ---- | -------\n' +
files
.map(file => {
const keys = Object.keys(file.t.translation);
const pct: number = (keys.length / masterKeys.length) * 100;
const missing = difference(masterKeys, keys);
return `${file.n} | ${pct.toFixed(0)}% | ${missing}`;
})
.join('\n');
const alteredReadmeTxt = `${before}${open}\n\n${report}\n${close}${after}`;
fs.writeFileSync(readmePath, alteredReadmeTxt);

180
ui/translations/ar.json vendored Normal file
View file

@ -0,0 +1,180 @@
{
"creator": "المؤلّف",
"username": "إسم المستخدم",
"post": "منشور",
"remove_post": "احذف المنشور",
"no_posts": "ليس هناك منشورات.",
"create_a_post": "أنشئ منشورا",
"create_post": "إنشاء منشور",
"posts": "منشورات",
"comments": "التعليقات",
"number_of_posts": "{{count}} منشورات",
"related_posts": "يمكن لهذه المنشورات أن تكون ذات صلة",
"communities": "المجتمعات",
"users": "المستخدِمون",
"create_community": "إنشاء مجتمع",
"remove_community": "حذف المجتمع",
"list_of_communities": "قائمة المجتمعات",
"send_secure_message": "ارسل الرسالة المؤمنة",
"send_message": "أرسل الرسالة",
"message": "رسالة",
"edit": "تعديل",
"reply": "رد",
"cancel": "إلغاء",
"preview": "معاينة",
"upload_image": "إرسال صورة",
"avatar": "الصورة الرمزية",
"show_avatars": "إظهار الصور الرمزية",
"view_source": "عرض المصدر",
"sticky": "تدبيس",
"unsticky": "فك التدبيس",
"link": "الرابط",
"mod": "مشرِف",
"moderates": "إشراف",
"settings": "الإعدادات",
"remove_as_mod": "إزالة كمُشرِف",
"appoint_as_mod": "تعيين كمُشرِف",
"admin": "مدير",
"admins": "المدراء",
"remove_as_admin": "إزالة كمدير",
"appoint_as_admin": "تعيين كمدير",
"remove": "إزالة",
"removed": "تمت إزالته",
"reason": "السبب",
"mark_as_read": "تعيين كمقروء",
"mark_as_unread": "تعيين كغير مقروء بعد",
"delete": "حذف",
"deleted": "تم حذفه",
"restore": "استعادة",
"ban": "طرد",
"ban_from_site": "طرده مِن الموقع",
"banned": "مطرود",
"save": "حفظ",
"number_of_users": "{{count}} مستخدِمين",
"number_of_points": "{{count}} نقاط",
"number_online": "{{count}} مستخدمين متّصلين",
"name": "الإسم",
"title": "العنوان",
"category": "الفئة",
"subscribers": "المتابِعون",
"both": "كلاهما",
"saved": "تم حفظه",
"subscribe": "اتبع",
"prev": "السابقة",
"next": "التالية",
"sidebar": "الشريط الجانبي",
"sort_type": "ترتيب حسب",
"hot": "المتداولة",
"new": "جديد",
"old": "قديم",
"month": "شهر",
"year": "سنة",
"all": "الكل",
"docs": "الدليل",
"type": "النوع",
"replies": "الإجابات",
"mentions": "الإشارات",
"message_sent": "تم إرسال الرسالة",
"search": "البحث",
"overview": "نظرة عامة",
"view": "اعرض",
"logout": "الخروج",
"login": "لِج",
"sign_up": "إنشاء حساب",
"messages": "لرسائل",
"password": "الكلمة السرية",
"verify_password": "تأكيد الكلمة السرية",
"forgot_password": "هل نسيت كلمتك السرية",
"new_password": "لكلمة السرية الجديدة",
"email": "البريد الإلكتروني",
"optional": "اختياري",
"community": "المجتمع",
"chat": "دردشة",
"recent_comments": "التعليقات الحديثة",
"no_results": "ليس هناك أية نتيجة.",
"setup": "التنصيب",
"your_site": "موقعك",
"modified": "تم تعديله",
"theme": "المظهر",
"donate_to_lemmy": "التبرّع إلى Lemmy",
"donate": "تبرع",
"joined": "عضو منذ",
"by": "مِن",
"to": "إلى",
"yes": "نعم",
"no": "لا",
"not_logged_in": "لستَ متصلا.",
"remove_comment": "احذف التعليق",
"create_a_community": "إنشاء مجتمع",
"create_private_message": "إنشاء رسالة خاصة",
"upload_avatar": "تحميل الصورة الرمزية",
"mods": "المُشرِفون",
"modlog": "تأريخ الإشراف",
"stickied": "تم تدبيسه",
"delete_account": "حذف الحساب",
"create": "إنشاء",
"email_or_username": "عنوان البريد أو اسم المستخدم",
"number_of_subscribers": "{{count}} مُتابِعين",
"unsubscribe": "إلغاء الإشتراك",
"week": "أسبوع",
"reply_sent": "تم إرسال الرد",
"login_sign_up": "لِج أو انشئ حسابا",
"old_password": "الكلمة السرية القديمة",
"matrix_user_id": "مستخدم ماتريكس",
"language": "اللغة",
"body": "المحتوى",
"setup_admin": "إنشاء مدير",
"are_you_sure": "هل أنت متأكّد؟",
"logged_in": "إنّك متّصل.",
"user_already_exists": "هذا المستخدِم موجود بالفعل.",
"number_of_communities": "{{count}} مجتمعات",
"subscribed": "مُتابِعون",
"url": "الرابط",
"nsfw": "محتوى حساس",
"couldnt_create_comment": "تعذّر إنشاءالتعليق.",
"site_ban": "لقد تم طردك مِن هذا الموقع",
"not_an_admin": "لستَ مديرا.",
"password_incorrect": "الكلمة السرية خاطئة.",
"passwords_dont_match": "الكلمات السرية غير متطابقة.",
"email_already_exists": "عنوان البريد الإلكتروني هذا موجود بالفعل.",
"time": "الساعة",
"more": "المزيد",
"community_ban": "لقد تم طردك مِن هذا المجتمع.",
"action": "الإجراء",
"expires": "تنتهي صلاحيته في",
"support_on_patreon": "ساندنا على Patreon",
"support_on_liberapay": "ساندنا عبر Liberapay",
"crypto": "العملات الرقمية",
"number_of_comments": "{{count}} تعليقات",
"cross_posts": "لقد تم نشر هذا الرابط كذلك على:",
"cross_post": "منشور نُشِر تبادليا",
"cross_posted_to": "نشر تبادلي إلى: ",
"trending_communities": "<1>المجتمعات</1> الشائعة",
"unlock": "إلغاء الحظر",
"lock": "حظر",
"archive_link": "أرشفة الرابط",
"locked": "محظور",
"unban": "إلغاء الطرد",
"unban_from_site": "إلغاء الطرد مِن الموقع",
"unsave": "إزالة",
"top": "المتداولة",
"api": "API",
"inbox": "صندوق الوارد",
"mark_all_as_read": "تعيين الكل كمقروء",
"unread": "غير مقروء",
"unread_messages": "الرسائل غير المقروءة",
"password_change": "تعديل الكلمة السرية",
"no_email_setup": "لم يتم إعداد البريد الإلكتروني في هذا الخادم بشكل جيد.",
"send_notifications_to_email": "إرسال الإشعارات عبر البريد الإلكتروني",
"browser_default": "افتراضي للمتصفح",
"downvotes_disabled": "تم تعطيل التصويتات السلبية",
"enable_downvotes": "تم تفعيل التصويتات الإيجابية",
"open_registration": "السماح بإنشاء الحسابات",
"registration_closed": "إنشاء الحسابات معطل",
"enable_nsfw": "تنشيط المحتوى الحساس",
"expand_here": "وسّعه مِن هنا",
"lemmy_instance_setup": "تنصيب مثيل خادم Lemmy",
"show_nsfw": "إظهار المحتوى الحساس",
"sponsors": "الرعاة",
"sponsors_of_lemmy": "رعاة مشروع Lemmy"
}

237
ui/translations/ca.json vendored Normal file
View file

@ -0,0 +1,237 @@
{
"post": "Publicar",
"remove_post": "Eliminar publicació",
"no_posts": "Sense publicacions.",
"create_a_post": "Crear una publicació",
"create_post": "Crear Publicació",
"number_of_posts": "{{count}} Publicacions",
"posts": "Publicacions",
"related_posts": "Aquestes publicacions podrien estar relacionades",
"cross_posts": "Aquest link també ha sigut publicat en:",
"cross_post": "cross-post",
"comments": "Comentaris",
"number_of_comments": "{{count}} Comentaris",
"remove_comment": "Eliminar Comentaris",
"communities": "Comunitats",
"users": "Usuaris",
"create_a_community": "Crear una comunitat",
"create_community": "Crear Comunitat",
"remove_community": "Eliminar Comunitat",
"subscribed_to_communities": "Subscrit a <1>comunitats</1>",
"trending_communities": "<1>Comunitats</1> en tendència",
"list_of_communities": "Llista de comunitats",
"number_of_communities": "{{count}} Comunitats",
"community_reqs": "minúscules, guió baix, i sense espais.",
"create_private_message": "Crear Missatge Privat",
"send_secure_message": "Enviar Missatge Segur",
"send_message": "Enviar Missatge",
"message": "Missatge",
"edit": "editar",
"reply": "respondre",
"cancel": "Cancelar",
"preview": "Previsualitzar",
"upload_image": "pujar imatge",
"avatar": "Avatar",
"upload_avatar": "Pujar Avatar",
"show_avatars": "Veure Avatares",
"formatting_help": "Ajuda de format",
"view_source": "veure font",
"unlock": "desbloquejar",
"lock": "bloquejar",
"sticky": "fijat",
"unsticky": "no fijat",
"link": "link",
"archive_link": "arxivar link",
"mod": "moderador",
"mods": "moderadores",
"moderates": "Modera",
"settings": "Configuració",
"remove_as_mod": "eliminar com moderador",
"appoint_as_mod": "designar com moderador",
"modlog": "Historial de moderació",
"admin": "administrador",
"admins": "administradors",
"remove_as_admin": "eliminar com administrador",
"appoint_as_admin": "designar com administrador",
"remove": "eliminar",
"removed": "eliminat",
"locked": "bloquejat",
"stickied": "fijat",
"reason": "Raó",
"mark_as_read": "marcar com llegit",
"mark_as_unread": "marcar com no llegit",
"delete": "eliminar",
"deleted": "eliminat",
"delete_account": "Eliminar Compte",
"delete_account_confirm":
"Avís: aquesta acció eliminarà permanentment la teva informació. Introdueix la teva contrasenya per a continuar",
"restore": "restaurar",
"ban": "expulsar",
"ban_from_site": "expulsar del lloc",
"unban": "admetre",
"unban_from_site": "admetre al lloc",
"banned": "expulsat",
"save": "guardar",
"unsave": "descartar",
"create": "crear",
"creator": "creador",
"username": "Nom d'Usuari",
"email_or_username": "Correu o Usuari",
"number_of_users": "{{count}} Usuaris",
"number_of_subscribers": "{{count}} Subscriptors",
"number_of_points": "{{count}} Punts",
"number_online": "{{count}} Usauris En Línia",
"name": "Nom",
"title": "Titol",
"category": "Categoria",
"subscribers": "Suscriptors",
"both": "Ambdos",
"saved": "Guardat",
"unsubscribe": "Desubscriure's",
"subscribe": "Subscriure's",
"subscribed": "Subscrit",
"prev": "Anterior",
"next": "Següent",
"sidebar": "Descripció de la comunitat",
"sort_type": "Tipus d'orden",
"hot": "Popular",
"new": "Nou",
"top_day": "El millor del dia",
"week": "Setmana",
"month": "Mes",
"year": "Any",
"all": "Tot",
"top": "Millor",
"api": "API",
"docs": "Docs",
"inbox": "Bústia d'entrada",
"inbox_for": "Bústia d'entrada per a <1>{{user}}</1>",
"mark_all_as_read": "marcar tot com llegit",
"type": "Tipus",
"unread": "No llegit",
"replies": "Respostes",
"mentions": "Menciones",
"reply_sent": "Resposta enviada",
"message_sent": "Missatge enviado",
"search": "Buscar",
"overview": "Resum",
"view": "Vista",
"logout": "Tancar sessió",
"login_sign_up": "Iniciar sessió / Crear compte",
"login": "Iniciar sessió",
"sign_up": "Crear compte",
"notifications_error":
"Notificacions d'escriptori no disponibles al teu navegador. Prova amb Firefox o Chrome.",
"unread_messages": "Missatges no llegits",
"messages": "Missatges",
"password": "Contrasenya",
"verify_password": "Verificar Contrasenya",
"old_password": "Antiga Contrasenya",
"forgot_password": "oblidí la meva contrasenya",
"reset_password_mail_sent": "Enviar correu per a restablir la contrasenya.",
"password_change": "Canvi de Contrasenya",
"new_password": "Nueva Contrasenya",
"no_email_setup": "Aquest servidor no ha activat correctament el correu.",
"email": "Correu electrònic",
"matrix_user_id": "Usuari Matricial",
"private_message_disclaimer":
"Avís: Els missatges privats en Lemmy no són segurs. Sisplau creu un compte en <1>Riot.im</1> per a mensajeria segura.",
"send_notifications_to_email": "Enviar notificacions al correu",
"optional": "Opcional",
"expires": "Expira",
"language": "Llenguatge",
"browser_default": "Per defecte del navegador",
"downvotes_disabled": "Vots negatius deshabilitats",
"enable_downvotes": "Habilitar vots negatius",
"open_registration": "Obrir registre",
"registration_closed": "Registre tancat",
"enable_nsfw": "Habilitar NSFW",
"url": "URL",
"body": "Descripció",
"copy_suggested_title": "Copiar el títol sugerido: {{title}}",
"community": "Comunitat",
"expand_here": "Expandir ací",
"subscribe_to_communities": "Subscriure's a algunes <1>comunitats</1>.",
"chat": "Chat",
"recent_comments": "Comentaris recients",
"no_results": "Sense resultats.",
"setup": "Configurar",
"lemmy_instance_setup": "Configuració d'instancia de Lemmy",
"setup_admin": "Configurar administrador del Lloc",
"your_site": "el teu lloc",
"modified": "modificat",
"nsfw": "NSFW",
"show_nsfw": "Mostrar contingut NSFW",
"theme": "Tema",
"sponsors": "Patrocinadors",
"sponsors_of_lemmy": "Patrocinadors de Lemmy",
"sponsor_message":
"Lemmy és programari lliure i de <1>codi obert</1>, la qual cosa significa que no tindrà publicitats, monetització, ni capitals emprenedors, mai. Les teves donacions secunden directament el desenvolupament a temps complet del projecte. Moltes gràcies a les següents persones:",
"support_on_patreon": "Suport a Patreon",
"donate_to_lemmy": "Donar a Lemmy",
"donate": "Donar",
"general_sponsors":
"Los Patrocinadores Generales son aquellos que señaron entre $10 y $39 a Lemmy.",
"crypto": "Crypto",
"bitcoin": "Bitcoin",
"ethereum": "Ethereum",
"monero": "Monero",
"code": "Codi",
"joined": "Es va unir",
"by": "per",
"to": "a",
"from": "des de",
"transfer_community": "transferir comunitat",
"transfer_site": "transferir lloc",
"are_you_sure": "Ets segur?",
"yes": "sí",
"no": "no",
"powered_by": "Impulsat per",
"landing_0":
"Lemmy és un <1>agregador de links</1> / alternativa a reddit, amb la intenció de funcionar al <2>fedivers</2>.<3></3>És allotjable per un mateix (sense necessitat de grans companyies), té actualització en directe de cadenes de comentaris, i és petit (<4>~80kB</4>). Federar amb el sistema de xarxes ActivityPub forma part dels objectius del projecte. <5></5>Aquesta és una <6>versió beta molt prematura</6>, i actualment moltes de les característiques són trencades o falten. <7></7>Suggereix noves característiques o reporta errors <8>aquí</8>.<9></9>Fet amb <10>Rust</10>, <11>Actix</11>, <12>Inferno</12>, <13>Typescript</13>.",
"not_logged_in": "No has iniciat sessió.",
"logged_in": "Has iniciat sessió.",
"community_ban": "Has sigut expulsat d'aquesta comunitat.",
"site_ban": "Has sigut expulsat d'aquest lloc.",
"couldnt_create_comment": "No s'ha pogut crear el comentari.",
"couldnt_like_comment": "No s'ha pogut donar m'agrada al comentari.",
"couldnt_update_comment": "No s'ha pogut actualitzar el comentari.",
"couldnt_save_comment": "No s'ha pogut guardar el comentari.",
"no_comment_edit_allowed": "No tens permisos per a editar el comentari.",
"no_post_edit_allowed": "No tens permisos per a editar la publicació.",
"no_community_edit_allowed": "No tens permisos per a editar la comunitat.",
"couldnt_find_community": "No s'ha pogut trobar la comunitat.",
"couldnt_update_community": "No s'ha pogut actualitzar la comunitat.",
"community_already_exists": "Aquesta comunitat ja existeix.",
"community_moderator_already_exists":
"Aquest moderador de la comunitat ja existeix.",
"community_follower_already_exists":
"Aquest seguidor de la comunitat ja existeix.",
"community_user_already_banned":
"Aquest usuari de la comunitat ja fou expulsat.",
"couldnt_create_post": "No s'ha pogut crear la publicació.",
"couldnt_like_post": "No s'ha pogut donar m'agrada a la publicació.",
"couldnt_find_post": "No s'ha pogut trobar la publicació.",
"couldnt_get_posts": "No s'han pogut obtindre les publicacions.",
"couldnt_update_post": "No s'ha pogut actualitzar la publicació.",
"couldnt_save_post": "No s'ha pogut guardar la publicació.",
"no_slurs": "Prohibit insultar.",
"not_an_admin": "No és un administrador.",
"site_already_exists": "El lloc ja existeix.",
"couldnt_update_site": "No s'ha pogut actualitzar el lloc.",
"couldnt_find_that_username_or_email":
"No s'ha pogut trobar aquest nom de usuari o correu electrònic.",
"password_incorrect": "Contrasenya incorrecta.",
"passwords_dont_match": "Les contrasenyes no coincideixen.",
"admin_already_created": "Ho sentim, ja hi ha un adminisitrador.",
"user_already_exists": "L'usuari ja existeix.",
"email_already_exists": "El correu ja és en ús.",
"couldnt_update_user": "No s'ha pogut actualitzar l'usuari.",
"system_err_login":
"Error del sistema. Intenti tancar sessió i ingressar de nou.",
"couldnt_create_private_message": "No s'ha pogut crear el missatge privat.",
"no_private_message_edit_allowed":
"Sense permisos per a editar el missatge privat.",
"couldnt_update_private_message":
"No s'ha pogut actualitzar el missatge privat."
}

239
ui/translations/de.json vendored Normal file
View file

@ -0,0 +1,239 @@
{
"post": "post",
"remove_post": "Beitrag löschen",
"no_posts": "Keine Beiträge.",
"create_a_post": "Einen Beitrag anlegen",
"create_post": "Beitrag anlegen",
"number_of_posts": "{{count}} Beitrag",
"number_of_posts_plural": "{{count}} Beiträge",
"posts": "Beiträge",
"related_posts": "Diese Beiträge könnten verwandt sein",
"cross_posts": "Dieser Link wurde auch veröffentlicht unter:",
"cross_post": "Crosspost",
"comments": "Kommentare",
"number_of_comments": "{{count}} Kommentar",
"number_of_comments_plural": "{{count}} Kommentare",
"remove_comment": "Kommentar löschen",
"communities": "Communities",
"users": "Benutzer",
"create_a_community": "Eine Gemeinschaft anlegen",
"create_community": "Gemeinschaft anlegen",
"remove_community": "Gemeinschaft entfernen",
"subscribed_to_communities": "Abonnierte <1>communities</1>",
"trending_communities": "Trending <1>communities</1>",
"list_of_communities": "Liste von communities",
"number_of_communities": "{{count}} Community",
"number_of_communities_plural": "{{count}} Communities",
"community_reqs": "Kleinbuchstaben, Großbuchstaben und keine Leerzeichen.",
"edit": "editieren",
"reply": "antworten",
"cancel": "Abbrechen",
"preview": "Vorschau",
"upload_image": "Bild hochladen",
"formatting_help": "Formatierungshilfe",
"view_source": "Quelle anzeigen",
"unlock": "entsperren",
"lock": "sperren",
"sticky": "haftend",
"unsticky": "nicht haftend",
"link": "link",
"archive_link": "Archiv-Link",
"mod": "Moderator",
"mods": "Moderatoren",
"moderates": "Moderiert",
"settings": "Einstellungen",
"remove_as_mod": "Als Moderator entfernen",
"appoint_as_mod": "Zum Moderator ernennen",
"modlog": "Modlog",
"admin": "Administrator",
"admins": "Administratoren",
"remove_as_admin": "Als Administrator entfernen",
"appoint_as_admin": "Zum Administrator ernennen",
"remove": "entfernen",
"removed": "entfernt",
"locked": "gesperrt",
"stickied": "angeheftet",
"reason": "Grund",
"mark_as_read": "als gelesen markieren",
"mark_as_unread": "als ungelesen markieren",
"delete": "löschen",
"deleted": "gelöscht",
"delete_account": "Konto löschen",
"delete_account_confirm": "Achtung: Dadurch werden alle Ihre Daten dauerhaft gelöscht. Geben Sie zur Bestätigung Ihr Passwort ein.",
"restore": "wiederherstellen",
"ban": "bannen",
"ban_from_site": "Von der Seite bannen",
"unban": "entbannen",
"unban_from_site": "Von der Seite entbannen",
"banned": "gesperrt",
"save": "speichern",
"unsave": "nicht speichern",
"create": "anlegen",
"creator": "Ersteller",
"username": "Benutzername",
"email_or_username": "E-mail oder Username",
"number_of_users": "{{count}} Benutzer",
"number_of_users_plural": "{{count}} Benutzer",
"number_of_subscribers": "{{count}} Abonnent",
"number_of_subscribers_plural": "{{count}} Abonnenten",
"number_of_points": "{{count}} Punkt",
"number_of_points_plural": "{{count}} Punkte",
"number_online": "{{count}} Benutzer online",
"number_online_plural": "{{count}} Benutzer online",
"name": "Name",
"title": "Titel",
"category": "Kategorie",
"subscribers": "Abonnenten",
"both": "Beide",
"saved": "Gespeichert",
"unsubscribe": "Abbestellen",
"subscribe": "Abonnieren",
"subscribed": "Abonniert",
"prev": "Zurück",
"next": "Weiter",
"sidebar": "Seitenleiste",
"sort_type": "Sortieren nach",
"hot": "Hot",
"new": "Neu",
"top_day": "Top täglich",
"week": "Woche",
"month": "Monat",
"year": "Jahr",
"all": "Alle",
"top": "Top",
"api": "API",
"inbox": "Posteingang",
"inbox_for": "Posteingang für <1>{{user}}</1>",
"mark_all_as_read": "Alle als gelesen markieren",
"type": "Typ",
"unread": "Ungelesen",
"replies": "Antworten",
"mentions": "Erwähnung",
"reply_sent": "Antwort gesendet",
"search": "Suchen",
"overview": "Übersicht",
"view": "Ansicht",
"logout": "Ausloggen",
"login_sign_up": "Einloggen / Registrieren",
"notifications_error": "Desktop-Benachrichtigungen sind in deinem browser nicht verfügbar. Versuche Firefox oder Chrome.",
"unread_messages": "Ungelesene Nachrichten",
"password": "Passwort",
"verify_password": "Passwort überprüfen",
"forgot_password": "Passwort vergessen",
"reset_password_mail_sent": "Eine E-Mail wurde geschickt, um dein Passwort zurückzusetzen.",
"password_change": "Passwort geändert",
"new_password": "neues Passwort",
"no_email_setup": "Dieser Server hat E-Mails nicht korrekt eingerichtet.",
"login": "Einloggen",
"sign_up": "Registrieren",
"email": "E-Mail",
"optional": "optional",
"expires": "Ablaufdatum",
"language": "Sprache",
"browser_default": "Standard-Browser",
"url": "URL",
"body": "Text",
"copy_suggested_title": "Vorgeschlagenen Titel übernehmen: {{title}}",
"community": "Gemeinschaft",
"expand_here": "hier erweitern",
"subscribe_to_communities": "Abonniere ein paar <1>communities</1>.",
"chat": "Chat",
"recent_comments": "Neueste Kommentare",
"no_results": "Keine Ergebnisse.",
"setup": "Einrichten",
"lemmy_instance_setup": "Lemmy Instanz Einrichten",
"setup_admin": "Seiten Administrator konfigurieren",
"your_site": "deine Seite",
"modified": "verändert",
"nsfw": "NSFW",
"show_nsfw": "NSFW-Inhalte anzeigen",
"theme": "Aussehen",
"sponsors": "Sponsoren",
"sponsors_of_lemmy": "Sponsoren von Lemmy",
"sponsor_message": "Lemmy ist freie <1>Open-Source</1> Software, also ohne Werbung, Monetarisierung oder Venturekapital, Punkt. Deine Spenden gehen direkt an die Vollzeit Entwicklung des Projekts. Vielen Dank an die folgenden Personen:",
"support_on_patreon": "Auf Patreon unterstützen",
"support_on_liberapay": "Auf Liberapay unterstützen",
"general_sponsors": "Allgemeine Sponsoren sind die, die zwischen $10 und $39 zu Lemmy beitragen.",
"crypto": "Kryptowährung",
"bitcoin": "Bitcoin",
"ethereum": "Ethereum",
"monero": "Monero",
"code": "Code",
"joined": "beigetreten",
"by": "von",
"to": "bis",
"transfer_community": "Gemeinschaft übertragen",
"transfer_site": "Transferseite",
"are_you_sure": "Bist du sicher?",
"yes": "Ja",
"no": "Nein",
"powered_by": "Bereitgestellt durch",
"landing_0": "Lemmy ist ein <1>Link-Aggregator</1> / Reddit Alternative im <2>Fediverse</2>.<3></3>Es ist selbst-hostbar, hat live-updates von Kommentar-threads und ist winzig (<4>~80kB</4>). Federation in das ActivityPub Netzwerk ist geplant. <5></5>Dies ist eine <6>sehr frühe Beta Version</6>, und viele Features funktionieren zurzeit nicht richtig oder fehlen. <7></7>Schlage neue Features vor oder melde Bugs <8>hier.</8><9></9>Gebaut mit <10>Rust</10>, <11>Actix</11>, <12>Inferno</12>, <13>Typescript</13>.",
"not_logged_in": "Nicht eingeloggt.",
"community_ban": "Du wurdest von dieser Gemeinschaft gebannt.",
"site_ban": "Du wurdest von dieser Seite gebannt",
"couldnt_create_comment": "Konnte Kommentar nicht anlegen.",
"couldnt_like_comment": "Konnte nicht liken.",
"couldnt_update_comment": "Konnte Kommentar nicht aktualisieren.",
"couldnt_save_comment": "Konnte Kommentar nicht speichern.",
"no_comment_edit_allowed": "Keine Erlaubnis Kommentar zu editieren.",
"no_post_edit_allowed": "Keine Erlaubnis Beitrag zu editieren.",
"no_community_edit_allowed": "Keine Erlaubnis Gemeinschaft zu editieren.",
"couldnt_find_community": "Konnte Gemeinschaft nicht finden.",
"couldnt_update_community": "Konnte Gemeinschaft nicht aktualisieren.",
"community_already_exists": "Gemeinschaft existiert bereits.",
"community_moderator_already_exists": "Gemeinschaft Moderator existiert bereits.",
"community_follower_already_exists": "Gemeinschaft Follower existiert bereits.",
"community_user_already_banned": "Gemeinschaft Nutzer schon gebannt.",
"couldnt_create_post": "Konnte Beitrag nicht anlegen.",
"couldnt_like_post": "Konnte Beitrag nicht liken.",
"couldnt_find_post": "Konnte Beitrag nicht finden.",
"couldnt_get_posts": "Konnte Beiträge nicht holen.",
"couldnt_update_post": "Konnte Beitrag nicht aktualisieren.",
"couldnt_save_post": "Konnte Beitrag nicht speichern.",
"no_slurs": "Keine Beleidigungen.",
"not_an_admin": "Kein Administrator.",
"site_already_exists": "Seite existiert bereits.",
"couldnt_update_site": "Konnte Seite nicht aktualisieren.",
"couldnt_find_that_username_or_email": "Konnte Username oder E-Mail nicht finden.",
"password_incorrect": "Passwort falsch.",
"passwords_dont_match": "Passwörter stimmen nicht überein.",
"admin_already_created": "Entschuldigung, es gibt schon einen Administrator.",
"user_already_exists": "Nutzer existiert bereits.",
"couldnt_update_user": "Konnte Nutzer nicht aktualisieren",
"system_err_login": "Systemfehler. Versuche dich aus- und wieder einzuloggen.",
"cross_posted_to": "Crossposted auf: ",
"create_private_message": "Privatnachricht erstellen",
"send_secure_message": "Sichere Nachricht absenden",
"send_message": "Nachricht absenden",
"message": "Nachricht",
"avatar": "Avatar",
"upload_avatar": "Avatar hochladen",
"show_avatars": "Avatare anzeigen",
"old": "Alt",
"docs": "Dokumentation",
"message_sent": "Nachricht versandt",
"messages": "Nachrichten",
"old_password": "Letztes Passwort",
"matrix_user_id": "Matrix Benutzer",
"private_message_disclaimer": "Achtung: Private Nachrichten sind in Lemmy nicht sicher. Bitte erstelle einen <1>Riot.im</1> Account für sicheren Nachrichtenverkehr.",
"send_notifications_to_email": "Sende Benachrichtigungen per Email",
"downvotes_disabled": "Downvotes deaktiviert",
"enable_downvotes": "Aktiviere Downvotes",
"open_registration": "Registrierung öffnen",
"registration_closed": "Registrierung geschlossen",
"enable_nsfw": "NSFW Erlauben",
"donate_to_lemmy": "Lemmy spenden",
"donate": "Spenden",
"from": "von",
"logged_in": "Eingeloggt",
"couldnt_get_comments": "Konnte Kommentare nicht laden.",
"post_title_too_long": "Posttitel zu lang.",
"email_already_exists": "Email existiert bereits.",
"couldnt_create_private_message": "Konnte Privatnachricht nicht erstelllen.",
"no_private_message_edit_allowed": "Editieren der Privatnachricht nicht erlaubt.",
"couldnt_update_private_message": "Konnte Privatnachricht nicht aktualisieren.",
"time": "Zeit",
"action": "Aktion",
"more": "mehr"
}

250
ui/translations/en.json vendored Normal file
View file

@ -0,0 +1,250 @@
{
"post": "post",
"remove_post": "Remove Post",
"no_posts": "No Posts.",
"create_a_post": "Create a post",
"create_post": "Create Post",
"number_of_posts": "{{count}} Post",
"number_of_posts_plural": "{{count}} Posts",
"posts": "Posts",
"related_posts": "These posts might be related",
"cross_posts": "This link has also been posted to:",
"cross_post": "cross-post",
"cross_posted_to": "cross-posted to: ",
"comments": "Comments",
"number_of_comments": "{{count}} Comment",
"number_of_comments_plural": "{{count}} Comments",
"remove_comment": "Remove Comment",
"communities": "Communities",
"users": "Users",
"create_a_community": "Create a community",
"create_community": "Create Community",
"remove_community": "Remove Community",
"subscribed_to_communities": "Subscribed to <1>communities</1>",
"trending_communities": "Trending <1>communities</1>",
"list_of_communities": "List of communities",
"number_of_communities": "{{count}} Community",
"number_of_communities_plural": "{{count}} Communities",
"community_reqs": "lowercase, underscores, and no spaces.",
"create_private_message": "Create Private Message",
"send_secure_message": "Send Secure Message",
"send_message": "Send Message",
"message": "Message",
"edit": "edit",
"reply": "reply",
"more": "more",
"cancel": "Cancel",
"preview": "Preview",
"upload_image": "upload image",
"avatar": "Avatar",
"upload_avatar": "Upload Avatar",
"show_avatars": "Show Avatars",
"formatting_help": "formatting help",
"sorting_help": "sorting help",
"view_source": "view source",
"unlock": "unlock",
"lock": "lock",
"sticky": "sticky",
"unsticky": "unsticky",
"link": "link",
"archive_link": "archive link",
"mod": "mod",
"mods": "mods",
"moderates": "Moderates",
"settings": "Settings",
"remove_as_mod": "remove as mod",
"appoint_as_mod": "appoint as mod",
"modlog": "Modlog",
"admin": "admin",
"admins": "admins",
"remove_as_admin": "remove as admin",
"appoint_as_admin": "appoint as admin",
"remove": "remove",
"removed": "removed",
"locked": "locked",
"stickied": "stickied",
"reason": "Reason",
"mark_as_read": "mark as read",
"mark_as_unread": "mark as unread",
"delete": "delete",
"deleted": "deleted",
"delete_account": "Delete Account",
"delete_account_confirm":
"Warning: this will permanently delete all your data. Enter your password to confirm.",
"restore": "restore",
"ban": "ban",
"ban_from_site": "ban from site",
"unban": "unban",
"unban_from_site": "unban from site",
"banned": "banned",
"save": "save",
"unsave": "unsave",
"create": "create",
"creator": "creator",
"username": "Username",
"email_or_username": "Email or Username",
"number_of_users": "{{count}} User",
"number_of_users_plural": "{{count}} Users",
"number_of_subscribers": "{{count}} Subscriber",
"number_of_subscribers_plural": "{{count}} Subscribers",
"number_of_points": "{{count}} Point",
"number_of_points_plural": "{{count}} Points",
"number_online": "{{count}} User Online",
"number_online_plural": "{{count}} Users Online",
"name": "Name",
"title": "Title",
"category": "Category",
"subscribers": "Subscribers",
"both": "Both",
"saved": "Saved",
"unsubscribe": "Unsubscribe",
"subscribe": "Subscribe",
"subscribed": "Subscribed",
"prev": "Prev",
"next": "Next",
"sidebar": "Sidebar",
"sort_type": "Sort type",
"hot": "Hot",
"new": "New",
"old": "Old",
"top_day": "Top day",
"week": "Week",
"month": "Month",
"year": "Year",
"all": "All",
"top": "Top",
"api": "API",
"docs": "Docs",
"inbox": "Inbox",
"inbox_for": "Inbox for <1>{{user}}</1>",
"mark_all_as_read": "mark all as read",
"type": "Type",
"unread": "Unread",
"replies": "Replies",
"mentions": "Mentions",
"reply_sent": "Reply sent",
"message_sent": "Message sent",
"search": "Search",
"overview": "Overview",
"view": "View",
"logout": "Logout",
"login_sign_up": "Login / Sign up",
"login": "Login",
"sign_up": "Sign Up",
"notifications_error":
"Desktop notifications not available in your browser. Try Firefox or Chrome.",
"unread_messages": "Unread Messages",
"messages": "Messages",
"password": "Password",
"verify_password": "Verify Password",
"old_password": "Old Password",
"forgot_password": "forgot password",
"reset_password_mail_sent": "Sent an Email to reset your password.",
"password_change": "Password Change",
"new_password": "New Password",
"no_email_setup": "This server hasn't correctly set up email.",
"email": "Email",
"matrix_user_id": "Matrix User",
"private_message_disclaimer":
"Warning: Private messages in Lemmy are not secure. Please create an account on <1>Riot.im</1> for secure messaging.",
"send_notifications_to_email": "Send notifications to Email",
"optional": "Optional",
"expires": "Expires",
"language": "Language",
"browser_default": "Browser Default",
"downvotes_disabled": "Downvotes disabled",
"enable_downvotes": "Enable Downvotes",
"upvote": "Upvote",
"downvote": "Downvote",
"open_registration": "Open Registration",
"registration_closed": "Registration closed",
"enable_nsfw": "Enable NSFW",
"url": "URL",
"body": "Body",
"copy_suggested_title": "copy suggested title: {{title}}",
"community": "Community",
"expand_here": "Expand here",
"subscribe_to_communities": "Subscribe to some <1>communities</1>.",
"chat": "Chat",
"recent_comments": "Recent Comments",
"no_results": "No results.",
"setup": "Setup",
"lemmy_instance_setup": "Lemmy Instance Setup",
"setup_admin": "Set Up Site Administrator",
"your_site": "your site",
"modified": "modified",
"nsfw": "NSFW",
"show_nsfw": "Show NSFW content",
"theme": "Theme",
"sponsors": "Sponsors",
"sponsors_of_lemmy": "Sponsors of Lemmy",
"sponsor_message":
"Lemmy is free, <1>open-source</1> software, meaning no advertising, monetizing, or venture capital, ever. Your donations directly support full-time development of the project. Thank you to the following people:",
"support_on_patreon": "Support on Patreon",
"support_on_liberapay": "Support on Liberapay",
"donate_to_lemmy": "Donate to Lemmy",
"donate": "Donate",
"general_sponsors":
"General Sponsors are those that pledged $10 to $39 to Lemmy.",
"crypto": "Crypto",
"bitcoin": "Bitcoin",
"ethereum": "Ethereum",
"monero": "Monero",
"code": "Code",
"joined": "Joined",
"by": "by",
"to": "to",
"from": "from",
"transfer_community": "transfer community",
"transfer_site": "transfer site",
"are_you_sure": "are you sure?",
"yes": "yes",
"no": "no",
"powered_by": "Powered by",
"landing_0":
"Lemmy is a <1>link aggregator</1> / reddit alternative, intended to work in the <2>fediverse</2>.<3></3>It's self-hostable, has live-updating comment threads, and is tiny (<4>~80kB</4>). Federation into the ActivityPub network is on the roadmap. <5></5>This is a <6>very early beta version</6>, and a lot of features are currently broken or missing. <7></7>Suggest new features or report bugs <8>here.</8><9></9>Made with <10>Rust</10>, <11>Actix</11>, <12>Inferno</12>, <13>Typescript</13>.",
"not_logged_in": "Not logged in.",
"logged_in": "Logged in.",
"community_ban": "You have been banned from this community.",
"site_ban": "You have been banned from the site",
"couldnt_create_comment": "Couldn't create comment.",
"couldnt_like_comment": "Couldn't like comment.",
"couldnt_update_comment": "Couldn't update comment.",
"couldnt_save_comment": "Couldn't save comment.",
"couldnt_get_comments": "Couldn't get comments.",
"no_comment_edit_allowed": "Not allowed to edit comment.",
"no_post_edit_allowed": "Not allowed to edit post.",
"no_community_edit_allowed": "Not allowed to edit community.",
"couldnt_find_community": "Couldn't find community.",
"couldnt_update_community": "Couldn't update Community.",
"community_already_exists": "Community already exists.",
"community_moderator_already_exists": "Community moderator already exists.",
"community_follower_already_exists": "Community follower already exists.",
"community_user_already_banned": "Community user already banned.",
"couldnt_create_post": "Couldn't create post.",
"post_title_too_long": "Post title too long.",
"couldnt_like_post": "Couldn't like post.",
"couldnt_find_post": "Couldn't find post.",
"couldnt_get_posts": "Couldn't get posts",
"couldnt_update_post": "Couldn't update post",
"couldnt_save_post": "Couldn't save post.",
"no_slurs": "No slurs.",
"not_an_admin": "Not an admin.",
"site_already_exists": "Site already exists.",
"couldnt_update_site": "Couldn't update site.",
"couldnt_find_that_username_or_email":
"Couldn't find that username or email.",
"password_incorrect": "Password incorrect.",
"passwords_dont_match": "Passwords do not match.",
"admin_already_created": "Sorry, there's already an admin.",
"user_already_exists": "User already exists.",
"email_already_exists": "Email already exists.",
"couldnt_update_user": "Couldn't update user.",
"system_err_login": "System error. Try logging out and back in.",
"couldnt_create_private_message": "Couldn't create private message.",
"no_private_message_edit_allowed": "Not allowed to edit private message.",
"couldnt_update_private_message": "Couldn't update private message.",
"time": "Time",
"action": "Action",
"block_leaving": "Are you sure you want to leave?"
}

175
ui/translations/eo.json vendored Normal file
View file

@ -0,0 +1,175 @@
{
"post": "Poŝti",
"remove_post": "Fortiri Poŝton",
"no_posts": "Ne Poŝtoj.",
"create_a_post": "Verki Poŝton",
"create_post": "Verki Poŝton",
"number_of_posts": "{{count}} Poŝtoj",
"posts": "Poŝtoj",
"related_posts": "Tiuj poŝtoj eble rilatas",
"cross_posts": "Tiuj ligilo ankaŭ estas poŝtinta al:",
"cross_post": "laŭapoŝto",
"comments": "Komentoj",
"number_of_comments": "{{count}} Komentoj",
"remove_comment": "Fortiri Komentojn",
"communities": "Komunumoj",
"users": "Uzantoj",
"create_a_community": "Krei komunumon",
"create_community": "Krei Komunumon",
"remove_community": "Forigi Komunumon",
"subscribed_to_communities": "Abonita al <1>komunumoj</1>",
"trending_communities": "Furora <1>komunumoj</1>",
"list_of_communities": "Listo de komunumoj",
"community_reqs": "minusklaj leteroj, substrekoj, kaj ne spacetoj.",
"edit": "redakti",
"reply": "repliki",
"cancel": "nuligi",
"unlock": "malŝlosi",
"lock": "ŝlosi",
"link": "ligi",
"mod": "moderanto",
"mods": "moderantoj",
"moderates": "Moderigas",
"settings": "Agordoj",
"remove_as_mod": "forigi per moderanto",
"appoint_as_mod": "nomumi per moderanto",
"modlog": "Moderlogo",
"admin": "administranto",
"admins": "administrantoj",
"remove_as_admin": "forigi per administranto",
"appoint_as_admin": "nomumi per administranto",
"remove": "fortiri",
"removed": "fortirita",
"locked": "ŝlosita",
"reason": "Kialo",
"mark_as_read": "marki kiel legita",
"mark_as_unread": "marki kiel nelegita",
"delete": "forigi",
"deleted": "forigita",
"restore": "restaŭri",
"ban": "forbari",
"ban_from_site": "forbari de retejo",
"unban": "malforbari",
"unban_from_site": "malforbari de retejo",
"save": "konservi",
"unsave": "malkonservi",
"create": "krei",
"username": "Uzantnomo",
"email_or_username": "Retadreso aŭ Uzantnomo",
"number_of_users": "{{count}} Uzantoj",
"number_of_subscribers": "{{count}} Abonantoj",
"number_of_points": "{{count}} Voĉdonoj",
"name": "Nomo",
"title": "Titolo",
"category": "Kategorio",
"subscribers": "Abonantoj",
"both": "Ambaŭ",
"saved": "Konservita",
"unsubscribe": "Malaboni",
"subscribe": "Aboni",
"subscribed": "Abonita",
"prev": "Antaŭe",
"next": "Poste",
"sidebar": "Flankstango",
"sort_type": "Klasi per kia",
"hot": "Varmaj",
"new": "Novaj",
"top_day": "Supraj tagaj",
"week": "Semajno",
"month": "Monato",
"year": "Jaro",
"all": "Ĉiam",
"top": "Supraj",
"api": "API",
"inbox": "Ricevujo",
"inbox_for": "Ricevujo de <1>{{user}}</1>",
"mark_all_as_read": "marki ĉiujn kiel legitaj",
"type": "Tipo",
"unread": "Nelegitaj",
"reply_sent": "Repliko sendis",
"search": "Serĉi",
"overview": "Resumo",
"view": "Rigardi",
"logout": "Elsaluti",
"login_sign_up": "Ensaluti / Registriĝi",
"login": "Ensaluti",
"sign_up": "Registriĝi",
"notifications_error":
"Labortablaj avizoj estas nehavebla en via retumilo. Provu Firefox-on aŭ Chrome-on.",
"unread_messages": "Nelegitaj Mesaĝoj",
"password": "Pasvorto",
"verify_password": "Konfirmu Vian Pasvorton",
"email": "Retadreso",
"optional": "Fakultativa",
"expires": "Finiĝos",
"url": "URL",
"body": "Ĉefparto",
"copy_suggested_title": "kopii la sugestiitan titolon: {{title}}",
"community": "Komunumo",
"expand_here": "Ekspansii ĉi tie",
"subscribe_to_communities": "Aboni al iuj <1>komunumoj</1>.",
"chat": "Babilo",
"recent_comments": "Freŝaj Komentoj",
"no_results": "Ne rezultoj.",
"setup": "Agordi",
"lemmy_instance_setup": "Agordi Instancon de Lemmy",
"setup_admin": "Agordi Retejan Administranton",
"your_site": "via retejo",
"modified": "modifita",
"nsfw": "NSFW",
"show_nsfw": "Vidigi NSFW-an enhavon",
"sponsors": "Subtenantoj",
"sponsors_of_lemmy": "Subtenantoj de Lemmy",
"sponsor_message":
"Lemmy estas senpaga, <1>liberkoda</1> programaro. Tio signifas ne reklami, pagigi, aŭ riska kapitalo, ĉiam. Viaj donacoj rekte subtenas plentempan evoluon de la projekto. Dankon al tiuj homoj:",
"support_on_patreon": "Subteni per Patreon",
"general_sponsors":
"Ĝeneralaj Subtenantoj estas tiuj ke donacis inter $10 kaj $39 al Lemmy.",
"crypto": "Crypto",
"bitcoin": "Bitcoin",
"ethereum": "Ethereum",
"monero": "Monero",
"code": "Kodo",
"joined": "Unuiĝis",
"by": "de",
"to": "al",
"transfer_community": "transdoni la komunumon",
"transfer_site": "transdoni la retejon",
"powered_by": "Konstruis per",
"landing_0":
"Lemmy estas <1>ligila agregatilo</1> / Reddit anstataŭo ke intenciĝas funkci en la <2>federacio-universo</2>.<3></3>ĝi estas mem-gastigebla, havas nuna-ĝisdatigajn komentarojn, kaj estas malgrandega (<4>~80kB</4>). Federacio en la ActivityPub-an reton estas planizita. <5></5>Estas <6>fruega beta versio</6>, kaj multaj trajtoj estas nune difektaj aŭ mankaj. <7></7>Sugestias novajn trajtojn aŭ raportas cimojn <8>ĉi tie.</8><9></9>Faris per <10>Rust</10>, <11>Actix</11>, <12>Inferno</12>, <13>Typescript</13>.",
"not_logged_in": "Ne estas ensalutinta.",
"community_ban": "Vi estas forbarita de la komunumo.",
"site_ban": "Vi estas forbarita de la retejo",
"couldnt_create_comment": "Ne povis krei la komenton.",
"couldnt_like_comment": "Ne povis ŝati la komenton.",
"couldnt_update_comment": "Ne povis ĝisdatigi komenton.",
"couldnt_save_comment": "Ne povis konservi komenton.",
"no_comment_edit_allowed": "Ne rajtas redakti la komenton.",
"no_post_edit_allowed": "Ne rajtas redakti la poŝton.",
"no_community_edit_allowed": "Ne rajtas redakti la komunumon.",
"couldnt_find_community": "Ne povis trovi la komunumon.",
"couldnt_update_community": "Ne povis ĝisdatigi la komunumon.",
"community_already_exists": "Komunumo jam ekzistas.",
"community_moderator_already_exists": "Komunuma moderanto jam ekzistas.",
"community_follower_already_exists": "Komunuma sekvanto.",
"community_user_already_banned": "Komunuma uzanto jam estas forbarita.",
"couldnt_create_post": "Ne povis krei la poŝton.",
"couldnt_like_post": "Ne povis ŝati la poŝton.",
"couldnt_find_post": "Ne povis trovi la poŝton.",
"couldnt_get_posts": "Ne povis irpreni poŝtojn",
"couldnt_update_post": "Ne povis ĝisdatigi la poŝton",
"couldnt_save_post": "Ne povis konservi la poŝton.",
"no_slurs": "Ne bigotaj vortoj.",
"not_an_admin": "Ne estas administranto.",
"site_already_exists": "Retejo jam ekzistas.",
"couldnt_update_site": "Ne povis ĝisdatigi la retejon.",
"couldnt_find_that_username_or_email":
"Ne povis trovi tiun uzantnomon aŭ retadreson.",
"password_incorrect": "Pasvorto malĝustas.",
"passwords_dont_match": "Pasvortoj ne samas.",
"admin_already_created": "Pardonu, jam estas administranto.",
"user_already_exists": "Uzanto jam ekzistas.",
"couldnt_update_user": "Ne povis ĝisdatigi la uzanton.",
"system_err_login": "Sistema eraro. Provu elsaluti kaj ensaluti."
}

240
ui/translations/es.json vendored Normal file
View file

@ -0,0 +1,240 @@
{
"post": "Publicar",
"remove_post": "Eliminar publicación",
"no_posts": "Sin publicaciones.",
"create_a_post": "Crear una publicación",
"create_post": "Crear Publicación",
"number_of_posts": "{{count}} Publicaciones",
"posts": "Publicaciones",
"related_posts": "Estas publicaciones podrían estar relacionadas",
"cross_posts": "Este link también ha sido publicado en:",
"cross_post": "cross-post",
"comments": "Comentarios",
"number_of_comments": "{{count}} Comentarios",
"remove_comment": "Eliminar Comentarios",
"communities": "Comunidades",
"users": "Usuarios",
"create_a_community": "Crear una comunidad",
"create_community": "Crear Comunidad",
"remove_community": "Eliminar Comunidad",
"subscribed_to_communities": "Suscrito a <1>comunidades</1>",
"trending_communities": "<1>Comunidades</1> en tendencia",
"list_of_communities": "Lista de comunidades",
"number_of_communities": "{{count}} Comunidades",
"community_reqs": "minúsculas, guión bajo, y sin espacios.",
"create_private_message": "Crear Mensaje Privado",
"send_secure_message": "Enviar Mensaje Seguro",
"send_message": "Enviar Mensaje",
"message": "Mensaje",
"edit": "editar",
"reply": "responder",
"cancel": "Cancelar",
"preview": "Previsualizar",
"upload_image": "subir imagen",
"avatar": "Avatar",
"upload_avatar": "Subir Avatar",
"show_avatars": "Ver Avatares",
"formatting_help": "Ayuda de formato",
"view_source": "ver fuente",
"unlock": "desbloquear",
"lock": "bloquear",
"sticky": "fijado",
"unsticky": "no fijado",
"link": "link",
"archive_link": "archivar link",
"mod": "moderador",
"mods": "moderadores",
"moderates": "Modera",
"settings": "Configuración",
"remove_as_mod": "eliminar como moderador",
"appoint_as_mod": "designar como moderador",
"modlog": "Historial de moderación",
"admin": "administrador",
"admins": "administradores",
"remove_as_admin": "eliminar como administrador",
"appoint_as_admin": "designar como administrador",
"remove": "eliminar",
"removed": "eliminado",
"locked": "bloqueado",
"stickied": "fijado",
"reason": "Razón",
"mark_as_read": "marcar como leído",
"mark_as_unread": "marcar como no leído",
"delete": "eliminar",
"deleted": "eliminado",
"delete_account": "Eliminar Cuenta",
"delete_account_confirm":
"Aviso: esta acción eliminará permanentemente tu información. Introduce tu contraseña para continuar",
"restore": "restaurar",
"ban": "expulsar",
"ban_from_site": "expulsar del sitio",
"unban": "admitir",
"unban_from_site": "admitir en el sitio",
"banned": "expulsado",
"save": "guardar",
"unsave": "descartar",
"create": "crear",
"creator": "creador",
"username": "Nombre de Usuario",
"email_or_username": "Correo o Usuario",
"number_of_users": "{{count}} Usuarios",
"number_of_subscribers": "{{count}} Suscriptores",
"number_of_points": "{{count}} Puntos",
"number_online": "{{count}} Usuarios En Línea",
"name": "Nombre",
"title": "Titulo",
"category": "Categoría",
"subscribers": "Suscriptores",
"both": "Ambos",
"saved": "Guardado",
"unsubscribe": "Desuscribirse",
"subscribe": "Suscribirse",
"subscribed": "Suscrito",
"prev": "Anterior",
"next": "Siguiente",
"sidebar": "Descripción de la comunidad",
"sort_type": "Tipo de orden",
"hot": "Popular",
"new": "Nuevo",
"top_day": "Lo mejor del día",
"week": "Semana",
"month": "Mes",
"year": "Año",
"all": "Todo",
"top": "Mejor",
"api": "API",
"docs": "Docs",
"inbox": "Buzón de entrada",
"inbox_for": "Buzón de entrada para <1>{{user}}</1>",
"mark_all_as_read": "marcar todo como leído",
"type": "Tipo",
"unread": "No leído",
"replies": "Respuestas",
"mentions": "Menciones",
"reply_sent": "Respuesta enviada",
"message_sent": "Mensaje enviado",
"search": "Buscar",
"overview": "Resumen",
"view": "Vista",
"logout": "Cerrar sesión",
"login_sign_up": "Iniciar sesión / Crear cuenta",
"login": "Iniciar sesión",
"sign_up": "Crear cuenta",
"notifications_error":
"Notificaciones de escritorio no disponibles en tu navegador. Prueba Firefox o Chrome.",
"unread_messages": "Mensajes no leídos",
"messages": "Mensajes",
"password": "Contraseña",
"verify_password": "Verificar contraseña",
"old_password": "Antigua Contraseña",
"forgot_password": "olvidé mi contraseña",
"reset_password_mail_sent": "Enviar correo para reestablecer la contraseña.",
"password_change": "Cambio de Contraseña",
"new_password": "Nueva Contraseña",
"no_email_setup": "Este servidor no ha activado correctamente el correo.",
"email": "Correo electrónico",
"matrix_user_id": "Usuario Matricial",
"private_message_disclaimer":
"Aviso: Los mensajes privados en Lemmy no son seguros. Por favor cree una cuenta en <1>Riot.im</1> para mensajeria segura.",
"send_notifications_to_email": "Enviar notificaciones al correo",
"optional": "Opcional",
"expires": "Expira",
"language": "Idioma",
"browser_default": "Por defecto del navegador",
"downvotes_disabled": "Votos negativos deshabilitados",
"enable_downvotes": "Habilitar votos negativos",
"open_registration": "Abrir registro",
"registration_closed": "Registro cerrado",
"enable_nsfw": "Habilitar NSFW",
"url": "URL",
"body": "Descripción",
"copy_suggested_title": "Copiar el título sugerido: {{title}}",
"community": "Comunidad",
"expand_here": "Expandir aquí",
"subscribe_to_communities": "Suscribirse a algunas <1>comunidades</1>.",
"chat": "Chat",
"recent_comments": "Comentarios recientes",
"no_results": "Sin resultados.",
"setup": "Configurar",
"lemmy_instance_setup": "Configuración de instancia de Lemmy",
"setup_admin": "Configurar administrador del Sitio",
"your_site": "tu sitio",
"modified": "modificado",
"nsfw": "NSFW",
"show_nsfw": "Mostrar contenido NSFW",
"theme": "Tema",
"sponsors": "Patrocinadores",
"sponsors_of_lemmy": "Patrocinadores de Lemmy",
"sponsor_message":
"Lemmy es software libre y de <1>código abierto</1>, lo que significa que no tendrá publicidades, monetización, ni capitales emprendedores, nunca. Tus donaciones apoyan directamente el desarrollo a tiempo completo del proyecto. Muchas gracias a las siguientes personas:",
"support_on_patreon": "Apoyo en Patreon",
"support_on_liberapay": "Apoyo en Liberapay",
"donate_to_lemmy": "Donar a Lemmy",
"donate": "Donar",
"general_sponsors":
"Los Patrocinadores Generales son aquellos que señaron entre $10 y $39 a Lemmy.",
"crypto": "Crypto",
"bitcoin": "Bitcoin",
"ethereum": "Ethereum",
"monero": "Monero",
"code": "Código",
"joined": "Se unió",
"by": "por",
"to": "a",
"from": "desde",
"transfer_community": "transferir comunidad",
"transfer_site": "transferir sitio",
"are_you_sure": "¿Estás seguro?",
"yes": "sí",
"no": "no",
"powered_by": "Impulsado por",
"landing_0":
"Lemmy es un <1>agregador de links</1> / alternativa a reddit, con la intención de funcionar en el <2>fediverso</2>.<3></3>Es alojable por uno mismo (sin necesidad de grandes compañías), tiene actualización en vivo de cadenas de comentarios, y es pequeño (<4>~80kB</4>). Federar con el sistema de redes ActivityPub forma parte de los objetivos del proyecto. <5></5>Esta es una <6>version beta muy prematura</6>, y actualmente muchas de las características están rotas o faltan. <7></7>Sugiere nuevas características o reporta errores <8>aquí</8>.<9></9>Hecho con <10>Rust</10>, <11>Actix</11>, <12>Inferno</12>, <13>Typescript</13>.",
"not_logged_in": "No has iniciado sesión.",
"logged_in": "Has iniciado sesión.",
"community_ban": "Has sido expulsado de esta comunidad.",
"site_ban": "Has sido expulsado del sitio",
"couldnt_create_comment": "No se pudo crear el comentario.",
"couldnt_like_comment": "No se pudo dar me gusta al comentario.",
"couldnt_update_comment": "No se pudo actualizar el comentario.",
"couldnt_save_comment": "No se pudo guardar el comentario.",
"no_comment_edit_allowed": "No tiene permisos para editar el comentario.",
"no_post_edit_allowed": "No tiene permisos para editar la publicación.",
"no_community_edit_allowed": "No tiene permisos para editar la comunidad.",
"couldnt_find_community": "No se pudo encontrar la comunidad.",
"couldnt_update_community": "No se pudo actualizar la comunidad.",
"community_already_exists": "Esta comunidad ya existe.",
"community_moderator_already_exists":
"Este moderador de la comunidad ya existe.",
"community_follower_already_exists":
"Este seguidor de la comunidad ya existe.",
"community_user_already_banned":
"Este usuario de la comunidad ya fue expulsado.",
"couldnt_create_post": "No se pudo crear la publicación.",
"couldnt_like_post": "No se pudo gustar la publicación.",
"couldnt_find_post": "No se pudo encontrar la publicación.",
"couldnt_get_posts": "No se pudo obtener las publicaciones",
"couldnt_update_post": "No se pudo actualizar la publicación",
"couldnt_save_post": "No se pudo guardar la publicación.",
"no_slurs": "Prohibido insultar.",
"not_an_admin": "No es un administrador.",
"site_already_exists": "El sitio ya existe.",
"couldnt_update_site": "No se pudo actualizar el sitio.",
"couldnt_find_that_username_or_email":
"No se pudo encontrar ese nombre de usuario o correo electrónico.",
"password_incorrect": "Contraseña incorrecta.",
"passwords_dont_match": "Las contraseñas no coinciden.",
"admin_already_created": "Lo sentimos, ya hay un adminisitrador.",
"user_already_exists": "El usuario ya existe.",
"email_already_exists": "El correo ya está en uso.",
"couldnt_update_user": "No se pudo actualizar el usuario.",
"system_err_login":
"Error del sistema. Intente cerrar sesión e ingresar de nuevo.",
"couldnt_create_private_message": "No se pudo crear el mensaje privado.",
"no_private_message_edit_allowed":
"Sin permisos para editar el mensaje privado.",
"couldnt_update_private_message": "No se pudo actualizar el mensaje privado.",
"old": "Antiguo",
"time": "Tiempo",
"action": "Acción"
}

167
ui/translations/fa.json vendored Normal file
View file

@ -0,0 +1,167 @@
{
"post": "مطلب",
"remove_post": "حذف مطلب",
"no_posts": "بدون مطلب.",
"create_a_post": "ایجاد یک مطلب",
"create_post": "ایجاد مطلب",
"number_of_posts": "{{count}} مطلب",
"posts": "مطالب",
"related_posts": "این مطالب ممکن است مرتبط باشند",
"cross_posts": "این پیوند در اینجا هم منتشر شده:",
"comments": "نظرات",
"number_of_comments": "{{count}} نظر",
"remove_comment": "حذف نظر",
"communities": "جوامع",
"users": "کاربران",
"create_a_community": "ایجاد یک جامعه جدید",
"create_community": "ایجاد جامعه",
"remove_community": "حذف جامعه",
"list_of_communities": "فهرست جوامع",
"number_of_communities": "{{count}} جامعه",
"community_reqs": "حروف کوچک, زیرخط, و بدون فاصله.",
"edit": "ویرایش",
"reply": "پاسخ",
"cancel": "لغو",
"preview": "پیش‌نمایش",
"upload_image": "بارگذاری تصویر",
"avatar": "آواتار",
"upload_avatar": "بارگذاری آواتار",
"show_avatars": "نمایش آواتارها",
"formatting_help": "راهنمای قالب‌بندی",
"view_source": "نمایش منبع",
"unlock": "بازکردن قفل",
"lock": "قفل کردن",
"sticky": "چسبان",
"unsticky": "غیرچسبان",
"link": "پیوند",
"archive_link": "بایگاهی پیوند",
"settings": "تنظیمات",
"admin": "مدیر",
"admins": "مدیران",
"remove_as_admin": "حذف به عنوان مدیر",
"appoint_as_admin": "انتصاب به عنوان مدیر",
"remove": "حذف",
"removed": "حذف شد",
"locked": "قفل شد",
"reason": "دلیل",
"mark_as_read": "علامت‌گذاری به عنوان خوانده شده",
"mark_as_unread": "علامت‌گذاری به عنوان خوانده نشده",
"delete": "پاک کردن",
"deleted": "پاک شد",
"delete_account": "پاک کردن حساب",
"delete_account_confirm":
"هشدار: این کنش، تمام اطلاعات شما را برای همیشه پاک می‌کند. برای تایید، گذرواژه خود را وارد کنید.",
"restore": "بازگردانی",
"save": "ذخیره",
"unsave": "عدم ذخیره",
"create": "ایجاد",
"creator": "سازنده",
"username": "نام‌کاربری",
"email_or_username": "رایانامه یا نام‌کاربری",
"number_of_users": "{{count}} کاربر",
"number_of_points": "{{count}} امتیاز",
"number_online": "{{count}} کاربر برخط",
"name": "نام",
"title": "عنوان",
"category": "دسته‌بندی",
"prev": "پیش",
"next": "بعد",
"sidebar": "نوار کناری",
"sort_type": "نوع ترتیب",
"hot": "داغ",
"new": "تازه",
"top_day": "بهترین‌های روز",
"week": "هفته",
"month": "ماه",
"year": "سال",
"all": "همه",
"top": "بالاترین",
"mark_all_as_read": "علامت زدن همه به عنوان خوانده شده",
"type": "نوع",
"unread": "خوانده‌نشده",
"replies": "پاسخ‌ها",
"mentions": "اشاره‌ها",
"reply_sent": "پاسخ فرستاده شد",
"search": "جستجو",
"overview": "دید کلی",
"view": "نما",
"logout": "خروج",
"login_sign_up": "ورود / نام‌نویسی",
"login": "ورود",
"sign_up": "نام‌نویسی",
"unread_messages": "پیام‌های خوانده نشده",
"password": "گذرواژه",
"verify_password": "تایید گذرواژه",
"old_password": "پسورد پیشین",
"forgot_password": "گذرواژه را فراموش کرده‌ام",
"reset_password_mail_sent": "رایانامه‌ای برای بازنشانی گذرواژه فرستاده شد.",
"password_change": "تغییر گذرواژه",
"new_password": "گذرواژه جدید",
"email": "رایانامه",
"send_notifications_to_email": "فرستادن اعلانات به رایانامه",
"optional": "انتخابی",
"expires": "منقضی شود",
"language": "زبان",
"browser_default": "پیش‌فرض مرورگر",
"downvotes_disabled": "رای پایین غیرفعال است",
"enable_downvotes": "فعال‌سازی رای پایین",
"open_registration": "باز کردن نام‌نویسی",
"registration_closed": "نام‌نویسی بسته است",
"enable_nsfw": "فعال‌سازی NSFW",
"chat": "گپ",
"recent_comments": "نظرات اخیر",
"no_results": "بدون نتیجه.",
"setup": "نصب",
"lemmy_instance_setup": "نصب نمونهٔ لمی",
"setup_admin": "نصب مدیریت پایگاه",
"your_site": "پایگاه شما",
"modified": "تغییر یافت",
"nsfw": "NSFW",
"show_nsfw": "نمایش محتوای NSFW",
"sponsors": "حامیان",
"sponsors_of_lemmy": "حامیان لمی",
"support_on_patreon": "حمایت روی Patreon",
"donate_to_lemmy": "اعطای اعانه به لمی",
"donate": "اعانه",
"crypto": "رمزارز",
"bitcoin": "بیت‌کوین",
"ethereum": "اتریوم",
"monero": "مونرو",
"code": "کد",
"transfer_community": "انتقال جامعه",
"transfer_site": "انتقال پایگاه",
"are_you_sure": "مطمئنید؟",
"yes": "بله",
"no": "خیر",
"powered_by": "نیرو گرفته از",
"not_logged_in": "وارد نشده‌اید.",
"community_ban": "فعالیت شما در این جامعه ممنوع شده است.",
"site_ban": "فعالیت شما در این پایگاه ممنوع شده است",
"couldnt_create_comment": "ناتوانی در ایجاد نظر.",
"couldnt_like_comment": "ناتوانی در پسنیدن نظر.",
"couldnt_update_comment": "ناتوانی در به‌روزرسانی نظر.",
"couldnt_save_comment": "ناتوانی در ذخیره نظر.",
"no_comment_edit_allowed": "مجاز به ویرایش نظر نیستید.",
"no_post_edit_allowed": "مجاز به ویرایش مطلب نیستید.",
"no_community_edit_allowed": "مجاز به ویرایش جامعه نیستید.",
"couldnt_find_community": "ناتوانی در یافتن جامعه.",
"couldnt_update_community": "ناتوانی در به‌روزرسانی جامعه.",
"community_already_exists": "این جامعه از قبل وجود داشته است.",
"couldnt_create_post": "ناتوانی در ایجاد مطلب.",
"couldnt_like_post": "ناتوانی در پسندیدن مطلب.",
"couldnt_find_post": "ناتوانی در یافتن مطلب.",
"couldnt_get_posts": "ناتوانی در دریافت مطالب",
"couldnt_update_post": "ناتوای در به‌روزرسانی مطلب",
"couldnt_save_post": "ناتوانی در ذخیره مطلب.",
"not_an_admin": "مدیر نیستید.",
"site_already_exists": "این پایگاه از قبل وجود داشته است.",
"couldnt_update_site": "ناتوانی در به‌روزرسانی پایگاه.",
"couldnt_find_that_username_or_email":
"ناتوانی در یافتن این نام کاربری یا رایانامه.",
"password_incorrect": "گذرواژه نادرست.",
"passwords_dont_match": "گذرواژه‌ها با هم منطبق نیستند.",
"user_already_exists": "این کاربر از قبل وجود دارد.",
"email_already_exists": "این رایانامه از قبل وجود دارد.",
"couldnt_update_user": "ناتوانی در به‌روزرسانی کاربر.",
"system_err_login": "خطای سامانه. سعی کنید خارج شده و دوباره وارد شوید."
}

234
ui/translations/fi.json vendored Normal file
View file

@ -0,0 +1,234 @@
{
"post": "viesti",
"remove_post": "Poista viesti",
"no_posts": "Ei viestjä.",
"create_a_post": "Luo viesti",
"create_post": "Luo viesti",
"number_of_posts": "{{count}} viestiä",
"posts": "Viestit",
"related_posts": "Nämä viestit voivat liittyä toisiinsa",
"cross_posts": "Tämä linkki on jaettu:",
"cross_post": "jaa ristiin",
"comments": "Kommentit",
"number_of_comments": "{{count}} kommenttia",
"remove_comment": "Poista kommentti",
"communities": "Yhteisöt",
"users": "Käyttäjät",
"create_a_community": "Luo yhteisö",
"create_community": "Luo yhteisö",
"remove_community": "Poista yhteisö",
"subscribed_to_communities": "Tilatut <1>yhteisöt</1>",
"trending_communities": "Nousevat <1>yhteisöt</1>",
"list_of_communities": "Lista yhteisöistä",
"number_of_communities": "{{count}} yhteisöä",
"community_reqs":
"pienillä kirjaimilla, alleviivauksella, eikä välilyöntejä.",
"create_private_message": "Luo yksityisviesti",
"send_secure_message": "Lähetä suojattu viesti",
"send_message": "Lähetä viesti",
"message": "Viesti",
"edit": "muokkaa",
"reply": "vastaa",
"cancel": "Peru",
"preview": "Esikatselu",
"upload_image": "lataa kuva",
"avatar": "avatar",
"upload_avatar": "Lähetä avatar",
"show_avatars": "Näytä avatarit",
"formatting_help": "apua muotoiluun",
"view_source": "näytä lähde",
"unlock": "avaa",
"lock": "lukitse",
"sticky": "kiinnitä",
"unsticky": "poista kiinnitys",
"link": "linkitä",
"archive_link": "arkistoi linkki",
"mod": "moderaattori",
"mods": "moderaattorit",
"moderates": "Moderoi",
"settings": "Asetukset",
"remove_as_mod": "Poista moderaattorina",
"appoint_as_mod": "Nimitä moderaattoriksi",
"modlog": "Moderoinnin loki",
"admin": "Ylläpitäjä",
"admins": "ylläpitäjät",
"remove_as_admin": "poista ylläpitäjänä",
"appoint_as_admin": "nimitä ylläpitäjäksi",
"remove": "poista",
"removed": "poistettu",
"locked": "lukittu",
"stickied": "kiinnitetty",
"reason": "Syy",
"mark_as_read": "merkitse luetuksi",
"mark_as_unread": "merkitse lukemattomaksi",
"delete": "poista",
"deleted": "deleted",
"delete_account": "Poista tili",
"delete_account_confirm":
"Varoitus: tämä poistaa pysyvästi kaiken datasi. Anna salasanasi varmistukseksi.",
"restore": "palauta",
"ban": "porttikielto",
"ban_from_site": "aseta porttikielto sivulle",
"unban": "poista porttikielto",
"unban_from_site": "poista porttikielto sivulta",
"banned": "asetettu porttikieltoon",
"save": "tallenna",
"unsave": "jätä tallentamatta",
"create": "luo",
"creator": "luoja",
"username": "Käyttäjänimi",
"email_or_username": "Sähköposti tai käyttäjätunnus",
"number_of_users": "{{count}} käyttäjää",
"number_of_subscribers": "{{count}} tilaajaa",
"number_of_points": "{{count}} pistettä",
"number_online": "{{count}} käyttäjää aktiivisena",
"name": "Nimi",
"title": "Kuvaus",
"category": "Luokka",
"subscribers": "Tilaajat",
"both": "Molemmat",
"saved": "Tallennettu",
"unsubscribe": "Poista tilaus",
"subscribe": "Tilaa",
"subscribed": "Tilattu",
"prev": "Edellinen",
"next": "Seuraava",
"sidebar": "Sivupalkki",
"sort_type": "Lajittele tyypin mukaan",
"hot": "Kuumat",
"new": "Uudet",
"top_day": "Päivän parhaimmat",
"week": "Viikko",
"month": "Kuukausi",
"year": "Vuosi",
"all": "Kaikki",
"top": "Parhaimmat",
"api": "API",
"docs": "Dokumentaatio",
"inbox": "Postilaatikko",
"inbox_for": "Postilaatikko käyttäjällä <1>{{user}}</1>",
"mark_all_as_read": "aseta kaikki luetuiksi",
"type": "Tyyppi",
"unread": "Lukematon",
"replies": "Vastaukset",
"mentions": "Maininnat",
"reply_sent": "Vastaus lähetetty",
"message_sent": "Viesti lähetetty",
"search": "Etsi",
"overview": "Yleiskatsaus",
"view": "Katso",
"logout": "Kirjaudu ulos",
"login_sign_up": "Kirjaudu sisään / Rekisteröidy",
"login": "Kirjaudu sisään",
"sign_up": "Rekisteröidy",
"notifications_error":
"Työpöydän ilmoitukset eivät ole saatavilla selaimellesi. Yritä Firefoxia tai Chromea.",
"unread_messages": "Lukemattomat viestit",
"messages": "Viestit",
"password": "Salasana",
"verify_password": "Vahvista salasana",
"old_password": "Vanha salasana",
"forgot_password": "unohdin salasanani",
"reset_password_mail_sent": "Sähköposti lähetettiin salasanan nollaamiseksi.",
"password_change": "Salasanan muutos",
"new_password": "Uusi salasana",
"no_email_setup": "Tämä palvelin ei ole asettanut sähköpostia oikein.",
"email": "Sähköposti",
"matrix_user_id": " Matrix-käyttäjä",
"private_message_disclaimer":
"Varoitus: Yksityisviestit Lemmyssä eivät ole turvallisia. Luo tili <1>Riot.im</1> -palveluun turvallista viestintää varten.",
"send_notifications_to_email": "Lähetä ilmoitukset sähköpostiin",
"optional": "Valinnainen",
"expires": "Umpeutuu",
"language": "Kieli",
"browser_default": "Selaimen oletus",
"downvotes_disabled": "Alaäänet otettu pois päältä",
"enable_downvotes": "Salli alaäänet",
"open_registration": "Avaa rekisteröityminen",
"registration_closed": "Rekisteröityminen suljettu",
"enable_nsfw": "Salli NSFW",
"url": "URL",
"body": "Body",
"copy_suggested_title": "kopioi ehdotettu otsikko: {{title}}",
"community": "Yhteisö",
"expand_here": "Laajenna tässä",
"subscribe_to_communities": "Tilaa joitakin <1>yhteisöjä</1>.",
"chat": "Chat",
"recent_comments": "Viimeaikaiset kommentit",
"no_results": "Ei tuloksia.",
"setup": "Asetus",
"lemmy_instance_setup": "Lemmy-instanssin asetus",
"setup_admin": "Aseta sivuston ylläpitäjä",
"your_site": "sivustosi",
"modified": "muokattu",
"nsfw": "NSFW",
"show_nsfw": "Näytä NSFW-sisältö",
"theme": "Teema",
"sponsors": "Sponsorit",
"sponsors_of_lemmy": "Lemmy-sponsorit",
"sponsor_message":
"Lemmy on vapaa, <1>avoimen lähdekoodin</1> -ohjelmisto, eli mainontaa, rahantekemistä, tai pääomasijoitusta täällä ei tule ikinä olemaan. Lahjoituksesi tukevat suoraan projektin täysipäiväistä kehitystä. Kiitokset seuraaville ihmisille:",
"support_on_patreon": "Tue Patreonissa",
"donate_to_lemmy": "Lahjoita Lemmylle",
"donate": "Lahjoita",
"general_sponsors":
"Yleisiä sponsoreja ovat he, jotka lupaavat 10-39 dollaria Lemmylle.",
"crypto": "Crypto",
"bitcoin": "Bitcoin",
"ethereum": "Ethereum",
"monero": "Monero",
"code": "Code",
"joined": "Liittyi",
"by": "käyttäjältä",
"to": "yhteisössä",
"from": "paikasta",
"transfer_community": "siirron yhteisö",
"transfer_site": "siirron määrä",
"are_you_sure": "oletko varma?",
"yes": "kyllä",
"no": "ei",
"powered_by": "Vauhdittajana",
"landing_0":
"Lemmy on <1>linkinkerääjä</1> / Reddit-vaihtoehto, tarkoitettu toimimaan <2>fediversessä</2>.<3></3>Sitä voi isännöidä itse, siinä on tosiaikaisesti päivittyvät kommenttiketjut, ja se on pieni (<4>~80 kilotavua</4>). Federointi ActivityPub-verkkoon on suunnittelun alla. <5></5>Tämä on <6>hyvin varhainen betaversio</6>, ja monet ominaisuudet ovat toistaiseksi rikki tai poissa. <7></7>Ehdota uusia ominaisuuksia tai raportoi bugeja <8>tänne.</8><9></9>Tehty teknologioilla <10>Rust</10>, <11>Actix</11>, <12>Inferno</12>, <13>Typescript</13>.",
"not_logged_in": "Ei kirjautunut sisään.",
"logged_in": "Kirjautunut sisään.",
"community_ban": "Sinulle on asetettu porttikielto tähän yhteisöön.",
"site_ban": "Sinut on asetettu porttikieltoon tältä sivustolta",
"couldnt_create_comment": "Kommenttia ei pystytty luomaan.",
"couldnt_like_comment": "Kommentista ei voitu tykätä.",
"couldnt_update_comment": "Kommenttia ei voitu päivittää.",
"couldnt_save_comment": "Kommenttia ei voitu tallentaa.",
"no_comment_edit_allowed": "Et ole sallittu muokkaamaan kommenttia.",
"no_post_edit_allowed": "Et ole sallittu muokkaamaan viestiä.",
"no_community_edit_allowed": "Et ole sallittu muokkaamaan yhteisöä.",
"couldnt_find_community": "Yhteisöä ei voitu löytää.",
"couldnt_update_community": "Yhteisöä ei voitu päivittää.",
"community_already_exists": "Yhteisö on jo olemassa.",
"community_moderator_already_exists": "Yhteisön moderaattori on jo olemassa.",
"community_follower_already_exists": "Yhteisön seuraaja on jo olemassa.",
"community_user_already_banned": "Yhteisön käyttäjä on jo porttikiellossa.",
"couldnt_create_post": "Ei voitu luoda viestiä.",
"couldnt_like_post": "Viestistä ei voitu tykätä.",
"couldnt_find_post": "Viestiä ei löytynyt.",
"couldnt_get_posts": "Viestejä ei saatu",
"couldnt_update_post": "Viestiä ei voitu päivittää",
"couldnt_save_post": "Viestiä ei voitu tallentaa.",
"no_slurs": "Ei loukkauksia.",
"not_an_admin": "Ei ole ylläpitäjä.",
"site_already_exists": "Sivusto on jo olemassa.",
"couldnt_update_site": "Sivustoa ei voitu päivittää.",
"couldnt_find_that_username_or_email":
"Käyttäjänimeä tai sähköpostia ei onnistuttu löytämään.",
"password_incorrect": "Salasana on väärin.",
"passwords_dont_match": "Salasanat eivät täsmää.",
"admin_already_created": "Anteeksi, mutta täällä on jo ylläpitäjä.",
"user_already_exists": "Käyttäjä on jo olemassa.",
"email_already_exists": "Sähköposti on jo olemassa.",
"couldnt_update_user": "Käyttäjää ei voitu päivittää.",
"system_err_login":
"Järjestelmävirhe. Yritä kirjautua ulos ja kirjautua uudestaan sisään.",
"couldnt_create_private_message": "Yksityisviestiä ei voitu luoda.",
"no_private_message_edit_allowed":
"Et ole sallittu muokkaamaan yksityisviestiä.",
"couldnt_update_private_message": "Yksityisviestiä ei voitu päivittää."
}

231
ui/translations/fr.json vendored Normal file
View file

@ -0,0 +1,231 @@
{
"post": "publication",
"remove_post": "Supprimer la publication",
"no_posts": "Pas de publications.",
"create_a_post": "Créer une publication",
"create_post": "Créer la publication",
"number_of_posts": "{{count}} Publications",
"posts": "Publications",
"related_posts": "Ces sujets peuvent être corrélés",
"cross_posts": "Ce sujet a également été posté sur :",
"cross_post": "publication croisée",
"cross_posted_to": "publication croisée à : ",
"comments": "Commentaires",
"number_of_comments": "{{count}} Commentaires",
"remove_comment": "Supprimer le commentaire",
"communities": "Communautés",
"users": "Utilisateurs",
"create_a_community": "Créer une communauté",
"create_community": "Créer la communauté",
"remove_community": "Supprimer la Communauté",
"subscribed_to_communities": "Abonné à ces <1>communautés</1>",
"trending_communities": "<1>Communautés</1> appréciées",
"list_of_communities": "Liste des communautés",
"number_of_communities": "{{count}} communautés",
"community_reqs": "en minuscule, sans espace et avec tiret du bas.",
"create_private_message": "Créer un message privé",
"send_secure_message": "Envoyer le message sécurisé",
"send_message": "Enovyer le message",
"message": "Message",
"edit": "éditer",
"reply": "répondre",
"cancel": "Annuler",
"preview": "prévisualiser",
"upload_image": "envoyer une image",
"avatar": "Avatar",
"upload_avatar": "Télécharger une avatar",
"show_avatars": "Afficher les avatars",
"formatting_help": "aide au formattage",
"view_source": "voir la source",
"unlock": "débloquer",
"lock": "bloquer",
"sticky": "épingler",
"unsticky": "décrocher",
"link": "lien",
"archive_link": "archiver le lien",
"mod": "modérateur",
"mods": "modérateurs",
"moderates": "Modérer",
"settings": "Paramètres",
"remove_as_mod": "Supprimer comme modérateur",
"appoint_as_mod": "Nommer comme modérateur",
"modlog": "Historique de modération",
"admin": "admin",
"admins": "admins",
"remove_as_admin": "Supprimer comme admin",
"appoint_as_admin": "Nommer comme admin",
"remove": "retirer",
"removed": "retiré",
"locked": "bloqué",
"stickied": "épinglé",
"reason": "Raison",
"mark_as_read": "marquer comme lu",
"mark_as_unread": "marquer comme non-lu",
"delete": "supprimer",
"deleted": "supprimé",
"delete_account": "Supprimer le compte",
"delete_account_confirm": "Avertissement : cette action supprimera toutes vos données de façons permanente ! Saisissez votre mot de passe pour confirmer.",
"restore": "restaurer",
"ban": "bannir",
"ban_from_site": "bannir du site",
"unban": "pardon",
"unban_from_site": "faire revenir sur le site",
"banned": "banni",
"save": "sauvegarder",
"unsave": "retirer",
"create": "créer",
"creator": "createur",
"username": "Nom d'utilisateur",
"email_or_username": "Email ou Nom d'utilisateur",
"number_of_users": "{{count}} Utilisateurs",
"number_of_subscribers": "{{count}} Abonnés",
"number_of_points": "{{count}} Points",
"number_online": "{{count}} Utilisateurs en ligne",
"name": "Nom",
"title": "Titre",
"category": "Catégorie",
"subscribers": "Abonnés",
"both": "Les deux",
"saved": "Sauvegardé",
"unsubscribe": "Se désabonner",
"subscribe": "S'abonner",
"subscribed": "Abonnés",
"prev": "Précédent",
"next": "Suivant",
"sidebar": "Texte latéral",
"sort_type": "Trier",
"hot": "Tendances",
"new": "Nouveaux",
"old": "Ancien",
"top_day": "Top du jour",
"week": "Semaine",
"month": "Mois",
"year": "Année",
"all": "Tout",
"top": "Top",
"api": "API",
"docs": "Documentations",
"inbox": "Boîte de réception",
"inbox_for": "Boîte de réception de <1>{{user}}</1>",
"mark_all_as_read": "Tout marquer comme lu",
"type": "Type",
"unread": "Non-lu",
"replies": "Réponses",
"mentions": "Mentions",
"reply_sent": "Réponse envoyée",
"message_sent": "Message envoyé",
"search": "Rechercher",
"overview": "Général",
"view": "Voir",
"logout": "Se déconnecter",
"login_sign_up": "Se connecter / S'inscrire",
"login": "Se connecter",
"sign_up": "S'inscrire",
"notifications_error": "Les notifications de bureau ne sont pas discponibles sur votre navigateur. Essayez Firefox ou Chrome.",
"unread_messages": "Messages non-lu",
"messages": "Messages",
"password": "Mot de passe",
"verify_password": "Vérifiez le mot de passe",
"old_password": "Ancien mot de passe",
"forgot_password": "Mot de passe oublié",
"reset_password_mail_sent": "Un email a été envoyé pour réinitialiser votre mot de passe.",
"password_change": "Changement de mot de passe",
"new_password": "Nouveau mot de passe",
"no_email_setup": "Ce serveur n'a pas correctement configuré la messagerie de email.",
"email": "Email",
"matrix_user_id": "Utilisateur Matrix",
"private_message_disclaimer": "Attention : les messages privés dans Lemmy ne sont pas sécurisés. Veuillez créer un compte sur <1>Riot.im</1> pour pouvoir envoyer des messages sécurisés.",
"send_notifications_to_email": "Envoyer des notifications par email",
"optional": "Optionnel",
"expires": "Expire",
"language": "Langue",
"browser_default": "Défaut pour le navigateur",
"downvotes_disabled": "Votes négatifs désactivés",
"enable_downvotes": "Votes négatifs activés",
"open_registration": "Ouvrir la regestration",
"registration_closed": "Régestration fermée",
"enable_nsfw": "Activer NSFW",
"url": "URL",
"body": "Texte",
"copy_suggested_title": "copier le titre suggéré : {{title}}",
"community": "Communauté",
"expand_here": "Développer ici",
"subscribe_to_communities": "S'abonner à quelques <1>communautés</1>.",
"chat": "Chat",
"recent_comments": "Commentaires récents",
"no_results": "Pas de résultats.",
"setup": "Installation",
"lemmy_instance_setup": "Installation d'une instance Lemmy",
"setup_admin": "Créer un administrateur",
"your_site": "votre site",
"modified": "modifié",
"nsfw": "Pas sûr pour le travail",
"show_nsfw": "Afficher le contenu NSFW",
"theme": "Thème",
"sponsors": "Sponsors",
"sponsors_of_lemmy": "Sponsors de Lemmy",
"sponsor_message": "Lemmy est un logiciel libre et <1>open-source</1>, cest à dire, il fonctionne sans publicité et sans monétisation aucune. Vos dons soutiennent directement le développement du projet à temps plein. Merci à toutes ces personnes :",
"support_on_patreon": "Soutenir sur Patreon",
"support_on_liberapay": "Soutenir sur Liberapay",
"donate_to_lemmy": "Faire un don à Lemmy",
"donate": "Faire un don",
"general_sponsors": "Les sponsors généraux sont ceux garantissant de 10 à 39$.",
"crypto": "Cryptomonnaies",
"bitcoin": "Bitcoin",
"ethereum": "Ethereum",
"monero": "Monero",
"code": "Code",
"joined": "Membre depuis",
"by": "par",
"to": "vers",
"from": "de",
"transfer_community": "transférer la communauté",
"transfer_site": "transférer le site",
"are_you_sure": "Êtes-vous sûr ?",
"yes": "oui",
"no": "non",
"powered_by": "Propulsé par",
"landing_0": "Lemmy est un <1>aggrégateur de lien</1>, similaire à reddit et conçu pour fonctionner sur le <2>fédiverse</2>.<3></3>Il est auto-hébergeable, se met à jour en direct et est léger (<4>~80kB</4>). La fédération via Activitypub est prévue. <5></5>Lemmy est une <6>version beta très précoce</6>, et de nombreuses fonctionnalités sont manquantes ou non fonctionnelles. <7></7>Vous pouvez rapporter des bugs et suggérez de nouvelles fonctionnalités <8>ici.</8><9></9>Crée avec <10>Rust</10>, <11>Actix</11>, <12>Inferno</12>, <13>Typescript</13>.",
"not_logged_in": "Vous n'êtes pas connecté.",
"logged_in": "Vous êtes connecté.",
"community_ban": "Vous avez été banni de cette communauté.",
"site_ban": "Vous avez été banni du site",
"couldnt_create_comment": "Impossible de poster le commentaire.",
"couldnt_like_comment": "Impossible d'aimer le commentaire.",
"couldnt_update_comment": "Impossible de mettre à jour le commentaire.",
"couldnt_save_comment": "Impossible de sauvegarder le commentaire.",
"couldnt_get_comments": "Impossible de obtenir les commentaires.",
"no_comment_edit_allowed": "Vous n'êtes pas autorisé à éditer ce commentaire.",
"no_post_edit_allowed": "Vous n'êtes pas autorisé à éditer sujet.",
"no_community_edit_allowed": "Vous n'êtes pas autorisé à éditer cette communauté.",
"couldnt_find_community": "Impossible de trouver cette communauté.",
"couldnt_update_community": "Impossible d'éditer cette communauté.",
"community_already_exists": "Cette communauté existe déjà.",
"community_moderator_already_exists": "Ce membre est déjà modérateur.",
"community_follower_already_exists": "Ce membre est déjà abonné.",
"community_user_already_banned": "Ce membre est déjà banni.",
"couldnt_create_post": "Impossible de créer le sujet.",
"post_title_too_long": "Sujet titre trop long.",
"couldnt_like_post": "Impossible d'aimer le sujet.",
"couldnt_find_post": "Impossible de trouver le sujet.",
"couldnt_get_posts": "Impossible d'obtenir les sujets",
"couldnt_update_post": "Impossible de mettre à jour le sujet",
"couldnt_save_post": "Impossible de sauvegarder le sujet.",
"no_slurs": "Pas d'insultes.",
"not_an_admin": "Pas administrateur.",
"site_already_exists": "Le site existe déjà.",
"couldnt_update_site": "Impossible de mettre à jour le site.",
"couldnt_find_that_username_or_email": "Impossible de trouver cet utilisateur ou cet email.",
"password_incorrect": "Mot de passe incorrect.",
"passwords_dont_match": "Les mots de passes ne correspondent pas..",
"admin_already_created": "Désolé, il y a déjà un admin.",
"user_already_exists": "L'utilisateur existe déjà.",
"email_already_exists": "Lemail existe déjà.",
"couldnt_update_user": "Impossible de mettre à jour l'utilisateur.",
"system_err_login": "Erreur système. Essayez de vous déconneter puis de vous reconnecter.",
"couldnt_create_private_message": "Impossible de créer un message privé.",
"no_private_message_edit_allowed": "Pas autorisé à modifier un message privé.",
"couldnt_update_private_message": "Impossible de modifier un message privé.",
"time": "Temps",
"action": "Action"
}

213
ui/translations/it.json vendored Normal file
View file

@ -0,0 +1,213 @@
{
"post": "post",
"remove_post": "Rimuovi Post",
"no_posts": "Nessun Post.",
"create_a_post": "Crea un post",
"create_post": "Crea Post",
"number_of_posts": "{{count}} Posts",
"posts": "Posts",
"related_posts": "Questi post potrebbero essere correlati",
"cross_posts": "Questo link è stato postato anche in:",
"cross_post": "cross-post",
"comments": "Commenti",
"number_of_comments": "{{count}} Commenti",
"remove_comment": "Rimuovi Commento",
"communities": "Comunità",
"users": "Utenti",
"create_a_community": "Crea una Comunità",
"create_community": "Crea Comunità",
"remove_community": "Rimuovi Comunità",
"subscribed_to_communities": "Iscritto alle <1>comunità</1>",
"trending_communities": "<1>Comunità</1> in crescita",
"list_of_communities": "Lista di comunità",
"number_of_communities": "{{count}} Comunità",
"community_reqs": "minuscole, trattini bassi e nessuno spazio.",
"edit": "modifica",
"reply": "rispondi",
"cancel": "Annulla",
"preview": "Anteprima",
"upload_image": "carica immagine",
"formatting_help": "aiuto formattazione",
"view_source": "visualizza sorgente",
"unlock": "sblocca",
"lock": "blocca",
"sticky": "evidenzia",
"unsticky": "rimuovi evidenza",
"link": "link",
"mod": "moderatore",
"mods": "moderatori",
"moderates": "Moderatore di",
"settings": "Impostazioni",
"remove_as_mod": "rimuovi come moderatore",
"appoint_as_mod": "nomina come moderatore",
"modlog": "Registro di moderazione",
"admin": "amministratore",
"admins": "amministratori",
"remove_as_admin": "rimuovi come amministratore",
"appoint_as_admin": "nomina come amministratore",
"remove": "rimuovi",
"removed": "rimosso",
"locked": "bloccato",
"stickied": "evidenziato",
"reason": "Ragione",
"mark_as_read": "segna come letto",
"mark_as_unread": "segna come non letto",
"delete": "cancella",
"deleted": "cancellato",
"delete_account": "Cancella Account",
"delete_account_confirm": "Attenzione: stai per cancellare permanentemente tutti i tuoi dati. Inserisci la tua password per confermare questa azione.",
"restore": "ripristina",
"ban": "ban",
"ban_from_site": "banna dal sito",
"unban": "rimuovi ban",
"unban_from_site": "rimuove il ban dal sito",
"banned": "bannato",
"save": "salva",
"unsave": "rimuovi",
"create": "crea",
"creator": "autore",
"username": "Username",
"email_or_username": "Email o Username",
"number_of_users": "{{count}} Utenti",
"number_of_subscribers": "{{count}} Iscritti",
"number_of_points": "{{count}} Punti",
"number_online": "{{count}} Utenti Online",
"name": "Nome",
"title": "Titolo",
"category": "Categoria",
"subscribers": "Iscritti",
"both": "Entrambi",
"saved": "Salvato",
"unsubscribe": "Disiscriviti",
"subscribe": "Iscriviti",
"subscribed": "Iscritto",
"prev": "Precedente",
"next": "Prossima",
"sidebar": "Barra laterale",
"sort_type": "Ordina per",
"hot": "Popolari",
"new": "Nuovi",
"top_day": "Migliori della giornata",
"week": "Settimana",
"month": "Mese",
"year": "Anno",
"all": "Tutti",
"top": "Migliori",
"api": "API",
"inbox": "Posta in arrivo",
"inbox_for": "Posta di <1>{{user}}</1>",
"mark_all_as_read": "segna tutti come letti",
"type": "Tipo",
"unread": "Non letti",
"replies": "Risposte",
"mentions": "Menzioni",
"reply_sent": "Risposta inviata",
"search": "Cerca",
"overview": "Panoramica",
"view": "Visualizza",
"logout": "Logout",
"login_sign_up": "Login / Iscriviti",
"login": "Login",
"sign_up": "Iscriviti",
"notifications_error": "Le notifiche desktop non sono supportate sul tuo browser. Prova Firefox o Chrome.",
"unread_messages": "Messaggi Non Letti",
"password": "Password",
"verify_password": "Verifica Password",
"email": "Email",
"optional": "Opzionale",
"expires": "Scade",
"url": "URL",
"body": "Contenuto",
"copy_suggested_title": "copia titolo suggerito: {{title}}",
"community": "Comunità",
"expand_here": "Visualizza qui",
"subscribe_to_communities": "Iscriviti ad una <1>comunità</1>.",
"chat": "Chat",
"recent_comments": "Commenti Recenti",
"no_results": "Nessun risultato.",
"setup": "Setup",
"lemmy_instance_setup": "Setup dell'istanza di Lemmy",
"setup_admin": "Imposta Amministratore del Sito",
"your_site": "il tuo sito",
"modified": "modificato",
"nsfw": "NSFW",
"show_nsfw": "Mostra contenuto NSFW",
"theme": "Tema",
"sponsors": "Sponsors",
"sponsors_of_lemmy": "Sponsors di Lemmy",
"sponsor_message": "Lemmy è un software gratuito e <1>open-source</1>, il che significa nessuna pubblicità, monetizzazione o investitori esterni, per sempre. Le tue donazioni supportano direttamente lo sviluppo full-time del progetto. Si ringraziano le seguenti persone:",
"support_on_patreon": "Supporta su Patreon",
"support_on_liberapay": "Supporta su Liberapay",
"general_sponsors": "I \"General Sponsors\" sono quelli che hanno investito dai 10$ ai 39$ su Lemmy.",
"crypto": "Crypto",
"bitcoin": "Bitcoin",
"ethereum": "Ethereum",
"monero": "Monero",
"code": "Code",
"joined": "Iscritto da",
"by": "di",
"to": "su",
"transfer_community": "trasferisci comunità",
"transfer_site": "trasferisci sito",
"are_you_sure": "sei sicuro?",
"yes": "si",
"no": "no",
"powered_by": "Powered by",
"landing_0": "Lemmy è un <1>aggregatore di link</1> / alternativa a reddit, creato per integrarsi con il <2>fediverse</2>. <3></3>È self-hosted, i commenti sono aggiornati in tempo reale ed è molto piccolo (<4>~80kB</4>). La Federazione con la rete ActivityPub sarà implementata nel futuro. <5></5>Questa versione è una <6>beta molto giovane</6> e molte funzionalità sono incomplete o mancanti. <7></7>Suggerisci nuove funzionalità o segnala errori a <8>questa pagina.</8><9></9>Sviluppato con <10>Rust</10>, <11>Actix</11>, <12>Inferno</12>, <13>Typescript</13>.",
"not_logged_in": "Non hai effettuato l'accesso.",
"community_ban": "Sei stato bannato da questa comunità.",
"site_ban": "Sei stato bannato dal sito",
"couldnt_create_comment": "Impossibile creare il commento.",
"couldnt_like_comment": "Impossibile mettere 'Mi piace' al commento.",
"couldnt_update_comment": "Impossibile aggiornare il commento.",
"couldnt_save_comment": "Impossibile salvare il commento.",
"no_comment_edit_allowed": "Non sei autorizzato a modificare il commento.",
"no_post_edit_allowed": "Non sei autorizzato a modificare il post.",
"no_community_edit_allowed": "Non sei autorizzato a modificare la comunità.",
"couldnt_find_community": "Impossibile trovare la comunità.",
"couldnt_update_community": "Impossibile aggiornare la comunità.",
"community_already_exists": "La comunità esiste già.",
"community_moderator_already_exists": "Questo utente è già moderatore della comunità.",
"community_follower_already_exists": "Questo utente è già moderatore della comunità.",
"community_user_already_banned": "L'utente della comunità è già stato bannato.",
"couldnt_create_post": "Impossibile creare il post.",
"couldnt_like_post": "Impossibile mettere 'Mi piace' post.",
"couldnt_find_post": "Impossibile trovare il post.",
"couldnt_get_posts": "Impossibile recuperare i post",
"couldnt_update_post": "Impossibile aggiornare il post",
"couldnt_save_post": "Impossibile salvare il post.",
"no_slurs": "Niente offese.",
"not_an_admin": "Non un amministratore.",
"site_already_exists": "Il sito esiste già.",
"couldnt_update_site": "Impossibile aggiornare il sito.",
"couldnt_find_that_username_or_email": "L'username o la email non sono stati trovati.",
"password_incorrect": "Password non corretta.",
"passwords_dont_match": "Le password non corrispondono.",
"admin_already_created": "Spiacente, esiste già un amministratore.",
"user_already_exists": "L'utente esiste già.",
"couldnt_update_user": "Impossibile aggiornare l'utente.",
"system_err_login": "Si è verificato un errore. Prova ad effettuare nuovamente il login.",
"more": "altro",
"message": "Messaggio",
"avatar": "Avatar",
"upload_avatar": "Carica Avatar",
"docs": "Documentazione",
"message_sent": "Messaggio inviato",
"messages": "Messaggi",
"show_avatars": "Mostra Avatar",
"old_password": "Vecchia Password",
"forgot_password": "password dimenticata",
"new_password": "Nuova Password",
"private_message_disclaimer": "Attenzione: i messaggi privati su Lemmy non sono sicuri. Crea un account su <1>Riot.im</1> per una messaggistica sicura.",
"language": "Lingua",
"enable_downvotes": "Abilita Downvote",
"enable_nsfw": "Abilita NSFW",
"donate_to_lemmy": "Dona a Lemmy",
"donate": "Dona",
"from": "da",
"archive_link": "link archivio",
"matrix_user_id": "Utente Matrix",
"downvotes_disabled": "Downvote disabilitati",
"post_title_too_long": "Titolo del post troppo lungo.",
"email_already_exists": "Indirizzo email già presente."
}

202
ui/translations/ja.json vendored Normal file
View file

@ -0,0 +1,202 @@
{
"post": "投稿",
"remove_post": "投稿を削除",
"no_posts": "投稿はありません。",
"create_a_post": "投稿を作成",
"create_post": "投稿を作成",
"number_of_posts": "{{count}} 件の投稿",
"posts": "投稿",
"related_posts": "こちらの投稿が関連しているかもしれません",
"cross_posts": "このリンクはこちらにも投稿されています:",
"cross_post": "クロスポスト",
"cross_posted_to": "こちらにも投稿済み: ",
"comments": "コメント",
"number_of_comments": "{{count}} 件のコメント",
"remove_comment": "コミュニティを削除",
"communities": "コミュニティ",
"users": "ユーザー",
"create_a_community": "コミュニティを作成",
"create_community": "コミュニティを作成",
"remove_community": "コミュニティを削除",
"subscribed_to_communities": "登録済みの<1>コミュニティ</1>",
"trending_communities": "話題の<1>コミュニティ</1>",
"list_of_communities": "コミュニティ一覧",
"number_of_communities": "{{count}} 個のコミュニティ",
"community_reqs": "英小文字、アンダースコア、空白なし。",
"create_private_message": "プライベートメッセージの作成",
"send_secure_message": "メッセージを安全に送信",
"send_message": "メッセージを送信",
"message": "メッセージ",
"edit": "編集",
"reply": "返信",
"cancel": "キャンセル",
"preview": "プレビュー",
"upload_image": "画像をアップロード",
"avatar": "アバター",
"upload_avatar": "アバターをアップロード",
"show_avatars": "アバターを表示",
"formatting_help": "書式のヘルプ",
"view_source": "ソースを表示",
"unlock": "凍結解除",
"lock": "凍結",
"sticky": "固定",
"unsticky": "固定解除",
"link": "リンク",
"archive_link": "リンクをアーカイブ",
"mod": "モデレーター",
"mods": "モデレーター",
"moderates": "モデレーター",
"settings": "設定",
"remove_as_mod": "モデレーターから除外",
"appoint_as_mod": "モデレーターに任命",
"modlog": "モデレーションログ",
"admin": "管理者",
"admins": "管理者",
"remove_as_admin": "管理者から除外",
"appoint_as_admin": "管理者に任命",
"remove": "強制削除",
"removed": "強制削除済み",
"locked": "凍結中",
"stickied": "固定中",
"reason": "理由",
"mark_as_read": "既読にする",
"mark_as_unread": "未読にする",
"delete": "削除",
"deleted": "削除済み",
"delete_account": "アカウントを削除",
"delete_account_confirm": "警告: あなたのデータを全て恒久的に削除します。確認のためパスワードを入力してください。",
"restore": "復元",
"ban": "アクセス禁止",
"ban_from_site": "サイトへアクセス禁止",
"unban": "アクセス禁止解除",
"unban_from_site": "サイトへのアクセス禁止解除",
"banned": "アクセス禁止中",
"save": "保存",
"unsave": "保存解除",
"create": "作成",
"creator": "投稿者",
"username": "ユーザー名",
"email_or_username": "メールアドレスまたはユーザー名",
"number_of_users": "{{count}} 名のユーザー",
"number_of_subscribers": "{{count}} 名の登録者",
"number_of_points": "{{count}} ポイント",
"number_online": "{{count}} 名のユーザーがオンライン",
"name": "名前",
"title": "タイトル",
"category": "カテゴリー",
"subscribers": "登録者",
"saved": "保存済み",
"unsubscribe": "登録解除",
"subscribe": "登録",
"subscribed": "登録済み",
"prev": "前",
"next": "次",
"sidebar": "説明",
"sort_type": "並び順の種類",
"hot": "人気",
"new": "新しい順",
"old": "古い順",
"top_day": "日間トップ",
"week": "週間",
"month": "月間",
"year": "年間",
"all": "全て",
"top": "トップ",
"api": "API",
"docs": "ドキュメント",
"inbox": "受信箱",
"inbox_for": "<1>{{user}}</1> の受信箱",
"mark_all_as_read": "全てを既読にする",
"type": "種類",
"unread": "未読",
"replies": "返信",
"mentions": "言及",
"reply_sent": "返信を送信しました",
"message_sent": "メッセージを送信しました",
"search": "検索",
"overview": "全種類",
"view": "表示",
"logout": "ログアウト",
"login_sign_up": "ログイン / 登録",
"login": "ログイン",
"sign_up": "登録",
"notifications_error": "お遣いのブラウザーではデスクトップ通知が利用不可能です。Firefox か Chrome をお試しください。",
"unread_messages": "未読のメッセージ",
"messages": "メッセージ",
"password": "パスワード",
"verify_password": "パスワードの確認",
"old_password": "現在のパスワード",
"forgot_password": "パスワードを忘れた",
"reset_password_mail_sent": "パスワードリセット用のメールを送信しました。",
"password_change": "パスワードの変更",
"new_password": "新しいパスワード",
"no_email_setup": "サーバーのメール設定が正しくありません。",
"email": "メールアドレス",
"matrix_user_id": "Matrix のユーザーアカウント",
"private_message_disclaimer": "Lemmy でのプライベートメッセージは安全ではありません。安全なメッセージを送るには <1>Riot.im</1> でアカウントを作成してください。",
"send_notifications_to_email": "通知をメール送信",
"optional": "任意",
"language": "言語",
"browser_default": "ブラウザーのデフォルト",
"enable_downvotes": "反対票を有効化",
"open_registration": "ユーザー登録を受け付ける",
"registration_closed": "登録は受け付けていません",
"enable_nsfw": "閲覧注意を有効化",
"url": "URL",
"body": "本文",
"copy_suggested_title": "タイトルの提案をコピーする: {{title}}",
"community": "コミュニティ",
"expand_here": "拡大表示",
"subscribe_to_communities": "<1>コミュニティ</1>をいくつか登録してみましょう。",
"recent_comments": "最新コメント",
"no_results": "検索結果なし。",
"setup": "設定",
"lemmy_instance_setup": "Lemmy インスタンス設定",
"setup_admin": "サイト管理者を設定",
"your_site": ":サイト",
"modified": "変更",
"nsfw": "閲覧注意",
"show_nsfw": "閲覧注意のコンテンツを表示",
"theme": "テーマ",
"sponsors": "スポンサー",
"sponsor_message": "Lemmy は自由で<1>オープンソース</1>の、つまり広告も収益化もベンチャーキャピタルも決してないソフトウェアです。あなたの寄付はプロジェクトの開発を直接支援します。次の方々に感謝します:",
"support_on_patreon": "Patreon で支援",
"support_on_liberapay": "Liberapay で支援",
"donate_to_lemmy": "Lemmy に寄付",
"donate": "寄付",
"general_sponsors": "ジェネラルスポンサーは Lemmy に $10 $39 の支払いを申し出てくれた方達です。",
"crypto": "暗号通貨",
"bitcoin": "ビットコイン",
"ethereum": "Ethereum",
"monero": "Monero",
"code": "コード",
"joined": "登録",
"by": "投稿者",
"to": "宛先",
"transfer_community": "コミュニティを譲渡",
"transfer_site": "サイトを譲渡",
"are_you_sure": "本当によろしいですか?",
"yes": "はい",
"no": "いいえ",
"powered_by": "Powered by",
"landing_0": "Lemmy は<1>リンクアグリゲーター</1> / Reddit 代替ソフトウェアで、<2>fediverse</2> 上で動作することを目的にしています。<3></3>セルフホスト可能で、リアルタイム更新のコメントスレッドがあり、小さい(<4>80kB以下</4>ものです。ActivityPub ネットワークへの連合が計画にあります。<5></5>まだ<6>初期のベータバージョン</6>で、現在は多くの機能がうまく動作しないか実装されていません。<7></7>新機能の提案やバグの報告は<8>こちら</8>でお願いします。<9></9><10>Rust</10>、<11>Actix</11>、<12>Inferno</12>、<13>Typescript</13>で作っています。",
"not_logged_in": "ログインしていません。",
"logged_in": "ログインしました。",
"community_ban": "このコミュニティへのアクセスを禁止されています。",
"site_ban": "サイトへのアクセスを禁止されています",
"couldnt_create_comment": "投稿を作成できませんでした。",
"couldnt_find_community": "コミュニティが見付かりません。",
"couldnt_find_post": "投稿が見付かりません。",
"couldnt_find_that_username_or_email": "ユーザー名またはメールアドレスが見付かりません。",
"password_incorrect": "パスワードが不正です。",
"passwords_dont_match": "パスワードが一致しません。",
"admin_already_created": "済みませんが、既に管理者が設定されています。",
"email_already_exists": "メールアドレスが既に使用されています。",
"time": "時刻",
"action": "行動",
"more": "さらに表示",
"upvote": "賛成票",
"downvote": "反対票",
"sorting_help": "並び順のヘルプ",
"block_leaving": "このページから離れてもよろしいですか?"
}

232
ui/translations/nl.json vendored Normal file
View file

@ -0,0 +1,232 @@
{
"post": "post",
"remove_post": "Verwijder post",
"no_posts": "Geen posts.",
"create_a_post": "Plaats een post",
"create_post": "Plaats post",
"number_of_posts": "{{count}} posts",
"posts": "posts",
"related_posts": "Deze posts kunnen gerelateerd zijn",
"cross_posts": "Deze link is ook geplaatst in:",
"cross_post": "cross-post",
"comments": "Reacties",
"number_of_comments": "{{count}} reacties",
"remove_comment": "Verwijder reactie",
"communities": "Communities",
"users": "Gebruikers",
"create_a_community": "Maak een community",
"create_community": "Maak community",
"remove_community": "Verwijder community",
"subscribed_to_communities": "Geabonneerd op <1>communities</1>",
"trending_communities": "Populaire <1>communities</1>",
"list_of_communities": "Lijst van communities",
"number_of_communities": "{{count}} communities",
"community_reqs": "kleine letters, onderstrepingsteken en geen spaties",
"edit": "bewerk",
"reply": "reageer",
"cancel": "Annuleer",
"unlock": "ontsluiten",
"lock": "sluiten",
"link": "link",
"mod": "moderator",
"mods": "moderators",
"moderates": "Modereert",
"settings": "Instellingen",
"remove_as_mod": "Verwijder als moderator",
"appoint_as_mod": "Benoemen tot moderator",
"modlog": "Moderatorlog",
"admin": "beheerder",
"admins": "beheerders",
"remove_as_admin": "verwijder als beheerder",
"appoint_as_admin": "benoemen tot beheerder",
"remove": "weghalen",
"removed": "weggehaald",
"locked": "gesloten",
"reason": "Reden",
"mark_as_read": "markeer als gelezen",
"mark_as_unread": "markeer als ongelezen",
"delete": "verwijder",
"deleted": "verwijderd",
"restore": "herstellen",
"ban": "verban",
"ban_from_site": "verban van site",
"unban": "verbanning opzeggen",
"unban_from_site": "verbanning van site opzeggen",
"save": "opslaan",
"unsave": "unsave",
"create": "maak",
"username": "Gebruikersnaam",
"email_or_username": "E-mail of gebruikersnaam",
"number_of_users": "{{count}} gebruikers",
"number_of_subscribers": "{{count}} abonnees",
"number_of_points": "{{count}} punten",
"name": "Naam",
"title": "Titel",
"category": "Categorie",
"subscribers": "Abonnees",
"both": "Beide",
"saved": "Opgeslagen",
"unsubscribe": "Afmelden",
"subscribe": "Abonneren",
"subscribed": "Geabonneerd",
"prev": "Vorige",
"next": "Volgende",
"sidebar": "Zijbalk",
"sort_type": "Sorteertype",
"hot": "Populair",
"new": "Nieuw",
"top_day": "Dagelijkse top",
"week": "Week",
"month": "Maand",
"year": "Jaar",
"all": "Alle",
"top": "Top",
"api": "API",
"inbox": "Postvak-in",
"inbox_for": "Postvak-in voor <1>{{user}}</1>",
"mark_all_as_read": "markeer alle als gelezen",
"type": "Type",
"unread": "Ongelezen",
"reply_sent": "Reactie gestuurd",
"search": "Zoek",
"overview": "Overzicht",
"view": "Beeld",
"logout": "Log uit",
"login_sign_up": "Log in / Aanmelden",
"login": "Log in",
"sign_up": "Aanmelden",
"notifications_error":
"Bureabladberichten niet beschikbaar in je browser. Probeer Firefox of Chrome.",
"unread_messages": "Ongelezen berichten",
"password": "Wachtwoord",
"verify_password": "Herhaal wachtwoord",
"email": "E-mail",
"optional": "Optioneel",
"expires": "Verloopt",
"url": "url",
"body": "Tekst",
"copy_suggested_title": "neem voorgestelde titel over: {{title}}",
"community": "Community",
"expand_here": "Breid hier uit",
"subscribe_to_communities": "Abonneer je op een paar <1>communities</1>.",
"chat": "Praat",
"recent_comments": "Recente reacties",
"no_results": "Geen resultaten",
"setup": "Installatie",
"lemmy_instance_setup": "Installatie van Lemmy-instantie",
"setup_admin": "Maak een administrator",
"your_site": "jouw site",
"modified": "bewerkt",
"nsfw": "NSFW",
"show_nsfw": "Laat NSFW-inhoud zien",
"sponsors": "Sponsoren",
"sponsors_of_lemmy": "Sponsoren van Lemmy",
"sponsor_message":
"Lemmy is vrije, <1>open-source</1> software, dus zonder reclame, winstoogmerk en durfkapitaal, punt. Jouw donaties gaan direct naar de full-time-ontwikkeling van het project. Met veel dank aan de volgende mensen:",
"support_on_patreon": "Ondersteun op Patreon",
"support_on_liberapay": "Ondersteun op Liberapay",
"general_sponsors":
"Algemene sponsors zijn sponsors die tussen de $10 en $39 hebben gegeven aan Lemmy.",
"crypto": "Cryptovaluta",
"bitcoin": "Bitcoin",
"ethereum": "Ethereum",
"monero": "Monero",
"code": "Code",
"joined": "toegetreden",
"by": "door",
"to": "aan",
"transfer_community": "community overplaatsen",
"transfer_site": "site overplaatsen",
"are_you_sure": "weet je het zeker?",
"yes": "ja",
"no": "nee",
"powered_by": "Mogelijk gemaakt door",
"landing_0":
"Lemmy is een <1>linkverzameler</1> / reddit-alternatief, bedoeld om in de <2>fediverse</2> te werken.<3></3>Lemmy kan door om het even wie gehost worden, heeft live-bijgewerkte reacties en is superklein (<4>ca. 80 kB</4>). Federatie in hte ActivityPub-netwerk is gepland. <5></5>Dit is een <6>erg vroege bèta-versie</6>, en een hoop functies zijn stuk of afwezig. <7></7>Stel nieuwe functies voor of meldt fouten <8>hier</8>.<9></9>Gemaakt met <10>Rust</10>, <11>Actix</11>, <12>Inferno</12> en <13>Typescript</13>.",
"not_logged_in": "Niet ingelogd.",
"community_ban": "Je bent verbannen uit deze community.",
"site_ban": "Je bent verbannen van deze site.",
"couldnt_create_comment": "Kon reactie niet maken.",
"couldnt_like_comment": "Kon reactie niet leuk vinden.",
"couldnt_update_comment": "Kon reactie niet bijwerken.",
"couldnt_save_comment": "Kon reactie niet opslaan.",
"no_comment_edit_allowed": "Niet toegestaan om reactie te bewerken.",
"no_post_edit_allowed": "Niet toegestaan om posts te bewerken.",
"no_community_edit_allowed": "Niet toegestaan om community te bewerken.",
"couldnt_find_community": "Kon community niet vinden.",
"couldnt_update_community": "Kon community niet bijwerken.",
"community_already_exists": "Community bestaat al.",
"community_moderator_already_exists": "Community-moderator bestaat al.",
"community_follower_already_exists": "Community-volger bestaat al.",
"community_user_already_banned": "Community-gebruiker reeds verbannen.",
"couldnt_create_post": "Kon post niet maken.",
"couldnt_like_post": "Kon post niet leuk vinden.",
"couldnt_find_post": "Kon post niet vinden.",
"couldnt_get_posts": "Kon posts niet ophalen.",
"couldnt_update_post": "Kon post niet bijwerken.",
"couldnt_save_post": "Kon post niet opslaan.",
"no_slurs": "Geen beledigingen.",
"not_an_admin": "Niet een beheerder.",
"site_already_exists": "Site bestaat al.",
"couldnt_update_site": "Kon site niet bijwerken.",
"couldnt_find_that_username_or_email":
"Kon gebruikersnaam of e-mailadres niet vinden.",
"password_incorrect": "Wachtwoord incorrect.",
"passwords_dont_match": "Wachtwoorden zijn niet gelijk.",
"admin_already_created": "Sorry, er is al een beheerder.",
"user_already_exists": "Gebruiker bestaat al.",
"couldnt_update_user": "Kon gebruiker niet bijwerken.",
"system_err_login":
"Systeemfout. Probeer uit te loggen en weer in te loggen.",
"preview": "voorbeeld",
"upload_image": "Afbeelding uploaden",
"avatar": "Avatar",
"upload_avatar": "Avatar uploaden",
"show_avatars": "Toon avatars",
"formatting_help": "Opmaak hulp",
"view_source": "bekijk bron",
"sticky": "vastplakken",
"unsticky": "loshalen",
"archive_link": "Archiveer link",
"stickied": "vastgeplakt",
"delete_account": "Verwijder account",
"delete_account_confirm": "Waarschuwing: dit zal al uw data voorgoed verwijderen, vul uw wachtwoord in om te bevestigen.",
"banned": "verbannen",
"creator": "auteur",
"number_online": "{{count}} gebruikers online",
"docs": "Documentatie",
"replies": "Reacties",
"mentions": "vermeldingen",
"old_password": "Oud wachtwoord",
"forgot_password": "wachtwoord vergeten",
"reset_password_mail_sent": "Stuur een email om uw wachtwoord te resetten",
"password_change": "Wachtwoord aanpassen",
"new_password": "Nieuw wachtwoord",
"no_email_setup": "Deze server heeft email niet correct opgezet",
"send_notifications_to_email": "Stuur meldingen naar je email",
"language": "Taal",
"browser_default": "Browser standaard",
"downvotes_disabled": "Downvotes geblokkeerd",
"enable_downvotes": "Downvotes toestaan",
"open_registration": "Open registratie",
"registration_closed": "Registratie gesloten",
"enable_nsfw": "NSFW toestaan",
"theme": "Thema",
"create_private_message": "Maak een beveiligd bericht",
"send_secure_message": "Verstuur beveiligd bericht",
"send_message": "Verstuur bericht",
"message": "Bericht",
"old": "Oud",
"message_sent": "Bericht verstuurd",
"messages": "Berichten",
"matrix_user_id": "Matrix gebruikers-id",
"private_message_disclaimer": "Waarschuwing: Privé berichten in Lemmy zijn niet beveiligd. Maak een account aan op <1>Riot.im</1> om veilig te communiceren",
"donate_to_lemmy": "Doneer aan Lemmy",
"donate": "Doneer",
"from": "van",
"logged_in": "Ingelogd",
"email_already_exists": "Email bestaat al",
"couldnt_create_private_message": "Kan beveiligd bericht niet maken",
"no_private_message_edit_allowed": "Niet toegestaan om privé berichten te wijzigen",
"couldnt_update_private_message": "Kan beveiligd bericht niet bijwerken"
}

243
ui/translations/pt_BR.json vendored Normal file
View file

@ -0,0 +1,243 @@
{
"post": "publicação",
"remove_post": "Apagar publicação",
"no_posts": "Sem publicações.",
"create_a_post": "Criar uma publicação",
"create_post": "Criar publicação",
"number_of_posts": "{{count}} publicação",
"number_of_posts_plural": "{{count}} publicações",
"posts": "Publicações",
"related_posts": "Essas publicações podem estar relacionadas",
"cross_posts": "Esse link também foi publicado em:",
"cross_post": "re-publicar",
"cross_posted_to": "Publicado também em: ",
"comments": "Comentários",
"number_of_comments": "{{count}} comentário",
"number_of_comments_plural": "{{count}} comentários",
"remove_comment": "Apagar comentário",
"communities": "Comunidades",
"users": "Usuários",
"create_a_community": "Criar uma comunidade",
"create_community": "Criar comunidade",
"remove_community": "Apagar comunidade",
"subscribed_to_communities": "Inscrito em <1>comunidades</1>",
"trending_communities": "<1>Comunidades</1> em tendência",
"list_of_communities": "Lista de comunidades",
"number_of_communities": "{{count}} comunidade",
"number_of_communities_plural": "{{count}} comunidades",
"community_reqs": "minúsculas, sublinhados e sem espaços.",
"create_private_message": "Criar mensagem privada",
"send_secure_message": "Enviar mensagem segura",
"send_message": "Enviar mensagem",
"message": "Mensagem",
"edit": "editar",
"reply": "responder",
"cancel": "Cancelar",
"preview": "Pré-visualização",
"upload_image": "fazer upload de imagem",
"avatar": "Avatar",
"upload_avatar": "Fazer upload de avatar",
"show_avatars": "Mostrar Avatars",
"formatting_help": "ajuda de formatação",
"view_source": "ver fonte",
"unlock": "desbloquear",
"lock": "bloquear",
"sticky": "fixar",
"unsticky": "desafixar",
"link": "link",
"archive_link": "arquivar link",
"mod": "moderador",
"mods": "moderadores",
"moderates": "Modera",
"settings": "Configurações",
"remove_as_mod": "remover como moderador",
"appoint_as_mod": "designar como moderador",
"modlog": "Registro de moderação",
"admin": "administrador",
"admins": "administradores",
"remove_as_admin": "remover como administrador",
"appoint_as_admin": "designar como administrador",
"remove": "remover",
"removed": "removido",
"locked": "trancado",
"stickied": "fixado",
"reason": "Motivo",
"mark_as_read": "marcar como lido",
"mark_as_unread": "marcar como não lido",
"delete": "apagar",
"deleted": "apagado",
"delete_account": "Apagar conta",
"delete_account_confirm": "Aviso: isso vai apagar seus dados de forma permanente. Escreva sua senha para confirmar.",
"restore": "restaurar",
"ban": "banir",
"ban_from_site": "banido do site",
"unban": "readmitido",
"unban_from_site": "readmitido ao site",
"banned": "banido",
"save": "guardar",
"unsave": "descartar",
"create": "criar",
"creator": "criador",
"username": "nome de usuário",
"email_or_username": "E-mail ou nome de usuário",
"number_of_users": "{{count}} usuário",
"number_of_users_plural": "{{count}} usuários",
"number_of_subscribers": "{{count}} inscrito",
"number_of_subscribers_plural": "{{count}} inscritos",
"number_of_points": "{{count}} ponto",
"number_of_points_plural": "{{count}} pontos",
"number_online": "{{count}} usuário online",
"number_online_plural": "{{count}} usuários online",
"name": "Nome",
"title": "Título",
"category": "Categoria",
"subscribers": "Inscritos",
"both": "Ambos",
"saved": "Guardado",
"unsubscribe": "Cancelar inscrição",
"subscribe": "Inscrever-se",
"subscribed": "Inscrito",
"prev": "Anterior",
"next": "Próximo",
"sidebar": "Barra lateral",
"sort_type": "Ordenação",
"hot": "Popular",
"new": "Novo",
"old": "Velho",
"top_day": "Top do dia",
"week": "Semana",
"month": "Mês",
"year": "Ano",
"all": "Tudo",
"top": "Top",
"api": "API",
"docs": "Docs",
"inbox": "Caixa de entrada",
"inbox_for": "Caixa de entrada de <1>{{user}}</1>",
"mark_all_as_read": "marcar tudo como lido",
"type": "Tipo",
"unread": "Não lido",
"replies": "Respostas",
"mentions": "Menções",
"reply_sent": "Resposta enviada",
"message_sent": "Mensagem enviada",
"search": "Busca",
"overview": "Visão geral",
"view": "Visualização",
"logout": "Sair",
"login_sign_up": "Entrar / Inscrever-se",
"login": "Entrar",
"sign_up": "Inscrever-se",
"notifications_error": "Seu navegador não oferece notificações para a área de trabalho. Tente o Firefox ou o Chrome.",
"unread_messages": "Mensagens não lidas",
"messages": "Mensagens",
"password": "Senha",
"verify_password": "Verifique a senha",
"old_password": "Senha antiga",
"forgot_password": "esqueci a senha",
"reset_password_mail_sent": "Enviado um e-mail para a alteração da senha.",
"password_change": "Alteração de senha",
"new_password": "Nova senha",
"no_email_setup": "Esse servidor não configurou corretamente o e-mail.",
"email": "E-mail",
"matrix_user_id": "Usuário Matrix",
"private_message_disclaimer": "Aviso: mensagens privadas no Lemmy não são seguras. Crie uma conta em <1>Riot.im</1> para troca segura de mensagens.",
"send_notifications_to_email": "Enviar notificações para o e-mail",
"optional": "Opcional",
"expires": "Expira",
"language": "Idioma",
"browser_default": "Padrão do navegador",
"downvotes_disabled": "Votos negativos desativados",
"enable_downvotes": "Permitir votos negativos",
"open_registration": "Permitir registro",
"registration_closed": "Registros desativados",
"enable_nsfw": "Permitir NSFW",
"url": "URL",
"body": "Conteúdo",
"copy_suggested_title": "copiar título sugerido: {{title}}",
"community": "Comunidade",
"expand_here": "Expandir aqui",
"subscribe_to_communities": "Inscreva-se em algumas <1>comunidades</1>.",
"chat": "Chat",
"recent_comments": "Últimos comentários",
"no_results": "Nenhum resultado.",
"setup": "Instalação",
"lemmy_instance_setup": "Criação de instância Lemmy",
"setup_admin": "Configurar administrador do site",
"your_site": "seu site",
"modified": "modificado",
"nsfw": "NSFW",
"show_nsfw": "Mostrar conteúdo NSFW",
"theme": "Tema",
"sponsors": "Patrocinadores",
"sponsors_of_lemmy": "Patrocinadores do Lemmy",
"sponsor_message": "Lemmy é um programa livre e de código aberto, o que significa que não haverá publicidade, monetização ou capital de risco, jamais. Suas doações apoiam de forma direta o desenvolvimento em tempo integral do projeto. Muitos agradecimentos às sequintes pessoas:",
"support_on_patreon": "Colabore no Patreon",
"support_on_liberapay": "Colabore no Liberapay",
"donate_to_lemmy": "Faça uma doação ao Lemmy",
"donate": "Doar",
"general_sponsors": "Patrocinadores são aqueles que doaram entre $10 e $39 ao Lemmy.",
"crypto": "Cryptomoedas",
"bitcoin": "Bitcoin",
"ethereum": "Ethereum",
"monero": "Monero",
"code": "Code",
"joined": "Entrou",
"by": "por",
"to": "para",
"from": "de",
"transfer_community": "transferir comunidade",
"transfer_site": "transferir site",
"are_you_sure": "tem certeza?",
"yes": "sim",
"no": "não",
"powered_by": "Fornecido por",
"landing_0": "Lemmy é um <1>agregador de links</1> / alternativa ao reddit, com a intenção de funcionar junto ao <2>fediverso</2>.<3></3>Pode ser hospedado em servidor próprio, tem atualização de comentários em tempo real e é minúsculo (<4>~80kB</4>). A federação com a rede ActivityPub está no roteiro do projeto. <5></5>Esta é uma <6>versão beta bastante antecipada</6>, e muitas funcionalidades ainda estão quebradas ou ausentes. <7></7>Sugira novas funcionalidades ou reporte erros <8>aqui.</8><9></9>Feito com <10>Rust</10>, <11>Actix</11>, <12>Inferno</12>, <13>Typescript</13>.",
"not_logged_in": "Não autenticado.",
"logged_in": "Autenticado.",
"community_ban": "Você foi banido desta comunidade.",
"site_ban": "Você foi banido do site",
"couldnt_create_comment": "Não foi possível criar o comentário.",
"couldnt_like_comment": "Não foi possível curtir o comentário.",
"couldnt_update_comment": "Não foi possível atualizar o comentário.",
"couldnt_save_comment": "Não foi possível salvar o comentário.",
"no_comment_edit_allowed": "Sem permissão para editar comentário.",
"no_post_edit_allowed": "Sem permissão para editar publicação.",
"no_community_edit_allowed": "Sem permissão para editar comunidade.",
"couldnt_find_community": "Não foi possível encontrar a comunidade.",
"couldnt_update_community": "Não foi possível atualizar a comunidade.",
"community_already_exists": "Esta comunidade já existe.",
"community_moderator_already_exists": "Este moderador da comunidade já existe.",
"community_follower_already_exists": "Este seguidor da comunidade já existe.",
"community_user_already_banned": "Este usuário da comunidade já foi banido.",
"couldnt_create_post": "Não foi possível criar a publicação.",
"couldnt_like_post": "Não foi possível curtir a publicação.",
"couldnt_find_post": "Não foi possível encontrar a publicação.",
"couldnt_get_posts": "Não foi possível obter as publicações",
"couldnt_update_post": "Não foi possível atualizar a publicação",
"couldnt_save_post": "Não foi possível guardar a publicação.",
"no_slurs": "Sem insultos.",
"not_an_admin": "Não é administrador.",
"site_already_exists": "O site já existe.",
"couldnt_update_site": "Não foi possível atualizar o site.",
"couldnt_find_that_username_or_email": "Não foi possível encontrar esse usuário ou e-mail.",
"password_incorrect": "Senha incorreta.",
"passwords_dont_match": "As senhas não são iguais.",
"admin_already_created": "Desculpe, já há um administrador.",
"user_already_exists": "Este usuário já existe.",
"email_already_exists": "Este e-mail já existe.",
"couldnt_update_user": "Não foi possível atualizar o usuário.",
"system_err_login": "Erro no sistema. Tente sair e autenticar-se outra vez.",
"couldnt_create_private_message": "Não foi possível criar mensagem privada.",
"no_private_message_edit_allowed": "Sem permissão para editar mensagem privada.",
"couldnt_update_private_message": "Não foi possível atualizar a mensagem privada.",
"time": "Tempo",
"action": "Ação",
"more": "mais",
"couldnt_get_comments": "Não foi possível obter os comentários.",
"post_title_too_long": "Título da publicação muito longo.",
"upvote": "Voto positivo",
"downvote": "Voto negativo",
"block_leaving": "Tem certeza que quer sair?",
"sorting_help": "ajuda sobre ordenação"
}

204
ui/translations/ru.json vendored Normal file
View file

@ -0,0 +1,204 @@
{
"post": "запись",
"remove_post": "Удалить запись",
"no_posts": "Нет записей.",
"create_a_post": "Создать запись",
"create_post": "Создать запись",
"number_of_posts": "{{count}} записей",
"posts": "Записи",
"related_posts": "Эти записи могут быть связаны",
"comments": "Комментарии",
"number_of_comments": "{{count}} комментариев",
"remove_comment": "Удалить комментарий",
"communities": "Сообщества",
"users": "Пользователи",
"create_a_community": "Создать сообщество",
"create_community": "Создать сообщество",
"remove_community": "Удалить сообщество",
"subscribed_to_communities": "Подписаны на <1>сообщества</1>",
"trending_communities": "<1>Сообщества</1> в тренде",
"list_of_communities": "Список сообществ",
"community_reqs": "строчными буквами, подчеркиваниями и без пробелов.",
"edit": "редактировать",
"reply": "ответить",
"cancel": "Отмена",
"unlock": "разблокировать",
"lock": "заблокировать",
"link": "ссылка",
"mod": "модератор",
"mods": "модераторы",
"moderates": "Модерация",
"settings": "Настройки",
"remove_as_mod": "снять из модераторов",
"appoint_as_mod": "назначить модератором",
"modlog": "Модлог",
"admin": "администратор",
"admins": "администраторы",
"remove_as_admin": "снять из администраторов",
"appoint_as_admin": "назначить администратором",
"remove": "убрать",
"removed": "убрано",
"locked": "заблокировано",
"reason": "Причина",
"mark_as_read": "пометить как прочитанное",
"mark_as_unread": "пометить как непрочитанное",
"delete": "удалить",
"deleted": "удалено",
"restore": "восстановить",
"ban": "заблокировать",
"ban_from_site": "заблокировать на сайте",
"unban": "разблокировать",
"unban_from_site": "разблокировать на сайте",
"save": "сохранить",
"unsave": "не сохранять",
"create": "создать",
"username": "Имя пользователя",
"email_or_username": "Электронная почта или имя пользователя",
"number_of_users": "{{count}} пользователей",
"number_of_subscribers": "{{count}} подписчиков",
"number_of_points": "{{count}} баллов",
"name": "Имя",
"title": "Название",
"category": "Категория",
"subscribers": "Подписчики",
"both": "Оба",
"saved": "Сохранено",
"unsubscribe": "Отписаться",
"subscribe": "Подписаться",
"subscribed": "Подписаны",
"prev": "Назад",
"next": "Далее",
"sidebar": "Боковая панель",
"sort_type": "Тип сортировки",
"hot": "Популярно",
"new": "Новое",
"top_day": "Лучшее за день",
"week": "Неделя",
"month": "Месяц",
"year": "Год",
"all": "Всё",
"top": "Лучшее",
"api": "API",
"inbox": "Входящие",
"inbox_for": "Входящие сообщения для <1>{{user}}</1>",
"mark_all_as_read": "пометить все как прочитанные",
"type": "Тип",
"unread": "Не прочитано",
"reply_sent": "Ответ отправлен",
"search": "Поиск",
"overview": "Обзор",
"view": "Просмотр",
"logout": "Выйти",
"login_sign_up": "Войти / Регистрация",
"login": "Авторизация",
"sign_up": "Регистрация",
"notifications_error": "Уведомления на рабочем столе недоступны в вашем браузере. Попробуйте Firefox или Chrome.",
"unread_messages": "Непрочитанные сообщения",
"password": "Пароль",
"verify_password": "Повторите пароль",
"email": "Электронная почта",
"optional": "Необязательно",
"expires": "Истёк",
"url": "URL",
"body": "Тело",
"copy_suggested_title": "предложенное название: {{title}}",
"community": "Сообщество",
"expand_here": "Расширить здесь",
"subscribe_to_communities": "Подпишитесь на некоторые <1>сообщества</1>.",
"chat": "Чат",
"no_results": "Нет результатов.",
"setup": "Установка",
"lemmy_instance_setup": "Установка инстанции Lemmy",
"setup_admin": "Настройка администратора сайта",
"your_site": "ваш сайт",
"modified": "изменено",
"nsfw": "NSFW",
"show_nsfw": "Показывать NSFW-контент",
"sponsors": "Спонсоры",
"sponsors_of_lemmy": "Спонсоры Lemmy",
"sponsor_message": "Lemmy это бесплатное, <1>открытое</1> программное обеспечение, что означает отсутствие рекламы, монетизации или венчурного капитала, никогда. Ваши пожертвования напрямую поддерживают развитие проекта. Спасибо нижеуказанным людям:",
"support_on_patreon": "Поддержать на Patreon",
"general_sponsors": "Генеральные спонсоры - это те, кто пообещал Lemmy от $10 до $39.",
"crypto": "Крипто",
"bitcoin": "Bitcoin",
"ethereum": "Ethereum",
"code": "Код",
"joined": "Присоединился",
"powered_by": "Работает на",
"landing_0": "Lemmy - это <1>агрегатор ссылок</1> / альтернатива reddit, предназначенный для работы в <2>федиверсе</2>.<3></3>Это самодостаточная система, с обновляемыми комментариями, и эта система крошечная (<4>~80 Кб</4>). Федерация в сети ActivityPub находится в разработке. <5></5>Это <6>очень ранняя бета-версия</6>, и многие функции в настоящее время сломаны или отсутствуют. <7></7>Предлагать новые функции или сообщать об ошибках можно <8>здесь.</8><9></9>Сделано на <10>Rust</10>, <11>Actix</11>, <12>Inferno</12>, <13>Typescript</13>.",
"not_logged_in": "Не авторизованы.",
"community_ban": "Вы были заблокированы на данном сообществе.",
"site_ban": "Вы были заблокированы на данном сайте",
"couldnt_create_comment": "Не получилось создать комментарий.",
"couldnt_like_comment": "Не получилось лайкнуть комментарий.",
"couldnt_update_comment": "Не получилось обновить комментарий.",
"couldnt_save_comment": "Не получилось сохранить комментарий.",
"no_comment_edit_allowed": "Невозможно отредактировать комментарий.",
"no_post_edit_allowed": "Невозможно отредактировать запись.",
"no_community_edit_allowed": "Невозможно отредактировать сообщество.",
"couldnt_find_community": "Не получилось найти сообщество.",
"couldnt_update_community": "Не получилось обновить сообщество.",
"community_already_exists": "Сообщество уже существует.",
"community_moderator_already_exists": "Модератор сообщества уже существует.",
"community_follower_already_exists": "Подписчик сообщества уже существует.",
"community_user_already_banned": "Пользователь сообщества уже заблокирован.",
"couldnt_create_post": "Не получилось создать запись.",
"couldnt_like_post": "Не получилось лайкнуть запись.",
"couldnt_find_post": "Не получилось найти запись.",
"couldnt_get_posts": "Не получилось найти записи",
"couldnt_update_post": "Не получилось обновить запись",
"couldnt_save_post": "Не получилось сохранить запись.",
"no_slurs": "Без оскорблений.",
"not_an_admin": "Не администратор.",
"site_already_exists": "Сайт уже существует.",
"couldnt_update_site": "Не получилось обновить сайт.",
"couldnt_find_that_username_or_email": "Не получилось найти данное имя пользователя или электронную почту.",
"password_incorrect": "Неверный пароль.",
"passwords_dont_match": "Пароли не совпадают.",
"admin_already_created": "Извините, уже есть администратор.",
"user_already_exists": "Пользователь уже существует.",
"couldnt_update_user": "Не получилось обновить пользователя.",
"system_err_login": "Системная ошибка. Попробуйте выйти из системы и вернуться обратно.",
"create_private_message": "Создать личное сообщение",
"send_secure_message": "Послать зашифрованное сообщение",
"send_message": "Послать сообщение",
"message": "Сообщение",
"avatar": "Аватар",
"show_avatars": "Показать Аватары",
"formatting_help": "Помощь в верстке текста",
"sticky": "",
"stickied": "закрепленный пост",
"delete_account": "Удалить аккаунт",
"delete_account_confirm": "Предупреждение: это действите полностью уничтожит все данные вашего аккаунта. Введите свой пароль для подтверждения.",
"docs": "Документация",
"replies": "Ответы",
"mentions": "Упоминания",
"message_sent": "Сообщение отправлено",
"old_password": "Действующий пароль",
"forgot_password": "я забыл(а) пароль",
"reset_password_mail_sent": "Имейл для восстановления пароля был выслан.",
"private_message_disclaimer": "Предупреждение: Приватные сообщения Lemmy на данный момент не зашифрованы. Для безопасной коммуникации создайте аккаунт на <1>Riot.im</1>.",
"send_notifications_to_email": "Посылать уведомления на e-mail адрес",
"language": "Язык",
"browser_default": "Браузер по умолчанию",
"open_registration": "Открыть регистрацию",
"registration_closed": "Регистрация закрыта",
"recent_comments": "Недавние комментарии",
"cross_posts": "Эта ссылка была также опубликована в следующих сообществах:",
"cross_post": "Опубликовать в других сообществах",
"cross_posted_to": "Также опубликовано в: ",
"support_on_liberapay": "Поддержать на Librepay",
"donate_to_lemmy": "Поддержать Lemmy",
"transfer_community": "передать сообщество",
"yes": "да",
"no": "нет",
"preview": "Предварительный просмотр",
"upload_image": "загрузить изображение",
"upload_avatar": "Загрузить Аватар",
"messages": "Сообщения",
"new_password": "Новый пароль",
"theme": "Визуальная тема",
"post_title_too_long": "Длина названия поста превышает допустимый лимит.",
"time": "Время",
"action": "Действие"
}

193
ui/translations/sv.json vendored Normal file
View file

@ -0,0 +1,193 @@
{
"post": "inlägg",
"remove_post": "Radera inlägg",
"no_posts": "Inga inlägg.",
"create_a_post": "Skriv ett inlägg",
"create_post": "Skapa inlägg",
"number_of_posts": "{{count}} inlägg",
"posts": "Inlägg",
"related_posts": "Dessa inlägg kan vara relaterade",
"cross_posts": "Den här länken har även publicerats i:",
"cross_post": "tvärinlägg",
"comments": "Kommentarer",
"number_of_comments": "{{count}} kommentarer",
"remove_comment": "Radera kommentar",
"communities": "Gemenskaper",
"users": "Användare",
"create_a_community": "Skapa en gemenskap",
"create_community": "Skapa gemenskap",
"remove_community": "Radera gemenskap",
"subscribed_to_communities": "Prenumererar på <1>gemenskaper</1>",
"trending_communities": "Populära <1>gemenskaper</1>",
"list_of_communities": "Lista över gemenskaper",
"number_of_communities": "{{count}} gemenskaper",
"community_reqs": "gemener, understreck och inga blanksteg.",
"edit": "redigera",
"reply": "svara",
"cancel": "Avbryt",
"preview": "Förhandsgranskning",
"upload_image": "ladda upp bild",
"formatting_help": "formateringshjälp",
"view_source": "visa källkod",
"unlock": "lås upp",
"lock": "lås",
"sticky": "fastnålad",
"unsticky": "inte fastnålad",
"link": "länk",
"mod": "moderator",
"mods": "moderatorer",
"moderates": "Modererar",
"settings": "Inställningar",
"remove_as_mod": "tag bort som moderator",
"appoint_as_mod": "lägg till som moderator",
"modlog": "Moderationslogg",
"admin": "administratör",
"admins": "administratörer",
"remove_as_admin": "tag bort som administratör",
"appoint_as_admin": "lägg till som administratör",
"remove": "ta bort",
"removed": "borttagen",
"locked": "låst",
"stickied": "fastnålad",
"reason": "Anledning",
"mark_as_read": "markera som läst",
"mark_as_unread": "markera som oläst",
"delete": "radera",
"deleted": "raderad",
"delete_account": "Ta bort konto",
"delete_account_confirm":
"Varning: den här åtgärden kommer radera alla dina data permanent. Är du säker?",
"restore": "återställ",
"ban": "blockera",
"ban_from_site": "blockera från webbplats",
"unban": "ta bort blockering",
"unban_from_site": "ta bort blockering från webbplats",
"banned": "blocerad",
"save": "spara",
"unsave": "förkasta",
"create": "skapa",
"creator": "skapare",
"username": "Användarnamn",
"email_or_username": "E-postadress eller användarnamn",
"number_of_users": "{{count}} användare",
"number_of_subscribers": "{{count}} prenumeranter",
"number_of_points": "{{count}} poäng",
"number_online": "{{count}} användare inloggade",
"name": "Namn",
"title": "Titel",
"category": "Kategori",
"subscribers": "Prenumeranter",
"both": "Båda",
"saved": "Sparade",
"unsubscribe": "Avbryt prenumeration",
"subscribe": "Prenumerera",
"subscribed": "Prenumererar",
"prev": "Föregående",
"next": "Nästa",
"sidebar": "Sidlist",
"sort_type": "Sorteringstyp",
"hot": "Hett",
"new": "Nytt",
"top_day": "Dagstoppen",
"week": "Vecka",
"month": "Månad",
"year": "År",
"all": "Samtliga",
"top": "Topp",
"api": "API",
"inbox": "Inkorg",
"inbox_for": "Inkorg tillhörande <1>{{user}}</1>",
"mark_all_as_read": "markera alla som lästa",
"type": "Typ",
"unread": "Oläst",
"reply_sent": "Svar skickat",
"search": "Sök",
"overview": "Översikt",
"view": "Vy",
"logout": "Logga ut",
"login_sign_up": "Logga in eller skapa konto",
"login": "Logga in",
"sign_up": "Skapa konto",
"notifications_error":
"Din webbläsare har inte stöd för skrivbordsaviseringar. Testa Firefox eller Chrome.",
"unread_messages": "Olästa meddelanden",
"password": "Lösenord",
"verify_password": "Bekräfta lösenord",
"email": "E-postadress",
"optional": "Valfritt",
"expires": "Går ut",
"url": "URL",
"body": "Text",
"copy_suggested_title": "kopiera föreslagen titel: {{title}}",
"community": "Gemenskap",
"expand_here": "Utvidga här",
"subscribe_to_communities": "Prenumerera på några <1>gemenskaper</1>.",
"chat": "Chatta",
"recent_comments": "Senaste kommentarer",
"no_results": "Inga resultat.",
"setup": "Installering",
"lemmy_instance_setup": "Installering av Lemmy-instans",
"setup_admin": "Skapa en administratör",
"your_site": "din webbplats",
"modified": "ändrades",
"nsfw": "Känsligt eller oförbehållsamt innehåll",
"show_nsfw": "Visa känsligt eller oförbehållsamt innehåll",
"theme": "Utseende",
"sponsors": "Sponsorer",
"sponsors_of_lemmy": "Lemmys sponsorer",
"sponsor_message":
"Lemmy är fri mjukvara med <1>öppen källkod</1>, vilket innebär att ingen reklam, vinstindrivning eller venturekapital förekommer, någonsin. Dina donationer går direkt till att stöda utvecklingen av projektet. Stort tack till följande personer:",
"support_on_patreon": "Stöd på Patreon",
"general_sponsors":
"Allmänna sponsorer är dem som givit mellan 10 och 39\u00a0dollar till Lemmy.",
"crypto": "Kryptovaluta",
"bitcoin": "Bitcoin",
"ethereum": "Ethereum",
"monero": "Monero",
"code": "Kod",
"joined": "Gick med",
"by": "av",
"to": "till",
"transfer_community": "flytta gemenskap",
"transfer_site": "flytta webbplats",
"are_you_sure": "är du säker?",
"yes": "ja",
"no": "nej",
"powered_by": "Drivs av",
"landing_0":
"Lemmy är en <1>länksamlare</1> och alternativ till reddit, ämnad att fungera i <2>Fediversumet</2>.<3></3>Lemmy kan drivas av vem som helst, har kommentarstrådar som updateras i realid och är mycket liten (<4>ca 80\u00a0kB</4>). Federering med ActivityPub-nätverket är planerat. <5></5>Detta är en <6>väldigt tidig betaversion</6> och många funktioner saknas därför eller är trasiga.<7></7>Föreslå nya funktioner eller anmäl buggar <8>här</8>.<9></9>Skapad i <10>Rust</10>, <11>Actix</11>, <12>Inferno</12> och <13>Typescript</13>.",
"not_logged_in": "Inte inloggad.",
"community_ban": "Du har blockerats från den här gemenskapen.",
"site_ban": "Du har blockerats från webbplatsen.",
"couldnt_create_comment": "Kunde inte skapa kommentar.",
"couldnt_like_comment": "Kunde inte gilla kommentar.",
"couldnt_update_comment": "Kunde inte uppdatera kommentar.",
"couldnt_save_comment": "Kunde inte spara kommentar.",
"no_comment_edit_allowed": "Har inte behörighet att redigera komentar.",
"no_post_edit_allowed": "Har inte behörighet att redigera inlägg.",
"no_community_edit_allowed": "Har inte behörighet att redigera gemenskap.",
"couldnt_find_community": "Kunde inte hitta gemenskap.",
"couldnt_update_community": "Kunde inte uppdatera gemenskap.",
"community_already_exists": "Gemenskapen finns redan.",
"community_moderator_already_exists": "Gemenskapsmoderatorn finns redan.",
"community_follower_already_exists": "Gemenskapsföljaren finns redan.",
"community_user_already_banned": "Gemenskapsanvändaren redan blockerad.",
"couldnt_create_post": "Kunde inte skapa inlägg.",
"couldnt_like_post": "Kunde inte gilla inlägg.",
"couldnt_find_post": "Kunde inte hitta inlägg.",
"couldnt_get_posts": "Kunde inte hämta inlägg.",
"couldnt_update_post": "Kunde inte uppdatera inlägg.",
"couldnt_save_post": "Kunde inte spara inlägg.",
"no_slurs": "Inga förolämpningar.",
"not_an_admin": "Inte en administratör.",
"site_already_exists": "Webbplatsen finns redan.",
"couldnt_update_site": "Kunde inte uppdatera webbplats.",
"couldnt_find_that_username_or_email":
"Kunde inte hitta det användarnamnet eller e-postadressen.",
"password_incorrect": "Ogiltigt lösenord.",
"passwords_dont_match": "Lösenorden stämmer inte överens.",
"admin_already_created": "Beklagar, men det finns redan en administratör.",
"user_already_exists": "Användaren finns redan.",
"couldnt_update_user": "Kunde inte uppdatera användare.",
"system_err_login": "Systemfel. Försök att logga ut och sedan in igen."
}

162
ui/translations/zh.json vendored Normal file
View file

@ -0,0 +1,162 @@
{
"post": "帖子",
"remove_post": "移除帖子",
"no_posts": "没有帖子.",
"create_a_post": "创建新帖子",
"create_post": "创建帖子",
"number_of_posts": "{{count}} 帖子",
"posts": "帖子",
"related_posts": "相关的帖子",
"comments": "评论",
"number_of_comments": "{{count}} 评论",
"remove_comment": "移除评论",
"communities": "节点",
"create_a_community": "创建新节点",
"create_community": "创建节点",
"remove_community": "移除节点",
"subscribed_to_communities": "订阅新 <1>节点</1>",
"trending_communities": "<1>节点</1>趋势",
"list_of_communities": "节点列表",
"community_reqs": "包含小写与下划线且没有空格的字符串.",
"edit": "编辑",
"reply": "回应",
"cancel": "取消",
"unlock": "解锁",
"lock": "加锁",
"link": "链接",
"mod": "监管人",
"mods": "监管人",
"moderates": "监管",
"remove_as_mod": "添加监管人",
"appoint_as_mod": "移除监管人",
"modlog": "监管记录",
"admin": "管理权限",
"admins": "管理权限",
"remove_as_admin": "移除管理权限",
"appoint_as_admin": "添加管理权限",
"remove": "移除",
"removed": "已移除",
"locked": "已加锁",
"reason": "原因",
"mark_as_read": "标记未读",
"mark_as_unread": "标记已读",
"delete": "删除",
"deleted": "已删除",
"restore": "恢复",
"ban": "禁止",
"ban_from_site": "禁止此站点",
"unban": "取消",
"unban_from_site": "取消禁止",
"save": "保存",
"unsave": "取消保存",
"create": "创建",
"username": "用户名",
"email_or_username": "邮箱或用户名",
"number_of_users": "{{count}} 用户",
"number_of_subscribers": "{{count}} 订阅",
"number_of_points": "{{count}} 分",
"name": "名字",
"title": "标题",
"category": "分类",
"subscribers": "订阅",
"both": "全部",
"saved": "保存",
"unsubscribe": "取消订阅",
"subscribe": "订阅",
"subscribed": "已订阅",
"prev": "上一页",
"next": "下一页",
"sidebar": "侧边栏",
"sort_type": "排序方式",
"hot": "最热",
"new": "最新",
"top_day": "今日",
"week": "周",
"month": "月",
"year": "年",
"all": "所有",
"top": "最热",
"api": "应用程式介面",
"inbox": "收件箱",
"inbox_for": "<1>{{user}}</1> 收件箱",
"mark_all_as_read": "标记所有已读",
"type": "类型",
"unread": "未读",
"reply_sent": "回复发送",
"search": "搜索",
"overview": "个人中心",
"view": "查看",
"logout": "注销",
"login_sign_up": "登录/注册",
"login": "登录",
"sign_up": "注册",
"notifications_error": "你的浏览器不支持桌面通知,尝试 Firefox 或 Chrome",
"unread_messages": "未读消息",
"password": "密码",
"verify_password": "确认密码",
"email": "邮箱",
"optional": "选项",
"expires": "过期",
"url": "网址",
"body": "内容",
"copy_suggested_title": "复制建议的标题: {{title}}",
"community": "节点",
"expand_here": "展开",
"subscribe_to_communities": "订阅一些 <1>节点</1>.",
"chat": "聊天",
"no_results": "没有结果.",
"setup": "设置",
"lemmy_instance_setup": "Lemmy Instance Setup",
"setup_admin": "设置管理员",
"your_site": "你的站点",
"modified": "修改",
"sponsors": "发起人",
"sponsors_of_lemmy": "Lemmy 的发起人",
"sponsor_message":
"Lemmy is free, <1>open-source</1> software, meaning no advertising, monetizing, or venture capital, ever. Your donations directly support full-time development of the project. Thank you to the following people:",
"support_on_patreon": "在 Patreon 赞助",
"support_on_liberapay": "在 on 赞助",
"general_sponsors":
"General Sponsors are those that pledged $10 to $39 to Lemmy.",
"crypto": "加密",
"bitcoin": "比特币",
"ethereum": "以太币",
"code": "代码",
"joined": "已加入",
"powered_by": "保留所有权利",
"landing_0":
"Lemmy is a <1>link aggregator</1> / reddit alternative, intended to work in the <2>fediverse</2>.<3></3>It's self-hostable, has live-updating comment threads, and is tiny (<4>~80kB</4>). Federation into the ActivityPub network is on the roadmap. <5></5>This is a <6>very early beta version</6>, and a lot of features are currently broken or missing. <7></7>Suggest new features or report bugs <8>here.</8><9></9>Made with <10>Rust</10>, <11>Actix</11>, <12>Inferno</12>, <13>Typescript</13>.",
"not_logged_in": "未登录.",
"community_ban": "你被此节点禁止.",
"site_ban": "你被此站点禁止",
"couldnt_create_comment": "不能创建评论.",
"couldnt_like_comment": "不能收藏评论.",
"couldnt_update_comment": "不能更新评论.",
"couldnt_save_comment": "不能保存评论.",
"no_comment_edit_allowed": "不允许编辑评论.",
"no_post_edit_allowed": "不运行编辑帖子.",
"no_community_edit_allowed": "不允许编辑节点.",
"couldnt_find_community": "不能找到节点.",
"couldnt_update_community": "不能更新节点.",
"community_already_exists": "节点已存在.",
"community_moderator_already_exists": "节点监管人已存在.",
"community_follower_already_exists": "节点追随者已存在.",
"community_user_already_banned": "节点用户已禁止.",
"couldnt_create_post": "不能创建帖子.",
"couldnt_like_post": "不能收藏帖子.",
"couldnt_find_post": "不能搜寻帖子.",
"couldnt_get_posts": "不能获取帖子",
"couldnt_update_post": "不能更新帖子",
"couldnt_save_post": "不能保持帖子.",
"no_slurs": "和谐.",
"not_an_admin": "不是管理员.",
"site_already_exists": "站点已存在.",
"couldnt_update_site": "不能更新站点.",
"couldnt_find_that_username_or_email": "用户名/邮箱不存在.",
"password_incorrect": "密码不正确.",
"passwords_dont_match": "密码不匹配.",
"admin_already_created": "抱歉,管理员已存在.",
"user_already_exists": "用户已存在.",
"couldnt_update_user": "不可以更新用户.",
"system_err_login": "系统错误. 尝试注销再登录"
}

59
ui/yarn.lock vendored
View file

@ -104,6 +104,11 @@
lodash "^4.17.13" lodash "^4.17.13"
to-fast-properties "^2.0.0" to-fast-properties "^2.0.0"
"@popperjs/core@^2.0.6":
version "2.0.6"
resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.0.6.tgz#5a39ac118811ca844155b0ad5190b8c24f35e533"
integrity sha512-zj7Gw8QC4jmR92eKUvtrZUEpl2ypRbq+qlE4pwf9n2hnUO9BOAcWUs4/Ht+gNIbFt98xtqhLvccdCfD469MzpQ==
"@samverschueren/stream-to-observable@^0.3.0": "@samverschueren/stream-to-observable@^0.3.0":
version "0.3.0" version "0.3.0"
resolved "https://registry.yarnpkg.com/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.0.tgz#ecdf48d532c58ea477acfcab80348424f8d0662f" resolved "https://registry.yarnpkg.com/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.0.tgz#ecdf48d532c58ea477acfcab80348424f8d0662f"
@ -2229,14 +2234,14 @@ inferno-i18next@nimbusec-oss/inferno-i18next:
inferno-shared "^7.1.12" inferno-shared "^7.1.12"
inferno-vnode-flags "^7.1.12" inferno-vnode-flags "^7.1.12"
inferno-router@^7.0.1: inferno-router@^7.4.2:
version "7.4.0" version "7.4.2"
resolved "https://registry.yarnpkg.com/inferno-router/-/inferno-router-7.4.0.tgz#0af6b931c58f426d0d7e7754d51a51300882364a" resolved "https://registry.yarnpkg.com/inferno-router/-/inferno-router-7.4.2.tgz#2e45f382f0c6adc1947da4c6c517f7e89d82f165"
integrity sha512-6Q76UjAiPd1mO/5sbDaEoEN9MdMHKkEXnYNOZ02sSudj5jWCFzJ/JnSF526uNxAHQpw2DKCh2pNiu6qf/b1vQQ== integrity sha512-3iNGhp/x16XXD9+/WCLEWLC0dH6UUl+ZKk14gPhrVJQdeqfV387aaVw9Y+YpHZZWDRkqIL9MNyHHK27QL8gY/A==
dependencies: dependencies:
history "^4.10.1" history "^4.10.1"
hoist-non-inferno-statics "^1.1.3" hoist-non-inferno-statics "^1.1.3"
inferno "7.4.0" inferno "7.4.2"
path-to-regexp-es6 "1.7.0" path-to-regexp-es6 "1.7.0"
inferno-shared@7.4.0, inferno-shared@^7.1.12: inferno-shared@7.4.0, inferno-shared@^7.1.12:
@ -2244,12 +2249,22 @@ inferno-shared@7.4.0, inferno-shared@^7.1.12:
resolved "https://registry.yarnpkg.com/inferno-shared/-/inferno-shared-7.4.0.tgz#4491deb75348019939b160cd5655196afa13ced0" resolved "https://registry.yarnpkg.com/inferno-shared/-/inferno-shared-7.4.0.tgz#4491deb75348019939b160cd5655196afa13ced0"
integrity sha512-6aa1fC/e4SP2lOLNg4ZS5Zz2SC+DnM7WxQbggmHhLSyOqZrsPrpZSlX25LbjR9lkhMrq6cmki3yInYFGuDzlRg== integrity sha512-6aa1fC/e4SP2lOLNg4ZS5Zz2SC+DnM7WxQbggmHhLSyOqZrsPrpZSlX25LbjR9lkhMrq6cmki3yInYFGuDzlRg==
inferno-shared@7.4.2:
version "7.4.2"
resolved "https://registry.yarnpkg.com/inferno-shared/-/inferno-shared-7.4.2.tgz#400cf6d19a077af9e5e852e1f189726391efa273"
integrity sha512-SULfgzj/PuyMd3rHThEXkeEdZorjcr/q+kaqbwr7C2XhIPCk4e5jcRKZujI6YCSahGA9WFwP2Mft1v5PsaaNeg==
inferno-vnode-flags@7.4.0, inferno-vnode-flags@^7.1.12: inferno-vnode-flags@7.4.0, inferno-vnode-flags@^7.1.12:
version "7.4.0" version "7.4.0"
resolved "https://registry.yarnpkg.com/inferno-vnode-flags/-/inferno-vnode-flags-7.4.0.tgz#5c049a73f3ff84a51458b06d279d6b18d09acdf0" resolved "https://registry.yarnpkg.com/inferno-vnode-flags/-/inferno-vnode-flags-7.4.0.tgz#5c049a73f3ff84a51458b06d279d6b18d09acdf0"
integrity sha512-TMPrvAxR2uUVSowLKnGgH34eWXErIYCdJ4d5hj8cSc8ta8knN6dj0z47UIw13qvmWfNjHgwm0C2/cm+G6fckiA== integrity sha512-TMPrvAxR2uUVSowLKnGgH34eWXErIYCdJ4d5hj8cSc8ta8knN6dj0z47UIw13qvmWfNjHgwm0C2/cm+G6fckiA==
inferno@7.4.0, inferno@^7.0.1, inferno@^7.1.12: inferno-vnode-flags@7.4.2:
version "7.4.2"
resolved "https://registry.yarnpkg.com/inferno-vnode-flags/-/inferno-vnode-flags-7.4.2.tgz#54982dabe34f308853ba17de7de4241e23769135"
integrity sha512-sV4KqqvZH4MW9/dNbC9blHInnpQSqMWouU5VlanbJ+NhJ8ufPwsDy0/+jiA2aODpg2HFHwVMJFF1fsewPqNtLQ==
inferno@7.4.0, inferno@^7.1.12:
version "7.4.0" version "7.4.0"
resolved "https://registry.yarnpkg.com/inferno/-/inferno-7.4.0.tgz#8d3dc03562c6851043a1a467fd509f222e9dbf85" resolved "https://registry.yarnpkg.com/inferno/-/inferno-7.4.0.tgz#8d3dc03562c6851043a1a467fd509f222e9dbf85"
integrity sha512-oEXx5iQmGXOvAPj1TZyCo6ndOc4qPg9zBLigMpkApAiV1SM/bri0M1eA/kD3e9jptcof9TwLBJD9bL6E6tq2tg== integrity sha512-oEXx5iQmGXOvAPj1TZyCo6ndOc4qPg9zBLigMpkApAiV1SM/bri0M1eA/kD3e9jptcof9TwLBJD9bL6E6tq2tg==
@ -2258,6 +2273,15 @@ inferno@7.4.0, inferno@^7.0.1, inferno@^7.1.12:
inferno-vnode-flags "7.4.0" inferno-vnode-flags "7.4.0"
opencollective-postinstall "^2.0.2" opencollective-postinstall "^2.0.2"
inferno@7.4.2, inferno@^7.4.2:
version "7.4.2"
resolved "https://registry.yarnpkg.com/inferno/-/inferno-7.4.2.tgz#833cc423ee7b939fad705c59ea41924f31c92453"
integrity sha512-RsmuN8F7lAWTTuy2juf3Tqn/BihkRNdy0WZN+vuyryuEySKHBA1fruyq6K0covF3Ja8mAdha5NNISZz9ltgcug==
dependencies:
inferno-shared "7.4.2"
inferno-vnode-flags "7.4.2"
opencollective-postinstall "^2.0.2"
inflight@^1.0.4: inflight@^1.0.4:
version "1.0.6" version "1.0.6"
resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
@ -4413,6 +4437,13 @@ tiny-warning@^1.0.0:
resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754" resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754"
integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==
tippy.js@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/tippy.js/-/tippy.js-6.0.0.tgz#6bc4f477ea82ef344db51ae34f106a8b25f2d02c"
integrity sha512-2NVc5A8cnO9N/Fk+tTU6KEm6m8ZXT1u3pOY756zZ5BE38rWDl/hVyoWhTfM79HW1nEJSpn/VujqAMMZGHsE9qQ==
dependencies:
"@popperjs/core" "^2.0.6"
tmp@^0.0.33: tmp@^0.0.33:
version "0.0.33" version "0.0.33"
resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9"
@ -4475,10 +4506,10 @@ tough-cookie@~2.4.3:
psl "^1.1.24" psl "^1.1.24"
punycode "^1.4.1" punycode "^1.4.1"
tributejs@^4.1.1: tributejs@^5.0.0:
version "4.1.1" version "5.0.0"
resolved "https://registry.yarnpkg.com/tributejs/-/tributejs-4.1.1.tgz#f169a4ad12e485241140ec1ab987b460950c974c" resolved "https://registry.yarnpkg.com/tributejs/-/tributejs-5.0.0.tgz#2c5301a79c19d7a72d23e995bf7c9f47c2a34f23"
integrity sha512-jc+PcaiNzMjCn2LAQb3i4ic94EsSfLW8Jlk1sK2cb6hLcZFalU9ThcF8rxuKkTUKv1GIvTwN8XseLzCXLxB4lw== integrity sha512-aPUpq4+NTXRq1OcdoeiFg9d+wM+J0b7dpL7MNVxqo8JIgChtkx8HnsPVl/uZ4Z1ChTF9UI1ffbvTfJRHqJjjAw==
ts-node@^8.6.2: ts-node@^8.6.2:
version "8.6.2" version "8.6.2"
@ -4572,10 +4603,10 @@ typescript@^2.6.2:
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.9.2.tgz#1cbf61d05d6b96269244eb6a3bce4bd914e0f00c" resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.9.2.tgz#1cbf61d05d6b96269244eb6a3bce4bd914e0f00c"
integrity sha512-Gr4p6nFNaoufRIY4NMdpQRNmgxVIGMs4Fcu/ujdYk3nAZqk7supzBE9idmvfZIlH/Cuj//dvi+019qEue9lV0w== integrity sha512-Gr4p6nFNaoufRIY4NMdpQRNmgxVIGMs4Fcu/ujdYk3nAZqk7supzBE9idmvfZIlH/Cuj//dvi+019qEue9lV0w==
typescript@^3.7.5: typescript@^3.8.3:
version "3.7.5" version "3.8.3"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.5.tgz#0692e21f65fd4108b9330238aac11dd2e177a1ae" resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.8.3.tgz#409eb8544ea0335711205869ec458ab109ee1061"
integrity sha512-/P5lkRXkWHNAbcJIiHPfRoKqyd7bsyCma1hZNUGfn20qm64T6ZBlrzprymeu918H+mB/0rIg2gGK/BXkhhYgBw== integrity sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w==
uc.micro@^1.0.1, uc.micro@^1.0.5: uc.micro@^1.0.1, uc.micro@^1.0.5:
version "1.0.6" version "1.0.6"