From b0882b25a99c027cd32bad825bca5cea6a6ceb62 Mon Sep 17 00:00:00 2001 From: freedit-dev Date: Mon, 21 Oct 2024 23:02:38 +0800 Subject: [PATCH] i18n (#301) * i18n * i18n * dedup feed items * fmt * update * typos * [wip] #208 * [wip] * i18n * i18n * i18n * typos * i18n * Update i18n/en.toml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * i18n * i18n * typos happy * typos happy --------- Co-authored-by: GitHub Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- Cargo.lock | 67 ++++++++-------- README.md | 8 ++ i18n/en.toml | 139 +++++++++++++++++++++++++++++++++ i18n/fr.toml | 139 +++++++++++++++++++++++++++++++++ i18n/ja.toml | 139 +++++++++++++++++++++++++++++++++ i18n/zh_cn.toml | 139 +++++++++++++++++++++++++++++++++ src/controller/admin.rs | 8 +- src/controller/feed.rs | 3 +- src/controller/fmt.rs | 7 ++ src/controller/inn.rs | 4 +- src/controller/message.rs | 1 + src/controller/meta_handler.rs | 9 ++- src/controller/mod.rs | 49 ++++++++++++ src/controller/notification.rs | 2 +- src/controller/solo.rs | 2 +- src/controller/tantivy.rs | 2 +- src/controller/upload.rs | 2 +- src/controller/user.rs | 49 ++++++++++-- templates/admin.html | 74 +++++++++++------- templates/admin_gallery.html | 16 ++-- templates/admin_view.html | 8 +- templates/feed.html | 40 +++++----- templates/feed_add.html | 16 ++-- templates/feed_read.html | 4 +- templates/gallery.html | 16 ++-- templates/inn.html | 86 ++++++++++---------- templates/inn_create.html | 34 ++++---- templates/inn_edit.html | 64 +++++++-------- templates/inn_list.html | 44 +++++------ templates/layout.html | 14 ++-- templates/notification.html | 24 +++--- templates/post.html | 50 ++++++------ templates/post_create.html | 6 +- templates/post_edit.html | 6 +- templates/preview.html | 12 ++- templates/reset.html | 10 +-- templates/search.html | 16 ++-- templates/show_recovery.html | 8 +- templates/signin.html | 15 ++-- templates/signup.html | 16 ++-- templates/solo.html | 30 +++---- templates/solo_list.html | 68 ++++++++-------- templates/tag.html | 14 ++-- templates/upload.html | 6 +- templates/user.html | 16 ++-- templates/user_list.html | 110 +++++++++++++------------- templates/user_setting.html | 68 ++++++++++------ typos.toml | 5 ++ 48 files changed, 1188 insertions(+), 477 deletions(-) create mode 100644 i18n/en.toml create mode 100644 i18n/fr.toml create mode 100644 i18n/ja.toml create mode 100644 i18n/zh_cn.toml create mode 100644 typos.toml diff --git a/Cargo.lock b/Cargo.lock index e46a8585..e0b9d50b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -89,9 +89,9 @@ checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "async-compression" -version = "0.4.14" +version = "0.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "998282f8f49ccd6116b0ed8a4de0fbd3151697920e7c7533416d6e25e76434a7" +checksum = "103db485efc3e41214fe4fda9f3dbeae2eb9082f48fd236e6095627a9422066e" dependencies = [ "futures-core", "memchr", @@ -340,9 +340,9 @@ checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "bytemuck" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94bbb0ad554ad961ddc5da507a12a29b14e4ae5bda06b19f575a3e6079d2e2ae" +checksum = "8334215b81e418a0a7bdb8ef0849474f40bb10c8b71f1c4ed315cff49f32494d" [[package]] name = "byteorder" @@ -418,9 +418,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.30" +version = "1.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b16803a61b81d9eabb7eae2588776c4c1e584b738ede45fdbb4c972cec1e9945" +checksum = "c2e7962b54006dcfcc61cb72735f4d89bb97061dd6a7ed882ec6b8ee53714c6f" dependencies = [ "jobserver", "libc", @@ -1082,9 +1082,9 @@ dependencies = [ [[package]] name = "hyper" -version = "1.4.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" +checksum = "bbbff0a806a4728c99295b254c8838933b5b082d75e3cb70c8dab21fdfbcfa9a" dependencies = [ "bytes", "futures-channel", @@ -1164,9 +1164,9 @@ dependencies = [ [[package]] name = "image" -version = "0.25.2" +version = "0.25.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99314c8a2152b8ddb211f924cdae532d8c5e4c8bb54728e12fff1b0cd5963a10" +checksum = "bc144d44a31d753b02ce64093d532f55ff8dc4ebf2ffb8a63c0dda691385acae" dependencies = [ "bytemuck", "byteorder-lite", @@ -1289,9 +1289,9 @@ checksum = "0c2cdeb66e45e9f36bfad5bbdb4d2384e70936afbee843c6f6543f0c551ebb25" [[package]] name = "libc" -version = "0.2.159" +version = "0.2.161" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" +checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" [[package]] name = "libm" @@ -1592,9 +1592,9 @@ checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "once_map" -version = "0.4.20" +version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed29bb6f7d6ac14023acb332a356f3891265d780e254057c866dbe7a909d2d2d" +checksum = "7bd2cae3bec3936bbed1ccc5a3343b3738858182419f9c0522c7260c80c430b0" dependencies = [ "ahash 0.8.11", "hashbrown 0.15.0", @@ -1782,18 +1782,18 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" [[package]] name = "proc-macro2" -version = "1.0.87" +version = "1.0.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a" +checksum = "7c3a7fc5db1e57d5a779a352c8cdb57b29aa4c40cc69c3a68a7fedc815fbf2f9" dependencies = [ "unicode-ident", ] [[package]] name = "pulldown-cmark" -version = "0.12.1" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "666f0f59e259aea2d72e6012290c09877a780935cc3c18b1ceded41f3890d59c" +checksum = "f86ba2052aebccc42cbbb3ed234b8b13ce76f75c3551a303cb2bcffcff12bb14" dependencies = [ "bitflags 2.6.0", "memchr", @@ -2169,9 +2169,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.14" +version = "0.23.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "415d9944693cb90382053259f89fbb077ea730ad7273047ec63b19bc9b160ba8" +checksum = "5fbb44d7acc4e873d613422379f69f237a1b141928c02f6bc6ccfddddc2d7993" dependencies = [ "once_cell", "ring", @@ -2192,9 +2192,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e696e35370c65c9c541198af4543ccd580cf17fc25d8e05c5a242b202488c55" +checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" [[package]] name = "rustls-webpki" @@ -2209,9 +2209,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" +checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" [[package]] name = "ryu" @@ -2256,9 +2256,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.128" +version = "1.0.132" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" +checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" dependencies = [ "itoa", "memchr", @@ -2443,9 +2443,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.79" +version = "2.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" +checksum = "198514704ca887dd5a1e408c6c6cdcba43672f9b4062e1b24aa34e74e6d7faae" dependencies = [ "proc-macro2", "quote", @@ -2914,12 +2914,9 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "unicase" -version = "2.7.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" -dependencies = [ - "version_check", -] +checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" [[package]] name = "unicode-bidi" @@ -2985,9 +2982,9 @@ checksum = "7fcfc827f90e53a02eaef5e535ee14266c1d569214c6aa70133a624d8a3164ba" [[package]] name = "uuid" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" +checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" dependencies = [ "getrandom", "serde", diff --git a/README.md b/README.md index cc8d5eef..c6a69201 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,14 @@ Demo: GitHub: +## Support + +Help support the development and maintenance of freedit. Your contributions are greatly appreciated! + +- Monero (XMR): `45JB1KbCM54gw7zDY8LzkDXjEibDgTspyKBzM8VWi8mL1gY3wCyzHsCSRGRsXBwGgdC6HX1EtJFoNYXZELnDQW8S7DRG8tL` + +All donations go towards hosting costs and continued development of freedit. Thank you for your support! + ## Features * Easy to deploy: one binary to run, using embedded database [sled](https://github.com/spacejam/sled) diff --git a/i18n/en.toml b/i18n/en.toml new file mode 100644 index 00000000..073e6a5b --- /dev/null +++ b/i18n/en.toml @@ -0,0 +1,139 @@ +about = "About" +active = "Active" +add = "Add" +admin = "Admin" +agree_terms = "I agree to the " +all = "All" +already_have_account = "Already have an account?" +apply = "Apply" +article_max_length = "Article Max Length" +avatar_help = "Please clear browser cache" +banned = "Banned" +captcha = "Captcha" +captcha_difficulty = "Captcha Difficulty" +captcha_name = "Captcha Name" +comment = "Comment" +comment_interval = "Comment Interval" +comment_max_length = "Comment Max Length" +created = "Created" +db_view = "DB View" +delete = "Delete" +delete_draft = "Delete Draft" +delete_permanently = "Delete Permanently" +delete_sure = "Are you sure you want to delete this?" +description = "Description" +domain = "Domain" +draft = "Draft" +early_birds = "Early Birds" +early_birds_help = "An early bird will be Fellow automatically." +easy = "Easy" +edit = "Edit" +error = "Error" +everyone = "Everyone" +exit = "Exit" +explore = "Explore" +feed_add_help = "Only works when new is selected" +feed_url_help = "rss/atom feed url" +fellow = "Fellow" +folder = "Folder" +followers = "Followers" +following = "Following" +forgot_password = "Forgot Password?" +gallery = "Gallery" +hard = "Hard" +hidden = "Hidden" +hide = "Hide" +home_page = "Default Home Page" +inn_feed_help = "Submit url again to unsubscribe." +inn_mod_max = "Inn Mod Max" +inn_name = "Inn Name" +inn_type = "Inn Type" +intern = "Intern" +is_public = "Is Public" +join = "Join" +join_to_comment = "Join to comment" +joined = "Joined" +just_me = "Just Me" +lang = "Language" +like = "Like" +limit_edit_seconds = "Limited Edit Seconds" +limit_edit_seconds_help = "How long before users are blocked from editing? (set 0 to allow anytime)" +limited = "Limited" +list = "List" +load_image = "Load Image" +lock = "Lock" +medium = "Medium" +members = "Members" +mod = "Mod" +new = "New" +new_comment = "New Comment" +new_folder = "New Folder" +new_password = "New Password" +new_post = "New Post" +next = "Next" +old_password = "Old Password" +password = "Password" +password_help = "Password must be 7 - 20 chars" +password_reset = "Password Reset" +pending = "Pending" +per_page = "Per Page" +pin = "Pin" +post = "Post" +post_interval = "Post Interval" +prev = "Prev" +preview = "Preview" +private = "Private" +private_help = "The Private inn can not be changed to other type." +private_hidden = "Private Hidden" +public = "Public" +re_enter_password = "Re-enter Password" +read_only = "Read Only" +recovery_code = "Recovery Code" +recovery_code_last_valid = "Each time you generate a new code and only the last one will be valid." +recovery_code_msg = "You have not set a recovery code. If you lose your password, you will not be able to recover your account." +recovery_code_note = "We will not save this code in database. If you close this page, nobody will see this code again." +recovery_code_privacy_note = "For your privacy, Freedit does not require your email. You can send emails directly to yourself and save them in your account." +recovery_generate = "Generate recovery code" +recovery_help = "You must input your password to generate or reset your recovery code." +refresh = "Refresh" +rejected = "Rejected" +remove = "Remove" +role = "Role" +save = "Save" +save_draft = "Save Draft" +search = "Search" +senior = "Senior" +sessions = "Sessions" +sign_in = "Sign In" +sign_in_to_comment = "Sign in to comment" +sign_out = "Sign Out" +sign_up = "Sign Up" +site_name = "Site Name" +site_settings = "Site Settings" +solo_interval = "Solo Interval" +source = "Source" +spam_regex = "Spam Regex" +standard = "Standard" +star = "Star" +stats = "Stats" +stay_logged_in = "Stay logged in" +submit = "Submit" +subscribe = "Subscribe" +super = "Super" +terms = "Terms and Conditions" +title_max_length = "Title Max Length" +topics = "Topics" +topics_help = "# separated" +uname_or_id = "Username or uid" +unhide = "Unhide" +unlock = "Unlock" +unpin = "Unpin" +unread = "Unread" +unsubscribe = "Unsubscribe" +upload = "Upload" +upload_help = "Max 10 pictures; jpg jpeg png wepb and gif is allowed." +url = "URL" +user_name = "User Name" +user_name_help = "Username, Not start with number, 2 - 10 chars" +users = "Users" +warning = "Warning" diff --git a/i18n/fr.toml b/i18n/fr.toml new file mode 100644 index 00000000..287a2d27 --- /dev/null +++ b/i18n/fr.toml @@ -0,0 +1,139 @@ +about = "À propos" +active = "Actif" +add = "Ajouter" +admin = "Administrateur" +agree_terms = "J'accepte les " +all = "Tous" +already_have_account = "Vous avez déjà un compte ?" +apply = "Appliquer" +article_max_length = "Longueur maximale de l'article" +avatar_help = "Veuillez vider le cache du navigateur" +banned = "Banni" +captcha = "Captcha" +captcha_difficulty = "Difficulté du captcha" +captcha_name = "Nom du captcha" +comment = "Commentaire" +comment_interval = "Intervalle des commentaires" +comment_max_length = "Longueur maximale du commentaire" +created = "Créé" +db_view = "Vue de la base de données" +delete = "Supprimer" +delete_draft = "Supprimer le brouillon" +delete_permanently = "Supprimer définitivement" +delete_sure = "Êtes-vous sûr de vouloir supprimer ceci ?" +description = "Description" +domain = "Domaine" +draft = "Brouillon" +early_birds = "Premiers inscrits" +early_birds_help = "Un premier inscrit deviendra automatiquement Fellow." +easy = "Facile" +edit = "Modifier" +error = "Erreur" +everyone = "Tout le monde" +exit = "Quitter" +explore = "Explorer" +feed_add_help = "Ne fonctionne que lorsque 'Nouveau' est sélectionné" +feed_url_help = "URL du flux rss/atom" +fellow = "Membre" +folder = "Dossier" +followers = "Abonnés" +following = "Abonnements" +forgot_password = "Mot de passe oublié ?" +gallery = "Galerie" +hard = "Difficile" +hidden = "Caché" +hide = "Cacher" +home_page = "Page d'accueil par défaut" +inn_feed_help = "Soumettez à nouveau l'URL pour vous désabonner." +inn_mod_max = "Max modérateurs" +inn_name = "Nom de l'auberge" +inn_type = "Type d'auberge" +intern = "Stagiaire" +is_public = "Est public" +join = "Rejoindre" +join_to_comment = "Rejoignez pour commenter" +joined = "Rejoint" +just_me = "Moi uniquement" +lang = "Langue" +like = "J'aime" +limit_edit_seconds = "Limite de temps d'édition (en secondes)" +limit_edit_seconds_help = "Combien de temps avant que les utilisateurs ne puissent plus modifier ? (mettre 0 pour permettre à tout moment)" +limited = "Limité" +list = "Liste" +load_image = "Charger une image" +lock = "Verrouiller" +medium = "Moyen" +members = "Membres" +mod = "Modérateur" +new = "Nouveau" +new_comment = "Nouveau commentaire" +new_folder = "Nouveau dossier" +new_password = "Nouveau mot de passe" +new_post = "Nouvel article" +next = "Suivant" +old_password = "Ancien mot de passe" +password = "Mot de passe" +password_help = "Le mot de passe doit comporter entre 7 et 20 caractères" +password_reset = "Réinitialiser le mot de passe" +pending = "En attente" +per_page = "Par page" +pin = "Épingler" +post = "Publier" +post_interval = "Intervalle de publication" +prev = "Précédent" +preview = "Aperçu" +private = "Privé" +private_help = "L'auberge privée ne peut pas être changée en un autre type." +private_hidden = "Privé caché" +public = "Public" +re_enter_password = "Confirmer le mot de passe" +read_only = "Lecture seule" +recovery_code = "Code de récupération" +recovery_code_last_valid = "Chaque fois que vous générez un nouveau code, seul le dernier sera valide." +recovery_code_msg = "Vous n'avez pas défini de code de récupération. Si vous perdez votre mot de passe, vous ne pourrez pas récupérer votre compte." +recovery_code_note = "Nous ne sauvegarderons pas ce code dans la base de données. Si vous fermez cette page, personne ne pourra voir ce code à nouveau." +recovery_code_privacy_note = "Pour votre vie privée, Freedit ne nécessite pas votre adresse e-mail. Vous pouvez envoyer des e-mails directement à vous-même et les enregistrer dans votre compte." +recovery_generate = "Générer le code de récupération" +recovery_help = "Vous devez saisir votre mot de passe pour générer ou réinitialiser votre code de récupération." +refresh = "Actualiser" +rejected = "Rejeté" +remove = "Supprimer" +role = "Rôle" +save = "Enregistrer" +save_draft = "Enregistrer le brouillon" +search = "Recherche" +senior = "Sénior" +sessions = "Sessions" +sign_in = "Se connecter" +sign_in_to_comment = "Connectez-vous pour commenter" +sign_out = "Se déconnecter" +sign_up = "S'inscrire" +site_name = "Nom du site" +site_settings = "Paramètres du site" +solo_interval = "Intervalle solo" +source = "Source" +spam_regex = "Regex spam" +standard = "Standard" +star = "Étoile" +stats = "Statistiques" +stay_logged_in = "Rester connecté" +submit = "Soumettre" +subscribe = "S'abonner" +super = "Super" +terms = "termes et conditions" +title_max_length = "Longueur maximale du titre" +topics = "Sujets" +topics_help = "Séparés par #" +uname_or_id = "Nom d'utilisateur ou uid" +unhide = "Révéler" +unlock = "Déverrouiller" +unpin = "Détacher" +unread = "Non lu" +unsubscribe = "Se désabonner" +upload = "Téléverser" +upload_help = "10 images max ; jpg jpeg png webp et gif sont autorisés." +url = "URL" +user_name = "Nom d'utilisateur" +user_name_help = "Nom d'utilisateur, ne commence pas par un chiffre, 2 à 10 caractères" +users = "Utilisateurs" +warning = "Avertissement" diff --git a/i18n/ja.toml b/i18n/ja.toml new file mode 100644 index 00000000..074fe78a --- /dev/null +++ b/i18n/ja.toml @@ -0,0 +1,139 @@ +about = "概要" +active = "アクティブ" +add = "追加" +admin = "管理者" +agree_terms = "同意します" +all = "すべて" +already_have_account = "既にアカウントをお持ちですか?" +apply = "適用" +article_max_length = "記事の最大長" +avatar_help = "ブラウザのキャッシュをクリアしてください" +banned = "禁止" +captcha = "キャプチャ" +captcha_difficulty = "キャプチャの難易度" +captcha_name = "キャプチャ名" +comment = "コメント" +comment_interval = "コメントの間隔" +comment_max_length = "コメントの最大長" +created = "作成日時" +db_view = "データベースビュー" +delete = "削除" +delete_draft = "ドラフトを削除" +delete_permanently = "完全に削除" +delete_sure = "本当に削除しますか?" +description = "説明" +domain = "ドメイン" +draft = "ドラフト" +early_birds = "早期ユーザー" +early_birds_help = "早期ユーザーは自動的に Fellow になります。" +easy = "簡単" +edit = "編集" +error = "エラー" +everyone = "すべての人" +exit = "終了" +explore = "探索" +feed_add_help = "新規選択時のみ機能します" +feed_url_help = "rss/atom フィードURL" +fellow = "フェロー" +folder = "フォルダ" +followers = "フォロワー" +following = "フォロー中" +forgot_password = "パスワードをお忘れですか?" +gallery = "ギャラリー" +hard = "難しい" +hidden = "非表示" +hide = "非表示" +home_page = "デフォルトホームページ" +inn_feed_help = "もう一度 URL を送信して購読を解除します。" +inn_mod_max = "最大管理者数" +inn_name = "イン名" +inn_type = "インタイプ" +intern = "インターン" +is_public = "公開されていますか?" +join = "参加" +join_to_comment = "コメントするには参加" +joined = "参加済み" +just_me = "自分のみ" +lang = "言語" +like = "いいね" +limit_edit_seconds = "編集制限時間(秒)" +limit_edit_seconds_help = "ユーザーが編集をブロックされるまでの時間(0 に設定するといつでも許可)" +limited = "制限付き" +list = "リスト" +load_image = "画像を読み込む" +lock = "ロック" +medium = "中" +members = "メンバー" +mod = "モデレーター" +new = "新規" +new_comment = "新しいコメント" +new_folder = "新しいフォルダ" +new_password = "新しいパスワード" +new_post = "新しい投稿" +next = "次" +old_password = "旧パスワード" +password = "パスワード" +password_help = "パスワードは7〜20文字で入力してください" +password_reset = "パスワードのリセット" +pending = "保留中" +per_page = "1ページあたり" +pin = "ピン" +post = "投稿" +post_interval = "投稿の間隔" +prev = "前" +preview = "プレビュー" +private = "非公開" +private_help = "非公開のインは他のタイプに変更できません。" +private_hidden = "非公開の非表示" +public = "公開" +re_enter_password = "パスワードを再入力" +read_only = "読み取り専用" +recovery_code = "回復コード" +recovery_code_last_valid = "新しいコードを生成するたびに、最後のコードのみが有効になります。" +recovery_code_msg = "回復コードを設定していません。パスワードを忘れると、アカウントを回復できません。" +recovery_code_note = "このコードはデータベースに保存されません。このページを閉じると、誰もこのコードを見ることはできません。" +recovery_code_privacy_note = "プライバシー保護のため、Freedit はメールアドレスを必要としません。自分宛にメールを直接送信し、アカウントに保存できます。" +recovery_generate = "回復コードを生成" +recovery_help = "回復コードを生成またはリセットするには、パスワードを入力する必要があります。" +refresh = "更新" +rejected = "拒否されました" +remove = "削除" +role = "役割" +save = "保存" +save_draft = "ドラフトを保存" +search = "検索" +senior = "シニア" +sessions = "セッション" +sign_in = "ログイン" +sign_in_to_comment = "コメントするにはログイン" +sign_out = "ログアウト" +sign_up = "サインアップ" +site_name = "サイト名" +site_settings = "サイト設定" +solo_interval = "個別投稿間隔" +source = "ソース" +spam_regex = "スパムの正規表現" +standard = "標準" +star = "スター" +stats = "統計" +stay_logged_in = "ログイン状態を維持" +submit = "送信" +subscribe = "購読" +super = "スーパー" +terms = "利用規約" +title_max_length = "タイトルの最大長" +topics = "トピック" +topics_help = "# で区切り" +uname_or_id = "ユーザー名またはユーザーID" +unhide = "非表示を解除" +unlock = "アンロック" +unpin = "ピンを外す" +unread = "未読" +unsubscribe = "購読を解除" +upload = "アップロード" +upload_help = "最大10枚の画像をアップロード可能です。jpg、jpeg、png、webp、gifが許可されています。" +url = "URL" +user_name = "ユーザー名" +user_name_help = "ユーザー名、数字で始まらない、2〜10文字" +users = "ユーザー" +warning = "警告" diff --git a/i18n/zh_cn.toml b/i18n/zh_cn.toml new file mode 100644 index 00000000..6d803778 --- /dev/null +++ b/i18n/zh_cn.toml @@ -0,0 +1,139 @@ +about = "关于" +active = "活跃" +add = "添加" +admin = "管理员" +agree_terms = "我同意" +all = "全部" +already_have_account = "已经有账号?" +apply = "应用" +article_max_length = "文章最大长度" +avatar_help = "请清除浏览器缓存" +banned = "已禁用" +captcha = "验证码" +captcha_difficulty = "验证码难度" +captcha_name = "验证码名称" +comment = "评论" +comment_interval = "评论间隔" +comment_max_length = "评论最大长度" +created = "创建时间" +db_view = "数据库视图" +delete = "删除" +delete_draft = "删除草稿" +delete_permanently = "永久删除" +delete_sure = "确定要删除吗?" +description = "描述" +domain = "域名" +draft = "草稿" +early_birds = "早起鸟" +early_birds_help = "早起鸟将自动成为 Fellow。" +easy = "简单" +edit = "编辑" +error = "错误" +everyone = "所有人" +exit = "退出" +explore = "探索" +feed_add_help = "仅在选择新建时有效" +feed_url_help = "rss/atom 源地址" +fellow = "Fellow" +folder = "文件夹" +followers = "关注者" +following = "关注" +forgot_password = "忘记密码?" +gallery = "画廊" +hard = "困难" +hidden = "隐藏" +hide = "隐藏" +home_page = "默认主页" +inn_feed_help = "再次提交 url 以取消订阅。" +inn_mod_max = "最大管理员数量" +inn_name = "小屋名称" +inn_type = "小屋类型" +intern = "实习生" +is_public = "是否公开" +join = "加入" +join_to_comment = "加入以评论" +joined = "已加入" +just_me = "仅限我" +lang = "语言" +like = "喜欢" +limit_edit_seconds = "限制编辑时间(秒)" +limit_edit_seconds_help = "用户被阻止编辑前的时间?(设为 0 表示随时允许)" +limited = "有限" +list = "列表" +load_image = "加载图片" +lock = "锁定" +medium = "中等" +members = "成员" +mod = "管理员" +new = "新建" +new_comment = "新评论" +new_folder = "新文件夹" +new_password = "新密码" +new_post = "新帖子" +next = "下一页" +old_password = "旧密码" +password = "密码" +password_help = "密码必须为 7 - 20 个字符" +password_reset = "密码重置" +pending = "待定" +per_page = "每页数量" +pin = "置顶" +post = "发布" +post_interval = "发布间隔" +prev = "上一页" +preview = "预览" +private = "私有" +private_help = "私有小屋不能更改为其他类型。" +private_hidden = "隐藏的私有" +public = "公开" +re_enter_password = "再次输入密码" +read_only = "只读" +recovery_code = "恢复代码" +recovery_code_last_valid = "每次生成新代码,只有最后一个有效。" +recovery_code_msg = "您尚未设置恢复代码。如果忘记密码,将无法恢复您的账户。" +recovery_code_note = "我们不会将此代码保存在数据库中。如果您关闭此页面,将再也看不到此代码。" +recovery_code_privacy_note = "为了您的隐私,Freedit 不需要您的电子邮件。您可以直接发送电子邮件给自己并将其保存在您的账户中。" +recovery_generate = "生成恢复代码" +recovery_help = "您必须输入密码才能生成或重置恢复代码。" +refresh = "刷新" +rejected = "已拒绝" +remove = "移除" +role = "角色" +save = "保存" +save_draft = "保存草稿" +search = "搜索" +senior = "资深" +sessions = "会话" +sign_in = "登录" +sign_in_to_comment = "登录后评论" +sign_out = "登出" +sign_up = "注册" +site_name = "站点名称" +site_settings = "站点设置" +solo_interval = "单独发布间隔" +source = "来源" +spam_regex = "垃圾信息正则表达式" +standard = "标准" +star = "收藏" +stats = "统计" +stay_logged_in = "保持登录" +submit = "提交" +subscribe = "订阅" +super = "超级管理员" +terms = "条款与条件" +title_max_length = "标题最大长度" +topics = "主题" +topics_help = "使用 # 分隔" +uname_or_id = "用户名或用户 ID" +unhide = "取消隐藏" +unlock = "解锁" +unpin = "取消置顶" +unread = "未读" +unsubscribe = "取消订阅" +upload = "上传" +upload_help = "最多上传 10 张图片;支持 jpg、jpeg、png、webp 和 gif 格式。" +url = "URL" +user_name = "用户名" +user_name_help = "用户名,不以数字开头,2 - 10 个字符" +users = "用户" +warning = "警告" diff --git a/src/controller/admin.rs b/src/controller/admin.rs index 6820eefb..62080d2e 100644 --- a/src/controller/admin.rs +++ b/src/controller/admin.rs @@ -7,7 +7,7 @@ use super::{ Claim, Feed, FormPost, Item, SiteConfig, }; use crate::{ - controller::{Comment, Inn, Post, Solo, User}, + controller::{filters, Comment, Inn, Post, Solo, User}, error::AppError, DB, }; @@ -284,6 +284,11 @@ pub(crate) async fn admin_view( let uid = u8_slice_to_u32(&k); ones.push(format!("{uid}: {}", v[0])); } + "lang" => { + let uid = u8_slice_to_u32(&k); + let lang = String::from_utf8_lossy(&v); + ones.push(format!("{uid}: {lang}")); + } "tan" => { let id = String::from_utf8_lossy(&k); ones.push(format!("{id}: {:?}", v)); @@ -393,6 +398,7 @@ impl Default for SiteConfig { captcha_name: "Lucy".into(), home_page: 0, spam_regex: None, + lang: "en".into(), } } } diff --git a/src/controller/feed.rs b/src/controller/feed.rs index cfc82433..cda4ad48 100644 --- a/src/controller/feed.rs +++ b/src/controller/feed.rs @@ -10,7 +10,7 @@ use super::{ }; use crate::{ config::CONFIG, - controller::{incr_id, Feed, Item}, + controller::{filters, incr_id, Feed, Item}, error::AppError, DB, }; @@ -275,6 +275,7 @@ pub(crate) async fn feed( } item_ids.sort_unstable_by(|a, b| a.1.cmp(&b.1).then(a.0.cmp(&b.0))); + item_ids.dedup_by(|a, b| a.0 == b.0); let n = site_config.per_page; let anchor = params.anchor.unwrap_or(0); diff --git a/src/controller/fmt.rs b/src/controller/fmt.rs index cf3f4a43..effea69b 100644 --- a/src/controller/fmt.rs +++ b/src/controller/fmt.rs @@ -71,6 +71,13 @@ pub(super) fn clean_html(raw: &str) -> String { .add_allowed_classes("span", &["replytag"]) .add_tag_attributes("pre", &["style"]) .add_tag_attributes("span", &["style"]) + // allow task list + .add_tags(&["input"]) + .add_tag_attributes("input", &["type", "checked", "disabled"]) + // allow footnotes + .add_allowed_classes("sup", &["footnote-reference", "footnote-definition-label"]) + .add_allowed_classes("div", &["footnote-definition"]) + .add_tag_attributes("div", &["id"]) .clean(raw) .to_string() } diff --git a/src/controller/inn.rs b/src/controller/inn.rs index f07d4fa6..758e4625 100644 --- a/src/controller/inn.rs +++ b/src/controller/inn.rs @@ -4,7 +4,7 @@ //! | role | comment | post | update timeline | lock post | inn admin | protected | Note | //! |---------|:-------:|:----:|:---------------:|:---------:|:---------:|:---------:|------------------| //! | Pending | | | | | | | Apply or Private | -//! | Deny | | | | | | | Apply or Private | +//! | Rejected| | | | | | | Apply or Private | //! | Limited | ✅ | | | | | | | //! | Intern | ✅ | ✅ | | | | | | //! | Fellow | ✅ | ✅ | ✅ | | | | | @@ -25,7 +25,7 @@ use super::{ user::{InnRole, Role}, Claim, Comment, Feed, FormPost, Inn, InnType, Post, PostContent, PostStatus, SiteConfig, User, }; -use crate::{error::AppError, DB}; +use crate::{controller::filters, error::AppError, DB}; use axum::{ extract::{Path, Query}, diff --git a/src/controller/message.rs b/src/controller/message.rs index 217c9246..85edb9ea 100644 --- a/src/controller/message.rs +++ b/src/controller/message.rs @@ -7,6 +7,7 @@ use axum_extra::{headers::Cookie, TypedHeader}; use rinja_axum::{into_response, Template}; use serde::Deserialize; +use crate::controller::filters; use crate::{controller::fmt::clean_html, error::AppError, DB}; use super::{ diff --git a/src/controller/meta_handler.rs b/src/controller/meta_handler.rs index 886a7d99..e87dd139 100644 --- a/src/controller/meta_handler.rs +++ b/src/controller/meta_handler.rs @@ -1,7 +1,7 @@ use std::sync::LazyLock; use super::{db_utils::u32_to_ivec, fmt::md2html, Claim, SiteConfig}; -use crate::{error::AppError, DB}; +use crate::{controller::filters, error::AppError, DB}; use axum::{ http::{HeaderMap, HeaderValue, Uri}, response::{IntoResponse, Redirect, Response}, @@ -176,6 +176,7 @@ pub(super) struct PageData<'a> { pub(super) site_description: String, pub(super) claim: Option, pub(super) has_unread: bool, + pub(super) lang: String, } impl<'a> PageData<'a> { @@ -186,12 +187,18 @@ impl<'a> PageData<'a> { has_unread: bool, ) -> Self { let site_description = md2html(&site_config.description); + let lang = claim + .as_ref() + .and_then(|claim| claim.lang.as_ref()) + .map_or_else(|| site_config.lang.clone(), |lang| lang.to_owned()); + Self { title, site_name: &site_config.site_name, site_description, claim, has_unread, + lang, } } } diff --git a/src/controller/mod.rs b/src/controller/mod.rs index eb4b99e7..b877f005 100644 --- a/src/controller/mod.rs +++ b/src/controller/mod.rs @@ -16,6 +16,7 @@ //! | default | "imgs_count" | N | //! | "home_pages" | `uid` | `u8` | //! | "tan" | `ctype#id` | `&[]` | +//! | "lang" | `uid` | `lang` | //! //! ### notification //! | tree | key | value | @@ -483,6 +484,8 @@ pub(super) struct SiteConfig { home_page: u8, #[garde(skip)] spam_regex: Option, + #[garde(length(max = 16))] + lang: String, } impl SiteConfig { @@ -502,4 +505,50 @@ struct Claim { role: u8, last_write: i64, session_id: String, + lang: Option, +} + +mod filters { + use std::{collections::HashMap, sync::LazyLock}; + use tracing::error; + + static I18N: LazyLock> = LazyLock::new(|| { + let mut i18n = HashMap::new(); + let en = include_str!("../../i18n/en.toml"); + let en = basic_toml::from_str::>(en).unwrap(); + for (k, v) in en.iter() { + i18n.insert(("en", *k), *v); + } + + let zh_cn = include_str!("../../i18n/zh_cn.toml"); + let zh_cn = basic_toml::from_str::>(zh_cn).unwrap(); + for (k, v) in zh_cn.iter() { + i18n.insert(("zh_cn", *k), *v); + } + + let ja = include_str!("../../i18n/ja.toml"); + let ja = basic_toml::from_str::>(ja).unwrap(); + for (k, v) in ja.iter() { + i18n.insert(("ja", *k), *v); + } + + let fr = include_str!("../../i18n/fr.toml"); + let fr = basic_toml::from_str::>(fr).unwrap(); + for (k, v) in fr.iter() { + i18n.insert(("fr", *k), *v); + } + i18n + }); + + pub(super) fn l10n(s: &str, lang: &str) -> ::rinja::Result<&'static str> { + if let Some(v) = I18N.get(&(lang, s)) { + Ok(v) + } else { + let Some(en) = I18N.get(&("en", s)) else { + panic!("No translation for {} in en", s); + }; + error!("No translation for {} in {}", s, lang); + Ok(en) + } + } } diff --git a/src/controller/notification.rs b/src/controller/notification.rs index 91667a5f..0c0dd377 100644 --- a/src/controller/notification.rs +++ b/src/controller/notification.rs @@ -5,7 +5,7 @@ use super::{ user::{InnRole, Role}, Claim, Comment, Inn, Post, SiteConfig, Solo, User, }; -use crate::{error::AppError, DB}; +use crate::{controller::filters, error::AppError, DB}; use axum::{extract::Query, response::IntoResponse}; use axum_extra::{headers::Cookie, TypedHeader}; use bincode::config::standard; diff --git a/src/controller/solo.rs b/src/controller/solo.rs index 0ef85c14..c2a7f118 100644 --- a/src/controller/solo.rs +++ b/src/controller/solo.rs @@ -11,7 +11,7 @@ use super::{ user::Role, Claim, SiteConfig, Solo, SoloType, User, }; -use crate::{error::AppError, DB}; +use crate::{controller::filters, error::AppError, DB}; use axum::{ extract::{Path, Query}, response::{IntoResponse, Redirect}, diff --git a/src/controller/tantivy.rs b/src/controller/tantivy.rs index 4891ed8f..c7ff0e7b 100644 --- a/src/controller/tantivy.rs +++ b/src/controller/tantivy.rs @@ -26,7 +26,7 @@ use whichlang::detect_language; use crate::{ config::CONFIG, - controller::{InnType, SoloType}, + controller::{filters, InnType, SoloType}, error::AppError, DB, }; diff --git a/src/controller/upload.rs b/src/controller/upload.rs index 4dd8335b..7255b922 100644 --- a/src/controller/upload.rs +++ b/src/controller/upload.rs @@ -8,7 +8,7 @@ use super::{ user::{InnRole, Role}, Claim, SiteConfig, User, }; -use crate::{config::CONFIG, error::AppError, DB}; +use crate::{config::CONFIG, controller::filters, error::AppError, DB}; use axum::{ extract::{Multipart, Path, Query}, response::{IntoResponse, Redirect}, diff --git a/src/controller/user.rs b/src/controller/user.rs index 1b91ce83..a233920a 100644 --- a/src/controller/user.rs +++ b/src/controller/user.rs @@ -5,6 +5,7 @@ use super::{ generate_nanoid_ttl, get_count, get_count_by_prefix, get_id_by_name, get_range, is_valid_name, ivec_to_u32, set_one, set_one_with_key, IterType, }, + filters, fmt::{clean_html, ts_to_date}, get_ids_by_prefix, get_one, incr_id, meta_handler::{PageData, ParamsPage}, @@ -241,7 +242,7 @@ impl Display for Role { #[repr(u8)] pub(super) enum InnRole { Pending = 1, - Deny = 2, + Rejected = 2, Limited = 3, Intern = 4, Fellow = 5, @@ -263,7 +264,7 @@ impl From for InnRole { fn from(value: u8) -> Self { match value { 1 => InnRole::Pending, - 2 => InnRole::Deny, + 2 => InnRole::Rejected, 3 => InnRole::Limited, 4 => InnRole::Intern, 5 => InnRole::Fellow, @@ -516,7 +517,7 @@ pub(crate) async fn role_post( DB.open_tree("inn_apply")?.insert(&inn_users_k, &[])?; 1 } - "Deny" => 2, + "Rejected" => 2, "Limited" => 3, "Intern" => 4, "Fellow" => 5, @@ -593,6 +594,8 @@ pub(crate) struct FormUser { url: String, #[garde(skip)] home_page: u8, + #[garde(skip)] + lang: String, } /// Page data: `user_setting.html` @@ -619,8 +622,12 @@ pub(crate) async fn user_setting( let mut sessions = Vec::new(); for i in DB.open_tree("sessions")?.iter() { - let (_, v) = i?; - let (claim2, _): (Claim, _) = bincode::decode_from_slice(&v, standard())?; + let (k, v) = i?; + let Ok((claim2, _)): Result<(Claim, _), _> = bincode::decode_from_slice(&v, standard()) + else { + DB.open_tree("sessions")?.remove(k)?; + continue; + }; if claim2.uid == claim.uid { sessions.push(claim2.session_id); } @@ -734,7 +741,7 @@ pub(crate) async fn user_setting_post( ) -> Result { let cookie = cookie.ok_or(AppError::NonLogin)?; let site_config = SiteConfig::get(&DB)?; - let claim = Claim::get(&DB, &cookie, &site_config).ok_or(AppError::NonLogin)?; + let mut claim = Claim::get(&DB, &cookie, &site_config).ok_or(AppError::NonLogin)?; let mut user: User = get_one(&DB, "users", claim.uid)?; let username = clean_html(&input.username); @@ -762,6 +769,16 @@ pub(crate) async fn user_setting_post( user.url = clean_html(&input.url); DB.open_tree("home_pages")? .insert(u32_to_ivec(user.uid), &[input.home_page])?; + + let lang = match input.lang.as_str() { + "en" | "zh_cn" | "ja" | "fr" => { + claim.update_lang(&DB, &input.lang)?; + &input.lang + } + _ => "en", + }; + + DB.open_tree("lang")?.insert(u32_to_ivec(user.uid), lang)?; set_one(&DB, "users", claim.uid, &user)?; let target = format!("/user/{}", claim.uid); @@ -1158,6 +1175,21 @@ impl Claim { Ok(()) } + pub(super) fn update_lang(&mut self, db: &Db, lang: &str) -> Result<(), AppError> { + let uid = self.uid; + let session_tree = db.open_tree("sessions")?; + for i in session_tree.iter() { + let (k, v) = i?; + let (mut claim, _): (Claim, _) = bincode::decode_from_slice(&v, standard())?; + if claim.uid == uid { + claim.lang = Some(lang.to_string()); + set_one_with_key(db, "sessions", k, &claim)?; + } + } + + Ok(()) + } + fn update_role(db: &Db, uid: u32) -> Result<(), AppError> { let user: User = get_one(db, "users", uid)?; @@ -1182,6 +1214,10 @@ impl Claim { let seconds = expire_seconds(expiry); let now = Timestamp::now().as_second(); let session_id = generate_nanoid_ttl(seconds); + let lang = db + .open_tree("lang")? + .get(u32_to_ivec(user.uid))? + .map(|s| String::from_utf8_lossy(&s).to_string()); let claim = Claim { uid: user.uid, @@ -1189,6 +1225,7 @@ impl Claim { role: user.role, last_write: now, session_id: session_id.clone(), + lang, }; set_one_with_key(db, "sessions", &session_id, &claim)?; diff --git a/templates/admin.html b/templates/admin.html index 03a2b8a6..40896672 100644 --- a/templates/admin.html +++ b/templates/admin.html @@ -5,7 +5,7 @@
- +
@@ -18,7 +18,7 @@
- +
@@ -31,7 +31,7 @@
- +
@@ -44,7 +44,7 @@
- +
@@ -58,7 +58,7 @@
- +
@@ -71,7 +71,7 @@
- +
@@ -84,7 +84,7 @@
- +
@@ -97,7 +97,7 @@
- +
@@ -110,7 +110,7 @@
- +
@@ -123,7 +123,7 @@
- +
@@ -136,7 +136,7 @@
- +
@@ -149,7 +149,7 @@
- +
@@ -162,15 +162,15 @@
- +
-

About captcha

+

{{"about"|l10n(page_data.lang)}} {{ "captcha"|l10n(page_data.lang) }}

- - - + + +
@@ -178,7 +178,7 @@
- +
@@ -194,19 +194,19 @@
- +
@@ -216,7 +216,7 @@
- +
@@ -232,12 +232,32 @@
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+
- +
diff --git a/templates/admin_gallery.html b/templates/admin_gallery.html index ce5c3c89..195b0d0d 100644 --- a/templates/admin_gallery.html +++ b/templates/admin_gallery.html @@ -6,10 +6,10 @@ {% for img in imgs %}
@@ -19,7 +19,7 @@

Delete permanently?

- Delete + {{ "delete"|l10n(page_data.lang) }}
{{img.2}}
@@ -33,15 +33,15 @@

Delete permanently?

{% endblock %} \ No newline at end of file diff --git a/templates/admin_view.html b/templates/admin_view.html index baefd117..401af321 100644 --- a/templates/admin_view.html +++ b/templates/admin_view.html @@ -21,15 +21,15 @@ {% endblock %} \ No newline at end of file diff --git a/templates/feed.html b/templates/feed.html index 02197659..e710a2c7 100644 --- a/templates/feed.html +++ b/templates/feed.html @@ -6,20 +6,20 @@
@@ -67,22 +67,22 @@ @@ -110,7 +110,7 @@ {% match username %} {% when None %} {% else %}{% endmatch %} diff --git a/templates/feed_add.html b/templates/feed_add.html index 58cee1aa..480fd6f8 100644 --- a/templates/feed_add.html +++ b/templates/feed_add.html @@ -5,12 +5,12 @@
- +
- +
@@ -18,7 +18,7 @@
- +
@@ -26,7 +26,7 @@ {% for folder in folders %} {% endfor %} - +
@@ -34,12 +34,12 @@
- +
- +
@@ -47,7 +47,7 @@
- +
@@ -64,7 +64,7 @@
- +
diff --git a/templates/feed_read.html b/templates/feed_read.html index 9281579b..2a10aa16 100644 --- a/templates/feed_read.html +++ b/templates/feed_read.html @@ -22,8 +22,8 @@

{{item.title|truncate(100)}}

📅 {{item.updated}}    ⚓ {{item.feed_title}}    - 🌐 Origin    - 🖼️ Load image + 🌐 {{ "source"|l10n(page_data.lang) }}    + 🖼️ {{ "load_image"|l10n(page_data.lang) }}

diff --git a/templates/gallery.html b/templates/gallery.html index c466e408..ea560eb6 100644 --- a/templates/gallery.html +++ b/templates/gallery.html @@ -11,17 +11,17 @@ {% for img in imgs %}
- Delete + {{ "delete"|l10n(page_data.lang) }}
![](/static/upload/{{img.1}})
@@ -35,15 +35,15 @@

Delete permanently?

{% endblock %} \ No newline at end of file diff --git a/templates/inn.html b/templates/inn.html index d746f5e6..8e7be84c 100644 --- a/templates/inn.html +++ b/templates/inn.html @@ -16,42 +16,42 @@
@@ -113,22 +113,22 @@ @@ -149,7 +149,7 @@
{% if inn_role >= 4 %} - New Post + {{ "new"|l10n(page_data.lang) }} Post {% else if inn_role == 3 %} - + {% else if inn_role == 2 %} - + {% else if inn_role == 1 %} - + {% else %} - Join + {{ "join"|l10n(page_data.lang) }} {% endif %}
- Description + {{ "description"|l10n(page_data.lang) }}

{{description}} @@ -229,7 +229,7 @@
-
Explore all ⚓ inns
+
{{ "explore"|l10n(page_data.lang) }} ⚓ inns
{% for inn in inns %} @@ -245,9 +245,9 @@
{% if inn.2 %} - + {% else %} - + {% endif %}
@@ -257,7 +257,7 @@
-
Active 👤 Users
+
{{ "active"|l10n(page_data.lang) }} 👤 {{ "users"|l10n(page_data.lang) }}
diff --git a/templates/inn_create.html b/templates/inn_create.html index b0c2adc7..fc01f613 100644 --- a/templates/inn_create.html +++ b/templates/inn_create.html @@ -5,12 +5,12 @@
- +
- +
@@ -18,12 +18,12 @@
- +
- +
@@ -31,7 +31,7 @@
- +
@@ -44,12 +44,12 @@
- +
- +
@@ -57,44 +57,44 @@
- +
- - - + + +
-

The Private inn can not be changed to other type.

+

{{ "inn_type"|l10n(page_data.lang) }}

- +
-

An early bird will be Fellow automatically.

+

{{ "early_birds_help"|l10n(page_data.lang) }}

- +
-

How long before users are blocked from editing? (set 0 to allow anytime)

+

{{ "limit_edit_seconds_help"|l10n(page_data.lang) }}

@@ -104,7 +104,7 @@
- +
diff --git a/templates/inn_edit.html b/templates/inn_edit.html index 4af20996..6f2e9306 100644 --- a/templates/inn_edit.html +++ b/templates/inn_edit.html @@ -16,9 +16,9 @@
-

Please clear browser cache (ctrl + f5)

+

{{ "avatar_help"|l10n(page_data.lang) }}

- +
@@ -30,12 +30,12 @@
- +
- +
@@ -43,12 +43,12 @@
- +
- +
@@ -56,7 +56,7 @@
- +
@@ -69,12 +69,12 @@
- +
- +
@@ -82,29 +82,29 @@
- +
{% if inn.inn_type == 0 %} - - - + + + {% else if inn.inn_type == 5 %} - - - + + + {% else if inn.inn_type == 20 %} - - - + + + {% else if inn.inn_type == 10 %} - - + + {% else if inn.inn_type == 30 %} - - + + {% endif %}
@@ -113,28 +113,28 @@
- +
-

An early bird will be Fellow automatically.

+

{{ "early_birds_help"|l10n(page_data.lang) }}

- +
-

How long before users are blocked from editing? (set 0 to allow anytime)

+

{{ "limit_edit_seconds_help"|l10n(page_data.lang) }}

@@ -144,7 +144,7 @@
- +
@@ -156,14 +156,14 @@
- +
- +
-

Submit url again to unsubscribe.

+

{{ "inn_feed_help"|l10n(page_data.lang) }}

@@ -173,7 +173,7 @@
- +
diff --git a/templates/inn_list.html b/templates/inn_list.html index 75de91f8..39153774 100644 --- a/templates/inn_list.html +++ b/templates/inn_list.html @@ -11,26 +11,26 @@
@@ -76,29 +76,29 @@
@@ -224,14 +224,14 @@

Delete permanently?

diff --git a/templates/post_create.html b/templates/post_create.html index 495468af..dc99d131 100644 --- a/templates/post_create.html +++ b/templates/post_create.html @@ -19,7 +19,7 @@
- +
@@ -52,14 +52,14 @@
@@ -159,37 +159,37 @@
@@ -30,12 +30,12 @@
- +
- +
@@ -56,12 +56,12 @@
- +
- +
@@ -69,7 +69,7 @@
- +
@@ -77,13 +77,33 @@
+
+
+
+
+
+ +
+
+ +
+
+
+
+
+
@@ -96,7 +116,7 @@
- +
@@ -108,7 +128,7 @@
- +
@@ -121,7 +141,7 @@
- +
@@ -134,7 +154,7 @@
- +
@@ -150,7 +170,7 @@
- +
@@ -163,14 +183,14 @@
- +
-

You must input your password to generate or reset your recovery code.

+

{{ "recovery_help"|l10n(page_data.lang) }}

@@ -180,7 +200,7 @@
- +
@@ -190,15 +210,15 @@
-

Sessions

+

{{ "sessions"|l10n(page_data.lang) }}

    {% match page_data.claim %} {% when Some(val) %} {% for i in sessions %} {% if val.session_id.as_str() == i %} -
  • {{i}}: current(Sign out)
  • +
  • {{i}}: current({{ "sign_out"|l10n(page_data.lang) }})
  • {% else %} -
  • {{i}}: remove
  • +
  • {{i}}: {{ "remove"|l10n(page_data.lang) }}
  • {% endif %} {% endfor %} {% else %} diff --git a/typos.toml b/typos.toml new file mode 100644 index 00000000..095019a2 --- /dev/null +++ b/typos.toml @@ -0,0 +1,5 @@ +[default.extend-words] +Fo = "Fo" +Limite = "Limite" +valide = "valide" +adresse = "adresse" \ No newline at end of file