mirror of
https://github.com/LemmyNet/lemmy.git
synced 2024-11-24 02:11:03 +00:00
commit
43c55027f9
44 changed files with 1018 additions and 188 deletions
41
README.md
vendored
41
README.md
vendored
|
@ -7,10 +7,8 @@
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
|
|
||||||
[![Github](https://img.shields.io/badge/-Github-blue)](https://github.com/dessalines/lemmy)
|
|
||||||
[![Gitlab](https://img.shields.io/badge/-Gitlab-yellowgreen)](https://gitlab.com/dessalines/lemmy)
|
|
||||||
[![Mastodon Follow](https://img.shields.io/mastodon/follow/810572?domain=https%3A%2F%2Fmastodon.social&style=social)](https://mastodon.social/@LemmyDev)
|
|
||||||
![GitHub stars](https://img.shields.io/github/stars/dessalines/lemmy?style=social)
|
![GitHub stars](https://img.shields.io/github/stars/dessalines/lemmy?style=social)
|
||||||
|
[![Mastodon Follow](https://img.shields.io/mastodon/follow/810572?domain=https%3A%2F%2Fmastodon.social&style=social)](https://mastodon.social/@LemmyDev)
|
||||||
[![Matrix](https://img.shields.io/matrix/rust-reddit-fediverse:matrix.org.svg?label=matrix-chat)](https://riot.im/app/#/room/#rust-reddit-fediverse:matrix.org)
|
[![Matrix](https://img.shields.io/matrix/rust-reddit-fediverse:matrix.org.svg?label=matrix-chat)](https://riot.im/app/#/room/#rust-reddit-fediverse:matrix.org)
|
||||||
![GitHub tag (latest SemVer)](https://img.shields.io/github/tag/dessalines/lemmy.svg)
|
![GitHub tag (latest SemVer)](https://img.shields.io/github/tag/dessalines/lemmy.svg)
|
||||||
[![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)
|
||||||
|
@ -50,24 +48,36 @@ Made with [Rust](https://www.rust-lang.org), [Actix](https://actix.rs/), [Infern
|
||||||
- [Releases / Changelog](/RELEASES.md)
|
- [Releases / Changelog](/RELEASES.md)
|
||||||
- [Contributing](https://dev.lemmy.ml/docs/contributing.html)
|
- [Contributing](https://dev.lemmy.ml/docs/contributing.html)
|
||||||
|
|
||||||
|
## Repository Mirrors
|
||||||
|
|
||||||
|
- [GitHub](https://github.com/dessalines/lemmy)
|
||||||
|
- [Gitea](https://yerbamate.dev/dessalines/lemmy)
|
||||||
|
- [GitLab](https://gitlab.com/dessalines/lemmy)
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- Open source, [AGPL License](/LICENSE).
|
- Open source, [AGPL License](/LICENSE).
|
||||||
- Self hostable, easy to deploy.
|
- Self hostable, easy to deploy.
|
||||||
- Comes with [Docker](#docker), [Ansible](#ansible), [Kubernetes](#kubernetes).
|
- Comes with [Docker](#docker), [Ansible](#ansible), [Kubernetes](#kubernetes).
|
||||||
- Clean, mobile-friendly interface.
|
- Clean, mobile-friendly interface.
|
||||||
|
- Only a minimum of a username and password is required to sign up!
|
||||||
|
- User avatar support.
|
||||||
- Live-updating Comment threads.
|
- Live-updating Comment threads.
|
||||||
- Full vote scores `(+/-)` like old reddit.
|
- Full vote scores `(+/-)` like old reddit.
|
||||||
- Themes, including light, dark, and solarized.
|
- Themes, including light, dark, and solarized.
|
||||||
- Emojis with autocomplete support. Start typing `:`
|
- Emojis with autocomplete support. Start typing `:`
|
||||||
- User tagging using `@`, Community tagging using `#`.
|
- User tagging using `@`, Community tagging using `#`.
|
||||||
|
- Integrated image uploading in both posts and comments.
|
||||||
|
- 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.
|
||||||
- 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.
|
||||||
- A *similar post search* when creating new posts. Great for question / answer communities.
|
- A *similar post search* when creating new posts. Great for question / answer communities.
|
||||||
- Moderation abilities.
|
- Moderation abilities.
|
||||||
- Public Moderation Logs.
|
- Public Moderation Logs.
|
||||||
|
- Can sticky posts to the top of communities.
|
||||||
- Both site admins, and community moderators, who can appoint other moderators.
|
- Both site admins, and community moderators, who can appoint other moderators.
|
||||||
- Can lock, remove, and restore posts and comments.
|
- Can lock, remove, and restore posts and comments.
|
||||||
- Can ban and unban users from communities and the site.
|
- Can ban and unban users from communities and the site.
|
||||||
|
@ -151,22 +161,23 @@ Lemmy is free, open-source software, meaning no advertising, monetizing, or vent
|
||||||
|
|
||||||
If you'd like to add translations, take a look a look at the [English translation file](ui/src/translations/en.ts).
|
If you'd like to add translations, take a look a look at the [English translation file](ui/src/translations/en.ts).
|
||||||
|
|
||||||
- Languages supported: English (`en`), Chinese (`zh`), Dutch (`nl`), Esperanto (`eo`), French (`fr`), Spanish (`es`), Swedish (`sv`), German (`de`), Russian (`ru`), Italian (`it`).
|
- Languages supported: Catalan, (`ca`), English (`en`), Chinese (`zh`), Dutch (`nl`), Esperanto (`eo`), Finnish (`fi`), French (`fr`), Spanish (`es`), Swedish (`sv`), German (`de`), Russian (`ru`), Italian (`it`).
|
||||||
|
|
||||||
<!-- translations -->
|
<!-- translations -->
|
||||||
|
|
||||||
lang | done | missing
|
lang | done | missing
|
||||||
--- | --- | ---
|
---- | ---- | -------
|
||||||
de | 88% | create_private_message,send_secure_message,send_message,message,avatar,upload_avatar,show_avatars,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,email_already_exists,couldnt_create_private_message,no_private_message_edit_allowed,couldnt_update_private_message
|
ca | 100% | old
|
||||||
eo | 76% | 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,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,donate_to_lemmy,donate,from,are_you_sure,yes,no,logged_in,email_already_exists,couldnt_create_private_message,no_private_message_edit_allowed,couldnt_update_private_message
|
de | 87% | 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,email_already_exists,couldnt_create_private_message,no_private_message_edit_allowed,couldnt_update_private_message
|
||||||
es | 83% | create_private_message,send_secure_message,send_message,message,avatar,upload_avatar,show_avatars,archive_link,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,donate_to_lemmy,donate,from,logged_in,email_already_exists,couldnt_create_private_message,no_private_message_edit_allowed,couldnt_update_private_message
|
eo | 75% | 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,donate_to_lemmy,donate,from,are_you_sure,yes,no,logged_in,email_already_exists,couldnt_create_private_message,no_private_message_edit_allowed,couldnt_update_private_message
|
||||||
fr | 83% | create_private_message,send_secure_message,send_message,message,avatar,upload_avatar,show_avatars,archive_link,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,donate_to_lemmy,donate,from,logged_in,email_already_exists,couldnt_create_private_message,no_private_message_edit_allowed,couldnt_update_private_message
|
es | 100% | old
|
||||||
it | 84% | create_private_message,send_secure_message,send_message,message,avatar,upload_avatar,show_avatars,archive_link,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,email_already_exists,couldnt_create_private_message,no_private_message_edit_allowed,couldnt_update_private_message
|
fi | 100% | old
|
||||||
nl | 93% | create_private_message,send_secure_message,send_message,message,message_sent,messages,matrix_user_id,private_message_disclaimer,donate_to_lemmy,donate,from,logged_in,email_already_exists,couldnt_create_private_message,no_private_message_edit_allowed,couldnt_update_private_message
|
fr | 83% | 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,donate_to_lemmy,donate,from,logged_in,email_already_exists,couldnt_create_private_message,no_private_message_edit_allowed,couldnt_update_private_message
|
||||||
ru | 72% | cross_posts,cross_post,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,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,donate_to_lemmy,donate,monero,by,to,from,transfer_community,transfer_site,are_you_sure,yes,no,logged_in,email_already_exists,couldnt_create_private_message,no_private_message_edit_allowed,couldnt_update_private_message
|
it | 84% | 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,email_already_exists,couldnt_create_private_message,no_private_message_edit_allowed,couldnt_update_private_message
|
||||||
sv | 83% | create_private_message,send_secure_message,send_message,message,avatar,upload_avatar,show_avatars,archive_link,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,donate_to_lemmy,donate,from,logged_in,email_already_exists,couldnt_create_private_message,no_private_message_edit_allowed,couldnt_update_private_message
|
nl | 92% | create_private_message,send_secure_message,send_message,message,old,message_sent,messages,matrix_user_id,private_message_disclaimer,donate_to_lemmy,donate,from,logged_in,email_already_exists,couldnt_create_private_message,no_private_message_edit_allowed,couldnt_update_private_message
|
||||||
zh | 70% | cross_posts,cross_post,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,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,email_already_exists,couldnt_create_private_message,no_private_message_edit_allowed,couldnt_update_private_message
|
ru | 72% | cross_posts,cross_post,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,donate_to_lemmy,donate,monero,by,to,from,transfer_community,transfer_site,are_you_sure,yes,no,logged_in,email_already_exists,couldnt_create_private_message,no_private_message_edit_allowed,couldnt_update_private_message
|
||||||
|
sv | 83% | 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,donate_to_lemmy,donate,from,logged_in,email_already_exists,couldnt_create_private_message,no_private_message_edit_allowed,couldnt_update_private_message
|
||||||
|
zh | 70% | cross_posts,cross_post,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,email_already_exists,couldnt_create_private_message,no_private_message_edit_allowed,couldnt_update_private_message
|
||||||
<!-- translationsstop -->
|
<!-- translationsstop -->
|
||||||
|
|
||||||
If you'd like to update this report, run:
|
If you'd like to update this report, run:
|
||||||
|
|
2
docker/dev/deploy.sh
vendored
2
docker/dev/deploy.sh
vendored
|
@ -9,7 +9,7 @@ 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 let version: string = '$(git describe --tags)';" > "ui/src/version.ts"
|
echo "export const version: string = '$(git describe --tags)';" > "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 = \"$(git describe --tags)\";" > "server/src/version.rs"
|
||||||
|
|
2
docker/prod/docker-compose.yml
vendored
2
docker/prod/docker-compose.yml
vendored
|
@ -11,7 +11,7 @@ services:
|
||||||
- lemmy_db:/var/lib/postgresql/data
|
- lemmy_db:/var/lib/postgresql/data
|
||||||
restart: always
|
restart: always
|
||||||
lemmy:
|
lemmy:
|
||||||
image: dessalines/lemmy:v0.6.4
|
image: dessalines/lemmy:v0.6.7
|
||||||
ports:
|
ports:
|
||||||
- "127.0.0.1:8536:8536"
|
- "127.0.0.1:8536:8536"
|
||||||
restart: always
|
restart: always
|
||||||
|
|
2
docs/src/contributing_local_development.md
vendored
2
docs/src/contributing_local_development.md
vendored
|
@ -9,7 +9,7 @@
|
||||||
```bash
|
```bash
|
||||||
psql -c "create user lemmy with password 'password' superuser;" -U postgres
|
psql -c "create user lemmy with password 'password' superuser;" -U postgres
|
||||||
psql -c 'create database lemmy with owner lemmy;' -U postgres
|
psql -c 'create database lemmy with owner lemmy;' -U postgres
|
||||||
export DATABASE_URL=postgres://lemmy:password@localhost:5432/lemmy
|
export LEMMY_DATABASE_URL=postgres://lemmy:password@localhost:5432/lemmy
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Running
|
#### Running
|
||||||
|
|
2
install.sh
vendored
2
install.sh
vendored
|
@ -1,7 +1,7 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
export DATABASE_URL=postgres://lemmy:password@localhost:5432/lemmy
|
export LEMMY_DATABASE_URL=postgres://lemmy:password@localhost:5432/lemmy
|
||||||
export JWT_SECRET=changeme
|
export JWT_SECRET=changeme
|
||||||
export HOSTNAME=rrr
|
export HOSTNAME=rrr
|
||||||
|
|
||||||
|
|
25
server/migrations/2020-01-29-011901_create_reply_materialized_view/down.sql
vendored
Normal file
25
server/migrations/2020-01-29-011901_create_reply_materialized_view/down.sql
vendored
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
-- Drop the materialized / built views
|
||||||
|
drop view reply_view;
|
||||||
|
create view reply_view as
|
||||||
|
with closereply as (
|
||||||
|
select
|
||||||
|
c2.id,
|
||||||
|
c2.creator_id as sender_id,
|
||||||
|
c.creator_id as recipient_id
|
||||||
|
from comment c
|
||||||
|
inner join comment c2 on c.id = c2.parent_id
|
||||||
|
where c2.creator_id != c.creator_id
|
||||||
|
-- Do union where post is null
|
||||||
|
union
|
||||||
|
select
|
||||||
|
c.id,
|
||||||
|
c.creator_id as sender_id,
|
||||||
|
p.creator_id as recipient_id
|
||||||
|
from comment c, post p
|
||||||
|
where c.post_id = p.id and c.parent_id is null and c.creator_id != p.creator_id
|
||||||
|
)
|
||||||
|
select cv.*,
|
||||||
|
closereply.recipient_id
|
||||||
|
from comment_view cv, closereply
|
||||||
|
where closereply.id = cv.id
|
||||||
|
;
|
27
server/migrations/2020-01-29-011901_create_reply_materialized_view/up.sql
vendored
Normal file
27
server/migrations/2020-01-29-011901_create_reply_materialized_view/up.sql
vendored
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
-- https://github.com/dessalines/lemmy/issues/197
|
||||||
|
drop view reply_view;
|
||||||
|
|
||||||
|
-- Do the reply_view referencing the comment_mview
|
||||||
|
create view reply_view as
|
||||||
|
with closereply as (
|
||||||
|
select
|
||||||
|
c2.id,
|
||||||
|
c2.creator_id as sender_id,
|
||||||
|
c.creator_id as recipient_id
|
||||||
|
from comment c
|
||||||
|
inner join comment c2 on c.id = c2.parent_id
|
||||||
|
where c2.creator_id != c.creator_id
|
||||||
|
-- Do union where post is null
|
||||||
|
union
|
||||||
|
select
|
||||||
|
c.id,
|
||||||
|
c.creator_id as sender_id,
|
||||||
|
p.creator_id as recipient_id
|
||||||
|
from comment c, post p
|
||||||
|
where c.post_id = p.id and c.parent_id is null and c.creator_id != p.creator_id
|
||||||
|
)
|
||||||
|
select cv.*,
|
||||||
|
closereply.recipient_id
|
||||||
|
from comment_mview cv, closereply
|
||||||
|
where closereply.id = cv.id
|
||||||
|
;
|
1
server/migrations/2020-01-29-030825_create_user_mention_materialized_view/down.sql
vendored
Normal file
1
server/migrations/2020-01-29-030825_create_user_mention_materialized_view/down.sql
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
drop view user_mention_mview;
|
67
server/migrations/2020-01-29-030825_create_user_mention_materialized_view/up.sql
vendored
Normal file
67
server/migrations/2020-01-29-030825_create_user_mention_materialized_view/up.sql
vendored
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
create view user_mention_mview as
|
||||||
|
with all_comment as
|
||||||
|
(
|
||||||
|
select
|
||||||
|
ca.*
|
||||||
|
from comment_aggregates_mview ca
|
||||||
|
)
|
||||||
|
|
||||||
|
select
|
||||||
|
ac.id,
|
||||||
|
um.id as user_mention_id,
|
||||||
|
ac.creator_id,
|
||||||
|
ac.post_id,
|
||||||
|
ac.parent_id,
|
||||||
|
ac.content,
|
||||||
|
ac.removed,
|
||||||
|
um.read,
|
||||||
|
ac.published,
|
||||||
|
ac.updated,
|
||||||
|
ac.deleted,
|
||||||
|
ac.community_id,
|
||||||
|
ac.banned,
|
||||||
|
ac.banned_from_community,
|
||||||
|
ac.creator_name,
|
||||||
|
ac.creator_avatar,
|
||||||
|
ac.score,
|
||||||
|
ac.upvotes,
|
||||||
|
ac.downvotes,
|
||||||
|
u.id as user_id,
|
||||||
|
coalesce(cl.score, 0) as my_vote,
|
||||||
|
(select cs.id::bool from comment_saved cs where u.id = cs.user_id and cs.comment_id = ac.id) as saved,
|
||||||
|
um.recipient_id
|
||||||
|
from user_ u
|
||||||
|
cross join all_comment ac
|
||||||
|
left join comment_like cl on u.id = cl.user_id and ac.id = cl.comment_id
|
||||||
|
left join user_mention um on um.comment_id = ac.id
|
||||||
|
|
||||||
|
union all
|
||||||
|
|
||||||
|
select
|
||||||
|
ac.id,
|
||||||
|
um.id as user_mention_id,
|
||||||
|
ac.creator_id,
|
||||||
|
ac.post_id,
|
||||||
|
ac.parent_id,
|
||||||
|
ac.content,
|
||||||
|
ac.removed,
|
||||||
|
um.read,
|
||||||
|
ac.published,
|
||||||
|
ac.updated,
|
||||||
|
ac.deleted,
|
||||||
|
ac.community_id,
|
||||||
|
ac.banned,
|
||||||
|
ac.banned_from_community,
|
||||||
|
ac.creator_name,
|
||||||
|
ac.creator_avatar,
|
||||||
|
ac.score,
|
||||||
|
ac.upvotes,
|
||||||
|
ac.downvotes,
|
||||||
|
null as user_id,
|
||||||
|
null as my_vote,
|
||||||
|
null as saved,
|
||||||
|
um.recipient_id
|
||||||
|
from all_comment ac
|
||||||
|
left join user_mention um on um.comment_id = ac.id
|
||||||
|
;
|
||||||
|
|
|
@ -17,6 +17,15 @@ psql -qAt -U lemmy -f explain.sql > community_view.json
|
||||||
echo "explain (analyze, format json) select * from site_view limit 1" > explain.sql
|
echo "explain (analyze, format json) select * from site_view limit 1" > explain.sql
|
||||||
psql -qAt -U lemmy -f explain.sql > site_view.json
|
psql -qAt -U lemmy -f explain.sql > site_view.json
|
||||||
|
|
||||||
|
echo "explain (analyze, format json) select * from reply_view where user_id = 34 and recipient_id = 34" > explain.sql
|
||||||
|
psql -qAt -U lemmy -f explain.sql > reply_view.json
|
||||||
|
|
||||||
|
echo "explain (analyze, format json) select * from user_mention_view where user_id = 34 and recipient_id = 34" > explain.sql
|
||||||
|
psql -qAt -U lemmy -f explain.sql > user_mention_view.json
|
||||||
|
|
||||||
|
echo "explain (analyze, format json) select * from user_mention_mview where user_id = 34 and recipient_id = 34" > explain.sql
|
||||||
|
psql -qAt -U lemmy -f explain.sql > user_mention_mview.json
|
||||||
|
|
||||||
grep "Execution Time" *.json
|
grep "Execution Time" *.json
|
||||||
|
|
||||||
rm explain.sql
|
rm explain.sql
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
use super::user_mention_view::user_mention_view::BoxedQuery;
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use diesel::pg::Pg;
|
use diesel::pg::Pg;
|
||||||
|
|
||||||
|
@ -31,6 +30,34 @@ table! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
table! {
|
||||||
|
user_mention_mview (id) {
|
||||||
|
id -> Int4,
|
||||||
|
user_mention_id -> Int4,
|
||||||
|
creator_id -> Int4,
|
||||||
|
post_id -> Int4,
|
||||||
|
parent_id -> Nullable<Int4>,
|
||||||
|
content -> Text,
|
||||||
|
removed -> Bool,
|
||||||
|
read -> Bool,
|
||||||
|
published -> Timestamp,
|
||||||
|
updated -> Nullable<Timestamp>,
|
||||||
|
deleted -> Bool,
|
||||||
|
community_id -> Int4,
|
||||||
|
banned -> Bool,
|
||||||
|
banned_from_community -> Bool,
|
||||||
|
creator_name -> Varchar,
|
||||||
|
creator_avatar -> Nullable<Text>,
|
||||||
|
score -> BigInt,
|
||||||
|
upvotes -> BigInt,
|
||||||
|
downvotes -> BigInt,
|
||||||
|
user_id -> Nullable<Int4>,
|
||||||
|
my_vote -> Nullable<Int4>,
|
||||||
|
saved -> Nullable<Bool>,
|
||||||
|
recipient_id -> Int4,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(
|
#[derive(
|
||||||
Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize, QueryableByName, Clone,
|
Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize, QueryableByName, Clone,
|
||||||
)]
|
)]
|
||||||
|
@ -63,7 +90,7 @@ pub struct UserMentionView {
|
||||||
|
|
||||||
pub struct UserMentionQueryBuilder<'a> {
|
pub struct UserMentionQueryBuilder<'a> {
|
||||||
conn: &'a PgConnection,
|
conn: &'a PgConnection,
|
||||||
query: BoxedQuery<'a, Pg>,
|
query: super::user_mention_view::user_mention_mview::BoxedQuery<'a, Pg>,
|
||||||
for_user_id: i32,
|
for_user_id: i32,
|
||||||
sort: &'a SortType,
|
sort: &'a SortType,
|
||||||
unread_only: bool,
|
unread_only: bool,
|
||||||
|
@ -73,9 +100,9 @@ pub struct UserMentionQueryBuilder<'a> {
|
||||||
|
|
||||||
impl<'a> UserMentionQueryBuilder<'a> {
|
impl<'a> UserMentionQueryBuilder<'a> {
|
||||||
pub fn create(conn: &'a PgConnection, for_user_id: i32) -> Self {
|
pub fn create(conn: &'a PgConnection, for_user_id: i32) -> Self {
|
||||||
use super::user_mention_view::user_mention_view::dsl::*;
|
use super::user_mention_view::user_mention_mview::dsl::*;
|
||||||
|
|
||||||
let query = user_mention_view.into_boxed();
|
let query = user_mention_mview.into_boxed();
|
||||||
|
|
||||||
UserMentionQueryBuilder {
|
UserMentionQueryBuilder {
|
||||||
conn,
|
conn,
|
||||||
|
@ -109,7 +136,7 @@ impl<'a> UserMentionQueryBuilder<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn list(self) -> Result<Vec<UserMentionView>, Error> {
|
pub fn list(self) -> Result<Vec<UserMentionView>, Error> {
|
||||||
use super::user_mention_view::user_mention_view::dsl::*;
|
use super::user_mention_view::user_mention_mview::dsl::*;
|
||||||
|
|
||||||
let mut query = self.query;
|
let mut query = self.query;
|
||||||
|
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
pub const VERSION: &str = "v0.6.4";
|
pub const VERSION: &str = "v0.6.7";
|
||||||
|
|
|
@ -291,6 +291,7 @@ impl Handler<StandardMessage> for ChatServer {
|
||||||
Err(e) => e.to_string(),
|
Err(e) => e.to_string(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
println!("Message Sent: {}", msg_out);
|
||||||
MessageResult(msg_out)
|
MessageResult(msg_out)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
3
ui/package.json
vendored
3
ui/package.json
vendored
|
@ -49,6 +49,7 @@
|
||||||
"fuse-box": "^3.1.3",
|
"fuse-box": "^3.1.3",
|
||||||
"lint-staged": "^10.0.2",
|
"lint-staged": "^10.0.2",
|
||||||
"sortpack": "^2.0.1",
|
"sortpack": "^2.0.1",
|
||||||
|
"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.7.5"
|
||||||
|
@ -59,7 +60,7 @@
|
||||||
"engineStrict": true,
|
"engineStrict": true,
|
||||||
"husky": {
|
"husky": {
|
||||||
"hooks": {
|
"hooks": {
|
||||||
"pre-commit": "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": "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"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"lint-staged": {
|
"lint-staged": {
|
||||||
|
|
24
ui/src/components/comment-form.tsx
vendored
24
ui/src/components/comment-form.tsx
vendored
|
@ -96,6 +96,7 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> {
|
||||||
className={`form-control ${this.state.previewMode && 'd-none'}`}
|
className={`form-control ${this.state.previewMode && 'd-none'}`}
|
||||||
value={this.state.commentForm.content}
|
value={this.state.commentForm.content}
|
||||||
onInput={linkEvent(this, this.handleCommentContentChange)}
|
onInput={linkEvent(this, this.handleCommentContentChange)}
|
||||||
|
onPaste={linkEvent(this, this.handleImageUploadPaste)}
|
||||||
required
|
required
|
||||||
disabled={this.props.disabled}
|
disabled={this.props.disabled}
|
||||||
rows={2}
|
rows={2}
|
||||||
|
@ -208,9 +209,22 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> {
|
||||||
i.props.onReplyCancel();
|
i.props.onReplyCancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleImageUploadPaste(i: CommentForm, event: any) {
|
||||||
|
let image = event.clipboardData.files[0];
|
||||||
|
if (image) {
|
||||||
|
i.handleImageUpload(i, image);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
handleImageUpload(i: CommentForm, event: any) {
|
handleImageUpload(i: CommentForm, event: any) {
|
||||||
event.preventDefault();
|
let file: any;
|
||||||
let file = event.target.files[0];
|
if (event.target) {
|
||||||
|
event.preventDefault();
|
||||||
|
file = event.target.files[0];
|
||||||
|
} else {
|
||||||
|
file = event;
|
||||||
|
}
|
||||||
|
|
||||||
const imageUploadUrl = `/pictshare/api/upload.php`;
|
const imageUploadUrl = `/pictshare/api/upload.php`;
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append('file', file);
|
formData.append('file', file);
|
||||||
|
@ -225,13 +239,15 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> {
|
||||||
.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/${res.url}`;
|
||||||
let markdown =
|
let imageMarkdown =
|
||||||
res.filetype == 'mp4' ? `[vid](${url}/raw)` : `![](${url})`;
|
res.filetype == 'mp4' ? `[vid](${url}/raw)` : `![](${url})`;
|
||||||
let content = i.state.commentForm.content;
|
let content = i.state.commentForm.content;
|
||||||
content = content ? `${content} ${markdown}` : markdown;
|
content = content ? `${content}\n${imageMarkdown}` : imageMarkdown;
|
||||||
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);
|
||||||
|
autosize.update(textarea);
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
i.state.imageLoading = false;
|
i.state.imageLoading = false;
|
||||||
|
|
18
ui/src/components/comment-node.tsx
vendored
18
ui/src/components/comment-node.tsx
vendored
|
@ -117,7 +117,6 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
||||||
.viewOnly && 'no-click'}`}
|
.viewOnly && 'no-click'}`}
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
disabled={!UserService.Instance.user}
|
|
||||||
className={`btn p-0 ${
|
className={`btn p-0 ${
|
||||||
node.comment.my_vote == 1 ? 'text-info' : 'text-muted'
|
node.comment.my_vote == 1 ? 'text-info' : 'text-muted'
|
||||||
}`}
|
}`}
|
||||||
|
@ -138,7 +137,6 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
||||||
</div>
|
</div>
|
||||||
{WebSocketService.Instance.site.enable_downvotes && (
|
{WebSocketService.Instance.site.enable_downvotes && (
|
||||||
<button
|
<button
|
||||||
disabled={!UserService.Instance.user}
|
|
||||||
className={`btn p-0 ${
|
className={`btn p-0 ${
|
||||||
node.comment.my_vote == -1 ? 'text-danger' : 'text-muted'
|
node.comment.my_vote == -1 ? 'text-danger' : 'text-muted'
|
||||||
}`}
|
}`}
|
||||||
|
@ -761,9 +759,11 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
handleCommentUpvote(i: CommentNodeI) {
|
handleCommentUpvote(i: CommentNodeI) {
|
||||||
this.setState({
|
if (UserService.Instance.user) {
|
||||||
upvoteLoading: true,
|
this.setState({
|
||||||
});
|
upvoteLoading: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
let form: CommentLikeForm = {
|
let form: CommentLikeForm = {
|
||||||
comment_id: i.comment.id,
|
comment_id: i.comment.id,
|
||||||
post_id: i.comment.post_id,
|
post_id: i.comment.post_id,
|
||||||
|
@ -773,9 +773,11 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
handleCommentDownvote(i: CommentNodeI) {
|
handleCommentDownvote(i: CommentNodeI) {
|
||||||
this.setState({
|
if (UserService.Instance.user) {
|
||||||
downvoteLoading: true,
|
this.setState({
|
||||||
});
|
downvoteLoading: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
let form: CommentLikeForm = {
|
let form: CommentLikeForm = {
|
||||||
comment_id: i.comment.id,
|
comment_id: i.comment.id,
|
||||||
post_id: i.comment.post_id,
|
post_id: i.comment.post_id,
|
||||||
|
|
2
ui/src/components/communities.tsx
vendored
2
ui/src/components/communities.tsx
vendored
|
@ -235,7 +235,7 @@ export class Communities extends Component<any, CommunitiesState> {
|
||||||
parseMessage(msg: WebSocketJsonResponse) {
|
parseMessage(msg: WebSocketJsonResponse) {
|
||||||
console.log(msg);
|
console.log(msg);
|
||||||
let res = wsJsonToRes(msg);
|
let res = wsJsonToRes(msg);
|
||||||
if (res.error) {
|
if (msg.error) {
|
||||||
toast(i18n.t(msg.error), 'danger');
|
toast(i18n.t(msg.error), 'danger');
|
||||||
return;
|
return;
|
||||||
} else if (res.op == UserOperation.ListCommunities) {
|
} else if (res.op == UserOperation.ListCommunities) {
|
||||||
|
|
2
ui/src/components/community-form.tsx
vendored
2
ui/src/components/community-form.tsx
vendored
|
@ -261,7 +261,7 @@ export class CommunityForm extends Component<
|
||||||
parseMessage(msg: WebSocketJsonResponse) {
|
parseMessage(msg: WebSocketJsonResponse) {
|
||||||
let res = wsJsonToRes(msg);
|
let res = wsJsonToRes(msg);
|
||||||
console.log(msg);
|
console.log(msg);
|
||||||
if (res.error) {
|
if (msg.error) {
|
||||||
toast(i18n.t(msg.error), 'danger');
|
toast(i18n.t(msg.error), 'danger');
|
||||||
this.state.loading = false;
|
this.state.loading = false;
|
||||||
this.setState(this.state);
|
this.setState(this.state);
|
||||||
|
|
13
ui/src/components/community.tsx
vendored
13
ui/src/components/community.tsx
vendored
|
@ -11,6 +11,7 @@ import {
|
||||||
SortType,
|
SortType,
|
||||||
Post,
|
Post,
|
||||||
GetPostsForm,
|
GetPostsForm,
|
||||||
|
GetCommunityForm,
|
||||||
ListingType,
|
ListingType,
|
||||||
GetPostsResponse,
|
GetPostsResponse,
|
||||||
CreatePostLikeResponse,
|
CreatePostLikeResponse,
|
||||||
|
@ -98,11 +99,11 @@ export class Community extends Component<any, State> {
|
||||||
() => console.log('complete')
|
() => console.log('complete')
|
||||||
);
|
);
|
||||||
|
|
||||||
if (this.state.communityId) {
|
let form: GetCommunityForm = {
|
||||||
WebSocketService.Instance.getCommunity(this.state.communityId);
|
id: this.state.communityId ? this.state.communityId : null,
|
||||||
} else if (this.state.communityName) {
|
name: this.state.communityName ? this.state.communityName : null,
|
||||||
WebSocketService.Instance.getCommunityByName(this.state.communityName);
|
};
|
||||||
}
|
WebSocketService.Instance.getCommunity(form);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
|
@ -258,7 +259,7 @@ export class Community extends Component<any, State> {
|
||||||
parseMessage(msg: WebSocketJsonResponse) {
|
parseMessage(msg: WebSocketJsonResponse) {
|
||||||
console.log(msg);
|
console.log(msg);
|
||||||
let res = wsJsonToRes(msg);
|
let res = wsJsonToRes(msg);
|
||||||
if (res.error) {
|
if (msg.error) {
|
||||||
toast(i18n.t(msg.error), 'danger');
|
toast(i18n.t(msg.error), 'danger');
|
||||||
this.context.router.history.push('/');
|
this.context.router.history.push('/');
|
||||||
return;
|
return;
|
||||||
|
|
6
ui/src/components/inbox.tsx
vendored
6
ui/src/components/inbox.tsx
vendored
|
@ -38,6 +38,8 @@ enum UnreadType {
|
||||||
Messages,
|
Messages,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ReplyType = Comment | PrivateMessageI;
|
||||||
|
|
||||||
interface InboxState {
|
interface InboxState {
|
||||||
unreadOrAll: UnreadOrAll;
|
unreadOrAll: UnreadOrAll;
|
||||||
unreadType: UnreadType;
|
unreadType: UnreadType;
|
||||||
|
@ -186,7 +188,7 @@ export class Inbox extends Component<any, InboxState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
all() {
|
all() {
|
||||||
let combined: Array<Comment | PrivateMessageI> = [];
|
let combined: Array<ReplyType> = [];
|
||||||
|
|
||||||
combined.push(...this.state.replies);
|
combined.push(...this.state.replies);
|
||||||
combined.push(...this.state.mentions);
|
combined.push(...this.state.mentions);
|
||||||
|
@ -324,7 +326,7 @@ export class Inbox extends Component<any, InboxState> {
|
||||||
parseMessage(msg: WebSocketJsonResponse) {
|
parseMessage(msg: WebSocketJsonResponse) {
|
||||||
console.log(msg);
|
console.log(msg);
|
||||||
let res = wsJsonToRes(msg);
|
let res = wsJsonToRes(msg);
|
||||||
if (res.error) {
|
if (msg.error) {
|
||||||
toast(i18n.t(msg.error), 'danger');
|
toast(i18n.t(msg.error), 'danger');
|
||||||
return;
|
return;
|
||||||
} else if (res.op == UserOperation.GetReplies) {
|
} else if (res.op == UserOperation.GetReplies) {
|
||||||
|
|
2
ui/src/components/login.tsx
vendored
2
ui/src/components/login.tsx
vendored
|
@ -295,7 +295,7 @@ export class Login extends Component<any, State> {
|
||||||
|
|
||||||
parseMessage(msg: WebSocketJsonResponse) {
|
parseMessage(msg: WebSocketJsonResponse) {
|
||||||
let res = wsJsonToRes(msg);
|
let res = wsJsonToRes(msg);
|
||||||
if (res.error) {
|
if (msg.error) {
|
||||||
toast(i18n.t(msg.error), 'danger');
|
toast(i18n.t(msg.error), 'danger');
|
||||||
this.state = this.emptyState;
|
this.state = this.emptyState;
|
||||||
this.setState(this.state);
|
this.setState(this.state);
|
||||||
|
|
2
ui/src/components/main.tsx
vendored
2
ui/src/components/main.tsx
vendored
|
@ -566,7 +566,7 @@ export class Main extends Component<any, MainState> {
|
||||||
parseMessage(msg: WebSocketJsonResponse) {
|
parseMessage(msg: WebSocketJsonResponse) {
|
||||||
console.log(msg);
|
console.log(msg);
|
||||||
let res = wsJsonToRes(msg);
|
let res = wsJsonToRes(msg);
|
||||||
if (res.error) {
|
if (msg.error) {
|
||||||
toast(i18n.t(msg.error), 'danger');
|
toast(i18n.t(msg.error), 'danger');
|
||||||
return;
|
return;
|
||||||
} else if (res.op == UserOperation.GetFollowedCommunities) {
|
} else if (res.op == UserOperation.GetFollowedCommunities) {
|
||||||
|
|
2
ui/src/components/modlog.tsx
vendored
2
ui/src/components/modlog.tsx
vendored
|
@ -425,7 +425,7 @@ export class Modlog extends Component<any, ModlogState> {
|
||||||
parseMessage(msg: WebSocketJsonResponse) {
|
parseMessage(msg: WebSocketJsonResponse) {
|
||||||
console.log(msg);
|
console.log(msg);
|
||||||
let res = wsJsonToRes(msg);
|
let res = wsJsonToRes(msg);
|
||||||
if (res.error) {
|
if (msg.error) {
|
||||||
toast(i18n.t(msg.error), 'danger');
|
toast(i18n.t(msg.error), 'danger');
|
||||||
return;
|
return;
|
||||||
} else if (res.op == UserOperation.GetModlog) {
|
} else if (res.op == UserOperation.GetModlog) {
|
||||||
|
|
6
ui/src/components/navbar.tsx
vendored
6
ui/src/components/navbar.tsx
vendored
|
@ -138,7 +138,7 @@ export class Navbar extends Component<any, NavbarState> {
|
||||||
</li>
|
</li>
|
||||||
<li className="nav-item">
|
<li className="nav-item">
|
||||||
<Link
|
<Link
|
||||||
class="nav-link ml-2"
|
class="nav-link"
|
||||||
to="/sponsors"
|
to="/sponsors"
|
||||||
title={i18n.t('donate_to_lemmy')}
|
title={i18n.t('donate_to_lemmy')}
|
||||||
>
|
>
|
||||||
|
@ -202,8 +202,8 @@ export class Navbar extends Component<any, NavbarState> {
|
||||||
|
|
||||||
parseMessage(msg: WebSocketJsonResponse) {
|
parseMessage(msg: WebSocketJsonResponse) {
|
||||||
let res = wsJsonToRes(msg);
|
let res = wsJsonToRes(msg);
|
||||||
if (res.error) {
|
if (msg.error) {
|
||||||
if (res.error == 'not_logged_in') {
|
if (msg.error == 'not_logged_in') {
|
||||||
UserService.Instance.logout();
|
UserService.Instance.logout();
|
||||||
location.reload();
|
location.reload();
|
||||||
}
|
}
|
||||||
|
|
20
ui/src/components/post-form.tsx
vendored
20
ui/src/components/post-form.tsx
vendored
|
@ -160,6 +160,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
|
||||||
class="form-control"
|
class="form-control"
|
||||||
value={this.state.postForm.url}
|
value={this.state.postForm.url}
|
||||||
onInput={linkEvent(this, this.handlePostUrlChange)}
|
onInput={linkEvent(this, this.handlePostUrlChange)}
|
||||||
|
onPaste={linkEvent(this, this.handleImageUploadPaste)}
|
||||||
/>
|
/>
|
||||||
{this.state.suggestedTitle && (
|
{this.state.suggestedTitle && (
|
||||||
<div
|
<div
|
||||||
|
@ -442,9 +443,22 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
|
||||||
i.setState(i.state);
|
i.setState(i.state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleImageUploadPaste(i: PostForm, event: any) {
|
||||||
|
let image = event.clipboardData.files[0];
|
||||||
|
if (image) {
|
||||||
|
i.handleImageUpload(i, image);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
handleImageUpload(i: PostForm, event: any) {
|
handleImageUpload(i: PostForm, event: any) {
|
||||||
event.preventDefault();
|
let file: any;
|
||||||
let file = event.target.files[0];
|
if (event.target) {
|
||||||
|
event.preventDefault();
|
||||||
|
file = event.target.files[0];
|
||||||
|
} else {
|
||||||
|
file = event;
|
||||||
|
}
|
||||||
|
|
||||||
const imageUploadUrl = `/pictshare/api/upload.php`;
|
const imageUploadUrl = `/pictshare/api/upload.php`;
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append('file', file);
|
formData.append('file', file);
|
||||||
|
@ -475,7 +489,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
|
||||||
|
|
||||||
parseMessage(msg: WebSocketJsonResponse) {
|
parseMessage(msg: WebSocketJsonResponse) {
|
||||||
let res = wsJsonToRes(msg);
|
let res = wsJsonToRes(msg);
|
||||||
if (res.error) {
|
if (msg.error) {
|
||||||
toast(i18n.t(msg.error), 'danger');
|
toast(i18n.t(msg.error), 'danger');
|
||||||
this.state.loading = false;
|
this.state.loading = false;
|
||||||
this.setState(this.state);
|
this.setState(this.state);
|
||||||
|
|
11
ui/src/components/post-listing.tsx
vendored
11
ui/src/components/post-listing.tsx
vendored
|
@ -119,7 +119,6 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
||||||
<div class="listing col-12">
|
<div class="listing col-12">
|
||||||
<div className={`vote-bar mr-2 float-left small text-center`}>
|
<div className={`vote-bar mr-2 float-left small text-center`}>
|
||||||
<button
|
<button
|
||||||
disabled={!UserService.Instance.user}
|
|
||||||
className={`btn p-0 ${
|
className={`btn p-0 ${
|
||||||
post.my_vote == 1 ? 'text-info' : 'text-muted'
|
post.my_vote == 1 ? 'text-info' : 'text-muted'
|
||||||
}`}
|
}`}
|
||||||
|
@ -138,7 +137,6 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
||||||
<div class={`font-weight-bold text-muted`}>{post.score}</div>
|
<div class={`font-weight-bold text-muted`}>{post.score}</div>
|
||||||
{WebSocketService.Instance.site.enable_downvotes && (
|
{WebSocketService.Instance.site.enable_downvotes && (
|
||||||
<button
|
<button
|
||||||
disabled={!UserService.Instance.user}
|
|
||||||
className={`btn p-0 ${
|
className={`btn p-0 ${
|
||||||
post.my_vote == -1 ? 'text-danger' : 'text-muted'
|
post.my_vote == -1 ? 'text-danger' : 'text-muted'
|
||||||
}`}
|
}`}
|
||||||
|
@ -740,17 +738,22 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
handlePostLike(i: PostListing) {
|
handlePostLike(i: PostListing) {
|
||||||
i.setState({ upvoteLoading: true });
|
if (UserService.Instance.user) {
|
||||||
|
i.setState({ upvoteLoading: true });
|
||||||
|
}
|
||||||
|
|
||||||
let form: CreatePostLikeForm = {
|
let form: CreatePostLikeForm = {
|
||||||
post_id: i.props.post.id,
|
post_id: i.props.post.id,
|
||||||
score: i.props.post.my_vote == 1 ? 0 : 1,
|
score: i.props.post.my_vote == 1 ? 0 : 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
WebSocketService.Instance.likePost(form);
|
WebSocketService.Instance.likePost(form);
|
||||||
}
|
}
|
||||||
|
|
||||||
handlePostDisLike(i: PostListing) {
|
handlePostDisLike(i: PostListing) {
|
||||||
i.setState({ downvoteLoading: true });
|
if (UserService.Instance.user) {
|
||||||
|
i.setState({ downvoteLoading: true });
|
||||||
|
}
|
||||||
|
|
||||||
let form: CreatePostLikeForm = {
|
let form: CreatePostLikeForm = {
|
||||||
post_id: i.props.post.id,
|
post_id: i.props.post.id,
|
||||||
|
|
27
ui/src/components/post.tsx
vendored
27
ui/src/components/post.tsx
vendored
|
@ -23,6 +23,7 @@ import {
|
||||||
SearchType,
|
SearchType,
|
||||||
SortType,
|
SortType,
|
||||||
SearchForm,
|
SearchForm,
|
||||||
|
GetPostForm,
|
||||||
SearchResponse,
|
SearchResponse,
|
||||||
GetSiteResponse,
|
GetSiteResponse,
|
||||||
GetCommunityResponse,
|
GetCommunityResponse,
|
||||||
|
@ -84,7 +85,10 @@ export class Post extends Component<any, PostState> {
|
||||||
() => console.log('complete')
|
() => console.log('complete')
|
||||||
);
|
);
|
||||||
|
|
||||||
WebSocketService.Instance.getPost(postId);
|
let form: GetPostForm = {
|
||||||
|
id: postId,
|
||||||
|
};
|
||||||
|
WebSocketService.Instance.getPost(form);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
|
@ -231,6 +235,18 @@ export class Post extends Component<any, PostState> {
|
||||||
onChange={linkEvent(this, this.handleCommentSortChange)}
|
onChange={linkEvent(this, this.handleCommentSortChange)}
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
|
<label
|
||||||
|
className={`btn btn-sm btn-secondary pointer ${this.state
|
||||||
|
.commentSort === CommentSortType.Old && 'active'}`}
|
||||||
|
>
|
||||||
|
{i18n.t('old')}
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
value={CommentSortType.Old}
|
||||||
|
checked={this.state.commentSort === CommentSortType.Old}
|
||||||
|
onChange={linkEvent(this, this.handleCommentSortChange)}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -313,6 +329,13 @@ export class Post extends Component<any, PostState> {
|
||||||
+a.comment.deleted - +b.comment.deleted ||
|
+a.comment.deleted - +b.comment.deleted ||
|
||||||
b.comment.published.localeCompare(a.comment.published)
|
b.comment.published.localeCompare(a.comment.published)
|
||||||
);
|
);
|
||||||
|
} else if (this.state.commentSort == CommentSortType.Old) {
|
||||||
|
tree.sort(
|
||||||
|
(a, b) =>
|
||||||
|
+a.comment.removed - +b.comment.removed ||
|
||||||
|
+a.comment.deleted - +b.comment.deleted ||
|
||||||
|
a.comment.published.localeCompare(b.comment.published)
|
||||||
|
);
|
||||||
} else if (this.state.commentSort == CommentSortType.Hot) {
|
} else if (this.state.commentSort == CommentSortType.Hot) {
|
||||||
tree.sort(
|
tree.sort(
|
||||||
(a, b) =>
|
(a, b) =>
|
||||||
|
@ -345,7 +368,7 @@ export class Post extends Component<any, PostState> {
|
||||||
parseMessage(msg: WebSocketJsonResponse) {
|
parseMessage(msg: WebSocketJsonResponse) {
|
||||||
console.log(msg);
|
console.log(msg);
|
||||||
let res = wsJsonToRes(msg);
|
let res = wsJsonToRes(msg);
|
||||||
if (res.error) {
|
if (msg.error) {
|
||||||
toast(i18n.t(msg.error), 'danger');
|
toast(i18n.t(msg.error), 'danger');
|
||||||
return;
|
return;
|
||||||
} else if (res.op == UserOperation.GetPost) {
|
} else if (res.op == UserOperation.GetPost) {
|
||||||
|
|
2
ui/src/components/private-message-form.tsx
vendored
2
ui/src/components/private-message-form.tsx
vendored
|
@ -283,7 +283,7 @@ export class PrivateMessageForm extends Component<
|
||||||
|
|
||||||
parseMessage(msg: WebSocketJsonResponse) {
|
parseMessage(msg: WebSocketJsonResponse) {
|
||||||
let res = wsJsonToRes(msg);
|
let res = wsJsonToRes(msg);
|
||||||
if (res.error) {
|
if (msg.error) {
|
||||||
toast(i18n.t(msg.error), 'danger');
|
toast(i18n.t(msg.error), 'danger');
|
||||||
this.state.loading = false;
|
this.state.loading = false;
|
||||||
this.setState(this.state);
|
this.setState(this.state);
|
||||||
|
|
2
ui/src/components/search.tsx
vendored
2
ui/src/components/search.tsx
vendored
|
@ -479,7 +479,7 @@ export class Search extends Component<any, SearchState> {
|
||||||
parseMessage(msg: WebSocketJsonResponse) {
|
parseMessage(msg: WebSocketJsonResponse) {
|
||||||
console.log(msg);
|
console.log(msg);
|
||||||
let res = wsJsonToRes(msg);
|
let res = wsJsonToRes(msg);
|
||||||
if (res.error) {
|
if (msg.error) {
|
||||||
toast(i18n.t(msg.error), 'danger');
|
toast(i18n.t(msg.error), 'danger');
|
||||||
return;
|
return;
|
||||||
} else if (res.op == UserOperation.Search) {
|
} else if (res.op == UserOperation.Search) {
|
||||||
|
|
2
ui/src/components/setup.tsx
vendored
2
ui/src/components/setup.tsx
vendored
|
@ -188,7 +188,7 @@ export class Setup extends Component<any, State> {
|
||||||
|
|
||||||
parseMessage(msg: WebSocketJsonResponse) {
|
parseMessage(msg: WebSocketJsonResponse) {
|
||||||
let res = wsJsonToRes(msg);
|
let res = wsJsonToRes(msg);
|
||||||
if (res.error) {
|
if (msg.error) {
|
||||||
toast(i18n.t(msg.error), 'danger');
|
toast(i18n.t(msg.error), 'danger');
|
||||||
this.state.userLoading = false;
|
this.state.userLoading = false;
|
||||||
this.setState(this.state);
|
this.setState(this.state);
|
||||||
|
|
4
ui/src/components/user.tsx
vendored
4
ui/src/components/user.tsx
vendored
|
@ -1016,12 +1016,12 @@ export class User extends Component<any, UserState> {
|
||||||
parseMessage(msg: WebSocketJsonResponse) {
|
parseMessage(msg: WebSocketJsonResponse) {
|
||||||
console.log(msg);
|
console.log(msg);
|
||||||
let res = wsJsonToRes(msg);
|
let res = wsJsonToRes(msg);
|
||||||
if (res.error) {
|
if (msg.error) {
|
||||||
toast(i18n.t(msg.error), 'danger');
|
toast(i18n.t(msg.error), 'danger');
|
||||||
this.state.deleteAccountLoading = false;
|
this.state.deleteAccountLoading = false;
|
||||||
this.state.avatarLoading = false;
|
this.state.avatarLoading = false;
|
||||||
this.state.userSettingsLoading = false;
|
this.state.userSettingsLoading = false;
|
||||||
if (res.error == 'couldnt_find_that_username_or_email') {
|
if (msg.error == 'couldnt_find_that_username_or_email') {
|
||||||
this.context.router.history.push('/');
|
this.context.router.history.push('/');
|
||||||
}
|
}
|
||||||
this.setState(this.state);
|
this.setState(this.state);
|
||||||
|
|
11
ui/src/env.ts
vendored
11
ui/src/env.ts
vendored
|
@ -1,6 +1,5 @@
|
||||||
let host = `${window.location.hostname}`;
|
const host = `${window.location.hostname}`;
|
||||||
let port = `${window.location.port == '4444' ? '8536' : window.location.port}`;
|
const port = `${window.location.port == '4444' ? '8536' : window.location.port}`;
|
||||||
let endpoint = `${host}:${port}`;
|
const endpoint = `${host}:${port}`;
|
||||||
export let wsUri = `${
|
|
||||||
window.location.protocol == 'https:' ? 'wss://' : 'ws://'
|
export const wsUri = `${window.location.protocol == 'https:' ? 'wss://' : 'ws://'}${endpoint}/api/v1/ws`;
|
||||||
}${endpoint}/api/v1/ws`;
|
|
||||||
|
|
13
ui/src/i18next.ts
vendored
13
ui/src/i18next.ts
vendored
|
@ -10,6 +10,8 @@ import { ru } from './translations/ru';
|
||||||
import { zh } from './translations/zh';
|
import { zh } from './translations/zh';
|
||||||
import { nl } from './translations/nl';
|
import { nl } from './translations/nl';
|
||||||
import { it } from './translations/it';
|
import { it } from './translations/it';
|
||||||
|
import { fi } from './translations/fi';
|
||||||
|
import { ca } from './translations/ca';
|
||||||
|
|
||||||
// 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 = {
|
||||||
|
@ -23,11 +25,12 @@ const resources = {
|
||||||
ru,
|
ru,
|
||||||
nl,
|
nl,
|
||||||
it,
|
it,
|
||||||
|
fi,
|
||||||
|
ca,
|
||||||
};
|
};
|
||||||
|
|
||||||
function format(value: any, format: any, lng: any) {
|
function format(value: any, format: any, lng: any): any {
|
||||||
if (format === 'uppercase') return value.toUpperCase();
|
return format === 'uppercase' ? value.toUpperCase() : value;
|
||||||
return value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
i18next.init({
|
i18next.init({
|
||||||
|
@ -38,9 +41,7 @@ i18next.init({
|
||||||
lng: getLanguage(),
|
lng: getLanguage(),
|
||||||
fallbackLng: 'en',
|
fallbackLng: 'en',
|
||||||
resources,
|
resources,
|
||||||
interpolation: {
|
interpolation: { format },
|
||||||
format: format,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export { i18next as i18n, resources };
|
export { i18next as i18n, resources };
|
||||||
|
|
43
ui/src/index.html
vendored
43
ui/src/index.html
vendored
|
@ -1,29 +1,28 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<!-- Required meta tags -->
|
||||||
|
<meta name="Description" content="Lemmy">
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||||
|
|
||||||
<head>
|
<!-- Icons -->
|
||||||
<!-- Required meta tags -->
|
<link rel="shortcut icon" type="image/svg+xml" href="/static/assets/favicon.svg" />
|
||||||
<meta name="Description" content="Lemmy">
|
<link rel="apple-touch-icon" href="/static/assets/apple-touch-icon.png" />
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
|
||||||
|
|
||||||
<!-- Icons -->
|
<!-- Styles -->
|
||||||
<link rel="shortcut icon" type="image/svg+xml" href="/static/assets/favicon.svg" />
|
<link rel="stylesheet" type="text/css" href="/static/assets/css/tribute.css" />
|
||||||
<link rel="apple-touch-icon" href="/static/assets/apple-touch-icon.png" />
|
<link rel="stylesheet" type="text/css" href="/static/assets/css/toastify.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/main.css" />
|
||||||
|
|
||||||
<!-- Styles -->
|
<!-- Scripts -->
|
||||||
<link rel="stylesheet" type="text/css" href="/static/assets/css/tribute.css" />
|
<script async src="/static/assets/libs/sortable/sortable.min.js"></script>
|
||||||
<link rel="stylesheet" type="text/css" href="/static/assets/css/toastify.css" />
|
</head>
|
||||||
<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" />
|
|
||||||
|
|
||||||
<!-- Scripts -->
|
|
||||||
<script async src="/static/assets/libs/sortable/sortable.min.js"></script>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<div id="app"></div>
|
|
||||||
$bundles
|
|
||||||
</body>
|
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<noscript>JavaScript is required for this page.</noscript>
|
||||||
|
<div id="app"></div>
|
||||||
|
$bundles
|
||||||
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
60
ui/src/interfaces.ts
vendored
60
ui/src/interfaces.ts
vendored
|
@ -47,6 +47,7 @@ export enum CommentSortType {
|
||||||
Hot,
|
Hot,
|
||||||
Top,
|
Top,
|
||||||
New,
|
New,
|
||||||
|
Old,
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum ListingType {
|
export enum ListingType {
|
||||||
|
@ -248,6 +249,10 @@ export interface FollowCommunityForm {
|
||||||
auth?: string;
|
auth?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface GetFollowedCommunitiesForm {
|
||||||
|
auth: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface GetFollowedCommunitiesResponse {
|
export interface GetFollowedCommunitiesResponse {
|
||||||
communities: Array<CommunityUser>;
|
communities: Array<CommunityUser>;
|
||||||
}
|
}
|
||||||
|
@ -523,6 +528,12 @@ export interface CommunityForm {
|
||||||
auth?: string;
|
auth?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface GetCommunityForm {
|
||||||
|
id?: number;
|
||||||
|
name?: string;
|
||||||
|
auth?: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface GetCommunityResponse {
|
export interface GetCommunityResponse {
|
||||||
community: Community;
|
community: Community;
|
||||||
moderators: Array<CommunityUser>;
|
moderators: Array<CommunityUser>;
|
||||||
|
@ -572,6 +583,11 @@ export interface PostFormParams {
|
||||||
community?: string;
|
community?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface GetPostForm {
|
||||||
|
id: number;
|
||||||
|
auth?: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface GetPostResponse {
|
export interface GetPostResponse {
|
||||||
post: Post;
|
post: Post;
|
||||||
comments: Array<Comment>;
|
comments: Array<Comment>;
|
||||||
|
@ -759,6 +775,45 @@ export interface PrivateMessageResponse {
|
||||||
message: PrivateMessage;
|
message: PrivateMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type MessageType =
|
||||||
|
| EditPrivateMessageForm
|
||||||
|
| LoginForm
|
||||||
|
| RegisterForm
|
||||||
|
| CommunityForm
|
||||||
|
| FollowCommunityForm
|
||||||
|
| ListCommunitiesForm
|
||||||
|
| GetFollowedCommunitiesForm
|
||||||
|
| PostForm
|
||||||
|
| GetPostForm
|
||||||
|
| GetPostsForm
|
||||||
|
| GetCommunityForm
|
||||||
|
| CommentForm
|
||||||
|
| CommentLikeForm
|
||||||
|
| SaveCommentForm
|
||||||
|
| CreatePostLikeForm
|
||||||
|
| BanFromCommunityForm
|
||||||
|
| AddAdminForm
|
||||||
|
| AddModToCommunityForm
|
||||||
|
| TransferCommunityForm
|
||||||
|
| TransferSiteForm
|
||||||
|
| SaveCommentForm
|
||||||
|
| BanUserForm
|
||||||
|
| AddAdminForm
|
||||||
|
| GetUserDetailsForm
|
||||||
|
| GetRepliesForm
|
||||||
|
| GetUserMentionsForm
|
||||||
|
| EditUserMentionForm
|
||||||
|
| GetModlogForm
|
||||||
|
| SiteForm
|
||||||
|
| SearchForm
|
||||||
|
| UserSettingsForm
|
||||||
|
| DeleteAccountForm
|
||||||
|
| PasswordResetForm
|
||||||
|
| PasswordChangeForm
|
||||||
|
| PrivateMessageForm
|
||||||
|
| EditPrivateMessageForm
|
||||||
|
| GetPrivateMessagesForm;
|
||||||
|
|
||||||
type ResponseType =
|
type ResponseType =
|
||||||
| SiteResponse
|
| SiteResponse
|
||||||
| GetFollowedCommunitiesResponse
|
| GetFollowedCommunitiesResponse
|
||||||
|
@ -784,11 +839,10 @@ type ResponseType =
|
||||||
export interface WebSocketResponse {
|
export interface WebSocketResponse {
|
||||||
op: UserOperation;
|
op: UserOperation;
|
||||||
data: ResponseType;
|
data: ResponseType;
|
||||||
error?: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface WebSocketJsonResponse {
|
export interface WebSocketJsonResponse {
|
||||||
op: string;
|
op?: string;
|
||||||
data: ResponseType;
|
data?: ResponseType;
|
||||||
error?: string;
|
error?: string;
|
||||||
}
|
}
|
||||||
|
|
27
ui/src/services/WebSocketService.ts
vendored
27
ui/src/services/WebSocketService.ts
vendored
|
@ -9,9 +9,12 @@ import {
|
||||||
CommentForm,
|
CommentForm,
|
||||||
SaveCommentForm,
|
SaveCommentForm,
|
||||||
CommentLikeForm,
|
CommentLikeForm,
|
||||||
|
GetPostForm,
|
||||||
GetPostsForm,
|
GetPostsForm,
|
||||||
CreatePostLikeForm,
|
CreatePostLikeForm,
|
||||||
|
GetCommunityForm,
|
||||||
FollowCommunityForm,
|
FollowCommunityForm,
|
||||||
|
GetFollowedCommunitiesForm,
|
||||||
GetUserDetailsForm,
|
GetUserDetailsForm,
|
||||||
ListCommunitiesForm,
|
ListCommunitiesForm,
|
||||||
GetModlogForm,
|
GetModlogForm,
|
||||||
|
@ -35,6 +38,7 @@ import {
|
||||||
PrivateMessageForm,
|
PrivateMessageForm,
|
||||||
EditPrivateMessageForm,
|
EditPrivateMessageForm,
|
||||||
GetPrivateMessagesForm,
|
GetPrivateMessagesForm,
|
||||||
|
MessageType,
|
||||||
} from '../interfaces';
|
} from '../interfaces';
|
||||||
import { webSocket } from 'rxjs/webSocket';
|
import { webSocket } from 'rxjs/webSocket';
|
||||||
import { Subject } from 'rxjs';
|
import { Subject } from 'rxjs';
|
||||||
|
@ -108,9 +112,9 @@ export class WebSocketService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public getFollowedCommunities() {
|
public getFollowedCommunities() {
|
||||||
let data = { auth: UserService.Instance.auth };
|
let form: GetFollowedCommunitiesForm = { auth: UserService.Instance.auth };
|
||||||
this.subject.next(
|
this.subject.next(
|
||||||
this.wsSendWrapper(UserOperation.GetFollowedCommunities, data)
|
this.wsSendWrapper(UserOperation.GetFollowedCommunities, form)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,19 +129,14 @@ export class WebSocketService {
|
||||||
this.subject.next(this.wsSendWrapper(UserOperation.CreatePost, postForm));
|
this.subject.next(this.wsSendWrapper(UserOperation.CreatePost, postForm));
|
||||||
}
|
}
|
||||||
|
|
||||||
public getPost(postId: number) {
|
public getPost(form: GetPostForm) {
|
||||||
let data = { id: postId, auth: UserService.Instance.auth };
|
this.setAuth(form, false);
|
||||||
this.subject.next(this.wsSendWrapper(UserOperation.GetPost, data));
|
this.subject.next(this.wsSendWrapper(UserOperation.GetPost, form));
|
||||||
}
|
}
|
||||||
|
|
||||||
public getCommunity(communityId: number) {
|
public getCommunity(form: GetCommunityForm) {
|
||||||
let data = { id: communityId, auth: UserService.Instance.auth };
|
this.setAuth(form, false);
|
||||||
this.subject.next(this.wsSendWrapper(UserOperation.GetCommunity, data));
|
this.subject.next(this.wsSendWrapper(UserOperation.GetCommunity, form));
|
||||||
}
|
|
||||||
|
|
||||||
public getCommunityByName(name: string) {
|
|
||||||
let data = { name: name, auth: UserService.Instance.auth };
|
|
||||||
this.subject.next(this.wsSendWrapper(UserOperation.GetCommunity, data));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public createComment(commentForm: CommentForm) {
|
public createComment(commentForm: CommentForm) {
|
||||||
|
@ -310,7 +309,7 @@ export class WebSocketService {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private wsSendWrapper(op: UserOperation, data: any) {
|
private wsSendWrapper(op: UserOperation, data: MessageType) {
|
||||||
let send = { op: UserOperation[op], data: data };
|
let send = { op: UserOperation[op], data: data };
|
||||||
console.log(send);
|
console.log(send);
|
||||||
return send;
|
return send;
|
||||||
|
|
239
ui/src/translations/ca.ts
vendored
Normal file
239
ui/src/translations/ca.ts
vendored
Normal file
|
@ -0,0 +1,239 @@
|
||||||
|
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.",
|
||||||
|
},
|
||||||
|
};
|
1
ui/src/translations/en.ts
vendored
1
ui/src/translations/en.ts
vendored
|
@ -97,6 +97,7 @@ export const en = {
|
||||||
sort_type: 'Sort type',
|
sort_type: 'Sort type',
|
||||||
hot: 'Hot',
|
hot: 'Hot',
|
||||||
new: 'New',
|
new: 'New',
|
||||||
|
old: 'Old',
|
||||||
top_day: 'Top day',
|
top_day: 'Top day',
|
||||||
week: 'Week',
|
week: 'Week',
|
||||||
month: 'Month',
|
month: 'Month',
|
||||||
|
|
92
ui/src/translations/es.ts
vendored
92
ui/src/translations/es.ts
vendored
|
@ -1,7 +1,7 @@
|
||||||
export const es = {
|
export const es = {
|
||||||
translation: {
|
translation: {
|
||||||
post: 'Publicar',
|
post: 'Publicar',
|
||||||
remove_post: 'Remover publicación',
|
remove_post: 'Eliminar publicación',
|
||||||
no_posts: 'Sin publicaciones.',
|
no_posts: 'Sin publicaciones.',
|
||||||
create_a_post: 'Crear una publicación',
|
create_a_post: 'Crear una publicación',
|
||||||
create_post: 'Crear Publicación',
|
create_post: 'Crear Publicación',
|
||||||
|
@ -12,22 +12,29 @@ export const es = {
|
||||||
cross_post: 'cross-post',
|
cross_post: 'cross-post',
|
||||||
comments: 'Comentarios',
|
comments: 'Comentarios',
|
||||||
number_of_comments: '{{count}} Comentarios',
|
number_of_comments: '{{count}} Comentarios',
|
||||||
remove_comment: 'Remover Comentarios',
|
remove_comment: 'Eliminar Comentarios',
|
||||||
communities: 'Comunidades',
|
communities: 'Comunidades',
|
||||||
users: 'Usuarios',
|
users: 'Usuarios',
|
||||||
create_a_community: 'Crear una comunidad',
|
create_a_community: 'Crear una comunidad',
|
||||||
create_community: 'Crear Comunidad',
|
create_community: 'Crear Comunidad',
|
||||||
remove_community: 'Remover Comunidad',
|
remove_community: 'Eliminar Comunidad',
|
||||||
subscribed_to_communities: 'Suscrito a <1>comunidades</1>',
|
subscribed_to_communities: 'Suscrito a <1>comunidades</1>',
|
||||||
trending_communities: '<1>Comunidades</1> en tendencia',
|
trending_communities: '<1>Comunidades</1> en tendencia',
|
||||||
list_of_communities: 'Lista de comunidades',
|
list_of_communities: 'Lista de comunidades',
|
||||||
number_of_communities: '{{count}} Comunidades',
|
number_of_communities: '{{count}} Comunidades',
|
||||||
community_reqs: 'minúsculas, guión bajo, y sin espacios.',
|
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',
|
edit: 'editar',
|
||||||
reply: 'responder',
|
reply: 'responder',
|
||||||
cancel: 'Cancelar',
|
cancel: 'Cancelar',
|
||||||
preview: 'Previsualizar',
|
preview: 'Previsualizar',
|
||||||
upload_image: 'Subir imagen',
|
upload_image: 'subir imagen',
|
||||||
|
avatar: 'Avatar',
|
||||||
|
upload_avatar: 'Subir Avatar',
|
||||||
|
show_avatars: 'Ver Avatares',
|
||||||
formatting_help: 'Ayuda de formato',
|
formatting_help: 'Ayuda de formato',
|
||||||
view_source: 'ver fuente',
|
view_source: 'ver fuente',
|
||||||
unlock: 'desbloquear',
|
unlock: 'desbloquear',
|
||||||
|
@ -35,19 +42,20 @@ export const es = {
|
||||||
sticky: 'fijado',
|
sticky: 'fijado',
|
||||||
unsticky: 'no fijado',
|
unsticky: 'no fijado',
|
||||||
link: 'link',
|
link: 'link',
|
||||||
mod: 'Moderador',
|
archive_link: 'archivar link',
|
||||||
mods: 'Moderadores',
|
mod: 'moderador',
|
||||||
|
mods: 'moderadores',
|
||||||
moderates: 'Modera',
|
moderates: 'Modera',
|
||||||
settings: 'Configuración',
|
settings: 'Configuración',
|
||||||
remove_as_mod: 'remover como moderador',
|
remove_as_mod: 'eliminar como moderador',
|
||||||
appoint_as_mod: 'designar como moderador',
|
appoint_as_mod: 'designar como moderador',
|
||||||
modlog: 'Historial de moderación',
|
modlog: 'Historial de moderación',
|
||||||
admin: 'administrador',
|
admin: 'administrador',
|
||||||
admins: 'administradores',
|
admins: 'administradores',
|
||||||
remove_as_admin: 'remover como administrador',
|
remove_as_admin: 'eliminar como administrador',
|
||||||
appoint_as_admin: 'designar como administrador',
|
appoint_as_admin: 'designar como administrador',
|
||||||
remove: 'remover',
|
remove: 'eliminar',
|
||||||
removed: 'removido',
|
removed: 'eliminado',
|
||||||
locked: 'bloqueado',
|
locked: 'bloqueado',
|
||||||
stickied: 'fijado',
|
stickied: 'fijado',
|
||||||
reason: 'Razón',
|
reason: 'Razón',
|
||||||
|
@ -57,19 +65,19 @@ export const es = {
|
||||||
deleted: 'eliminado',
|
deleted: 'eliminado',
|
||||||
delete_account: 'Eliminar Cuenta',
|
delete_account: 'Eliminar Cuenta',
|
||||||
delete_account_confirm:
|
delete_account_confirm:
|
||||||
'Peligro: esta acción eliminará permanentemente tu información. ¿Estás seguro?',
|
'Aviso: esta acción eliminará permanentemente tu información. Introduce tu contraseña para continuar',
|
||||||
restore: 'restaurar',
|
restore: 'restaurar',
|
||||||
ban: 'expulsar',
|
ban: 'expulsar',
|
||||||
ban_from_site: 'expulsar del sitio',
|
ban_from_site: 'expulsar del sitio',
|
||||||
unban: 'admitir',
|
unban: 'admitir',
|
||||||
unban_from_site: 'admitir al sitio',
|
unban_from_site: 'admitir en el sitio',
|
||||||
banned: 'expulsado',
|
banned: 'expulsado',
|
||||||
save: 'guardar',
|
save: 'guardar',
|
||||||
unsave: 'descartar',
|
unsave: 'descartar',
|
||||||
create: 'crear',
|
create: 'crear',
|
||||||
creator: 'creador',
|
creator: 'creador',
|
||||||
username: 'Nombre de Usuario',
|
username: 'Nombre de Usuario',
|
||||||
email_or_username: 'Correo electrónico o Nombre de Usuario',
|
email_or_username: 'Correo o Usuario',
|
||||||
number_of_users: '{{count}} Usuarios',
|
number_of_users: '{{count}} Usuarios',
|
||||||
number_of_subscribers: '{{count}} Suscriptores',
|
number_of_subscribers: '{{count}} Suscriptores',
|
||||||
number_of_points: '{{count}} Puntos',
|
number_of_points: '{{count}} Puntos',
|
||||||
|
@ -80,8 +88,8 @@ export const es = {
|
||||||
subscribers: 'Suscriptores',
|
subscribers: 'Suscriptores',
|
||||||
both: 'Ambos',
|
both: 'Ambos',
|
||||||
saved: 'Guardado',
|
saved: 'Guardado',
|
||||||
unsubscribe: 'Abandonar comunidad',
|
unsubscribe: 'Desuscribirse',
|
||||||
subscribe: 'Suscribir',
|
subscribe: 'Suscribirse',
|
||||||
subscribed: 'Suscrito',
|
subscribed: 'Suscrito',
|
||||||
prev: 'Anterior',
|
prev: 'Anterior',
|
||||||
next: 'Siguiente',
|
next: 'Siguiente',
|
||||||
|
@ -96,12 +104,16 @@ export const es = {
|
||||||
all: 'Todo',
|
all: 'Todo',
|
||||||
top: 'Mejor',
|
top: 'Mejor',
|
||||||
api: 'API',
|
api: 'API',
|
||||||
|
docs: 'Docs',
|
||||||
inbox: 'Buzón de entrada',
|
inbox: 'Buzón de entrada',
|
||||||
inbox_for: 'Buzón de entrada para <1>{{user}}</1>',
|
inbox_for: 'Buzón de entrada para <1>{{user}}</1>',
|
||||||
mark_all_as_read: 'marcar todo como leído',
|
mark_all_as_read: 'marcar todo como leído',
|
||||||
type: 'Tipo',
|
type: 'Tipo',
|
||||||
unread: 'No leído',
|
unread: 'No leído',
|
||||||
|
replies: 'Respuestas',
|
||||||
|
mentions: 'Menciones',
|
||||||
reply_sent: 'Respuesta enviada',
|
reply_sent: 'Respuesta enviada',
|
||||||
|
message_sent: 'Mensaje enviado',
|
||||||
search: 'Buscar',
|
search: 'Buscar',
|
||||||
overview: 'Resumen',
|
overview: 'Resumen',
|
||||||
view: 'Vista',
|
view: 'Vista',
|
||||||
|
@ -112,11 +124,29 @@ export const es = {
|
||||||
notifications_error:
|
notifications_error:
|
||||||
'Notificaciones de escritorio no disponibles en tu navegador. Prueba Firefox o Chrome.',
|
'Notificaciones de escritorio no disponibles en tu navegador. Prueba Firefox o Chrome.',
|
||||||
unread_messages: 'Mensajes no leídos',
|
unread_messages: 'Mensajes no leídos',
|
||||||
|
messages: 'Mensajes',
|
||||||
password: 'Contraseña',
|
password: 'Contraseña',
|
||||||
verify_password: 'Verificar 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',
|
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',
|
optional: 'Opcional',
|
||||||
expires: 'Expira',
|
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',
|
url: 'URL',
|
||||||
body: 'Descripción',
|
body: 'Descripción',
|
||||||
copy_suggested_title: 'Copiar el título sugerido: {{title}}',
|
copy_suggested_title: 'Copiar el título sugerido: {{title}}',
|
||||||
|
@ -139,8 +169,10 @@ export const es = {
|
||||||
sponsor_message:
|
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:',
|
'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_patreon: 'Apoyo en Patreon',
|
||||||
|
donate_to_lemmy: 'Donar a Lemmy',
|
||||||
|
donate: 'Donar',
|
||||||
general_sponsors:
|
general_sponsors:
|
||||||
'Patrocinadores Generales son aquellos que señaron entre $10 y $39 a Lemmy.',
|
'Los Patrocinadores Generales son aquellos que señaron entre $10 y $39 a Lemmy.',
|
||||||
crypto: 'Crypto',
|
crypto: 'Crypto',
|
||||||
bitcoin: 'Bitcoin',
|
bitcoin: 'Bitcoin',
|
||||||
ethereum: 'Ethereum',
|
ethereum: 'Ethereum',
|
||||||
|
@ -148,7 +180,8 @@ export const es = {
|
||||||
code: 'Código',
|
code: 'Código',
|
||||||
joined: 'Se unió',
|
joined: 'Se unió',
|
||||||
by: 'por',
|
by: 'por',
|
||||||
to: 'en',
|
to: 'a',
|
||||||
|
from: 'desde',
|
||||||
transfer_community: 'transferir comunidad',
|
transfer_community: 'transferir comunidad',
|
||||||
transfer_site: 'transferir sitio',
|
transfer_site: 'transferir sitio',
|
||||||
are_you_sure: '¿Estás seguro?',
|
are_you_sure: '¿Estás seguro?',
|
||||||
|
@ -158,24 +191,22 @@ export const es = {
|
||||||
landing_0:
|
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>.',
|
'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.',
|
not_logged_in: 'No has iniciado sesión.',
|
||||||
|
logged_in: 'Has iniciado sesión.',
|
||||||
community_ban: 'Has sido expulsado de esta comunidad.',
|
community_ban: 'Has sido expulsado de esta comunidad.',
|
||||||
site_ban: 'Has sido expulsado del sitio',
|
site_ban: 'Has sido expulsado del sitio',
|
||||||
couldnt_create_comment: 'No se pudo crear el comentario.',
|
couldnt_create_comment: 'No se pudo crear el comentario.',
|
||||||
couldnt_like_comment: 'No se pudo gustar el comentario.',
|
couldnt_like_comment: 'No se pudo dar me gusta al comentario.',
|
||||||
couldnt_update_comment: 'No se pudo actualizar el comentario.',
|
couldnt_update_comment: 'No se pudo actualizar el comentario.',
|
||||||
couldnt_save_comment: 'No se pudo guardar el comentario.',
|
couldnt_save_comment: 'No se pudo guardar el comentario.',
|
||||||
no_comment_edit_allowed: 'No tiene permitido editar el comentario.',
|
no_comment_edit_allowed: 'No tiene permisos para editar el comentario.',
|
||||||
no_post_edit_allowed: 'No tiene permitido editar la publicación.',
|
no_post_edit_allowed: 'No tiene permisos para editar la publicación.',
|
||||||
no_community_edit_allowed: 'No tiene permitido editar la comunidad.',
|
no_community_edit_allowed: 'No tiene permisos para editar la comunidad.',
|
||||||
couldnt_find_community: 'No se pudo encontrar la comunidad.',
|
couldnt_find_community: 'No se pudo encontrar la comunidad.',
|
||||||
couldnt_update_community: 'No se pudo actualizar la comunidad.',
|
couldnt_update_community: 'No se pudo actualizar la comunidad.',
|
||||||
community_already_exists: 'Esta comunidad ya existe.',
|
community_already_exists: 'Esta comunidad ya existe.',
|
||||||
community_moderator_already_exists:
|
community_moderator_already_exists: 'Este moderador de la comunidad ya existe.',
|
||||||
'Este moderador de la comunidad ya existe.',
|
community_follower_already_exists: 'Este seguidor de la comunidad ya existe.',
|
||||||
community_follower_already_exists:
|
community_user_already_banned: 'Este usuario de la comunidad ya fue expulsado.',
|
||||||
'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_create_post: 'No se pudo crear la publicación.',
|
||||||
couldnt_like_post: 'No se pudo gustar la publicación.',
|
couldnt_like_post: 'No se pudo gustar la publicación.',
|
||||||
couldnt_find_post: 'No se pudo encontrar la publicación.',
|
couldnt_find_post: 'No se pudo encontrar la publicación.',
|
||||||
|
@ -192,8 +223,11 @@ export const es = {
|
||||||
passwords_dont_match: 'Las contraseñas no coinciden.',
|
passwords_dont_match: 'Las contraseñas no coinciden.',
|
||||||
admin_already_created: 'Lo sentimos, ya hay un adminisitrador.',
|
admin_already_created: 'Lo sentimos, ya hay un adminisitrador.',
|
||||||
user_already_exists: 'El usuario ya existe.',
|
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.',
|
couldnt_update_user: 'No se pudo actualizar el usuario.',
|
||||||
system_err_login:
|
system_err_login: 'Error del sistema. Intente cerrar sesión e ingresar de nuevo.',
|
||||||
'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.",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
233
ui/src/translations/fi.ts
vendored
Normal file
233
ui/src/translations/fi.ts
vendored
Normal file
|
@ -0,0 +1,233 @@
|
||||||
|
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ää.",
|
||||||
|
},
|
||||||
|
};
|
10
ui/src/utils.ts
vendored
10
ui/src/utils.ts
vendored
|
@ -7,6 +7,8 @@ import 'moment/locale/sv';
|
||||||
import 'moment/locale/ru';
|
import 'moment/locale/ru';
|
||||||
import 'moment/locale/nl';
|
import 'moment/locale/nl';
|
||||||
import 'moment/locale/it';
|
import 'moment/locale/it';
|
||||||
|
import 'moment/locale/fi';
|
||||||
|
import 'moment/locale/ca';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
UserOperation,
|
UserOperation,
|
||||||
|
@ -251,11 +253,13 @@ export function debounce(
|
||||||
}
|
}
|
||||||
|
|
||||||
export const languages = [
|
export const languages = [
|
||||||
|
{ code: 'ca', name: 'Català' },
|
||||||
{ code: 'en', name: 'English' },
|
{ code: 'en', name: 'English' },
|
||||||
{ code: 'eo', name: 'Esperanto' },
|
{ code: 'eo', name: 'Esperanto' },
|
||||||
{ code: 'es', name: 'Español' },
|
{ code: 'es', name: 'Español' },
|
||||||
{ code: 'de', name: 'Deutsch' },
|
{ code: 'de', name: 'Deutsch' },
|
||||||
{ code: 'zh', name: '中文' },
|
{ code: 'zh', name: '中文' },
|
||||||
|
{ code: 'fi', name: 'Suomi' },
|
||||||
{ code: 'fr', name: 'Français' },
|
{ code: 'fr', name: 'Français' },
|
||||||
{ code: 'sv', name: 'Svenska' },
|
{ code: 'sv', name: 'Svenska' },
|
||||||
{ code: 'ru', name: 'Русский' },
|
{ code: 'ru', name: 'Русский' },
|
||||||
|
@ -298,6 +302,10 @@ export function getMomentLanguage(): string {
|
||||||
lang = 'nl';
|
lang = 'nl';
|
||||||
} else if (lang.startsWith('it')) {
|
} else if (lang.startsWith('it')) {
|
||||||
lang = 'it';
|
lang = 'it';
|
||||||
|
} else if (lang.startsWith('fi')) {
|
||||||
|
lang = 'fi';
|
||||||
|
} else if (lang.startsWith('ca')) {
|
||||||
|
lang = 'ca';
|
||||||
} else {
|
} else {
|
||||||
lang = 'en';
|
lang = 'en';
|
||||||
}
|
}
|
||||||
|
@ -382,6 +390,8 @@ export function toast(text: string, background: string = 'success') {
|
||||||
Toastify({
|
Toastify({
|
||||||
text: text,
|
text: text,
|
||||||
backgroundColor: backgroundColor,
|
backgroundColor: backgroundColor,
|
||||||
|
gravity: 'bottom',
|
||||||
|
position: 'left',
|
||||||
}).showToast();
|
}).showToast();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
2
ui/src/version.ts
vendored
2
ui/src/version.ts
vendored
|
@ -1 +1 @@
|
||||||
export let version: string = 'v0.6.4';
|
export const version: string = 'v0.6.7';
|
||||||
|
|
76
ui/translation_report.ts
vendored
76
ui/translation_report.ts
vendored
|
@ -8,51 +8,51 @@ import { sv } from './src/translations/sv';
|
||||||
import { ru } from './src/translations/ru';
|
import { ru } from './src/translations/ru';
|
||||||
import { nl } from './src/translations/nl';
|
import { nl } from './src/translations/nl';
|
||||||
import { it } from './src/translations/it';
|
import { it } from './src/translations/it';
|
||||||
|
import { fi } from './src/translations/fi';
|
||||||
|
import { ca } from './src/translations/ca';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
|
|
||||||
let readmePath = '../README.md';
|
const files = [
|
||||||
|
{ t: ca, n: 'ca' },
|
||||||
|
{ t: de, n: 'de' },
|
||||||
|
{ 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: ru, n: 'ru' },
|
||||||
|
{ t: sv, n: 'sv' },
|
||||||
|
{ t: zh, n: 'zh' },
|
||||||
|
];
|
||||||
|
const masterKeys = Object.keys(en.translation);
|
||||||
|
|
||||||
let open = '<!-- translations -->';
|
const readmePath = '../README.md';
|
||||||
let close = '<!-- translationsstop -->';
|
|
||||||
|
|
||||||
let readmeTxt = fs.readFileSync(readmePath, { encoding: 'utf8' });
|
const open = '<!-- translations -->';
|
||||||
|
const close = '<!-- translationsstop -->';
|
||||||
|
|
||||||
let before = readmeTxt.split(open)[0];
|
const readmeTxt = fs.readFileSync(readmePath, { encoding: 'utf8' });
|
||||||
let after = readmeTxt.split(close)[1];
|
|
||||||
|
|
||||||
let report = buildReport();
|
const before = readmeTxt.split(open)[0];
|
||||||
|
const after = readmeTxt.split(close)[1];
|
||||||
let alteredReadmeTxt = `${before}${open}\n\n${report}\n${close}${after}`;
|
|
||||||
|
|
||||||
fs.writeFileSync(readmePath, alteredReadmeTxt);
|
|
||||||
|
|
||||||
function buildReport(): string {
|
|
||||||
let files = [
|
|
||||||
{ t: de, n: 'de' },
|
|
||||||
{ t: eo, n: 'eo' },
|
|
||||||
{ t: es, n: 'es' },
|
|
||||||
{ t: fr, n: 'fr' },
|
|
||||||
{ t: it, n: 'it' },
|
|
||||||
{ t: nl, n: 'nl' },
|
|
||||||
{ t: ru, n: 'ru' },
|
|
||||||
{ t: sv, n: 'sv' },
|
|
||||||
{ t: zh, n: 'zh' },
|
|
||||||
];
|
|
||||||
let masterKeys = Object.keys(en.translation);
|
|
||||||
|
|
||||||
let report = 'lang | done | missing\n';
|
|
||||||
report += '--- | --- | ---\n';
|
|
||||||
|
|
||||||
for (let file of files) {
|
|
||||||
let keys = Object.keys(file.t.translation);
|
|
||||||
let pct: number = (keys.length / masterKeys.length) * 100;
|
|
||||||
let missing = difference(masterKeys, keys);
|
|
||||||
report += `${file.n} | ${pct.toFixed(0)}% | ${missing} \n`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return report;
|
|
||||||
}
|
|
||||||
|
|
||||||
function difference(a: Array<string>, b: Array<string>): Array<string> {
|
function difference(a: Array<string>, b: Array<string>): Array<string> {
|
||||||
return a.filter(x => !b.includes(x));
|
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);
|
||||||
|
|
33
ui/yarn.lock
vendored
33
ui/yarn.lock
vendored
|
@ -382,6 +382,11 @@ app-root-path@^2.0.1:
|
||||||
resolved "https://registry.yarnpkg.com/app-root-path/-/app-root-path-2.2.1.tgz#d0df4a682ee408273583d43f6f79e9892624bc9a"
|
resolved "https://registry.yarnpkg.com/app-root-path/-/app-root-path-2.2.1.tgz#d0df4a682ee408273583d43f6f79e9892624bc9a"
|
||||||
integrity sha512-91IFKeKk7FjfmezPKkwtaRvSpnUc4gDwPAjA1YZ9Gn0q0PPeW+vbeUsZuyDwjI7+QTHhcLen2v25fi/AmhvbJA==
|
integrity sha512-91IFKeKk7FjfmezPKkwtaRvSpnUc4gDwPAjA1YZ9Gn0q0PPeW+vbeUsZuyDwjI7+QTHhcLen2v25fi/AmhvbJA==
|
||||||
|
|
||||||
|
arg@^4.1.0:
|
||||||
|
version "4.1.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.2.tgz#e70c90579e02c63d80e3ad4e31d8bfdb8bd50064"
|
||||||
|
integrity sha512-+ytCkGcBtHZ3V2r2Z06AncYO8jz46UEamcspGoU8lHcEbpn6J77QK0vdWvChsclg/tM5XIJC5tnjmPp7Eq6Obg==
|
||||||
|
|
||||||
argparse@^1.0.7:
|
argparse@^1.0.7:
|
||||||
version "1.0.10"
|
version "1.0.10"
|
||||||
resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
|
resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
|
||||||
|
@ -1036,6 +1041,11 @@ destroy@~1.0.4:
|
||||||
resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80"
|
resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80"
|
||||||
integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=
|
integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=
|
||||||
|
|
||||||
|
diff@^4.0.1:
|
||||||
|
version "4.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d"
|
||||||
|
integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==
|
||||||
|
|
||||||
doctrine@1.5.0:
|
doctrine@1.5.0:
|
||||||
version "1.5.0"
|
version "1.5.0"
|
||||||
resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa"
|
resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa"
|
||||||
|
@ -2910,6 +2920,11 @@ loose-envify@^1.2.0, loose-envify@^1.4.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
js-tokens "^3.0.0 || ^4.0.0"
|
js-tokens "^3.0.0 || ^4.0.0"
|
||||||
|
|
||||||
|
make-error@^1.1.1:
|
||||||
|
version "1.3.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.5.tgz#efe4e81f6db28cadd605c70f29c831b58ef776c8"
|
||||||
|
integrity sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g==
|
||||||
|
|
||||||
map-cache@^0.2.2:
|
map-cache@^0.2.2:
|
||||||
version "0.2.2"
|
version "0.2.2"
|
||||||
resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf"
|
resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf"
|
||||||
|
@ -4123,7 +4138,7 @@ source-map-resolve@^0.5.0:
|
||||||
source-map-url "^0.4.0"
|
source-map-url "^0.4.0"
|
||||||
urix "^0.1.0"
|
urix "^0.1.0"
|
||||||
|
|
||||||
source-map-support@~0.5.12:
|
source-map-support@^0.5.6, source-map-support@~0.5.12:
|
||||||
version "0.5.16"
|
version "0.5.16"
|
||||||
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.16.tgz#0ae069e7fe3ba7538c64c98515e35339eac5a042"
|
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.16.tgz#0ae069e7fe3ba7538c64c98515e35339eac5a042"
|
||||||
integrity sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ==
|
integrity sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ==
|
||||||
|
@ -4477,6 +4492,17 @@ tributejs@^4.1.1:
|
||||||
resolved "https://registry.yarnpkg.com/tributejs/-/tributejs-4.1.1.tgz#f169a4ad12e485241140ec1ab987b460950c974c"
|
resolved "https://registry.yarnpkg.com/tributejs/-/tributejs-4.1.1.tgz#f169a4ad12e485241140ec1ab987b460950c974c"
|
||||||
integrity sha512-jc+PcaiNzMjCn2LAQb3i4ic94EsSfLW8Jlk1sK2cb6hLcZFalU9ThcF8rxuKkTUKv1GIvTwN8XseLzCXLxB4lw==
|
integrity sha512-jc+PcaiNzMjCn2LAQb3i4ic94EsSfLW8Jlk1sK2cb6hLcZFalU9ThcF8rxuKkTUKv1GIvTwN8XseLzCXLxB4lw==
|
||||||
|
|
||||||
|
ts-node@^8.6.2:
|
||||||
|
version "8.6.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-8.6.2.tgz#7419a01391a818fbafa6f826a33c1a13e9464e35"
|
||||||
|
integrity sha512-4mZEbofxGqLL2RImpe3zMJukvEvcO1XP8bj8ozBPySdCUXEcU5cIRwR0aM3R+VoZq7iXc8N86NC0FspGRqP4gg==
|
||||||
|
dependencies:
|
||||||
|
arg "^4.1.0"
|
||||||
|
diff "^4.0.1"
|
||||||
|
make-error "^1.1.1"
|
||||||
|
source-map-support "^0.5.6"
|
||||||
|
yn "3.1.1"
|
||||||
|
|
||||||
ts-transform-classcat@^0.0.2:
|
ts-transform-classcat@^0.0.2:
|
||||||
version "0.0.2"
|
version "0.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/ts-transform-classcat/-/ts-transform-classcat-0.0.2.tgz#2386c9418f3a7c1f03261ff51225b70d0a7664fb"
|
resolved "https://registry.yarnpkg.com/ts-transform-classcat/-/ts-transform-classcat-0.0.2.tgz#2386c9418f3a7c1f03261ff51225b70d0a7664fb"
|
||||||
|
@ -4769,3 +4795,8 @@ yaml@^1.7.2:
|
||||||
integrity sha512-qXROVp90sb83XtAoqE8bP9RwAkTTZbugRUTm5YeFCBfNRPEp2YzTeqWiz7m5OORHzEvrA/qcGS8hp/E+MMROYw==
|
integrity sha512-qXROVp90sb83XtAoqE8bP9RwAkTTZbugRUTm5YeFCBfNRPEp2YzTeqWiz7m5OORHzEvrA/qcGS8hp/E+MMROYw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/runtime" "^7.6.3"
|
"@babel/runtime" "^7.6.3"
|
||||||
|
|
||||||
|
yn@3.1.1:
|
||||||
|
version "3.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"
|
||||||
|
integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==
|
||||||
|
|
Loading…
Reference in a new issue