Weighs the soul of incoming HTTP requests to stop AI crawlers

feat(localization): Add Traditional Chinese language translation (#759)

* Add translation for Traditional Chinese

* Add translation for Traditional Chinese: test

* Add translation for Traditional Chinese: Add PR number to CHANGELOG

* Add translation for Traditional Chinese: test: remove empty lines

* Add translation for Traditional Chinese: test: remove empty lines

authored by XLion and committed by GitHub 289c802a 543b942b

Changed files
+88 -1
docs
lib
+1
docs/docs/CHANGELOG.md
··· 29 29 - Add translation for Turkish language ([#751](https://github.com/TecharoHQ/anubis/pull/751)) 30 30 - Allow [Common Crawl](https://commoncrawl.org/) by default so scrapers have less incentive to scrape 31 31 - The [bbolt storage backend](./admin/policies.mdx#bbolt) now runs its cleanup every hour instead of every five minutes. 32 + - Add translation for Traditional Chinese ([#759](https://github.com/TecharoHQ/anubis/pull/759)) 32 33 33 34 ### Potentially breaking changes 34 35
+1 -1
lib/localization/locales/manifest.json
··· 1 1 { 2 - "supportedLanguages": ["en", "fr", "es", "pt-BR", "de", "tr"] 2 + "supportedLanguages": ["en", "fr", "es", "pt-BR", "de", "tr", "zh-TW"] 3 3 }
+63
lib/localization/locales/zh-TW.json
··· 1 + { 2 + "loading": "載入中...", 3 + "why_am_i_seeing": "為什麼我看到這個?", 4 + "protected_by": "保護由", 5 + "made_with": "在 🇨🇦 用 ❤️ 製作", 6 + "mascot_design": "吉祥物由", 7 + "ai_companies_explanation": "您會看到這個畫面,是因為網站管理員啟用了 Anubis 來保護伺服器,避免 AI 公司大量爬取網站內容。這類行為會導致網站當機,讓所有使用者都無法正常存取資源。", 8 + "anubis_compromise": "Anubis 是一種折衷做法。它採用了類似 Hashcash 的工作量證明機制(Proof-of-Work),該機制最初是為了減少垃圾郵件而提出。其核心概念是:對個別使用者而言,額外的運算負擔可以忽略,但對大規模爬蟲來說,累積起來的成本將大幅增加,從而讓爬取行為變得更困難。", 9 + "hack_purpose": "本質上,這是一種權宜的解法,目的是提供一個「夠用」的暫時性防護措施,好讓開發者有更多時間針對無頭瀏覽器進行指紋特徵辨識(例如:分析其字型渲染方式),以便未來不再需要對可能為合法使用者的訪客展示工作量證明頁面。", 10 + "jshelter_note": "請注意,Anubis 需要使用現代 JavaScript 功能,而像 JShelter 這類外掛可能會阻擋這些功能。請為此網域停用 JShelter 或類似的插件。", 11 + "version_info": "這個網站正在運行 Anubis 版本", 12 + "try_again": "再試一次", 13 + "go_home": "回首頁", 14 + "contact_webmaster": "或者您覺得您不應該被封鎖,請聯絡站點管理員於", 15 + "connection_security": "請稍等,我們需要在繼續之前檢閱您的連線安全性。", 16 + "javascript_required": "很遺憾,您必須啟用 JavaScript 才能通過這項驗證。這是因為 AI 公司已經改變了網站託管的社會契約,因此我們必須採取這樣的保護機制。無需 JavaScript 的解法仍在開發中。", 17 + "benchmark_requires_js": "執行基準測試工具需要啟用 JavaScript。", 18 + "difficulty": "難度:", 19 + "algorithm": "演算法:", 20 + "compare": "比較:", 21 + "time": "時間", 22 + "iters": "迭代", 23 + "time_a": "時間 A", 24 + "iters_a": "迭代 A", 25 + "time_b": "時間 B", 26 + "iters_b": "迭代 B", 27 + "static_check_endpoint": "這是提供給您的反向代理伺服器使用的檢查端點。", 28 + "authorization_required": "需要認證", 29 + "cookies_disabled": "您的瀏覽器目前已停用 Cookie,為了確認您是合法使用者,Anubis 需要啟用 Cookie。 請為此網域啟用 Cookie", 30 + "access_denied": "拒絕存取:錯誤代碼", 31 + "dronebl_entry": "DroneBL 回報了一筆紀錄", 32 + "see_dronebl_lookup": "見", 33 + "internal_server_error": "內部伺服器錯誤:管理員錯誤地配置了 Anubis。 請聯絡管理員要求他們檢閱日誌", 34 + "invalid_redirect": "無效的重新導向", 35 + "redirect_not_parseable": "重新導向 URL 無法解析", 36 + "redirect_domain_not_allowed": "重新導向的網域並不允許", 37 + "failed_to_sign_jwt": "簽署 JWT 失敗", 38 + "invalid_invocation": "無效的 MakeChallenge 呼叫", 39 + "client_error_browser": "客戶端錯誤:請確保您的瀏覽器是最新版本並稍候再試。", 40 + "oh_noes": "哎呀糟糕了!", 41 + "benchmarking_anubis": "正在進行 Anubis 效能測試!", 42 + "you_are_not_a_bot": "你不是機器人!", 43 + "making_sure_not_bot": "正在確認你是不是機器人!", 44 + "celphase": "CELPHASE 設計", 45 + "js_web_crypto_error": "您的瀏覽器無法正常使用 web.crypto 元件。您是否透過安全連線(HTTPS)檢視此網站?", 46 + "js_web_workers_error": "您的瀏覽器並不支援 Web workers (Anubis 使用這個來避免凍結您的瀏覽器 )您有安裝像是 JShelter 之類的插件嗎?", 47 + "js_cookies_error": "您的瀏覽器無法儲存 Cookie。 Anubis 會使用 Cookie 儲存簽署的憑證,以判斷使用者是否已通過驗證。請為此網域啟用 Cookie 儲存功能。 請注意,Anubis 儲存的 Cookie 名稱可能會變動,且其名稱與內容不屬於公開 API 的一部分。", 48 + "js_context_not_secure": "您的內容並不安全", 49 + "js_context_not_secure_msg": "請嘗試使用 HTTPS 連線,或聯繫網站管理員設定 HTTPS。更多資訊請參見 <a href=\"https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts#when_is_a_context_considered_secure\">MDN</a>。", 50 + "js_calculating": "計算中...", 51 + "js_missing_feature": "缺少功能", 52 + "js_challenge_error": "挑戰錯誤!", 53 + "js_challenge_error_msg": "解決檢查演算法失敗。 您可能會想要重整頁面。", 54 + "js_calculating_difficulty": "計算中...<br/>難度:", 55 + "js_speed": "速度:", 56 + "js_verification_longer": "驗證所花的時間高於預期。 請不要重整頁面。", 57 + "js_success": "成功!", 58 + "js_done_took": "完成! 花費", 59 + "js_iterations": "迭代", 60 + "js_finished_reading": "我讀完了,繼續 →", 61 + "js_calculation_error": "計算錯誤!", 62 + "js_calculation_error_msg": "計算挑戰失敗:" 63 + }
+23
lib/localization/localization_test.go
··· 43 43 } 44 44 }) 45 45 46 + t.Run("Traditional Chinese localization", func(t *testing.T) { 47 + localizer := service.GetLocalizer("zh-TW") 48 + result := localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "loading"}) 49 + if result != "載入中..." { 50 + t.Errorf("Expected '載入中...', got '%s'", result) 51 + } 52 + }) 53 + 46 54 t.Run("All required keys exist in English", func(t *testing.T) { 47 55 localizer := service.GetLocalizer("en") 48 56 requiredKeys := []string{ ··· 75 83 76 84 t.Run("All required keys exist in Turkish", func(t *testing.T) { 77 85 localizer := service.GetLocalizer("tr") 86 + requiredKeys := []string{ 87 + "loading", "why_am_i_seeing", "protected_by", "made_with", 88 + "mascot_design", "try_again", "go_home", "javascript_required", 89 + } 90 + 91 + for _, key := range requiredKeys { 92 + result := localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: key}) 93 + if result == "" { 94 + t.Errorf("Key '%s' returned empty string", key) 95 + } 96 + } 97 + }) 98 + 99 + t.Run("All required keys exist in Traditional Chinese", func(t *testing.T) { 100 + localizer := service.GetLocalizer("zh-TW") 78 101 requiredKeys := []string{ 79 102 "loading", "why_am_i_seeing", "protected_by", "made_with", 80 103 "mascot_design", "try_again", "go_home", "javascript_required",