Merge branch 'dev' into nutomic-ansible
This commit is contained in:
commit
be6bd0b36f
30 changed files with 613 additions and 102 deletions
27
README.md
vendored
27
README.md
vendored
|
@ -159,25 +159,26 @@ Lemmy is free, open-source software, meaning no advertising, monetizing, or vent
|
|||
|
||||
## Translations
|
||||
|
||||
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 at the [English translation file](ui/src/translations/en.ts).
|
||||
|
||||
- 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`).
|
||||
- Languages supported: Catalan, (`ca`), Farsi (`fa`), English (`en`), Chinese (`zh`), Dutch (`nl`), Esperanto (`eo`), Finnish (`fi`), French (`fr`), Spanish (`es`), Swedish (`sv`), German (`de`), Russian (`ru`), Italian (`it`).
|
||||
|
||||
<!-- translations -->
|
||||
|
||||
lang | done | missing
|
||||
---- | ---- | -------
|
||||
ca | 100% |
|
||||
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
|
||||
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
|
||||
es | 100% |
|
||||
fi | 100% |
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
ca | 100% | old
|
||||
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
|
||||
fa | 73% | cross_post,subscribed_to_communities,trending_communities,create_private_message,send_secure_message,send_message,message,mod,mods,moderates,remove_as_mod,appoint_as_mod,modlog,stickied,ban,ban_from_site,unban,unban_from_site,banned,number_of_subscribers,subscribers,both,saved,unsubscribe,subscribe,subscribed,old,api,docs,inbox,inbox_for,message_sent,notifications_error,messages,no_email_setup,matrix_user_id,private_message_disclaimer,url,body,copy_suggested_title,community,expand_here,subscribe_to_communities,theme,sponsor_message,general_sponsors,joined,by,to,from,landing_0,logged_in,community_moderator_already_exists,community_follower_already_exists,community_user_already_banned,no_slurs,admin_already_created,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
|
||||
es | 100% | old
|
||||
fi | 100% | old
|
||||
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
|
||||
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
|
||||
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
|
||||
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 -->
|
||||
|
||||
If you'd like to update this report, run:
|
||||
|
|
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
|
||||
restart: always
|
||||
lemmy:
|
||||
image: dessalines/lemmy:v0.6.5
|
||||
image: dessalines/lemmy:v0.6.7
|
||||
ports:
|
||||
- "127.0.0.1:8536:8536"
|
||||
restart: always
|
||||
|
|
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
|
||||
;
|
||||
|
3
server/query_testing/apache_bench_report.sh
vendored
3
server/query_testing/apache_bench_report.sh
vendored
|
@ -1,4 +1,5 @@
|
|||
#!/bin/sh
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
declare -a arr=(
|
||||
"https://mastodon.social/"
|
||||
|
|
34
server/query_testing/api_benchmark.sh
vendored
Executable file
34
server/query_testing/api_benchmark.sh
vendored
Executable file
|
@ -0,0 +1,34 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# By default, this script runs against `http://127.0.0.1:8536`, but you can pass a different Lemmy instance,
|
||||
# eg `./api_benchmark.sh "https://example.com"`.
|
||||
DOMAIN=${1:-"http://127.0.0.1:8536"}
|
||||
|
||||
declare -a arr=(
|
||||
"/api/v1/site"
|
||||
"/api/v1/categories"
|
||||
"/api/v1/modlog"
|
||||
"/api/v1/search?q=test&type_=Posts&sort=Hot"
|
||||
"/api/v1/community"
|
||||
"/api/v1/community/list?sort=Hot"
|
||||
"/api/v1/post/list?sort=Hot&type_=All"
|
||||
)
|
||||
|
||||
## now loop through the above array
|
||||
for path in "${arr[@]}"
|
||||
do
|
||||
URL="$DOMAIN$path"
|
||||
printf "\n\n\n"
|
||||
echo "testing $URL"
|
||||
curl --show-error --fail --silent "$URL" >/dev/null
|
||||
ab -c 64 -t 10 "$URL" > out.abtest
|
||||
grep "Server Hostname:" out.abtest
|
||||
grep "Document Path:" out.abtest
|
||||
grep "Requests per second" out.abtest
|
||||
grep "(mean, across all concurrent requests)" out.abtest
|
||||
grep "Transfer rate:" out.abtest
|
||||
echo "---"
|
||||
done
|
||||
|
||||
rm *.abtest
|
12
server/query_testing/generate_explain_reports.sh
vendored
12
server/query_testing/generate_explain_reports.sh
vendored
|
@ -1,4 +1,5 @@
|
|||
#!/bin/sh
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Do the views first
|
||||
|
||||
|
@ -17,6 +18,15 @@ psql -qAt -U lemmy -f explain.sql > community_view.json
|
|||
echo "explain (analyze, format json) select * from site_view limit 1" > explain.sql
|
||||
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
|
||||
|
||||
rm explain.sql
|
||||
|
|
|
@ -3,7 +3,7 @@ use diesel::PgConnection;
|
|||
use std::str::FromStr;
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct ListCategories;
|
||||
pub struct ListCategories {}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct ListCategoriesResponse {
|
||||
|
@ -72,7 +72,7 @@ pub struct EditSite {
|
|||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct GetSite;
|
||||
pub struct GetSite {}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct SiteResponse {
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
use super::user_mention_view::user_mention_view::BoxedQuery;
|
||||
use super::*;
|
||||
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(
|
||||
Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize, QueryableByName, Clone,
|
||||
)]
|
||||
|
@ -63,7 +90,7 @@ pub struct UserMentionView {
|
|||
|
||||
pub struct UserMentionQueryBuilder<'a> {
|
||||
conn: &'a PgConnection,
|
||||
query: BoxedQuery<'a, Pg>,
|
||||
query: super::user_mention_view::user_mention_mview::BoxedQuery<'a, Pg>,
|
||||
for_user_id: i32,
|
||||
sort: &'a SortType,
|
||||
unread_only: bool,
|
||||
|
@ -73,9 +100,9 @@ pub struct UserMentionQueryBuilder<'a> {
|
|||
|
||||
impl<'a> UserMentionQueryBuilder<'a> {
|
||||
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 {
|
||||
conn,
|
||||
|
@ -109,7 +136,7 @@ impl<'a> UserMentionQueryBuilder<'a> {
|
|||
}
|
||||
|
||||
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;
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
pub const VERSION: &str = "v0.6.5";
|
||||
pub const VERSION: &str = "v0.6.7";
|
||||
|
|
3
ui/package.json
vendored
3
ui/package.json
vendored
|
@ -49,6 +49,7 @@
|
|||
"fuse-box": "^3.1.3",
|
||||
"lint-staged": "^10.0.2",
|
||||
"sortpack": "^2.0.1",
|
||||
"ts-node": "^8.6.2",
|
||||
"ts-transform-classcat": "^0.0.2",
|
||||
"ts-transform-inferno": "^4.0.2",
|
||||
"typescript": "^3.7.5"
|
||||
|
@ -59,7 +60,7 @@
|
|||
"engineStrict": true,
|
||||
"husky": {
|
||||
"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": {
|
||||
|
|
18
ui/src/components/comment-form.tsx
vendored
18
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'}`}
|
||||
value={this.state.commentForm.content}
|
||||
onInput={linkEvent(this, this.handleCommentContentChange)}
|
||||
onPaste={linkEvent(this, this.handleImageUploadPaste)}
|
||||
required
|
||||
disabled={this.props.disabled}
|
||||
rows={2}
|
||||
|
@ -208,9 +209,22 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> {
|
|||
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) {
|
||||
event.preventDefault();
|
||||
let file = event.target.files[0];
|
||||
let file: any;
|
||||
if (event.target) {
|
||||
event.preventDefault();
|
||||
file = event.target.files[0];
|
||||
} else {
|
||||
file = event;
|
||||
}
|
||||
|
||||
const imageUploadUrl = `/pictshare/api/upload.php`;
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
|
|
11
ui/src/components/community.tsx
vendored
11
ui/src/components/community.tsx
vendored
|
@ -11,6 +11,7 @@ import {
|
|||
SortType,
|
||||
Post,
|
||||
GetPostsForm,
|
||||
GetCommunityForm,
|
||||
ListingType,
|
||||
GetPostsResponse,
|
||||
CreatePostLikeResponse,
|
||||
|
@ -98,11 +99,11 @@ export class Community extends Component<any, State> {
|
|||
() => console.log('complete')
|
||||
);
|
||||
|
||||
if (this.state.communityId) {
|
||||
WebSocketService.Instance.getCommunity(this.state.communityId);
|
||||
} else if (this.state.communityName) {
|
||||
WebSocketService.Instance.getCommunityByName(this.state.communityName);
|
||||
}
|
||||
let form: GetCommunityForm = {
|
||||
id: this.state.communityId ? this.state.communityId : null,
|
||||
name: this.state.communityName ? this.state.communityName : null,
|
||||
};
|
||||
WebSocketService.Instance.getCommunity(form);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
|
|
4
ui/src/components/inbox.tsx
vendored
4
ui/src/components/inbox.tsx
vendored
|
@ -38,6 +38,8 @@ enum UnreadType {
|
|||
Messages,
|
||||
}
|
||||
|
||||
type ReplyType = Comment | PrivateMessageI;
|
||||
|
||||
interface InboxState {
|
||||
unreadOrAll: UnreadOrAll;
|
||||
unreadType: UnreadType;
|
||||
|
@ -186,7 +188,7 @@ export class Inbox extends Component<any, InboxState> {
|
|||
}
|
||||
|
||||
all() {
|
||||
let combined: Array<Comment | PrivateMessageI> = [];
|
||||
let combined: Array<ReplyType> = [];
|
||||
|
||||
combined.push(...this.state.replies);
|
||||
combined.push(...this.state.mentions);
|
||||
|
|
2
ui/src/components/navbar.tsx
vendored
2
ui/src/components/navbar.tsx
vendored
|
@ -138,7 +138,7 @@ export class Navbar extends Component<any, NavbarState> {
|
|||
</li>
|
||||
<li className="nav-item">
|
||||
<Link
|
||||
class="nav-link ml-2"
|
||||
class="nav-link"
|
||||
to="/sponsors"
|
||||
title={i18n.t('donate_to_lemmy')}
|
||||
>
|
||||
|
|
18
ui/src/components/post-form.tsx
vendored
18
ui/src/components/post-form.tsx
vendored
|
@ -160,6 +160,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
|
|||
class="form-control"
|
||||
value={this.state.postForm.url}
|
||||
onInput={linkEvent(this, this.handlePostUrlChange)}
|
||||
onPaste={linkEvent(this, this.handleImageUploadPaste)}
|
||||
/>
|
||||
{this.state.suggestedTitle && (
|
||||
<div
|
||||
|
@ -442,9 +443,22 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
|
|||
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) {
|
||||
event.preventDefault();
|
||||
let file = event.target.files[0];
|
||||
let file: any;
|
||||
if (event.target) {
|
||||
event.preventDefault();
|
||||
file = event.target.files[0];
|
||||
} else {
|
||||
file = event;
|
||||
}
|
||||
|
||||
const imageUploadUrl = `/pictshare/api/upload.php`;
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
|
|
25
ui/src/components/post.tsx
vendored
25
ui/src/components/post.tsx
vendored
|
@ -23,6 +23,7 @@ import {
|
|||
SearchType,
|
||||
SortType,
|
||||
SearchForm,
|
||||
GetPostForm,
|
||||
SearchResponse,
|
||||
GetSiteResponse,
|
||||
GetCommunityResponse,
|
||||
|
@ -84,7 +85,10 @@ export class Post extends Component<any, PostState> {
|
|||
() => console.log('complete')
|
||||
);
|
||||
|
||||
WebSocketService.Instance.getPost(postId);
|
||||
let form: GetPostForm = {
|
||||
id: postId,
|
||||
};
|
||||
WebSocketService.Instance.getPost(form);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
|
@ -231,6 +235,18 @@ export class Post extends Component<any, PostState> {
|
|||
onChange={linkEvent(this, this.handleCommentSortChange)}
|
||||
/>
|
||||
</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>
|
||||
);
|
||||
}
|
||||
|
@ -313,6 +329,13 @@ export class Post extends Component<any, PostState> {
|
|||
+a.comment.deleted - +b.comment.deleted ||
|
||||
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) {
|
||||
tree.sort(
|
||||
(a, b) =>
|
||||
|
|
2
ui/src/i18next.ts
vendored
2
ui/src/i18next.ts
vendored
|
@ -12,6 +12,7 @@ import { nl } from './translations/nl';
|
|||
import { it } from './translations/it';
|
||||
import { fi } from './translations/fi';
|
||||
import { ca } from './translations/ca';
|
||||
import { fa } from './translations/fa';
|
||||
|
||||
// https://github.com/nimbusec-oss/inferno-i18next/blob/master/tests/T.test.js#L66
|
||||
const resources = {
|
||||
|
@ -27,6 +28,7 @@ const resources = {
|
|||
it,
|
||||
fi,
|
||||
ca,
|
||||
fa,
|
||||
};
|
||||
|
||||
function format(value: any, format: any, lng: any): any {
|
||||
|
|
55
ui/src/interfaces.ts
vendored
55
ui/src/interfaces.ts
vendored
|
@ -47,6 +47,7 @@ export enum CommentSortType {
|
|||
Hot,
|
||||
Top,
|
||||
New,
|
||||
Old,
|
||||
}
|
||||
|
||||
export enum ListingType {
|
||||
|
@ -248,6 +249,10 @@ export interface FollowCommunityForm {
|
|||
auth?: string;
|
||||
}
|
||||
|
||||
export interface GetFollowedCommunitiesForm {
|
||||
auth: string;
|
||||
}
|
||||
|
||||
export interface GetFollowedCommunitiesResponse {
|
||||
communities: Array<CommunityUser>;
|
||||
}
|
||||
|
@ -523,6 +528,12 @@ export interface CommunityForm {
|
|||
auth?: string;
|
||||
}
|
||||
|
||||
export interface GetCommunityForm {
|
||||
id?: number;
|
||||
name?: string;
|
||||
auth?: string;
|
||||
}
|
||||
|
||||
export interface GetCommunityResponse {
|
||||
community: Community;
|
||||
moderators: Array<CommunityUser>;
|
||||
|
@ -572,6 +583,11 @@ export interface PostFormParams {
|
|||
community?: string;
|
||||
}
|
||||
|
||||
export interface GetPostForm {
|
||||
id: number;
|
||||
auth?: string;
|
||||
}
|
||||
|
||||
export interface GetPostResponse {
|
||||
post: Post;
|
||||
comments: Array<Comment>;
|
||||
|
@ -759,6 +775,45 @@ export interface PrivateMessageResponse {
|
|||
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 =
|
||||
| SiteResponse
|
||||
| GetFollowedCommunitiesResponse
|
||||
|
|
31
ui/src/services/WebSocketService.ts
vendored
31
ui/src/services/WebSocketService.ts
vendored
|
@ -9,9 +9,12 @@ import {
|
|||
CommentForm,
|
||||
SaveCommentForm,
|
||||
CommentLikeForm,
|
||||
GetPostForm,
|
||||
GetPostsForm,
|
||||
CreatePostLikeForm,
|
||||
GetCommunityForm,
|
||||
FollowCommunityForm,
|
||||
GetFollowedCommunitiesForm,
|
||||
GetUserDetailsForm,
|
||||
ListCommunitiesForm,
|
||||
GetModlogForm,
|
||||
|
@ -35,6 +38,7 @@ import {
|
|||
PrivateMessageForm,
|
||||
EditPrivateMessageForm,
|
||||
GetPrivateMessagesForm,
|
||||
MessageType,
|
||||
} from '../interfaces';
|
||||
import { webSocket } from 'rxjs/webSocket';
|
||||
import { Subject } from 'rxjs';
|
||||
|
@ -108,15 +112,15 @@ export class WebSocketService {
|
|||
}
|
||||
|
||||
public getFollowedCommunities() {
|
||||
let data = { auth: UserService.Instance.auth };
|
||||
let form: GetFollowedCommunitiesForm = { auth: UserService.Instance.auth };
|
||||
this.subject.next(
|
||||
this.wsSendWrapper(UserOperation.GetFollowedCommunities, data)
|
||||
this.wsSendWrapper(UserOperation.GetFollowedCommunities, form)
|
||||
);
|
||||
}
|
||||
|
||||
public listCategories() {
|
||||
this.subject.next(
|
||||
this.wsSendWrapper(UserOperation.ListCategories, undefined)
|
||||
this.wsSendWrapper(UserOperation.ListCategories, {})
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -125,19 +129,14 @@ export class WebSocketService {
|
|||
this.subject.next(this.wsSendWrapper(UserOperation.CreatePost, postForm));
|
||||
}
|
||||
|
||||
public getPost(postId: number) {
|
||||
let data = { id: postId, auth: UserService.Instance.auth };
|
||||
this.subject.next(this.wsSendWrapper(UserOperation.GetPost, data));
|
||||
public getPost(form: GetPostForm) {
|
||||
this.setAuth(form, false);
|
||||
this.subject.next(this.wsSendWrapper(UserOperation.GetPost, form));
|
||||
}
|
||||
|
||||
public getCommunity(communityId: number) {
|
||||
let data = { id: communityId, auth: UserService.Instance.auth };
|
||||
this.subject.next(this.wsSendWrapper(UserOperation.GetCommunity, data));
|
||||
}
|
||||
|
||||
public getCommunityByName(name: string) {
|
||||
let data = { name: name, auth: UserService.Instance.auth };
|
||||
this.subject.next(this.wsSendWrapper(UserOperation.GetCommunity, data));
|
||||
public getCommunity(form: GetCommunityForm) {
|
||||
this.setAuth(form, false);
|
||||
this.subject.next(this.wsSendWrapper(UserOperation.GetCommunity, form));
|
||||
}
|
||||
|
||||
public createComment(commentForm: CommentForm) {
|
||||
|
@ -255,7 +254,7 @@ export class WebSocketService {
|
|||
}
|
||||
|
||||
public getSite() {
|
||||
this.subject.next(this.wsSendWrapper(UserOperation.GetSite, undefined));
|
||||
this.subject.next(this.wsSendWrapper(UserOperation.GetSite, {}));
|
||||
}
|
||||
|
||||
public search(form: SearchForm) {
|
||||
|
@ -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 };
|
||||
console.log(send);
|
||||
return send;
|
||||
|
|
64
ui/src/translations/de.ts
vendored
64
ui/src/translations/de.ts
vendored
|
@ -15,9 +15,9 @@ export const de = {
|
|||
remove_comment: 'Kommentar löschen',
|
||||
communities: 'Communities',
|
||||
users: 'Benutzer',
|
||||
create_a_community: 'Eine community anlegen',
|
||||
create_community: 'Community anlegen',
|
||||
remove_community: 'Community entfernen',
|
||||
create_a_community: 'Eine Gemeinschaft anlegen',
|
||||
create_community: 'Gemeinschaft anlegen',
|
||||
remove_community: 'Gemeinschaft entfernen',
|
||||
subscribed_to_communities: 'Abonnierte <1>communities</1>',
|
||||
trending_communities: 'Trending <1>communities</1>',
|
||||
list_of_communities: 'Liste von communities',
|
||||
|
@ -36,17 +36,17 @@ export const de = {
|
|||
unsticky: 'nicht haftend',
|
||||
link: 'link',
|
||||
archive_link: 'Archiv-Link',
|
||||
mod: 'mod',
|
||||
mods: 'mods',
|
||||
mod: 'Moderator',
|
||||
mods: 'Moderatoren',
|
||||
moderates: 'Moderiert',
|
||||
settings: 'Einstellungen',
|
||||
remove_as_mod: 'Als mod entfernen',
|
||||
appoint_as_mod: 'Zum mod ernennen',
|
||||
remove_as_mod: 'Als Moderator entfernen',
|
||||
appoint_as_mod: 'Zum Moderator ernennen',
|
||||
modlog: 'Modlog',
|
||||
admin: 'admin',
|
||||
admins: 'admins',
|
||||
remove_as_admin: 'Als admin entfernen',
|
||||
appoint_as_admin: 'Zum admin ernennen',
|
||||
admin: 'Administrator',
|
||||
admins: 'Administratoren',
|
||||
remove_as_admin: 'Als Administrator entfernen',
|
||||
appoint_as_admin: 'Zum Administrator ernennen',
|
||||
remove: 'entfernen',
|
||||
removed: 'entfernt',
|
||||
locked: 'gesperrt',
|
||||
|
@ -66,11 +66,11 @@ export const de = {
|
|||
unban_from_site: 'Von der Seite entbannen',
|
||||
banned: 'gesperrt',
|
||||
save: 'speichern',
|
||||
unsave: 'unsave',
|
||||
unsave: 'nicht speichern',
|
||||
create: 'anlegen',
|
||||
creator: 'Ersteller',
|
||||
username: 'Username',
|
||||
email_or_username: 'Email oder Username',
|
||||
username: 'Benutzername',
|
||||
email_or_username: 'E-mail oder Username',
|
||||
number_of_users: '{{count}} Benutzer',
|
||||
number_of_subscribers: '{{count}} Abonnenten',
|
||||
number_of_points: '{{count}} Punkte',
|
||||
|
@ -86,7 +86,7 @@ export const de = {
|
|||
subscribed: 'Abonniert',
|
||||
prev: 'Zurück',
|
||||
next: 'Weiter',
|
||||
sidebar: 'Sidebar',
|
||||
sidebar: 'Seitenleiste',
|
||||
sort_type: 'Sortieren nach',
|
||||
hot: 'Hot',
|
||||
new: 'Neu',
|
||||
|
@ -122,22 +122,22 @@ export const de = {
|
|||
no_email_setup: "Dieser Server hat E-Mails nicht korrekt eingerichtet.",
|
||||
login: 'Einloggen',
|
||||
sign_up: 'Registrieren',
|
||||
email: 'Email',
|
||||
optional: 'Optional',
|
||||
email: 'E-Mail',
|
||||
optional: 'optional',
|
||||
expires: 'Ablaufdatum',
|
||||
language: 'Sprache',
|
||||
browser_default: 'Standard-Browser',
|
||||
url: 'URL',
|
||||
body: 'Text',
|
||||
copy_suggested_title: 'Vorgeschlagenen Titel übernehmen: {{title}}',
|
||||
community: 'Community',
|
||||
expand_here: 'Expand here',
|
||||
community: 'Gemeinschaft',
|
||||
expand_here: 'hier erweitern',
|
||||
subscribe_to_communities: 'Abonniere ein paar <1>communities</1>.',
|
||||
chat: 'Chat',
|
||||
recent_comments: 'Neueste Kommentare',
|
||||
no_results: 'Keine Ergebnisse.',
|
||||
setup: 'Setup',
|
||||
lemmy_instance_setup: 'Lemmy Instanz Setup',
|
||||
setup: 'Einrichten',
|
||||
lemmy_instance_setup: 'Lemmy Instanz Einrichten',
|
||||
setup_admin: 'Seiten Administrator konfigurieren',
|
||||
your_site: 'deine Seite',
|
||||
modified: 'verändert',
|
||||
|
@ -151,7 +151,7 @@ export const de = {
|
|||
support_on_patreon: 'Auf Patreon unterstützen',
|
||||
general_sponsors:
|
||||
'Allgemeine Sponsoren sind die, die zwischen $10 und $39 zu Lemmy beitragen.',
|
||||
crypto: 'Crypto',
|
||||
crypto: 'Kryptowährung',
|
||||
bitcoin: 'Bitcoin',
|
||||
ethereum: 'Ethereum',
|
||||
monero: 'Monero',
|
||||
|
@ -159,16 +159,16 @@ export const de = {
|
|||
joined: 'beigetreten',
|
||||
by: 'von',
|
||||
to: 'bis',
|
||||
transfer_community: 'Transfer-Community',
|
||||
transfer_community: 'Gemeinschaft übertragen',
|
||||
transfer_site: 'Transferseite',
|
||||
are_you_sure: 'Bist du sicher?',
|
||||
yes: 'Ja',
|
||||
no: 'Nein',
|
||||
powered_by: 'Bereitgestellt durch',
|
||||
landing_0:
|
||||
'Lemmy ist ein <1>Link Aggregator</1> / Reddit Alternative im <2>Fediverse</2>.<3></3>Es ist selbst-hostbar, hat live-updates von Kommentar-threads und ist winzig (<4>~80kB</4>). Federation in das ActivityPub Netzwerk ist geplant. <5></5>Dies ist eine <6>sehr frühe Beta Version</6>, und viele Features funktionieren zurzeit nicht richtig oder fehlen. <7></7>Schlage neue Features vor oder melde Bugs <8>hier.</8><9></9>Gebaut mit <10>Rust</10>, <11>Actix</11>, <12>Inferno</12>, <13>Typescript</13>.',
|
||||
'Lemmy ist ein <1>Link-Aggregator</1> / Reddit Alternative im <2>Fediverse</2>.<3></3>Es ist selbst-hostbar, hat live-updates von Kommentar-threads und ist winzig (<4>~80kB</4>). Federation in das ActivityPub Netzwerk ist geplant. <5></5>Dies ist eine <6>sehr frühe Beta Version</6>, und viele Features funktionieren zurzeit nicht richtig oder fehlen. <7></7>Schlage neue Features vor oder melde Bugs <8>hier.</8><9></9>Gebaut mit <10>Rust</10>, <11>Actix</11>, <12>Inferno</12>, <13>Typescript</13>.',
|
||||
not_logged_in: 'Nicht eingeloggt.',
|
||||
community_ban: 'Du wurdest von dieser Community gebannt.',
|
||||
community_ban: 'Du wurdest von dieser Gemeinschaft gebannt.',
|
||||
site_ban: 'Du wurdest von dieser Seite gebannt',
|
||||
couldnt_create_comment: 'Konnte Kommentar nicht anlegen.',
|
||||
couldnt_like_comment: 'Konnte nicht liken.',
|
||||
|
@ -176,14 +176,14 @@ export const de = {
|
|||
couldnt_save_comment: 'Konnte Kommentar nicht speichern.',
|
||||
no_comment_edit_allowed: 'Keine Erlaubnis Kommentar zu editieren.',
|
||||
no_post_edit_allowed: 'Keine Erlaubnis Beitrag zu editieren.',
|
||||
no_community_edit_allowed: 'Keine Erlaubnis Community zu editieren.',
|
||||
couldnt_find_community: 'Konnte Community nicht finden.',
|
||||
couldnt_update_community: 'Konnte Community nicht aktualisieren.',
|
||||
community_already_exists: 'Community existiert bereits.',
|
||||
no_community_edit_allowed: 'Keine Erlaubnis Gemeinschaft zu editieren.',
|
||||
couldnt_find_community: 'Konnte Gemeinschaft nicht finden.',
|
||||
couldnt_update_community: 'Konnte Gemeinschaft nicht aktualisieren.',
|
||||
community_already_exists: 'Gemeinschaft existiert bereits.',
|
||||
community_moderator_already_exists:
|
||||
'Community Moderator existiert bereits.',
|
||||
community_follower_already_exists: 'Community Follower existiert bereits.',
|
||||
community_user_already_banned: 'Community Nutzer schon gebannt.',
|
||||
'Gemeinschaft Moderator existiert bereits.',
|
||||
community_follower_already_exists: 'Gemeinschaft Follower existiert bereits.',
|
||||
community_user_already_banned: 'Gemeinschaft Nutzer schon gebannt.',
|
||||
couldnt_create_post: 'Konnte Beitrag nicht anlegen.',
|
||||
couldnt_like_post: 'Konnte Beitrag nicht liken.',
|
||||
couldnt_find_post: 'Konnte Beitrag nicht finden.',
|
||||
|
|
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',
|
||||
hot: 'Hot',
|
||||
new: 'New',
|
||||
old: 'Old',
|
||||
top_day: 'Top day',
|
||||
week: 'Week',
|
||||
month: 'Month',
|
||||
|
|
169
ui/src/translations/fa.ts
vendored
Normal file
169
ui/src/translations/fa.ts
vendored
Normal file
|
@ -0,0 +1,169 @@
|
|||
export const fa = {
|
||||
translation: {
|
||||
post: 'مطلب',
|
||||
remove_post: 'حذف مطلب',
|
||||
no_posts: 'بدون مطلب.',
|
||||
create_a_post: 'ایجاد یک مطلب',
|
||||
create_post: 'ایجاد مطلب',
|
||||
number_of_posts: '{{count}} مطلب',
|
||||
posts: 'مطالب',
|
||||
related_posts: 'این مطالب ممکن است مرتبط باشند',
|
||||
cross_posts: 'این پیوند در اینجا هم منتشر شده:',
|
||||
comments: 'نظرات',
|
||||
number_of_comments: '{{count}} نظر',
|
||||
remove_comment: 'حذف نظر',
|
||||
communities: 'جوامع',
|
||||
users: 'کاربران',
|
||||
create_a_community: 'ایجاد یک جامعه جدید',
|
||||
create_community: 'ایجاد جامعه',
|
||||
remove_community: 'حذف جامعه',
|
||||
list_of_communities: 'فهرست جوامع',
|
||||
number_of_communities: '{{count}} جامعه',
|
||||
community_reqs: 'حروف کوچک, زیرخط, و بدون فاصله.',
|
||||
edit: 'ویرایش',
|
||||
reply: 'پاسخ',
|
||||
cancel: 'لغو',
|
||||
preview: 'پیشنمایش',
|
||||
upload_image: 'بارگذاری تصویر',
|
||||
avatar: 'آواتار',
|
||||
upload_avatar: 'بارگذاری آواتار',
|
||||
show_avatars: 'نمایش آواتارها',
|
||||
formatting_help: 'راهنمای قالببندی',
|
||||
view_source: 'نمایش منبع',
|
||||
unlock: 'بازکردن قفل',
|
||||
lock: 'قفل کردن',
|
||||
sticky: 'چسبان',
|
||||
unsticky: 'غیرچسبان',
|
||||
link: 'پیوند',
|
||||
archive_link: 'بایگاهی پیوند',
|
||||
settings: 'تنظیمات',
|
||||
admin: 'مدیر',
|
||||
admins: 'مدیران',
|
||||
remove_as_admin: 'حذف به عنوان مدیر',
|
||||
appoint_as_admin: 'انتصاب به عنوان مدیر',
|
||||
remove: 'حذف',
|
||||
removed: 'حذف شد',
|
||||
locked: 'قفل شد',
|
||||
reason: 'دلیل',
|
||||
mark_as_read: 'علامتگذاری به عنوان خوانده شده',
|
||||
mark_as_unread: 'علامتگذاری به عنوان خوانده نشده',
|
||||
delete: 'پاک کردن',
|
||||
deleted: 'پاک شد',
|
||||
delete_account: 'پاک کردن حساب',
|
||||
delete_account_confirm:
|
||||
'هشدار: این کنش، تمام اطلاعات شما را برای همیشه پاک میکند. برای تایید، گذرواژه خود را وارد کنید.',
|
||||
restore: 'بازگردانی',
|
||||
save: 'ذخیره',
|
||||
unsave: 'عدم ذخیره',
|
||||
create: 'ایجاد',
|
||||
creator: 'سازنده',
|
||||
username: 'نامکاربری',
|
||||
email_or_username: 'رایانامه یا نامکاربری',
|
||||
number_of_users: '{{count}} کاربر',
|
||||
number_of_points: '{{count}} امتیاز',
|
||||
number_online: '{{count}} کاربر برخط',
|
||||
name: 'نام',
|
||||
title: 'عنوان',
|
||||
category: 'دستهبندی',
|
||||
prev: 'پیش',
|
||||
next: 'بعد',
|
||||
sidebar: 'نوار کناری',
|
||||
sort_type: 'نوع ترتیب',
|
||||
hot: 'داغ',
|
||||
new: 'تازه',
|
||||
top_day: 'بهترینهای روز',
|
||||
week: 'هفته',
|
||||
month: 'ماه',
|
||||
year: 'سال',
|
||||
all: 'همه',
|
||||
top: 'بالاترین',
|
||||
mark_all_as_read: 'علامت زدن همه به عنوان خوانده شده',
|
||||
type: 'نوع',
|
||||
unread: 'خواندهنشده',
|
||||
replies: 'پاسخها',
|
||||
mentions: 'اشارهها',
|
||||
reply_sent: 'پاسخ فرستاده شد',
|
||||
search: 'جستجو',
|
||||
overview: 'دید کلی',
|
||||
view: 'نما',
|
||||
logout: 'خروج',
|
||||
login_sign_up: 'ورود / نامنویسی',
|
||||
login: 'ورود',
|
||||
sign_up: 'نامنویسی',
|
||||
unread_messages: 'پیامهای خوانده نشده',
|
||||
password: 'گذرواژه',
|
||||
verify_password: 'تایید گذرواژه',
|
||||
old_password: 'پسورد پیشین',
|
||||
forgot_password: 'گذرواژه را فراموش کردهام',
|
||||
reset_password_mail_sent: 'رایانامهای برای بازنشانی گذرواژه فرستاده شد.',
|
||||
password_change: 'تغییر گذرواژه',
|
||||
new_password: 'گذرواژه جدید',
|
||||
email: 'رایانامه',
|
||||
send_notifications_to_email: 'فرستادن اعلانات به رایانامه',
|
||||
optional: 'انتخابی',
|
||||
expires: 'منقضی شود',
|
||||
language: 'زبان',
|
||||
browser_default: 'پیشفرض مرورگر',
|
||||
downvotes_disabled: 'رای پایین غیرفعال است',
|
||||
enable_downvotes: 'فعالسازی رای پایین',
|
||||
open_registration: 'باز کردن نامنویسی',
|
||||
registration_closed: 'نامنویسی بسته است',
|
||||
enable_nsfw: 'فعالسازی NSFW',
|
||||
chat: 'گپ',
|
||||
recent_comments: 'نظرات اخیر',
|
||||
no_results: 'بدون نتیجه.',
|
||||
setup: 'نصب',
|
||||
lemmy_instance_setup: 'نصب نمونهٔ لمی',
|
||||
setup_admin: 'نصب مدیریت پایگاه',
|
||||
your_site: 'پایگاه شما',
|
||||
modified: 'تغییر یافت',
|
||||
nsfw: 'NSFW',
|
||||
show_nsfw: 'نمایش محتوای NSFW',
|
||||
sponsors: 'حامیان',
|
||||
sponsors_of_lemmy: 'حامیان لمی',
|
||||
support_on_patreon: 'حمایت روی Patreon',
|
||||
donate_to_lemmy: 'اعطای اعانه به لمی',
|
||||
donate: 'اعانه',
|
||||
crypto: 'رمزارز',
|
||||
bitcoin: 'بیتکوین',
|
||||
ethereum: 'اتریوم',
|
||||
monero: 'مونرو',
|
||||
code: 'کد',
|
||||
transfer_community: 'انتقال جامعه',
|
||||
transfer_site: 'انتقال پایگاه',
|
||||
are_you_sure: 'مطمئنید؟',
|
||||
yes: 'بله',
|
||||
no: 'خیر',
|
||||
powered_by: 'نیرو گرفته از',
|
||||
not_logged_in: 'وارد نشدهاید.',
|
||||
community_ban: 'فعالیت شما در این جامعه ممنوع شده است.',
|
||||
site_ban: 'فعالیت شما در این پایگاه ممنوع شده است',
|
||||
couldnt_create_comment: 'ناتوانی در ایجاد نظر.',
|
||||
couldnt_like_comment: 'ناتوانی در پسنیدن نظر.',
|
||||
couldnt_update_comment: 'ناتوانی در بهروزرسانی نظر.',
|
||||
couldnt_save_comment: 'ناتوانی در ذخیره نظر.',
|
||||
no_comment_edit_allowed: 'مجاز به ویرایش نظر نیستید.',
|
||||
no_post_edit_allowed: 'مجاز به ویرایش مطلب نیستید.',
|
||||
no_community_edit_allowed: 'مجاز به ویرایش جامعه نیستید.',
|
||||
couldnt_find_community: 'ناتوانی در یافتن جامعه.',
|
||||
couldnt_update_community: 'ناتوانی در بهروزرسانی جامعه.',
|
||||
community_already_exists: 'این جامعه از قبل وجود داشته است.',
|
||||
couldnt_create_post: 'ناتوانی در ایجاد مطلب.',
|
||||
couldnt_like_post: 'ناتوانی در پسندیدن مطلب.',
|
||||
couldnt_find_post: 'ناتوانی در یافتن مطلب.',
|
||||
couldnt_get_posts: 'ناتوانی در دریافت مطالب',
|
||||
couldnt_update_post: 'ناتوای در بهروزرسانی مطلب',
|
||||
couldnt_save_post: 'ناتوانی در ذخیره مطلب.',
|
||||
not_an_admin: 'مدیر نیستید.',
|
||||
site_already_exists: 'این پایگاه از قبل وجود داشته است.',
|
||||
couldnt_update_site: 'ناتوانی در بهروزرسانی پایگاه.',
|
||||
couldnt_find_that_username_or_email:
|
||||
'ناتوانی در یافتن این نام کاربری یا رایانامه.',
|
||||
password_incorrect: 'گذرواژه نادرست.',
|
||||
passwords_dont_match: 'گذرواژهها با هم منطبق نیستند.',
|
||||
user_already_exists: 'این کاربر از قبل وجود دارد.',
|
||||
email_already_exists: 'این رایانامه از قبل وجود دارد.',
|
||||
couldnt_update_user: 'ناتوانی در بهروزرسانی کاربر.',
|
||||
system_err_login: 'خطای سامانه. سعی کنید خارج شده و دوباره وارد شوید.',
|
||||
},
|
||||
};
|
30
ui/src/translations/zh.ts
vendored
30
ui/src/translations/zh.ts
vendored
|
@ -25,14 +25,14 @@ export const zh = {
|
|||
unlock: '解锁',
|
||||
lock: '加锁',
|
||||
link: '链接',
|
||||
mod: 'mod',
|
||||
mods: 'mods',
|
||||
moderates: 'Moderates',
|
||||
remove_as_mod: 'remove as mod',
|
||||
appoint_as_mod: 'appoint as mod',
|
||||
modlog: 'Modlog',
|
||||
admin: 'admin',
|
||||
admins: 'admins',
|
||||
mod: '监管人',
|
||||
mods: '监管人',
|
||||
moderates: '监管',
|
||||
remove_as_mod: '添加监管人',
|
||||
appoint_as_mod: '移除监管人',
|
||||
modlog: '监管记录',
|
||||
admin: '管理权限',
|
||||
admins: '管理权限',
|
||||
remove_as_admin: '移除管理权限',
|
||||
appoint_as_admin: '添加管理权限',
|
||||
remove: '移除',
|
||||
|
@ -77,7 +77,7 @@ export const zh = {
|
|||
year: '年',
|
||||
all: '所有',
|
||||
top: '最热',
|
||||
api: 'API',
|
||||
api: '应用程式介面',
|
||||
inbox: '收件箱',
|
||||
inbox_for: '<1>{{user}}</1> 收件箱',
|
||||
mark_all_as_read: '标记所有已读',
|
||||
|
@ -98,7 +98,7 @@ export const zh = {
|
|||
email: '邮箱',
|
||||
optional: '选项',
|
||||
expires: '过期',
|
||||
url: 'URL',
|
||||
url: '网址',
|
||||
body: '内容',
|
||||
copy_suggested_title: '复制建议的标题: {{title}}',
|
||||
community: '节点',
|
||||
|
@ -111,11 +111,11 @@ export const zh = {
|
|||
setup_admin: '设置管理员',
|
||||
your_site: '你的站点',
|
||||
modified: '修改',
|
||||
sponsors: 'Sponsors',
|
||||
sponsors_of_lemmy: 'Sponsors of Lemmy',
|
||||
sponsors: '发起人',
|
||||
sponsors_of_lemmy: 'Lemmy 的发起人',
|
||||
sponsor_message:
|
||||
'Lemmy is free, <1>open-source</1> software, meaning no advertising, monetizing, or venture capital, ever. Your donations directly support full-time development of the project. Thank you to the following people:',
|
||||
support_on_patreon: 'Support on Patreon',
|
||||
support_on_patreon: '在 Patreon 赞助',
|
||||
general_sponsors:
|
||||
'General Sponsors are those that pledged $10 to $39 to Lemmy.',
|
||||
crypto: '加密',
|
||||
|
@ -139,8 +139,8 @@ export const zh = {
|
|||
couldnt_find_community: '不能找到节点.',
|
||||
couldnt_update_community: '不能更新节点.',
|
||||
community_already_exists: '节点已存在.',
|
||||
community_moderator_already_exists: '节点 moderator 已存在.',
|
||||
community_follower_already_exists: '节点 follower 已存在.',
|
||||
community_moderator_already_exists: '节点监管人已存在.',
|
||||
community_follower_already_exists: '节点追随者已存在.',
|
||||
community_user_already_banned: '节点用户已禁止.',
|
||||
couldnt_create_post: '不能创建帖子.',
|
||||
couldnt_like_post: '不能收藏帖子.',
|
||||
|
|
4
ui/src/utils.ts
vendored
4
ui/src/utils.ts
vendored
|
@ -9,6 +9,7 @@ import 'moment/locale/nl';
|
|||
import 'moment/locale/it';
|
||||
import 'moment/locale/fi';
|
||||
import 'moment/locale/ca';
|
||||
import 'moment/locale/fa';
|
||||
|
||||
import {
|
||||
UserOperation,
|
||||
|
@ -258,6 +259,7 @@ export const languages = [
|
|||
{ code: 'eo', name: 'Esperanto' },
|
||||
{ code: 'es', name: 'Español' },
|
||||
{ code: 'de', name: 'Deutsch' },
|
||||
{ code: 'fa', name: 'فارسی' },
|
||||
{ code: 'zh', name: '中文' },
|
||||
{ code: 'fi', name: 'Suomi' },
|
||||
{ code: 'fr', name: 'Français' },
|
||||
|
@ -306,6 +308,8 @@ export function getMomentLanguage(): string {
|
|||
lang = 'fi';
|
||||
} else if (lang.startsWith('ca')) {
|
||||
lang = 'ca';
|
||||
} else if (lang.startsWith('fa')) {
|
||||
lang = 'fa';
|
||||
} else {
|
||||
lang = 'en';
|
||||
}
|
||||
|
|
2
ui/src/version.ts
vendored
2
ui/src/version.ts
vendored
|
@ -1 +1 @@
|
|||
export const version: string = 'v0.6.5';
|
||||
export const version: string = 'v0.6.7';
|
||||
|
|
2
ui/translation_report.ts
vendored
2
ui/translation_report.ts
vendored
|
@ -2,6 +2,7 @@ import { en } from './src/translations/en';
|
|||
import { eo } from './src/translations/eo';
|
||||
import { es } from './src/translations/es';
|
||||
import { de } from './src/translations/de';
|
||||
import { fa } from './src/translations/fa';
|
||||
import { zh } from './src/translations/zh';
|
||||
import { fr } from './src/translations/fr';
|
||||
import { sv } from './src/translations/sv';
|
||||
|
@ -15,6 +16,7 @@ import fs from 'fs';
|
|||
const files = [
|
||||
{ t: ca, n: 'ca' },
|
||||
{ t: de, n: 'de' },
|
||||
{ t: fa, n: 'fa' },
|
||||
{ t: eo, n: 'eo' },
|
||||
{ t: es, n: 'es' },
|
||||
{ t: fi, n: 'fi' },
|
||||
|
|
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"
|
||||
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:
|
||||
version "1.0.10"
|
||||
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"
|
||||
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:
|
||||
version "1.5.0"
|
||||
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:
|
||||
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:
|
||||
version "0.2.2"
|
||||
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"
|
||||
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"
|
||||
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.16.tgz#0ae069e7fe3ba7538c64c98515e35339eac5a042"
|
||||
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"
|
||||
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:
|
||||
version "0.0.2"
|
||||
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==
|
||||
dependencies:
|
||||
"@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