From 536c3f491546b4546f43a46e7a1a699ca9ac2934 Mon Sep 17 00:00:00 2001 From: Dessalines Date: Fri, 9 Aug 2019 17:14:43 -0700 Subject: [PATCH] Adding support for internationalization / i18n (#189) * Still not working * Starting to work on internationalization * Main done. * i18n translations first pass. * Localization testing mostly done. * Second front end pass. * Added a few more translations. * Adding back end translations. --- server/src/api/comment.rs | 34 +++--- server/src/api/community.rs | 48 ++++---- server/src/api/post.rs | 46 +++---- server/src/api/site.rs | 16 +-- server/src/api/user.rs | 34 +++--- ui/package.json | 3 + ui/src/components/comment-form.tsx | 10 +- ui/src/components/comment-node.tsx | 51 ++++---- ui/src/components/comment-nodes.tsx | 2 +- ui/src/components/communities.tsx | 36 +++--- ui/src/components/community-form.tsx | 23 ++-- ui/src/components/community.tsx | 25 ++-- ui/src/components/create-community.tsx | 6 +- ui/src/components/create-post.tsx | 6 +- ui/src/components/footer.tsx | 9 +- ui/src/components/home.tsx | 0 ui/src/components/inbox.tsx | 36 +++--- ui/src/components/login.tsx | 27 +++-- ui/src/components/main.tsx | 122 ++++++++++++------- ui/src/components/modlog.tsx | 2 +- ui/src/components/moment-time.tsx | 6 +- ui/src/components/navbar.tsx | 21 ++-- ui/src/components/post-form.tsx | 22 ++-- ui/src/components/post-listing.tsx | 36 +++--- ui/src/components/post-listings.tsx | 7 +- ui/src/components/post.tsx | 12 +- ui/src/components/search.tsx | 42 +++---- ui/src/components/setup.tsx | 22 ++-- ui/src/components/sidebar.tsx | 38 +++--- ui/src/components/site-form.tsx | 13 +- ui/src/components/sponsors.tsx | 20 ++-- ui/src/components/user.tsx | 48 ++++---- ui/src/i18next.ts | 33 +++++ ui/src/index.tsx | 68 ++++++----- ui/src/services/WebSocketService.ts | 3 +- ui/src/translations/de.ts | 124 +++++++++++++++++++ ui/src/translations/en.ts | 160 +++++++++++++++++++++++++ ui/src/utils.ts | 4 + ui/yarn.lock | 57 ++++++++- 39 files changed, 862 insertions(+), 410 deletions(-) delete mode 100644 ui/src/components/home.tsx create mode 100644 ui/src/i18next.ts create mode 100644 ui/src/translations/de.ts create mode 100644 ui/src/translations/en.ts diff --git a/server/src/api/comment.rs b/server/src/api/comment.rs index ffd7da2ea..19752d833 100644 --- a/server/src/api/comment.rs +++ b/server/src/api/comment.rs @@ -53,7 +53,7 @@ impl Perform for Oper { let claims = match Claims::decode(&data.auth) { Ok(claims) => claims.claims, Err(_e) => { - return Err(APIError::err(&self.op, "Not logged in."))? + return Err(APIError::err(&self.op, "not_logged_in"))? } }; @@ -62,12 +62,12 @@ impl Perform for Oper { // Check for a community ban let post = Post::read(&conn, data.post_id)?; if CommunityUserBanView::get(&conn, user_id, post.community_id).is_ok() { - return Err(APIError::err(&self.op, "You have been banned from this community"))? + return Err(APIError::err(&self.op, "community_ban"))? } // Check for a site ban if UserView::read(&conn, user_id)?.banned { - return Err(APIError::err(&self.op, "You have been banned from the site"))? + return Err(APIError::err(&self.op, "site_ban"))? } let content_slurs_removed = remove_slurs(&data.content.to_owned()); @@ -86,7 +86,7 @@ impl Perform for Oper { let inserted_comment = match Comment::create(&conn, &comment_form) { Ok(comment) => comment, Err(_e) => { - return Err(APIError::err(&self.op, "Couldn't create Comment"))? + return Err(APIError::err(&self.op, "couldnt_create_comment"))? } }; @@ -101,7 +101,7 @@ impl Perform for Oper { let _inserted_like = match CommentLike::like(&conn, &like_form) { Ok(like) => like, Err(_e) => { - return Err(APIError::err(&self.op, "Couldn't like comment."))? + return Err(APIError::err(&self.op, ""))? } }; @@ -124,7 +124,7 @@ impl Perform for Oper { let claims = match Claims::decode(&data.auth) { Ok(claims) => claims.claims, Err(_e) => { - return Err(APIError::err(&self.op, "Not logged in."))? + return Err(APIError::err(&self.op, "not_logged_in"))? } }; @@ -153,17 +153,17 @@ impl Perform for Oper { ); if !editors.contains(&user_id) { - return Err(APIError::err(&self.op, "Not allowed to edit comment."))? + return Err(APIError::err(&self.op, "no_comment_edit_allowed"))? } // Check for a community ban if CommunityUserBanView::get(&conn, user_id, orig_comment.community_id).is_ok() { - return Err(APIError::err(&self.op, "You have been banned from this community"))? + return Err(APIError::err(&self.op, "community_ban"))? } // Check for a site ban if UserView::read(&conn, user_id)?.banned { - return Err(APIError::err(&self.op, "You have been banned from the site"))? + return Err(APIError::err(&self.op, "site_ban"))? } } @@ -184,7 +184,7 @@ impl Perform for Oper { let _updated_comment = match Comment::update(&conn, data.edit_id, &comment_form) { Ok(comment) => comment, Err(_e) => { - return Err(APIError::err(&self.op, "Couldn't update Comment"))? + return Err(APIError::err(&self.op, "couldnt_update_comment"))? } }; @@ -220,7 +220,7 @@ impl Perform for Oper { let claims = match Claims::decode(&data.auth) { Ok(claims) => claims.claims, Err(_e) => { - return Err(APIError::err(&self.op, "Not logged in."))? + return Err(APIError::err(&self.op, "not_logged_in"))? } }; @@ -235,14 +235,14 @@ impl Perform for Oper { match CommentSaved::save(&conn, &comment_saved_form) { Ok(comment) => comment, Err(_e) => { - return Err(APIError::err(&self.op, "Couldnt do comment save"))? + return Err(APIError::err(&self.op, "couldnt_save_comment"))? } }; } else { match CommentSaved::unsave(&conn, &comment_saved_form) { Ok(comment) => comment, Err(_e) => { - return Err(APIError::err(&self.op, "Couldnt do comment save"))? + return Err(APIError::err(&self.op, "couldnt_save_comment"))? } }; } @@ -266,7 +266,7 @@ impl Perform for Oper { let claims = match Claims::decode(&data.auth) { Ok(claims) => claims.claims, Err(_e) => { - return Err(APIError::err(&self.op, "Not logged in."))? + return Err(APIError::err(&self.op, "not_logged_in"))? } }; @@ -275,12 +275,12 @@ impl Perform for Oper { // Check for a community ban let post = Post::read(&conn, data.post_id)?; if CommunityUserBanView::get(&conn, user_id, post.community_id).is_ok() { - return Err(APIError::err(&self.op, "You have been banned from this community"))? + return Err(APIError::err(&self.op, "community_ban"))? } // Check for a site ban if UserView::read(&conn, user_id)?.banned { - return Err(APIError::err(&self.op, "You have been banned from the site"))? + return Err(APIError::err(&self.op, "site_ban"))? } let like_form = CommentLikeForm { @@ -299,7 +299,7 @@ impl Perform for Oper { let _inserted_like = match CommentLike::like(&conn, &like_form) { Ok(like) => like, Err(_e) => { - return Err(APIError::err(&self.op, "Couldn't like comment."))? + return Err(APIError::err(&self.op, "couldnt_like_comment"))? } }; } diff --git a/server/src/api/community.rs b/server/src/api/community.rs index be4bb41aa..fe2257942 100644 --- a/server/src/api/community.rs +++ b/server/src/api/community.rs @@ -135,14 +135,14 @@ impl Perform for Oper { let community_view = match CommunityView::read(&conn, community_id, user_id) { Ok(community) => community, Err(_e) => { - return Err(APIError::err(&self.op, "Couldn't find Community"))? + return Err(APIError::err(&self.op, "couldnt_find_community"))? } }; let moderators = match CommunityModeratorView::for_community(&conn, community_id) { Ok(moderators) => moderators, Err(_e) => { - return Err(APIError::err(&self.op, "Couldn't find Community"))? + return Err(APIError::err(&self.op, "couldnt_find_community"))? } }; @@ -168,21 +168,21 @@ impl Perform for Oper { let claims = match Claims::decode(&data.auth) { Ok(claims) => claims.claims, Err(_e) => { - return Err(APIError::err(&self.op, "Not logged in."))? + return Err(APIError::err(&self.op, "not_logged_in"))? } }; if has_slurs(&data.name) || has_slurs(&data.title) || (data.description.is_some() && has_slurs(&data.description.to_owned().unwrap())) { - return Err(APIError::err(&self.op, "No slurs"))? + return Err(APIError::err(&self.op, "no_slurs"))? } let user_id = claims.id; // Check for a site ban if UserView::read(&conn, user_id)?.banned { - return Err(APIError::err(&self.op, "You have been banned from the site"))? + return Err(APIError::err(&self.op, "site_ban"))? } // When you create a community, make sure the user becomes a moderator and a follower @@ -200,7 +200,7 @@ impl Perform for Oper { let inserted_community = match Community::create(&conn, &community_form) { Ok(community) => community, Err(_e) => { - return Err(APIError::err(&self.op, "Community already exists."))? + return Err(APIError::err(&self.op, "community_already_exists"))? } }; @@ -212,7 +212,7 @@ impl Perform for Oper { let _inserted_community_moderator = match CommunityModerator::join(&conn, &community_moderator_form) { Ok(user) => user, Err(_e) => { - return Err(APIError::err(&self.op, "Community moderator already exists."))? + return Err(APIError::err(&self.op, "community_moderator_already_exists"))? } }; @@ -224,7 +224,7 @@ impl Perform for Oper { let _inserted_community_follower = match CommunityFollower::follow(&conn, &community_follower_form) { Ok(user) => user, Err(_e) => { - return Err(APIError::err(&self.op, "Community follower already exists."))? + return Err(APIError::err(&self.op, "community_follower_already_exists"))? } }; @@ -244,7 +244,7 @@ impl Perform for Oper { let data: &EditCommunity = &self.data; if has_slurs(&data.name) || has_slurs(&data.title) { - return Err(APIError::err(&self.op, "No slurs"))? + return Err(APIError::err(&self.op, "no_slurs"))? } let conn = establish_connection(); @@ -252,7 +252,7 @@ impl Perform for Oper { let claims = match Claims::decode(&data.auth) { Ok(claims) => claims.claims, Err(_e) => { - return Err(APIError::err(&self.op, "Not logged in."))? + return Err(APIError::err(&self.op, "not_logged_in"))? } }; @@ -260,7 +260,7 @@ impl Perform for Oper { // Check for a site ban if UserView::read(&conn, user_id)?.banned { - return Err(APIError::err(&self.op, "You have been banned from the site"))? + return Err(APIError::err(&self.op, "site_ban"))? } // Verify its a mod @@ -280,7 +280,7 @@ impl Perform for Oper { .collect() ); if !editors.contains(&user_id) { - return Err(APIError::err(&self.op, "Not allowed to edit community"))? + return Err(APIError::err(&self.op, "no_community_edit_allowed"))? } let community_form = CommunityForm { @@ -297,7 +297,7 @@ impl Perform for Oper { let _updated_community = match Community::update(&conn, data.edit_id, &community_form) { Ok(community) => community, Err(_e) => { - return Err(APIError::err(&self.op, "Couldn't update Community"))? + return Err(APIError::err(&self.op, "couldnt_update_community"))? } }; @@ -369,7 +369,7 @@ impl Perform for Oper { let claims = match Claims::decode(&data.auth) { Ok(claims) => claims.claims, Err(_e) => { - return Err(APIError::err(&self.op, "Not logged in."))? + return Err(APIError::err(&self.op, "not_logged_in"))? } }; @@ -384,14 +384,14 @@ impl Perform for Oper { match CommunityFollower::follow(&conn, &community_follower_form) { Ok(user) => user, Err(_e) => { - return Err(APIError::err(&self.op, "Community follower already exists."))? + return Err(APIError::err(&self.op, "community_follower_already_exists"))? } }; } else { match CommunityFollower::ignore(&conn, &community_follower_form) { Ok(user) => user, Err(_e) => { - return Err(APIError::err(&self.op, "Community follower already exists."))? + return Err(APIError::err(&self.op, "community_follower_already_exists"))? } }; } @@ -416,7 +416,7 @@ impl Perform for Oper { let claims = match Claims::decode(&data.auth) { Ok(claims) => claims.claims, Err(_e) => { - return Err(APIError::err(&self.op, "Not logged in."))? + return Err(APIError::err(&self.op, "not_logged_in"))? } }; @@ -425,7 +425,7 @@ impl Perform for Oper { let communities: Vec = match CommunityFollowerView::for_user(&conn, user_id) { Ok(communities) => communities, Err(_e) => { - return Err(APIError::err(&self.op, "System error, try logging out and back in."))? + return Err(APIError::err(&self.op, "system_err_login"))? } }; @@ -448,7 +448,7 @@ impl Perform for Oper { let claims = match Claims::decode(&data.auth) { Ok(claims) => claims.claims, Err(_e) => { - return Err(APIError::err(&self.op, "Not logged in."))? + return Err(APIError::err(&self.op, "not_logged_in"))? } }; @@ -463,14 +463,14 @@ impl Perform for Oper { match CommunityUserBan::ban(&conn, &community_user_ban_form) { Ok(user) => user, Err(_e) => { - return Err(APIError::err(&self.op, "Community user ban already exists"))? + return Err(APIError::err(&self.op, "community_user_already_banned"))? } }; } else { match CommunityUserBan::unban(&conn, &community_user_ban_form) { Ok(user) => user, Err(_e) => { - return Err(APIError::err(&self.op, "Community user ban already exists"))? + return Err(APIError::err(&self.op, "community_user_already_banned"))? } }; } @@ -511,7 +511,7 @@ impl Perform for Oper { let claims = match Claims::decode(&data.auth) { Ok(claims) => claims.claims, Err(_e) => { - return Err(APIError::err(&self.op, "Not logged in."))? + return Err(APIError::err(&self.op, "not_logged_in"))? } }; @@ -526,14 +526,14 @@ impl Perform for Oper { match CommunityModerator::join(&conn, &community_moderator_form) { Ok(user) => user, Err(_e) => { - return Err(APIError::err(&self.op, "Community moderator already exists."))? + return Err(APIError::err(&self.op, "community_moderator_already_exists"))? } }; } else { match CommunityModerator::leave(&conn, &community_moderator_form) { Ok(user) => user, Err(_e) => { - return Err(APIError::err(&self.op, "Community moderator already exists."))? + return Err(APIError::err(&self.op, "community_moderator_already_exists"))? } }; } diff --git a/server/src/api/post.rs b/server/src/api/post.rs index a60107812..df6ea852f 100644 --- a/server/src/api/post.rs +++ b/server/src/api/post.rs @@ -94,25 +94,25 @@ impl Perform for Oper { let claims = match Claims::decode(&data.auth) { Ok(claims) => claims.claims, Err(_e) => { - return Err(APIError::err(&self.op, "Not logged in."))? + return Err(APIError::err(&self.op, "not_logged_in"))? } }; if has_slurs(&data.name) || (data.body.is_some() && has_slurs(&data.body.to_owned().unwrap())) { - return Err(APIError::err(&self.op, "No slurs"))? + return Err(APIError::err(&self.op, "no_slurs"))? } let user_id = claims.id; // Check for a community ban if CommunityUserBanView::get(&conn, user_id, data.community_id).is_ok() { - return Err(APIError::err(&self.op, "You have been banned from this community"))? + return Err(APIError::err(&self.op, "community_ban"))? } // Check for a site ban if UserView::read(&conn, user_id)?.banned { - return Err(APIError::err(&self.op, "You have been banned from the site"))? + return Err(APIError::err(&self.op, "site_ban"))? } let post_form = PostForm { @@ -130,7 +130,7 @@ impl Perform for Oper { let inserted_post = match Post::create(&conn, &post_form) { Ok(post) => post, Err(_e) => { - return Err(APIError::err(&self.op, "Couldn't create Post"))? + return Err(APIError::err(&self.op, "couldnt_create_post"))? } }; @@ -145,7 +145,7 @@ impl Perform for Oper { let _inserted_like = match PostLike::like(&conn, &like_form) { Ok(like) => like, Err(_e) => { - return Err(APIError::err(&self.op, "Couldn't like post."))? + return Err(APIError::err(&self.op, "couldnt_like_post"))? } }; @@ -153,7 +153,7 @@ impl Perform for Oper { let post_view = match PostView::read(&conn, inserted_post.id, Some(user_id)) { Ok(post) => post, Err(_e) => { - return Err(APIError::err(&self.op, "Couldn't find Post"))? + return Err(APIError::err(&self.op, "couldnt_find_post"))? } }; @@ -187,7 +187,7 @@ impl Perform for Oper { let post_view = match PostView::read(&conn, data.id, user_id) { Ok(post) => post, Err(_e) => { - return Err(APIError::err(&self.op, "Couldn't find Post"))? + return Err(APIError::err(&self.op, "couldnt_find_post"))? } }; @@ -248,7 +248,7 @@ impl Perform for Oper { data.limit) { Ok(posts) => posts, Err(_e) => { - return Err(APIError::err(&self.op, "Couldn't get posts"))? + return Err(APIError::err(&self.op, "couldnt_get_posts"))? } }; @@ -270,7 +270,7 @@ impl Perform for Oper { let claims = match Claims::decode(&data.auth) { Ok(claims) => claims.claims, Err(_e) => { - return Err(APIError::err(&self.op, "Not logged in."))? + return Err(APIError::err(&self.op, "not_logged_in"))? } }; @@ -279,12 +279,12 @@ impl Perform for Oper { // Check for a community ban let post = Post::read(&conn, data.post_id)?; if CommunityUserBanView::get(&conn, user_id, post.community_id).is_ok() { - return Err(APIError::err(&self.op, "You have been banned from this community"))? + return Err(APIError::err(&self.op, "community_ban"))? } // Check for a site ban if UserView::read(&conn, user_id)?.banned { - return Err(APIError::err(&self.op, "You have been banned from the site"))? + return Err(APIError::err(&self.op, "site_ban"))? } let like_form = PostLikeForm { @@ -302,7 +302,7 @@ impl Perform for Oper { let _inserted_like = match PostLike::like(&conn, &like_form) { Ok(like) => like, Err(_e) => { - return Err(APIError::err(&self.op, "Couldn't like post."))? + return Err(APIError::err(&self.op, "couldnt_like_post"))? } }; } @@ -310,7 +310,7 @@ impl Perform for Oper { let post_view = match PostView::read(&conn, data.post_id, Some(user_id)) { Ok(post) => post, Err(_e) => { - return Err(APIError::err(&self.op, "Couldn't find Post"))? + return Err(APIError::err(&self.op, "couldnt_find_post"))? } }; @@ -329,7 +329,7 @@ impl Perform for Oper { let data: &EditPost = &self.data; if has_slurs(&data.name) || (data.body.is_some() && has_slurs(&data.body.to_owned().unwrap())) { - return Err(APIError::err(&self.op, "No slurs"))? + return Err(APIError::err(&self.op, "no_slurs"))? } let conn = establish_connection(); @@ -337,7 +337,7 @@ impl Perform for Oper { let claims = match Claims::decode(&data.auth) { Ok(claims) => claims.claims, Err(_e) => { - return Err(APIError::err(&self.op, "Not logged in."))? + return Err(APIError::err(&self.op, "not_logged_in"))? } }; @@ -360,17 +360,17 @@ impl Perform for Oper { .collect() ); if !editors.contains(&user_id) { - return Err(APIError::err(&self.op, "Not allowed to edit post."))? + return Err(APIError::err(&self.op, "no_post_edit_allowed"))? } // Check for a community ban if CommunityUserBanView::get(&conn, user_id, data.community_id).is_ok() { - return Err(APIError::err(&self.op, "You have been banned from this community"))? + return Err(APIError::err(&self.op, "community_ban"))? } // Check for a site ban if UserView::read(&conn, user_id)?.banned { - return Err(APIError::err(&self.op, "You have been banned from the site"))? + return Err(APIError::err(&self.op, "site_ban"))? } let post_form = PostForm { @@ -388,7 +388,7 @@ impl Perform for Oper { let _updated_post = match Post::update(&conn, data.edit_id, &post_form) { Ok(post) => post, Err(_e) => { - return Err(APIError::err(&self.op, "Couldn't update Post"))? + return Err(APIError::err(&self.op, "couldnt_update_post"))? } }; @@ -431,7 +431,7 @@ impl Perform for Oper { let claims = match Claims::decode(&data.auth) { Ok(claims) => claims.claims, Err(_e) => { - return Err(APIError::err(&self.op, "Not logged in."))? + return Err(APIError::err(&self.op, "not_logged_in"))? } }; @@ -446,14 +446,14 @@ impl Perform for Oper { match PostSaved::save(&conn, &post_saved_form) { Ok(post) => post, Err(_e) => { - return Err(APIError::err(&self.op, "Couldnt do post save"))? + return Err(APIError::err(&self.op, "couldnt_save_post"))? } }; } else { match PostSaved::unsave(&conn, &post_saved_form) { Ok(post) => post, Err(_e) => { - return Err(APIError::err(&self.op, "Couldnt do post save"))? + return Err(APIError::err(&self.op, "couldnt_save_post"))? } }; } diff --git a/server/src/api/site.rs b/server/src/api/site.rs index 315411689..08fefae45 100644 --- a/server/src/api/site.rs +++ b/server/src/api/site.rs @@ -144,20 +144,20 @@ impl Perform for Oper { let claims = match Claims::decode(&data.auth) { Ok(claims) => claims.claims, Err(_e) => { - return Err(APIError::err(&self.op, "Not logged in."))? + return Err(APIError::err(&self.op, "not_logged_in"))? } }; if has_slurs(&data.name) || (data.description.is_some() && has_slurs(&data.description.to_owned().unwrap())) { - return Err(APIError::err(&self.op, "No slurs"))? + return Err(APIError::err(&self.op, "no_slurs"))? } let user_id = claims.id; // Make sure user is an admin if !UserView::read(&conn, user_id)?.admin { - return Err(APIError::err(&self.op, "Not an admin."))? + return Err(APIError::err(&self.op, "not_an_admin"))? } let site_form = SiteForm { @@ -170,7 +170,7 @@ impl Perform for Oper { match Site::create(&conn, &site_form) { Ok(site) => site, Err(_e) => { - return Err(APIError::err(&self.op, "Site exists already"))? + return Err(APIError::err(&self.op, "site_already_exists"))? } }; @@ -194,20 +194,20 @@ impl Perform for Oper { let claims = match Claims::decode(&data.auth) { Ok(claims) => claims.claims, Err(_e) => { - return Err(APIError::err(&self.op, "Not logged in."))? + return Err(APIError::err(&self.op, "not_logged_in"))? } }; if has_slurs(&data.name) || (data.description.is_some() && has_slurs(&data.description.to_owned().unwrap())) { - return Err(APIError::err(&self.op, "No slurs"))? + return Err(APIError::err(&self.op, "no_slurs"))? } let user_id = claims.id; // Make sure user is an admin if UserView::read(&conn, user_id)?.admin == false { - return Err(APIError::err(&self.op, "Not an admin."))? + return Err(APIError::err(&self.op, "not_an_admin"))? } let found_site = Site::read(&conn, 1)?; @@ -222,7 +222,7 @@ impl Perform for Oper { match Site::update(&conn, 1, &site_form) { Ok(site) => site, Err(_e) => { - return Err(APIError::err(&self.op, "Couldn't update site."))? + return Err(APIError::err(&self.op, "couldnt_update_site"))? } }; diff --git a/server/src/api/user.rs b/server/src/api/user.rs index d6d5962eb..5d5f1a6be 100644 --- a/server/src/api/user.rs +++ b/server/src/api/user.rs @@ -102,13 +102,13 @@ impl Perform for Oper { // Fetch that username / email let user: User_ = match User_::find_by_email_or_username(&conn, &data.username_or_email) { Ok(user) => user, - Err(_e) => return Err(APIError::err(&self.op, "Couldn't find that username or email"))? + Err(_e) => return Err(APIError::err(&self.op, "couldnt_find_that_username_or_email"))? }; // Verify the password let valid: bool = verify(&data.password, &user.password_encrypted).unwrap_or(false); if !valid { - return Err(APIError::err(&self.op, "Password incorrect"))? + return Err(APIError::err(&self.op, "password_incorrect"))? } // Return the jwt @@ -129,16 +129,16 @@ impl Perform for Oper { // Make sure passwords match if &data.password != &data.password_verify { - return Err(APIError::err(&self.op, "Passwords do not match."))? + return Err(APIError::err(&self.op, "passwords_dont_match"))? } if has_slurs(&data.username) { - return Err(APIError::err(&self.op, "No slurs"))? + return Err(APIError::err(&self.op, "no_slurs"))? } // Make sure there are no admins if data.admin && UserView::admins(&conn)?.len() > 0 { - return Err(APIError::err(&self.op, "Sorry, there's already an admin."))? + return Err(APIError::err(&self.op, "admin_already_created"))? } // Register the new user @@ -157,7 +157,7 @@ impl Perform for Oper { let inserted_user = match User_::register(&conn, &user_form) { Ok(user) => user, Err(_e) => { - return Err(APIError::err(&self.op, "User already exists."))? + return Err(APIError::err(&self.op, "user_already_exists"))? } }; @@ -188,7 +188,7 @@ impl Perform for Oper { let _inserted_community_follower = match CommunityFollower::follow(&conn, &community_follower_form) { Ok(user) => user, Err(_e) => { - return Err(APIError::err(&self.op, "Community follower already exists."))? + return Err(APIError::err(&self.op, "community_follower_already_exists"))? } }; @@ -202,7 +202,7 @@ impl Perform for Oper { let _inserted_community_moderator = match CommunityModerator::join(&conn, &community_moderator_form) { Ok(user) => user, Err(_e) => { - return Err(APIError::err(&self.op, "Community moderator already exists."))? + return Err(APIError::err(&self.op, "community_moderator_already_exists"))? } }; @@ -321,7 +321,7 @@ impl Perform for Oper { let claims = match Claims::decode(&data.auth) { Ok(claims) => claims.claims, Err(_e) => { - return Err(APIError::err(&self.op, "Not logged in."))? + return Err(APIError::err(&self.op, "not_logged_in"))? } }; @@ -329,7 +329,7 @@ impl Perform for Oper { // Make sure user is an admin if UserView::read(&conn, user_id)?.admin == false { - return Err(APIError::err(&self.op, "Not an admin."))? + return Err(APIError::err(&self.op, "not_an_admin"))? } let read_user = User_::read(&conn, data.user_id)?; @@ -348,7 +348,7 @@ impl Perform for Oper { match User_::update(&conn, data.user_id, &user_form) { Ok(user) => user, Err(_e) => { - return Err(APIError::err(&self.op, "Couldn't update user"))? + return Err(APIError::err(&self.op, "couldnt_update_user"))? } }; @@ -380,7 +380,7 @@ impl Perform for Oper { let claims = match Claims::decode(&data.auth) { Ok(claims) => claims.claims, Err(_e) => { - return Err(APIError::err(&self.op, "Not logged in."))? + return Err(APIError::err(&self.op, "not_logged_in"))? } }; @@ -388,7 +388,7 @@ impl Perform for Oper { // Make sure user is an admin if UserView::read(&conn, user_id)?.admin == false { - return Err(APIError::err(&self.op, "Not an admin."))? + return Err(APIError::err(&self.op, "not_an_admin"))? } let read_user = User_::read(&conn, data.user_id)?; @@ -407,7 +407,7 @@ impl Perform for Oper { match User_::update(&conn, data.user_id, &user_form) { Ok(user) => user, Err(_e) => { - return Err(APIError::err(&self.op, "Couldn't update user"))? + return Err(APIError::err(&self.op, "couldnt_update_user"))? } }; @@ -448,7 +448,7 @@ impl Perform for Oper { let claims = match Claims::decode(&data.auth) { Ok(claims) => claims.claims, Err(_e) => { - return Err(APIError::err(&self.op, "Not logged in."))? + return Err(APIError::err(&self.op, "not_logged_in"))? } }; @@ -476,7 +476,7 @@ impl Perform for Oper { let claims = match Claims::decode(&data.auth) { Ok(claims) => claims.claims, Err(_e) => { - return Err(APIError::err(&self.op, "Not logged in."))? + return Err(APIError::err(&self.op, "not_logged_in"))? } }; @@ -499,7 +499,7 @@ impl Perform for Oper { let _updated_comment = match Comment::update(&conn, reply.id, &comment_form) { Ok(comment) => comment, Err(_e) => { - return Err(APIError::err(&self.op, "Couldn't update Comment"))? + return Err(APIError::err(&self.op, "couldnt_update_comment"))? } }; } diff --git a/ui/package.json b/ui/package.json index 20ecdd82a..d86725f25 100644 --- a/ui/package.json +++ b/ui/package.json @@ -23,7 +23,9 @@ "autosize": "^4.0.2", "classcat": "^1.1.3", "dotenv": "^6.1.0", + "i18next": "^17.0.9", "inferno": "^7.0.1", + "inferno-i18next": "nimbusec-oss/inferno-i18next", "inferno-router": "^7.0.1", "js-cookie": "^2.2.0", "jwt-decode": "^2.2.0", @@ -35,6 +37,7 @@ "ws": "^7.0.0" }, "devDependencies": { + "@types/i18next": "^12.1.0", "fuse-box": "^3.1.3", "ts-transform-classcat": "^0.0.2", "ts-transform-inferno": "^4.0.2", diff --git a/ui/src/components/comment-form.tsx b/ui/src/components/comment-form.tsx index 5181e45e1..ed62fcf5c 100644 --- a/ui/src/components/comment-form.tsx +++ b/ui/src/components/comment-form.tsx @@ -1,7 +1,10 @@ import { Component, linkEvent } from 'inferno'; import { CommentNode as CommentNodeI, CommentForm as CommentFormI } from '../interfaces'; +import { capitalizeFirstLetter } from '../utils'; import { WebSocketService, UserService } from '../services'; import * as autosize from 'autosize'; +import { i18n } from '../i18next'; +import { T } from 'inferno-i18next'; interface CommentFormProps { postId?: number; @@ -25,12 +28,13 @@ export class CommentForm extends Component { post_id: this.props.node ? this.props.node.comment.post_id : this.props.postId, creator_id: UserService.Instance.user ? UserService.Instance.user.id : null, }, - buttonTitle: !this.props.node ? "Post" : this.props.edit ? "Edit" : "Reply", + buttonTitle: !this.props.node ? capitalizeFirstLetter(i18n.t('post')) : this.props.edit ? capitalizeFirstLetter(i18n.t('edit')) : capitalizeFirstLetter(i18n.t('reply')), } constructor(props: any, context: any) { super(props, context); + this.state = this.emptyState; if (this.props.node) { @@ -62,7 +66,7 @@ export class CommentForm extends Component {
- {this.props.node && } + {this.props.node && }
@@ -84,7 +88,7 @@ export class CommentForm extends Component { if (i.props.node) { i.props.onReplyCancel(); } - + autosize.update(document.querySelector('textarea')); } diff --git a/ui/src/components/comment-node.tsx b/ui/src/components/comment-node.tsx index a201ddd6b..a1ac93b38 100644 --- a/ui/src/components/comment-node.tsx +++ b/ui/src/components/comment-node.tsx @@ -7,6 +7,8 @@ import * as moment from 'moment'; import { MomentTime } from './moment-time'; import { CommentForm } from './comment-form'; import { CommentNodes } from './comment-nodes'; +import { i18n } from '../i18next'; +import { T } from 'inferno-i18next'; enum BanType {Community, Site}; @@ -74,10 +76,10 @@ export class CommentNode extends Component { {node.comment.creator_name} {this.isMod && -
  • mod
  • +
  • #
  • } {this.isAdmin && -
  • admin
  • +
  • #
  • }
  • ( @@ -97,24 +99,24 @@ export class CommentNode extends Component { {this.state.showEdit && } {!this.state.showEdit && !this.state.collapsed &&
    -
    +
      {UserService.Instance.user && !this.props.viewOnly && <>
    • - reply + #
    • - {node.comment.saved ? 'unsave' : 'save'} + {node.comment.saved ? i18n.t('unsave') : i18n.t('save')}
    • {this.myComment && <>
    • - edit + #
    • - {!this.props.node.comment.deleted ? 'delete' : 'restore'} + {!this.props.node.comment.deleted ? i18n.t('delete') : i18n.t('restore')}
    • @@ -123,8 +125,8 @@ export class CommentNode extends Component { {this.canMod &&
    • {!this.props.node.comment.removed ? - remove : - restore + # : + # }
    • } @@ -134,14 +136,14 @@ export class CommentNode extends Component { {!this.isMod &&
    • {!this.props.node.comment.banned_from_community ? - ban : - unban + # : + # }
    • } {!this.props.node.comment.banned_from_community &&
    • - {`${this.isMod ? 'remove' : 'appoint'} as mod`} + {this.isMod ? i18n.t('remove_as_mod') : i18n.t('appoint_as_mod')}
    • } @@ -152,14 +154,14 @@ export class CommentNode extends Component { {!this.isAdmin &&
    • {!this.props.node.comment.banned ? - ban from site : - unban from site + # : + # }
    • } {!this.props.node.comment.banned &&
    • - {`${this.isAdmin ? 'remove' : 'appoint'} as admin`} + {this.isAdmin ? i18n.t('remove_as_admin') : i18n.t('appoint_as_admin')}
    • } @@ -167,11 +169,11 @@ export class CommentNode extends Component { }
    • - link + #
    • {this.props.markable &&
    • - {`mark as ${node.comment.read ? 'unread' : 'read'}`} + {node.comment.read ? i18n.t('mark_as_unread') : i18n.t('mark_as_read')}
    • }
    @@ -180,23 +182,23 @@ export class CommentNode extends Component {
    {this.state.showRemoveDialog &&
    - - + +
    } {this.state.showBanDialog &&
    - - + +
    {/* TODO hold off on expires until later */} {/*
    */} {/* */} - {/* */} + {/* */} {/*
    */}
    - +
    } @@ -387,9 +389,6 @@ export class CommentNode extends Component { handleModBanBothSubmit(i: CommentNode) { event.preventDefault(); - console.log(BanType[i.state.banType]); - console.log(i.props.node.comment.banned); - if (i.state.banType == BanType.Community) { let form: BanFromCommunityForm = { user_id: i.props.node.comment.creator_id, diff --git a/ui/src/components/comment-nodes.tsx b/ui/src/components/comment-nodes.tsx index da67bbc7f..fca323e39 100644 --- a/ui/src/components/comment-nodes.tsx +++ b/ui/src/components/comment-nodes.tsx @@ -32,7 +32,7 @@ export class CommentNodes extends Component + /> )}
    ) diff --git a/ui/src/components/communities.tsx b/ui/src/components/communities.tsx index c4efe1fbe..49b982dc9 100644 --- a/ui/src/components/communities.tsx +++ b/ui/src/components/communities.tsx @@ -5,6 +5,8 @@ import { retryWhen, delay, take } from 'rxjs/operators'; import { UserOperation, Community, ListCommunitiesResponse, CommunityResponse, FollowCommunityForm, ListCommunitiesForm, SortType } from '../interfaces'; import { WebSocketService } from '../services'; import { msgOp } from '../utils'; +import { i18n } from '../i18next'; +import { T } from 'inferno-i18next'; declare const Sortable: any; @@ -26,12 +28,12 @@ export class Communities extends Component { super(props, context); this.state = this.emptyState; this.subscription = WebSocketService.Instance.subject - .pipe(retryWhen(errors => errors.pipe(delay(3000), take(10)))) - .subscribe( - (msg) => this.parseMessage(msg), + .pipe(retryWhen(errors => errors.pipe(delay(3000), take(10)))) + .subscribe( + (msg) => this.parseMessage(msg), (err) => console.error(err), () => console.log('complete') - ); + ); this.refetch(); @@ -46,7 +48,7 @@ export class Communities extends Component { } componentDidMount() { - document.title = `Communities - ${WebSocketService.Instance.site.name}`; + document.title = `${i18n.t('communities')} - ${WebSocketService.Instance.site.name}`; } // Necessary for back button for some reason @@ -64,17 +66,17 @@ export class Communities extends Component { {this.state.loading ?
    :
    -
    List of communities
    +
    #
    - - - - - - + + + + + + @@ -89,8 +91,8 @@ export class Communities extends Component { @@ -109,9 +111,9 @@ export class Communities extends Component { return (
    {this.state.page > 1 && - + } - +
    ); } @@ -165,7 +167,7 @@ export class Communities extends Component { console.log(msg); let op: UserOperation = msgOp(msg); if (msg.error) { - alert(msg.error); + alert(i18n.t(msg.error)); return; } else if (op == UserOperation.ListCommunities) { let res: ListCommunitiesResponse = msg; diff --git a/ui/src/components/community-form.tsx b/ui/src/components/community-form.tsx index e295dcbed..b039fb4d9 100644 --- a/ui/src/components/community-form.tsx +++ b/ui/src/components/community-form.tsx @@ -3,8 +3,10 @@ import { Subscription } from "rxjs"; import { retryWhen, delay, take } from 'rxjs/operators'; import { CommunityForm as CommunityFormI, UserOperation, Category, ListCategoriesResponse, CommunityResponse } from '../interfaces'; import { WebSocketService } from '../services'; -import { msgOp } from '../utils'; +import { msgOp, capitalizeFirstLetter } from '../utils'; import * as autosize from 'autosize'; +import { i18n } from '../i18next'; +import { T } from 'inferno-i18next'; import { Community } from '../interfaces'; @@ -74,25 +76,25 @@ export class CommunityForm extends Component
    - +
    - +
    - +
    - +
    NameTitleCategorySubscribersPostsComments######
    {community.number_of_comments} {community.subscribed ? - Unsubscribe : - Subscribe + # : + # }