diff --git a/api/routes.py b/api/routes.py index 63739194..d55df8fa 100644 --- a/api/routes.py +++ b/api/routes.py @@ -2561,6 +2561,15 @@ _LOGIN_LOCALE = { "invalid_pw": "\ube44\ubc00\ubc88\ud638\uac00 \uc62c\ubc14\ub974\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4", "conn_failed": "\uc5f0\uacb0 \uc2e4\ud328", }, + "tr": { + "lang": "tr-TR", + "title": "Oturum a\u00e7", + "subtitle": "Devam etmek i\u00e7in \u015fifrenizi girin", + "placeholder": "\u015eifre", + "btn": "Oturum a\u00e7", + "invalid_pw": "Ge\u00e7ersiz \u015fifre", + "conn_failed": "Ba\u011flant\u0131 ba\u015far\u0131s\u0131z", + }, } diff --git a/static/i18n.js b/static/i18n.js index 5e54d9d6..867b8d58 100644 --- a/static/i18n.js +++ b/static/i18n.js @@ -13110,6 +13110,1223 @@ const LOCALES = { usage_total: 'Total de tokens', usage_unknown: 'inconnu', workspace_auto_create_folder: 'Créer le dossier s\'il n\'existe pas', + }, + + tr: { + + offline_title: 'Bağlantı kesildi', + offline_browser_detail: 'Tarayıcınız bu cihazın çevrimdışı olduğunu bildiriyor.', + offline_network_detail: 'Hermes\'e şu anda bu tarayıcıdan ulaşılamıyor.', + offline_autorefresh: 'Hermes\'e tekrar ulaşılabilir olduğunda bu sayfayı otomatik olarak yenileyeceğim.', + offline_check_now: 'Şimdi kontrol et', + offline_checking: 'Kontrol ediliyor\\u2026', + offline_stream_waiting: 'Bağlantı kesildi. Yenilenmesi bekleniyor\\u2026', + _lang: 'tr', + _label: 'Türkçe', + _speech: 'tr-TR', + // boot.js + cancelling: 'İptal ediliyor\\u2026', + cancel_failed: 'İptal başarısız oldu:', + mic_denied: 'Mikrofon erişimi reddedildi. Tarayıcı izinlerini kontrol edin.', + mic_no_speech: 'Konuşma algılanmadı. Tekrar deneyin.', + mic_network: 'Konuşma tanıma kullanılamıyor.', + mic_error: 'Ses girişi hatası:', + session_imported: 'Oturum içe aktarıldı', + import_failed: 'İçe aktarma başarısız oldu:', + import_invalid_json: 'Geçersiz JSON', + image_pasted: 'Yapıştırılan resim:', + // messages.js + edit_message: 'Mesajı düzenle', + regenerate: 'Yanıtı yeniden oluştur', + copy: 'Kopyala', + copied: 'Kopyalandı!', + copy_failed: 'Kopyalama başarısız oldu', + selected_text_reply: 'Seçimle yanıtla', + selected_text_reply_title: 'Seçilen sohbet metnini alıntılanan bağlam olarak ekle', + selected_text_reply_appended: 'Seçilen metin besteciye eklendi', + + diff_loading: 'Fark yükleniyor', + diff_error: 'Yama dosyası yüklenemedi', + diff_too_large: 'Yama dosyası satır içi görüntülenemeyecek kadar büyük', + tree_view: 'Ağaç', + raw_view: 'Çiğ', + parse_failed_note: 'ayrıştırma başarısız oldu', + you: 'Sen', + mcp_servers_title: 'MCP Sunucuları', + mcp_servers_desc: 'config.yaml dosyasında yapılandırılmış MCP sunucularını görüntüleyin.', + mcp_no_servers: 'Hiçbir MCP sunucusu yapılandırılmadı.', + mcp_add_server: '+ Sunucu Ekle', + mcp_field_name: 'Sunucu Adı', + mcp_transport_label: 'Taşıma Türü', + mcp_field_command: 'Emretmek', + mcp_field_args: 'Bağımsız Değişkenler (virgülle ayrılmış)', + mcp_field_url: 'URL\'si', + mcp_field_timeout: 'Zaman aşımı (saniye)', + mcp_save: 'Kaydetmek', + mcp_cancel: 'İptal etmek', + mcp_name_required: 'Sunucu adı gerekli.', + mcp_url_required: 'HTTP aktarımı için URL gereklidir.', + mcp_command_required: 'Stdio aktarımı için komut gereklidir.', + mcp_saved: 'MCP sunucusu kaydedildi.', + mcp_save_failed: 'MCP sunucusu kaydedilemedi.', + mcp_delete_confirm_title: 'MCP Sunucusunu Sil', + mcp_delete_confirm_message: '"{0}" MCP sunucusu silinsin mi? Bu eylem geri alınamaz.', + mcp_deleted: 'MCP sunucusu silindi.', + mcp_delete_failed: 'MCP sunucusu silinemedi.', + mcp_load_failed: 'MCP sunucuları yüklenemedi.', + mcp_restart_hint: 'Sunucu değişiklikleri şimdilik burada salt okunurdur. Değişikliklerin etkili olması için config.yaml dosyasını düzenleyin ve Hermes\'i yeniden başlatın.', + mcp_toggle_followup: 'Etkinleştirme/devre dışı bırakma kontrolleri, MCP yeniden yükleme semantiği açıkça ortaya çıkana kadar kasıtlı olarak ertelenir.', + mcp_status_active: 'Aktif', + mcp_status_configured: 'Yapılandırılmış', + mcp_status_disabled: 'Engelli', + mcp_status_invalid_config: 'Geçersiz yapılandırma', + mcp_status_unknown: 'Bilinmiyor', + mcp_tool_count: '{0} araç', + mcp_enabled_yes: 'Etkinleştirilmiş', + mcp_enabled_no: 'Engelli', + mcp_tools_title: 'MCP Araçları', + mcp_tools_desc: 'Aktif MCP sunucularında bilinen araçları arayın.', + mcp_tools_search_placeholder: 'Araçlarda ada, sunucuya veya açıklamaya göre arama yapın\\u2026', + mcp_tools_no_tools: 'Etkin çalışma zamanı envanterinde hiçbir MCP aracı mevcut değil.', + mcp_tools_no_matches: 'Aramanızla eşleşen MCP aracı yok.', + mcp_tools_load_failed: 'MCP araçları yüklenemedi.', + mcp_tools_schema_empty: 'Şema parametresi yok.', + mcp_tools_runtime_note: 'Araç envanteri yalnızca önceden bilinen etkin MCP çalışma zamanı verilerini kullanır; WebUI sunucuları başlatmaz veya sorgulamaz.', + mcp_tools_summary_no_matches: (query,total) => `“${query}” ile eşleşen MCP aracı yok (toplam ${total} MCP araç).`, + mcp_tools_summary_none: 'Gösterilecek MCP aracı yok.', + mcp_tools_summary_matching: (query) => `"${query}" ile eşleşen`, + mcp_tools_summary_total_note: (total) => `(${total} toplam MCP araç)`, + mcp_tools_summary_showing: (start,end,filtered,searchNote,totalNote,page,pages) => `${start}-${end} / ${filtered} MCPtools${searchNote}${totalNote} gösteriliyor. Sayfa ${page} / ${pages}.`, + mcp_tools_page_size_prefix: 'Göstermek', + mcp_tools_page_size_suffix: 'sayfa başına', + mcp_tools_per_page_aria: 'Sayfa başına MCP araçları', + mcp_tools_inactive_configured_servers: (servers) => `Yapılandırılmış ancak bu WebUI çalışma zamanında etkin değil: ${servers}.`, + mcp_tools_pagination_label: 'MCP araçları sayfalandırması', + mcp_tools_previous_page: '‹ Önceki', + mcp_tools_previous_page_aria: 'Önceki MCP araçları sayfası', + mcp_tools_next_page: 'Sonraki >', + mcp_tools_next_page_aria: 'Sonraki MCP araçları sayfası', + thinking: 'Düşünme', + expand_all: 'Tümünü genişlet', + collapse_all: 'Tümünü daralt', + edit_failed: 'Düzenleme başarısız oldu:', + regen_failed: 'Yeniden oluşturma başarısız oldu:', + reconnect_active: 'Halen bir yanıt oluşturuluyor. Hazır olduğunuzda yeniden yüklensin mi?', + reconnect_finished: 'En son ayrıldığınızda bir yanıt sürüyordu. Mesajlar güncellenmiş olabilir.', + // approval card + approval_heading: 'Onay gerekli', + approval_desc_prefix: 'Tehlikeli komut algılandı', + approval_btn_once: 'Bir kez izin ver', + approval_btn_once_title: 'Bu tek komuta izin ver (Enter)', + approval_btn_session: 'Oturuma izin ver', + approval_btn_session_title: 'Bu konuşma oturumuna izin ver', + approval_btn_always: 'Her zaman izin ver', + approval_btn_always_title: 'Bu komut düzenine her zaman izin ver', + approval_btn_deny: 'Reddetmek', + approval_btn_deny_title: 'Reddet — bu komutu çalıştırma', + approval_responding: 'Yanıt veriliyor\\u2026', + clarify_heading: 'Açıklama gerekli', + clarify_hint: 'Bir seçim yapın veya kendi cevabınızı aşağıya yazın.', + clarify_other: 'Diğer', + clarify_send: 'Göndermek', + clarify_input_placeholder: 'Yanıtınızı yazın\\u2026', + clarify_responding: 'Yanıt veriliyor\\u2026', + untitled: 'İsimsiz', + n_messages: (n) => `${n}개 메시지`, + load_older_messages: '↑ Eski mesajları yüklemek için yukarı kaydırın veya tıklayın', + session_jump_start: 'Başlangıç', + session_jump_start_label: 'Oturumun başlangıcına atla', + session_jump_end: 'Son', + session_jump_end_label: 'Oturumun sonuna atla', + jump_to_question: 'sorgulamak', + jump_to_question_label: 'Bu yanıt için soruya geçin', + queued_label: 'Yanıttan sonra gönderilir', + queued_count: (n) => n === 1 ? '1 queued' : `${n} queued`, + queued_cancel: 'Sıraya alınmış mesajı iptal et', + model_unavailable: '(mevcut değil)', + model_unavailable_title: 'Bu model artık mevcut sağlayıcı listenizde değil', + provider_mismatch_warning: (m,p) => `"${m}" yapılandırılmış sağlayıcınızla (${p}) çalışmayabilir. Yine de gönderin veya geçiş yapmak için terminalinizde \`hermes model\` komutunu çalıştırın.`, + provider_mismatch_label: 'Sağlayıcı uyumsuzluğu', + model_not_found_label: 'Model bulunamadı', + model_custom_label: 'Özel model kimliği', + model_custom_placeholder: 'örneğin openai/gpt-5.4', + model_search_placeholder: 'Modelleri ara\\u2026', + session_toolsets: 'Session Toolsets', // TODO: translate + session_toolsets_desc: 'Restrict available tools for this session (blank = use global config)', // TODO: translate + session_toolsets_global: 'Global (default)', // TODO: translate + session_toolsets_custom: 'Custom', // TODO: translate + session_toolsets_placeholder: 'tool1, tool2, \u2026', // TODO: translate + session_toolsets_apply: 'Apply', // TODO: translate + session_toolsets_clear: 'Clear (use global)', // TODO: translate + session_toolsets_applied: 'Toolsets updated', // TODO: translate + session_toolsets_cleared: 'Toolsets cleared — using global config', // TODO: translate + session_toolsets_failed: 'Failed to update toolsets: ', // TODO: translate + model_search_no_results: 'Hiçbir model bulunamadı', + model_group_configured: 'Yapılandırılmış', + ws_search_placeholder: 'Çalışma alanlarını arayın\\u2026', + ws_no_results: 'Çalışma alanı bulunamadı', + workspace_new_worktree_conversation: 'Worktree\'de yeni konuşma', + workspace_new_worktree_conversation_meta: 'Bu çalışma alanı için yalıtılmış bir git çalışma ağacı oluşturun.', + workspace_worktree_created: 'Worktree görüşmesi oluşturuldu', + workspace_worktree_failed: 'Çalışma ağacı oluşturma işlemi başarısız oldu:', + session_worktree_badge: 'Çalışma Ağacı', + model_scope_advisory: 'Bir sonraki mesajınızdan itibaren bu görüşmeye uygulanır.', + model_scope_toast: 'Bir sonraki mesajınızdan itibaren bu görüşmeye uygulanır.', + // commands.js + cmd_clear: 'Konuşma mesajlarını temizle', + cmd_compress: 'Konuşma içeriğini manuel olarak sıkıştırın (kullanım: /compress [konuya odaklan])', + ctx_compress_hint: 'Yer açmak için bağlamı sıkıştırın →', + ctx_compress_action: '⚠ Şimdi serbest bağlama sıkıştırın', + cmd_compact_alias: '/compress için eski takma ad', + cmd_model: 'Modeli değiştir (ör. /model gpt-4o)', + cmd_workspace: 'Çalışma alanını ada göre değiştir', + cmd_terminal: 'Çalışma alanı terminalini açın', + cmd_new: 'Yeni bir sohbet oturumu başlatın', + cmd_usage: 'Token kullanımı ekranını aç/kapat', + cmd_theme: 'Görünümü değiştir (tema: system/dark/light, skin: default/ares/mono/slate/poseidon/sisyphus/charizard/sienna/catppuccin/nous/geist-contrast)', + cmd_personality: 'Temsilci kişiliğini değiştir', + cmd_skills: 'Mevcut Hermes becerilerini listele', + available_commands: 'Mevcut komutlar:', + type_slash: 'Komutları görmek için / yazın', + conversation_cleared: 'Görüşme temizlendi', + command_label: 'Emretmek', + context_compaction_label: 'Bağlam sıkıştırma', + retrieval_context_label: 'Dizine alınmış bağlam', + retrieval_context_preview: 'Daha önceki mesajlar depolanır ve bağlam araçlarıyla alınabilir', + preserved_task_list_label: 'Korunmuş görev listesi', + reference_only_label: 'Yalnızca referans', + model_usage: 'Kullanım: /model ', + no_model_match: 'Eşleşen model yok"', + switched_to: 'Şuraya geçildi:', + workspace_usage: 'Kullanım: /workspace ', + no_workspace_match: 'Eşleşen çalışma alanı yok "', + switched_workspace: 'Çalışma alanına geçildi:', + workspace_switch_failed: 'Çalışma alanı anahtarı başarısız oldu:', + new_session: 'Yeni oturum oluşturuldu', + new_session_creating: 'Yeni görüşme oluşturuluyor\\u2026', + compressing: 'Bağlam sıkıştırması isteniyor...', + compress_running_label: 'Sıkıştırma', + compress_complete_label: 'Sıkıştırma tamamlandı', + auto_compress_label: 'Otomatik sıkıştırma', + compress_failed_label: 'Sıkıştırma başarısız oldu', + focus_label: 'Odak', + token_usage_on: 'Jeton kullanımı açık', + token_usage_off: 'Jeton kullanımı kapalı', + usage_cache_hit_detail: 'Önbellek: %{0} isabet ({1} okuma / {2} yazma)', + usage_cached_percent: '%{0} önbelleğe alındı', + theme_usage: 'Kullanım: /tema', + theme_set: 'Tema:', + no_active_session: 'Aktif oturum yok', + cmd_queue: 'Bir sonraki dönüş için bir mesajı sıraya koy', + cmd_goal: 'Kalıcı bir hedef belirleyin veya inceleyin', + goal_evaluating_progress: 'Hedef ilerlemesi değerlendiriliyor\\u2026', + goal_working_toward: 'Hedefe doğru çalışmak\\u2026', + goal_continuing_toast: 'Hedefe doğru devam\\u2026', + goal_status_none: 'Aktif hedef yok. /goal ile bir tane ayarlayın.', + goal_status_active: (turns, max_turns, goal) => `⊙ Hedef (aktif, ${turns}/${max_turns} tur): ${goal}`, + goal_status_paused: (turns, max_turns, reason, goal) => `⏸ Hedef (duraklatıldı, ${turns}/${max_turns}${reason ? `, ${reason}` : ''}): ${goal}`, + goal_status_done: (turns, max_turns, goal) => `✓ Hedef tamamlandı (${turns}/${max_turns}): ${goal}`, + goal_set: (turns, goal) => `⊙ Hedef belirlendi (${turns}-dönüş bütçesi): ${goal}`, + goal_paused: (goal) => `⏸ Hedef duraklatıldı: ${goal}`, + goal_resumed: (goal) => `▶ Hedef devam ettirildi: ${goal}`, + goal_cleared: 'Hedef temizlendi.', + goal_no_goal: 'Aktif hedef yok.', + goal_achieved: (reason) => `✓ Hedefe ulaşıldı: ${reason}`, + goal_paused_budget_exhausted: (turns, max_turns) => `⏸ Hedef duraklatıldı — ${turns}/${max_turns} tur kullanıldı. Devam etmek için /goal devamını, durdurmak için /goal clear komutunu kullanın.`, + goal_continuing: (turns, max_turns, reason) => `↻ Hedefe doğru devam ediyoruz (${turns}/${max_turns}): ${reason}`, + cmd_interrupt: 'Mevcut dönüşü iptal et ve yeni bir mesaj gönder', + cmd_steer: 'Temsilciyi kesintiye uğratmadan dönüş ortası düzeltmesi enjekte edin', + cmd_queue_no_msg: 'Kullanım: /queue ', + cmd_queue_not_busy: 'Etkin görev yok; yalnızca normal şekilde gönderin', + cmd_queue_confirm: 'İleti sıraya alındı', + cmd_interrupt_no_msg: 'Kullanım: /interrupt ', + cmd_interrupt_confirm: 'Kesintiye uğradı — yeni mesaj gönderilir', + cmd_steer_no_msg: 'Kullanım: /steer ', + cmd_steer_fallback: 'Yönlendirme kullanılamıyor - bunun yerine bir sonraki dönüş için sıraya alındı', + cmd_steer_delivered: 'Yönlendirme teslim edildi — temsilci bunu bir sonraki takım sonucunda görecek', + steer_leftover_queued: 'Direksiyon bir sonraki dönüş için kuyruğa alındı', + busy_steer_fallback: 'Yönlendirme kullanılamıyor — bir sonraki dönüş için kuyruğa alındı', + busy_interrupt_confirm: 'Kesintiye uğradı — yeni mesaj gönderilir', + settings_label_busy_input_mode: 'Meşgul giriş modu', + settings_desc_busy_input_mode: 'Aracı çalışırken bir mesaj gönderdiğinizde ne olacağını kontrol eder. Sıra bekler; Interrupt iptal eder ve yeniden başlar; Steer, dönüşün ortasında kesintiye uğramadan bir düzeltme enjekte eder (aracı veya akış mevcut olmadığında kuyruğa geri döner).', + settings_label_fade_text_effect: 'Metin efektini soldur', + settings_desc_fade_text_effect: 'Asistan yanıt verirken yeni aktarılan sözcüklerin geçişini sağlayın. OpenWebUI\'ye benzer; Maksimum performans için varsayılan olarak kapalıdır.', + settings_busy_input_mode_queue: 'Sıra takibi', + settings_busy_input_mode_interrupt: 'Mevcut dönüşü kes', + settings_busy_input_mode_steer: 'Yönlendirme (dönüş ortası düzeltme)', + + slash_skill_badge: 'Yetenek', + slash_skill_desc: 'Bu beceriyi çağır', + cmd_stop: 'Mevcut yanıtı durdur', + cmd_title: 'Oturum başlığını alın veya ayarlayın', + cmd_retry: 'Son mesajı tekrar gönder', + cmd_undo: 'Son değişimi kaldır', + cmd_btw: 'Bir yan soru sorun (geçici)', + cmd_btw_usage: '/btw — oturum bağlamını kullanarak bir yan soru sorun', + cmd_background: 'Arka planda bir istem çalıştır', + cmd_background_usage: '/background — engellemeden paralel olarak çalıştır', + btw_asking: 'Yan soruyu sormak...', + btw_label: 'Yan soru – tarihte değil', + btw_done: 'Yan soru cevaplandı', + btw_no_answer: 'Cevap alınmadı.', + btw_failed: 'Yan soru başarısız oldu:', + bg_running: 'Arka planda çalışıyor...', + bg_complete: 'Arka plan görevi tamamlandı', + bg_label: 'Arka plan sonucu:', + bg_no_answer: '(cevap yok)', + bg_failed: 'Arka plan görevi başarısız oldu:', + undo_exchange: 'Son değişimi geri al', + cmd_status: 'Oturum bilgilerini göster', + cmd_voice: 'Mikrofon girişini değiştir', + stream_stopped: 'Yanıt durduruldu.', + no_active_task: 'Durdurulacak etkin görev yok.', + cancel_unavailable: 'İptal kullanılamıyor.', + retry_failed: 'Yeniden deneme başarısız oldu:', + undo_failed: 'Geri alma başarısız oldu:', + undid_n_messages: 'Kaldırıldı', + undid_messages_suffix: 'mesaj(lar).', + status_heading: 'Oturum Durumu', + status_session_id: 'Oturum Kimliği', + status_title: 'Başlık', + status_model: 'Modeli', + status_provider: 'sağlayıcı', + status_workspace: 'Çalışma alanı', + status_personality: 'Kişilik', + status_messages: 'Mesajlar', + status_agent_running: 'Aracı çalışıyor', + status_profile: 'Profil', + status_hermes_home: 'Hermes\'in evi', + status_started: 'Başlatıldı', + status_tokens: 'Jetonlar', + status_updated: 'Güncellendi', + status_ephemeral: 'Geçici anlık görüntü — transkript geçmişine kaydedilmez.', + status_no_tokens: 'Hiç jeton kullanılmadı', + status_unknown: 'Bilinmiyor', + status_yes: 'Evet', + status_no: 'HAYIR', + status_load_failed: 'Durum yüklenemedi:', + title_current: 'Mevcut başlık', + title_change_hint: 'Yeniden adlandırmak için `/title ` kullanın.', + title_set: 'Başlık şu şekilde ayarlandı:', + cmd_webui_only_session: 'Bu komut CLI\'den içe aktarılan oturumlar için kullanılamaz.', + cmd_voice_use_mic: 'Bestecideki mikrofon düğmesine tıklayın.', + usage_heading: 'Jeton Kullanımı', + usage_default_model: 'varsayılan', + usage_unknown: 'bilinmiyor', + usage_input_tokens: 'Giriş jetonları', + usage_output_tokens: 'Çıkış jetonları', + usage_total: 'Toplam jeton', + usage_estimated_cost: 'Tahmini maliyet', + usage_settings_tip: 'Not: Maliyet tahminleri yaklaşık değerlerdir.', + usage_load_failed: 'Kullanım yüklenemedi:', + usage_personality_none: 'hiçbiri', + no_personalities: 'Hiç kişilik bulunamadı (onları ~/.hermes/personalities/ dosyasına ekleyin)', + available_personalities: 'Mevcut kişilikler:', + personality_switch_hint: 'Geçiş yapmak için `/kişilik ` kullanın veya temizlemek için `/kişilik yok` kullanın.', + personalities_load_failed: 'Kişilikler yüklenemedi', + personality_cleared: 'Kişilik temizlendi', + personality_set: 'Kişilik:', + failed_colon: 'Arızalı:', + // ui.js + no_workspace: 'Çalışma alanı yok', + terminal_open_title: 'Çalışma alanı terminalini aç', + terminal_no_workspace_title: 'Terminali açmak için bir çalışma alanı seçin', + terminal_title: 'terminal', + terminal_clear: 'Temizle', + terminal_copy_output: 'Çıktıyı kopyala', + terminal_restart: 'Tekrar başlat', + terminal_collapse: 'Yıkılmak', + terminal_expand: 'Genişletmek', + terminal_close: 'Kapalı', + terminal_input_placeholder: 'Bir komut çalıştır...', + terminal_start_failed: 'Terminal başlatma başarısız oldu:', + terminal_input_failed: 'Terminal girişi başarısız oldu:', + terminal_copy_failed: 'Kopyalama başarısız oldu:', + terminal_error: 'Terminal hatası', + workspace_empty_no_path: 'Çalışma alanı seçilmedi. Dosyalara göz atmak için Ayarlar \\u2192 Çalışma Alanı\'nda bir çalışma alanı ayarlayın.', + workspace_empty_dir: 'Bu çalışma alanı boş.', + workspace_show_hidden_files: 'Gizli dosyaları göster', + workspace_show_hidden_files_desc: 'Dosya ağacına .DS_Store, .git, node_modules ve diğer gizli / sistem dosyalarını ekleyin.', + workspace_hidden_files_visible: 'gizli görünür', + workspace_hidden_files_visible_title: 'Gizli dosyalar görünür — seçenekler için tıklayın', + workspace_options: 'Çalışma alanı seçenekleri', + dialog_confirm_title: 'İşlemi onayla', + dialog_prompt_title: 'Bir değer girin', + dialog_confirm_btn: 'Onaylamak', + // workspace.js + unsaved_confirm: 'Önizlemede kaydedilmemiş değişiklikleriniz var. Atılıp gezinilsin mi?', + discard: 'At', + save: 'Kaydetmek', + edit: 'Düzenlemek', + clear: 'Temizle', + create: 'Yaratmak', + remove: 'Kaldırmak', + save_title: 'Değişiklikleri kaydet', + edit_title: 'Bu dosyayı düzenle', + saved: 'Kaydedildi', + save_failed: 'Kaydetme başarısız oldu:', + image_load_failed: 'Resim yüklenemedi', + file_open_failed: 'Dosya açılamadı', + downloading: (name) => `${name} indiriliyor\u2026`, + double_click_rename: 'Yeniden adlandırmak için çift tıklayın', + renamed_to: 'Yeniden adlandırıldı', + rename_failed: 'Yeniden adlandırma başarısız oldu:', + delete_title: 'Silmek', + delete_confirm: (name) => `${name}을(를) nerelisin?`, + delete_dir_confirm: (name) => `"${name}" ne işe yaradı?`, + rename_title: 'Yeniden isimlendirmek', + rename_prompt: 'Yeni isim:', + deleted: 'Silindi', + delete_failed: 'Silinemedi:', + reveal_in_finder: 'Dosya Yöneticisinde Göster', + reveal_failed: 'Açıklanamadı:', + copy_file_path: 'Dosya yolunu kopyala', + download_folder: 'Download Folder', // TODO: translate + path_copied: 'Dosya yolu panoya kopyalandı', + path_copy_failed: 'Yol kopyalanamadı:', + session_rename: 'Konuşmayı yeniden adlandır', + session_rename_desc: 'Bu görüşmenin başlığını düzenleyin', + new_file_prompt: 'Yeni dosya adı (örn. Notes.md):', + project_name_prompt: 'Proje adı:', + created: 'Oluşturuldu', + create_failed: 'Oluşturma başarısız oldu:', + new_folder_prompt: 'Yeni klasör adı:', + folder_created: 'Oluşturulan klasör', + folder_create_failed: 'Klasör oluşturulamadı:', + workspace_auto_create_folder: 'Mevcut değilse klasör oluşturun', + folder_add_as_space_btn: 'Alan Olarak Ekle', + folder_add_as_space_msg: 'Bu klasör çalışma alanı listenize yeni bir alan olarak eklensin mi?', + archive_extracted: (n, c) => `${c}개 압축 파일에서 ${n}개 파일 압축 해제됨`, + folder_add_as_space_title: 'Alan olarak eklensin mi?', + remove_title: 'Kaldırmak', + empty_dir: '(boş)', + upload_failed: 'Yükleme başarısız oldu:', + upload_too_large: (maxMb, fileMb) => `Dosya çok büyük (${fileMb} MB). Maksimum yükleme boyutu ${maxMb} MB'tır.`, + all_uploads_failed: (n) => `${n} yüklemenin tümü başarısız oldu`, + session_pin: 'Görüşmeyi sabitle', + session_unpin: 'Görüşmenin sabitlemesini kaldır', + session_pin_desc: 'Bu sohbeti en üstte tut', + session_unpin_desc: 'Sabitlenenlerden kaldır', + session_pin_failed: 'Pin başarısız oldu:', + session_move_project: 'Projeye taşı', + session_move_project_desc_has: 'Bu görüşmenin projesini değiştirin', + session_move_project_desc_none: 'Bu görüşmeye bir proje atayın', + session_archive: 'Konuşmayı arşivle', + session_hide_external: 'Listeden gizle', + session_restore: 'Konuşmayı geri yükle', + session_archive_desc: 'Arşivlendi gösterilene kadar bu konuşmayı gizle', + session_archive_worktree_desc: 'Bu konuşmayı gizle; çalışma ağacını diskte tut', + session_hide_external_desc: 'Kaynak geçmişini silmeden içe aktarılan bu oturumu WebUI\'dan gizleyin.', + session_restore_desc: 'Bu görüşmeyi ana listeye geri getir', + session_archived: 'Oturum arşivlendi', + session_archived_worktree: 'Oturum arşivlendi. Worktree diskte kalır.', + session_hidden: 'Oturum listede gizlendi', + session_restored: 'Oturum geri yüklendi', + session_archive_failed: 'Arşivleme başarısız oldu:', + session_duplicate: 'Yinelenen görüşme', + session_duplicate_desc: 'Aynı çalışma alanı ve modelle bir kopya oluşturun', + session_duplicated: 'Oturum kopyalandı', + session_duplicate_failed: 'Kopyalama başarısız oldu:', + session_stop_response: 'Yanıtı durdur', + session_stop_response_desc: 'Bu görüşme için çalışan yanıtı iptal edin', + session_delete: 'Konuşmayı sil', + session_delete_desc: 'Bu görüşmeyi kalıcı olarak kaldır', + session_delete_confirm: 'Bu görüşme silinsin mi?', + session_delete_worktree_desc: 'Yalnızca WebUI görüşmesini silin; çalışma ağacını diskte tut', + session_delete_worktree_confirm: (path) => `Ne düşünüyorsunuz? ${path}의 worktree는 디스크에 남아 있습니다.`, + session_deleted: 'Görüşme silindi', + session_deleted_worktree: 'Görüşme silindi. Worktree diskte kalır.', + session_worktree_remove: 'Çalışma ağacını kaldır', + session_worktree_remove_desc: (path) => `${path}의 git worktree를 디스크에서 삭제합니다`, + session_worktree_remove_confirm: (path) => `git worktree를 디스크에서 삭제하시겠습니까?\n\n경로: ${path}\n\n전체 worktree 디렉토리가 삭제됩니다. WebUI에 보존됩니다.`, + session_worktree_remove_not_exists: (path) => `${path}의 worktree가 디스크에 더 이상 존재하지 않습니다.`, + session_worktree_remove_confirm_label: 'Kaldırmak', + session_worktree_removed: 'Worktree kaldırıldı.', + session_worktree_remove_failed: 'Çalışma ağacı kaldırılamadı:', + session_worktree_remove_status_failed: 'Çalışma ağacı durumu okunamadı:', + session_worktree_remove_locked_by_stream: 'Kaldırılamıyor — etkin bir akış oturumu bu çalışma ağacını kullanıyor.', + session_worktree_remove_locked_by_terminal: 'Kaldırılamıyor — etkin bir terminal oturumu bu çalışma ağacını kullanıyor.', + session_worktree_remove_unsafe_blocked: 'Bu çalışma ağacını kaldırmadan önce yerel değişiklikleri veya gönderilmemiş taahhütleri çözümleyin.', + session_worktree_remove_dirty_warning: 'UYARI: Bu çalışma ağacında kaybolacak kaydedilmemiş değişiklikler var.', + session_worktree_remove_untracked_warning: (count) => `${count}개의 추적되지 않은 파일이 영구적으로 삭제됩니다.`, + session_worktree_remove_ahead_warning: (ahead) => `${ahead} 푸시되지 않은 커밋이 손실됩니다.`, + session_select_mode: 'Seçme', + session_select_mode_desc: 'Toplu olarak yönetilecek konuşmaları seçin', + session_select_all: 'Tümünü seç', + session_deselect_all: 'Tümünün seçimini kaldır', + session_selected_count: '{0} seçildi', + session_batch_archive: 'Arşiv', + session_batch_delete: 'Silmek', + session_batch_move: 'Projeye taşı', + session_batch_delete_confirm: '{0} görüşme silinsin mi?', + session_batch_archive_confirm: '{0} ileti dizisi arşivlensin mi?', + session_batch_delete_worktree_confirm: '{0} görüşme silinsin mi? {1} çalışma ağacı destekli konuşma, çalışma ağacı dizinlerini diskte bırakacak.', + session_batch_archive_worktree_confirm: '{0} ileti dizisi arşivlensin mi? {1} çalışma ağacı destekli görüşme, çalışma ağacı dizinlerini diskte tutacak.', + session_no_selection: 'Hiçbir görüşme seçilmedi', + // settings panel + settings_heading_title: 'Kontrol Merkezi', + settings_heading_subtitle: 'Tercihler, konuşma araçları ve sistem kontrolleri.', + settings_section_conversation_title: 'Konuşma', + settings_section_appearance_title: 'Dış görünüş', + settings_section_appearance_meta: 'Tema, vurgu renkleri ve görsel stil.', + settings_section_preferences_title: 'Tercihler', + settings_section_preferences_meta: 'Hermes Web Kullanıcı Arayüzü için varsayılanlar ve Kullanıcı Arayüzü davranışı.', + settings_section_system_title: 'Sistem', + settings_section_system_meta: 'Örnek sürümü ve erişim kontrolleri.', + settings_check_now: 'Şimdi kontrol et', + settings_checking: 'Kontrol ediliyor\\u2026', + settings_up_to_date: 'Güncel \\u2713', + settings_updates_available: '{count} güncelleme mevcut', + settings_updates_disabled: 'Güncelleme kontrolleri devre dışı bırakıldı', + settings_update_check_failed: 'Güncelleme kontrolü başarısız oldu', + settings_label_workspace_panel_open: 'Çalışma alanı panelini varsayılan olarak açık tut', + settings_desc_workspace_panel_open: 'Etkinleştirildiğinde, çalışma alanı / dosya tarayıcı paneli her yeni oturumda otomatik olarak açılır. Yine de istediğiniz zaman manuel olarak kapatabilirsiniz.', + settings_label_session_jump_buttons: 'Oturum atlama düğmelerini göster', + settings_desc_session_jump_buttons: 'Uzun oturum geçmişlerini okurken kayan Başlat ve Bitir düğmelerini gösterin.', + + settings_label_session_endless_scroll: 'Yukarı kaydırırken eski mesajları yükle', + + settings_desc_session_endless_scroll: 'Etkinleştirildiğinde, yukarı doğru kaydırdığınızda eski mesajlar otomatik olarak yüklenir. Devre dışı bırakıldığında eski mesajlar düğmesini kullanın.', + + settings_label_tab_visibility: 'Kenar çubuğu sekmeleri', + settings_desc_tab_visibility: 'Kenar çubuğunda ve rayda hangi sekmelerin görüneceğini seçin. Sohbet ve Ayarlar her zaman görünür durumdadır.', + open_in_browser: 'Tarayıcıda aç', + settings_dropdown_conversation: 'Konuşma', + settings_dropdown_appearance: 'Dış görünüş', + settings_dropdown_preferences: 'Tercihler', + settings_dropdown_providers: 'Sağlayıcılar', + settings_dropdown_system: 'Sistem', + settings_tab_conversation: 'Konuşma', + settings_tab_appearance: 'Dış görünüş', + settings_tab_preferences: 'Tercihler', + settings_tab_plugins: 'Eklentiler', + settings_plugins_title: 'Plugins', // TODO: translate + settings_plugins_meta: 'View installed Hermes plugins and the lifecycle hooks they register. This panel is read-only.', // TODO: translate + settings_plugins_empty: 'No Hermes plugins are currently visible. Install or enable plugins from the Hermes CLI/config to see them here.', // TODO: translate + plugins_unnamed: 'Unnamed plugin', // TODO: translate + plugins_no_description: 'No description provided.', // TODO: translate + plugins_no_hooks: 'No registered lifecycle hooks', // TODO: translate + plugins_registered_hooks: 'Registered hooks', // TODO: translate + plugins_enabled: 'Enabled', // TODO: translate + plugins_disabled: 'Disabled', // TODO: translate + plugins_active_provider: 'Active (provider)', // TODO: translate + plugins_provider_no_hooks: 'Provider plugin — no agent-visibility hooks', // TODO: translate + plugins_load_failed: 'Failed to load plugins: ', // TODO: translate + settings_tab_system: 'Sistem', + settings_title: 'Ayarlar', + settings_save_btn: 'Ayarları Kaydet', + settings_label_model: 'Varsayılan Model', + settings_desc_model: 'Yeni konuşmalar için kullanılır. Mevcut konuşmalar seçilen modellerini korur.', + settings_label_send_key: 'Anahtar Gönder', + settings_label_theme: 'Tema', + settings_label_skin: 'Deri', + settings_label_font_size: 'Yazı tipi boyutu', + font_size_small: 'Küçük', + font_size_default: 'Varsayılan', + font_size_large: 'Büyük', + font_size_xlarge: 'Ekstra Büyük', + settings_autosave_saving: 'Kaydediliyor\\u2026', + settings_autosave_saved: 'Kaydedildi', + settings_autosave_failed: 'Kaydetme başarısız oldu', + settings_autosave_retry: 'Yeniden dene', + settings_label_language: 'Dil', + settings_label_quota_chip: 'Bestecide sağlayıcı kota çipini göster', + settings_desc_quota_chip: 'Besteci altbilgisinde bir ortam kalan kota göstergesini (örn. OpenRouter kredi bakiyesi) görüntüler. Varsayılan kapalı. Besteciyi dizüstü bilgisayar ve standart masaüstü genişliklerinde düzenli tutmak için yalnızca etkinleştirildiğinde geniş ekranlarda (≥1400 piksel) görünür.', + settings_label_hide_suggestions: 'Yeni sohbet önerilerini gizle', + settings_desc_hide_suggestions: 'Yanlışlıkla dokunmayı önlemek için boş yeni sohbet ekranındaki üç varsayılan öneri düğmesini gizleyin.', + settings_label_token_usage: 'Jeton kullanımını göster', + settings_label_sidebar_density: 'Kenar çubuğu yoğunluğu', + cmd_reasoning: 'Düşünme görünürlüğünü değiştirin (göster/gizle), çaba düzeyini ayarlayın veya mevcut durumu kontrol edin', + settings_label_external_sessions: 'WebUI olmayan oturumları göster', + settings_label_previous_messaging_sessions: 'Önceki mesajlaşma oturumlarını göster', + settings_label_sync_insights: 'Analizlerle senkronize edin', + settings_label_check_updates: 'Güncellemeleri kontrol edin', + settings_label_whats_new_summary: "Summarize What's New with AI", + settings_label_bot_name: 'Varsayılan asistanın adı', + settings_label_password: 'Erişim Şifresi', + settings_saved: 'Ayarlar kaydedildi', + settings_save_failed: 'Kaydetme başarısız oldu:', + settings_load_failed: 'Ayarlar yüklenemedi:', + settings_saved_pw: 'Ayarlar kaydedildi - şifre koruması etkin ve bu tarayıcıda oturum açık kalıyor', + settings_saved_pw_updated: 'Ayarlar kaydedildi — şifre güncellendi', + // login page (used server-side via /api/i18n/login endpoint) + login_title: 'Oturum aç', + login_subtitle: 'Devam etmek için şifrenizi girin', + login_placeholder: 'Şifre', + login_btn: 'Oturum aç', + login_invalid_pw: 'Geçersiz şifre', + login_conn_failed: 'Bağlantı başarısız oldu', + // Sidebar & Tabs + tab_chat: 'Sohbet', + tab_tasks: 'Görevler', + tab_skills: 'Yetenekler', + tab_memory: 'Hafıza', + tab_workspaces: 'Alanlar', + tab_profiles: 'Agent profilleri', + tab_kanban: 'Kanban', + kanban_board: 'Pano', + kanban_visible_tasks: '{0} görünür görev', + kanban_search_tasks: 'Görevleri ara', + kanban_all_assignees: 'Tüm atananlar', + kanban_all_tenants: 'Tüm kiracılar', + kanban_include_archived: 'Arşivlenenleri dahil et', + kanban_no_matching_tasks: 'Eşleşen görev yok', + kanban_no_data: 'Kanban verisi yok', + kanban_work_queue_hint: 'Bu Hermes Ajanının iş kuyruğudur. Bir görev oluşturun veya önceliklendirin, atayın, Hazır\'a taşıyın ve sevk görevlisinin görevi talep etmesine izin verin.', + kanban_unavailable: 'Kanban kullanılamıyor', + kanban_read_only: 'Salt okunur görünüm', + kanban_empty: 'Boş', + kanban_task: 'Görev', + kanban_no_description: 'Açıklama yok', + kanban_refresh: 'Yenile', + kanban_status_triage: 'Triyaj', + kanban_status_todo: 'Yapılacaklar', + kanban_status_ready: 'Hazır', + kanban_status_running: 'Koşma', + kanban_status_blocked: 'Engellendi', + kanban_status_done: 'Tamamlamak', + kanban_status_original_hint: 'Gerçek durum: {0}. Bu iletişim kutusu yalnızca Triyaj/Yapılacak/Hazır düzenlemelerini destekler.', + kanban_comments_count: 'Yorumlar ({0})', + kanban_events_count: 'Etkinlikler ({0})', + kanban_links: 'Bağlantılar', + kanban_parents: 'Ebeveynler', + kanban_children: 'Çocuklar', + kanban_runs_count: 'Çalıştırmalar ({0})', + kanban_no_comments: 'Yorum yok', + kanban_no_events: 'Etkinlik yok', + kanban_no_runs: 'Koşu yok', + kanban_title: 'Başlık', + kanban_description: 'Tanım', + kanban_description_placeholder: 'İsteğe bağlı - ne olması gerekiyor, kabul kriterleri, bağlantılar', + kanban_status: 'Durum', + kanban_assignee: 'Vekil', + kanban_assignee_placeholder: 'İsteğe bağlı — herhangi bir çalışan için boş bırakın', + kanban_tenant: 'Kiracı', + kanban_tenant_placeholder: 'İsteğe bağlı – proje veya ekip bilgisi', + kanban_priority: 'Öncelik', + kanban_priority_hint: 'Önce yüksek sayılar çalıştırılır. Varsayılan 0.', + kanban_title_required: 'Başlık gerekli.', + kanban_edit_task: 'Görevi düzenle', + kanban_run_dispatcher: 'Dağıtıcıyı çalıştır', + kanban_run_dispatcher_confirm: 'Bu, bu panodaki Hazır görevleri talep edecek ve çalışan alt süreçlerini oluşturacaktır (görev başına bir, tıklama başına en fazla 8). Devam etmek?', + kanban_assignee_profiles_label: 'Hermes profilleri', + kanban_assignee_other_label: 'Diğer (CLI hatları / kaldırılan profiller)', + kanban_assignee_unassigned: '— Atanmadı (otomatik olarak çalıştırılmayacak) —', + kanban_ready_needs_assignee: 'Atanmamış + Hazır\'ı seçtiniz. Gönderici bu görevi atlayacaktır. Onaylamak için tekrar gönderin veya bir profil seçin.', + kanban_dispatch_preview_prefix: 'Önizleme:', + kanban_dispatch_run_prefix: 'Sevk edilen:', + kanban_dispatch_spawned: 'yumurtladı', + kanban_dispatch_promoted: 'terfi ettirildi', + kanban_dispatch_reclaimed: 'geri kazanılmış', + kanban_dispatch_skipped_unassigned: 'atlandı (atanan yok)', + kanban_dispatch_skipped_nonspawnable: 'atlandı (bilinmeyen profil)', + kanban_dispatch_auto_blocked: 'otomatik olarak engellendi', + kanban_dispatch_timed_out: 'zaman aşımına uğradı', + kanban_dispatch_crashed: 'çöktü', + kanban_new_task: 'Yeni görev', + kanban_add_comment: 'Yorum ekle', + kanban_only_mine: 'Sadece benim', + kanban_bulk_action: 'Toplu işlem', + kanban_nudge_dispatcher: 'Göndericiyi önizleyin', + kanban_stats: 'İstatistikler', + kanban_worker_log: 'İşçi günlüğü', + kanban_block: 'Engellemek', + kanban_unblock: 'Engellemeyi kaldır', + kanban_back_to_board: 'Panoya geri dön', + kanban_lanes_by_profile: 'Profile göre şeritler', + kanban_new_board: 'Yeni yönetim kurulu\\u2026', + kanban_rename_board: 'Mevcut panoyu yeniden adlandır\\u2026', + kanban_archive_board: 'Mevcut panoyu arşivle\\u2026', + kanban_archive_board_confirm: 'Arşiv panosu "{name}"? Görevler diskte kalır ve pano kanban/boards/_archived/ adresinden geri yüklenebilir.', + kanban_board_archived: 'Pano arşivlendi', + kanban_board_name: 'İsim', + kanban_board_slug: 'Bilgi notu (küçük harf, kısa çizgi)', + kanban_board_description: 'Açıklama (isteğe bağlı)', + kanban_board_icon: 'Simge (emoji, isteğe bağlı)', + kanban_board_color: 'Renk (isteğe bağlı)', + kanban_board_name_required: 'Ad gerekli', + kanban_board_slug_required: 'Sümüklüböcek gerekli', + kanban_card_complete: 'tamamlamak', + kanban_card_archive: 'arşiv', + kanban_unassigned: 'atanmamış', + kanban_status_archived: 'Arşivlendi', + tab_todos: 'Yapılacaklar', + tab_insights: 'Analizler', + tab_dashboard: 'Hermes Kontrol Paneli', + dashboard_loopback_warning: 'Kontrol Paneli sunucuda yalnızca geri döngüye sahiptir. Ya sunucunun kendisinden göz atın ya da --host 0.0.0.0 (güvenli değil) ile yeniden başlatın.', + tab_logs: 'Günlükler', + tab_settings: 'Ayarlar', + + logs_title: 'Logs', // TODO: translate + logs_file: 'File', // TODO: translate + logs_tail: 'Tail', // TODO: translate + logs_auto_refresh: 'Auto-refresh (5s)', // TODO: translate + logs_wrap: 'Wrap lines', // TODO: translate + logs_copy_all: 'Copy all', // TODO: translate + logs_empty: 'No log lines yet.', // TODO: translate + logs_loading: 'Loading logs…', // TODO: translate + logs_load_failed: 'Logs failed to load', // TODO: translate + logs_status_idle: 'Choose a log file to view recent lines.', // TODO: translate + logs_no_mtime: 'not written yet', // TODO: translate + logs_truncated_hint: 'Showing the tail of a large log file; older bytes were skipped to keep memory bounded.', // TODO: translate + logs_copied: 'Logs copied', // TODO: translate + logs_severity: 'Şiddet', + logs_severity_all: 'Tüm', + logs_severity_errors: 'Hatalar', + logs_severity_warnings: 'Uyarılar+', + logs_filter_active: 'gösteriliyor (filtre etkin)', + new_conversation: 'Yeni görüşme', + filter_conversations: 'Konuşmaları filtrele...', + session_time_unknown: 'Bilinmiyor', + session_time_minutes_ago: (n) => `${n} milyon dolar`, + session_time_hours_ago: (n) => `${n}sa`, + session_time_days_ago: (n) => `${n}d`, + session_time_last_week: '1 saat', + session_time_bucket_today: 'Bugün', + session_time_bucket_yesterday: 'Dün', + session_time_bucket_this_week: 'Bu hafta', + session_time_bucket_last_week: 'Geçen hafta', + session_time_bucket_older: 'daha yaşlı', + scheduled_jobs: 'Planlanmış işler', + new_job: 'Yeni iş', + loading: 'Yükleniyor...', + search_skills: 'Arama becerileri...', + new_skill: 'Yeni beceri', + personal_memory: 'Kişisel hafıza', + current_task_list: 'Mevcut görev listesi', + workspace_desc: 'Oturumlarınız için çalışma alanları ekleyin ve değiştirin.', + session_meta_messages: (n) => `${n} mesaj${n === 1 ? '' : 'S'}`, + session_meta_children: (n) => `${n} çocuk${n === 1 ? '' : 'ren'}`, + session_meta_segments: (n) => `${n} segment${n === 1 ? '' : 'S'}`, + session_lineage_segment_untitled: 'Başlıksız segment', + session_lineage_segment_open: 'Soy segmentini aç', + new_profile: 'Yeni profil', + transcript: 'Deşifre metni', + download_transcript: 'Markdown olarak indir', + import: 'İçe aktarmak', + export_session_json: 'JSON', + export_session_json_tooltip: 'Tüm oturumu JSON olarak dışa aktar', + import_session_json_tooltip: 'JSON\'dan oturumu içe aktar', + clear_conversation_btn_tooltip: 'Bu görüşmedeki tüm mesajları temizle', + // Settings detail + settings_label_rtl: 'Sağdan sola sohbet düzeni', + settings_desc_rtl: 'Arapça veya İbranice gibi diller için sohbet mesajlarının ve besteci girişinin hizalamasını değiştirir. Yalnızca sohbet alanını etkiler; kenar çubuğu ve diğer paneller soldan sağa kalır.', + settings_label_sound: 'Bildirim sesi', + settings_desc_sound: 'Asistan bir yanıtı bitirdiğinde bir ses çalın.', + settings_label_notifications: 'Tarayıcı bildirimleri', + settings_desc_notifications: 'Uygulama arka plandayken bir yanıt tamamlandığında bir sistem bildirimi gösterin.', + settings_desc_token_usage: 'Her Asistan yanıtının altında giriş/çıkış jeton sayılarını gösterir. /usage ile de değiştirilebilir.', + settings_sidebar_density_compact: 'Kompakt', + settings_sidebar_density_detailed: 'Ayrıntılı', + settings_desc_sidebar_density: 'Oturum listesinin sol kenar çubuğunda ne kadar meta veri göstereceğini kontrol eder.', + settings_label_auto_title_refresh: 'Uyarlanabilir başlık yenileme', + settings_auto_title_refresh_off: 'Kapalı', + settings_auto_title_refresh_5: 'Her 5 değişimde bir', + settings_auto_title_refresh_10: 'Her 10 değişimde bir', + settings_auto_title_refresh_20: 'Her 20 değişimde bir', + settings_desc_auto_title_refresh: 'Oturum başlıklarını en son konuşmaya göre otomatik olarak yeniden oluşturarak konuşma ilerledikçe başlıkların alakalı kalmasını sağlar. LLM başlık oluşturma modeli yapılandırması gerektirir.', + settings_desc_external_sessions: 'Oturum listesinde CLI, Telegram, Discord, Slack ve diğer kanallardan gelen konuşmaları gösterin. İçe aktarmak ve devam etmek için tıklayın.', + settings_desc_previous_messaging_sessions: 'Sıfırlama veya sıkıştırmayla değiştirilen eski Discord, Telegram, Slack ve Weixin oturumlarını gösterin.', + settings_desc_sync_insights: 'WebUI belirteci kullanımını state.db\'ye yansıtır, böylece hermes /insights tarayıcı oturum verilerini içerir. Varsayılan olarak kapalıdır.', + settings_desc_check_updates: 'WebUI veya Agent\'ın daha yeni sürümleri mevcut olduğunda bir banner gösterin. Periyodik olarak bir arka plan git getirme işlemi çalıştırır.', + settings_desc_whats_new_summary: "Changes the What's New action from opening the raw diff first to generating a short, human-readable summary. The regular diff comparison stays available after the summary.", + settings_desc_bot_name: 'Yalnızca varsayılan profil için kullanılır. Diğer profiller kendi profil adlarını kullanır.', + settings_desc_password: 'Ayarlamak veya değiştirmek için yeni bir şifre girin. Geçerli ayarı korumak için boş bırakın.', + password_placeholder: 'Yeni şifreyi girin\\u2026', + password_env_var_locked: 'HERMES_WEBUI_PASSWORD ortam değişkeni şu anda ayarlıdır ve önceliklidir. Şifreyi buradan yönetmek için ayarı kaldırın ve sunucuyu yeniden başlatın.', + password_env_var_locked_placeholder: 'Kilitli: HERMES_WEBUI_PASSWORD ortam değişkeni ayarlandı', + disable_auth: 'Kimlik Doğrulamasını Devre Dışı Bırak', + sign_out: 'Oturumu Kapat', + // Providers panel + providers_tab_title: 'Sağlayıcılar', + providers_section_title: 'Sağlayıcılar', + providers_section_meta: 'Yapay zeka sağlayıcıları için API anahtarlarını yönetin. Değişiklikler hemen yürürlüğe girer.', + providers_status_configured: 'API anahtarı yapılandırıldı', + providers_status_not_configured: 'API anahtarı yok', + providers_status_oauth: 'OAuth', + providers_status_api_key: 'API anahtarı', + providers_status_not_configured_label: 'Yapılandırılmadı', + providers_oauth_hint: 'OAuth aracılığıyla kimlik doğrulaması yapıldı. API anahtarına gerek yok.', + providers_oauth_config_yaml_hint: 'Belirteç config.yaml aracılığıyla yapılandırıldı. Güncellemek için config.yaml dosyanızdaki sağlayıcılar bölümünü düzenleyin veya hermes auth\'u çalıştırın.', + providers_oauth_not_configured_hint: 'Kimliği doğrulanmadı. Bu sağlayıcıyı yapılandırmak için terminalde Hermes Auth komutunu çalıştırın.', + providers_save: 'Kaydetmek', + providers_remove: 'Kaldırmak', + providers_saving: 'Kaydediliyor\\u2026', + providers_removing: 'Kaldırılıyor\\u2026', + providers_enter_key: 'Lütfen bir API anahtarı girin', + providers_empty: 'Yapılandırılabilir sağlayıcı bulunamadı.', + providers_key_updated: 'API anahtarı kaydedildi', + providers_key_removed: 'API anahtarı kaldırıldı', + providers_key_placeholder_new: 'sk-...', + providers_key_placeholder_replace: 'Değiştirilecek yeni anahtarı girin\\u2026', + provider_quota_title: 'Etkin sağlayıcı kotası', + provider_quota_active_provider: 'Aktif sağlayıcı', + provider_quota_last_checked_after_refresh: 'Yenilemeden sonra son kontrol edildi', + provider_quota_last_checked: 'Son kontrol edilen {0}', + provider_quota_refresh_usage: 'Kullanımı yenile', + provider_quota_refreshing: 'Yenileniyor...', + provider_quota_refresh_title: 'Sağlayıcı kullanım sınırlarını şimdi yenileyin', + provider_quota_refresh_succeeded: 'Sağlayıcı kullanımı yenilendi', + provider_quota_refresh_failed: 'Sağlayıcı kullanımı yenileme başarısız oldu', + provider_quota_session_limit: '5 saat sınırı', + provider_quota_weekly_limit: 'Haftalık limit', + provider_quota_window_fallback: 'Pencere', + provider_quota_metric_remaining: 'Geriye kalan', + provider_quota_metric_used: 'Kullanılmış', + provider_quota_metric_limit: 'Sınır', + provider_quota_status_available: 'mevcut', + provider_quota_status_exhausted: 'yorgun', + provider_quota_status_unavailable: 'müsait değil', + provider_quota_status_failed: 'arızalı', + provider_quota_status_checked: 'kontrol edildi', + provider_quota_status_no_key: 'anahtar yok', + provider_quota_status_invalid_key: 'geçersiz anahtar', + provider_quota_status_unsupported: 'desteklenmeyen', + provider_quota_used_meta: '{0} kullanıldı', + provider_quota_resets_meta: '{0} sıfırlanır', + provider_quota_credential_pool: 'Kimlik bilgisi havuzu', + provider_quota_credential_label: 'Kimlik bilgisi {0}', + provider_quota_pool_plans: 'Planlar: {0}', + provider_quota_pool_no_windows: 'Hesap sınırı aralığı bildirilmedi.', + provider_quota_account_limits_loaded: 'Hesap limitleri yüklendi.', + provider_quota_unavailable: 'Kota durumu mevcut değil', + provider_quota_retry_after: '{0} sonrasında yeniden deneyin', + provider_quota_pool_summary_available: '{0}/{1} mevcut', + provider_quota_pool_summary_exhausted: '{0} bitkin', + provider_quota_pool_summary_failed: '{0} başarısız oldu', + provider_quota_pool_summary_checked: '{0} işaretlendi', + cancel: 'İptal etmek', + create_job: 'İş oluştur', + save_skill: 'Beceriyi kaydet', + editing: 'Düzenleme', + // Empty state + empty_title: 'Hangi konuda yardımcı olabilirim?', + empty_subtitle: 'İstediğiniz şeyi sorun, komutları çalıştırın, dosyaları keşfedin veya planlanmış görevlerinizi yönetin.', + suggest_files: 'Bu çalışma alanında hangi dosyalar var?', + suggest_schedule: 'Nerelerdesiniz?', + suggest_plan: 'Küçük bir proje planlamama yardım et.', + // onboarding + onboarding_badge: 'İLK ÇALIŞMA', + onboarding_title: 'Hermes Web Kullanıcı Arayüzüne Hoş Geldiniz', + onboarding_lead: 'Hızlı yönlendirmeli kurulum, Hermes\'i doğrulayacak, gerçek bir sağlayıcı yapılandırmasını kaydedecek, bir çalışma alanı ve modeli seçecek ve isteğe bağlı olarak uygulamayı bir parola ile koruyacaktır.', + onboarding_back: 'Geri', + onboarding_continue: 'Devam etmek', + onboarding_skip: 'Kurulumu atla', + onboarding_skipped: 'Kurulum atlandı — mevcut yapılandırma kullanılıyor.', + onboarding_open: 'Hermes\'i aç', + onboarding_step_system_title: 'Sistem kontrolü', + onboarding_step_system_desc: 'Hermes Agent\'ı ve yapılandırma görünürlüğünü doğrulayın.', + onboarding_step_setup_title: 'Sağlayıcı kurulumu', + onboarding_step_setup_desc: 'Minimum Hermes sağlayıcı yapılandırmasını kaydedin.', + onboarding_step_workspace_title: 'Çalışma alanı + modeli', + onboarding_step_workspace_desc: 'Yeni oturumlar ve sohbet için varsayılanları seçin.', + onboarding_step_password_title: 'İsteğe bağlı şifre', + onboarding_step_password_desc: 'Web kullanıcı arayüzünü paylaşmadan önce koruyun.', + onboarding_step_finish_title: 'Sona ermek', + onboarding_step_finish_desc: 'Uygulamayı inceleyin ve girin.', + onboarding_notice_system_ready: 'Hermes Agent\'a Web kullanıcı arayüzünden ulaşılabilir görünüyor.', + onboarding_notice_system_unavailable: 'Hermes Agent henüz tam olarak mevcut değil. Bootstrap bunu kurabilir ancak sağlayıcı kurulumu yine de bir terminal gerektirebilir.', + onboarding_check_agent: 'Hermes Temsilcisi', + onboarding_check_agent_ready: 'Tespit edildi ve içe aktarılabilir', + onboarding_check_agent_missing: 'Eksik veya kısmen içe aktarılabilir', + onboarding_check_password: 'Şifre', + onboarding_check_password_enabled: 'Zaten etkin', + onboarding_check_password_disabled: 'Henüz etkinleştirilmedi', + onboarding_check_provider: 'Sağlayıcı yapılandırması', + onboarding_check_provider_ready: 'Sohbete hazır', + onboarding_check_provider_partial: 'Kaydedildi ancak eksik', + onboarding_check_provider_pending: 'Doğrulama gerekiyor', + onboarding_config_file: 'Yapılandırma dosyası:', + onboarding_env_file: '.env dosyası:', + onboarding_unknown: 'Bilinmiyor', + onboarding_current_provider: 'Mevcut kurulum:', + onboarding_missing_imports: 'Eksik içe aktarmalar:', + onboarding_notice_setup_required: 'Burada basit bir sağlayıcı yolu seçin. Gelişmiş OAuth akışları şimdilik Hermes CLI\'ye ait olmaya devam ediyor.', + onboarding_notice_setup_already_ready: 'Çalışan bir Hermes sağlayıcı kurulumu zaten algılandı. Burada saklayabilir veya değiştirebilirsiniz.', + onboarding_oauth_provider_ready_title: 'Sağlayıcının kimliği zaten doğrulandı', + onboarding_oauth_provider_ready_body: 'Bu örnek, Hermes CLI aracılığıyla ayarlanmış bir OAuth sağlayıcısını ({provider) kullanacak şekilde yapılandırılmıştır. Burada API anahtarına gerek yoktur; kurulumu tamamlamak için Devam\'a tıklayın.', + onboarding_oauth_provider_not_ready_title: 'OAuth sağlayıcısının kimliği henüz doğrulanmadı', + onboarding_oauth_provider_not_ready_body: 'Bu örnek, API anahtarı yerine OAuth kullanan {provider\'i kullanacak şekilde yapılandırılmıştır. Kimlik doğrulaması yapmak için bir terminalde hermes auth veya hermes model\'i çalıştırın, ardından Web kullanıcı arayüzünü yeniden yükleyin.', + onboarding_oauth_switch_hint: 'Veya API anahtarı kurulumuna geçmek için aşağıdan farklı bir sağlayıcı seçin:', + onboarding_notice_workspace: 'Bu değerler normal uygulamayla aynı ayar API\'lerini yeniden kullanır.', + onboarding_workspace_label: 'Çalışma alanı', + onboarding_workspace_or_path: 'Veya bir çalışma alanı yolu girin', + onboarding_workspace_placeholder: '/ev/siz/çalışma alanı', + onboarding_provider_label: 'Kurulum modu', + onboarding_quick_setup_badge: 'hızlı kurulum', + provider_category_easy_start: 'Kolay başlangıç', + provider_category_self_hosted: 'Açık / kendi kendine barındırılan', + provider_category_specialized: 'Uzmanlaşmış', + onboarding_api_key_label: 'API anahtarı', + oauth_login_codex: 'Login with Codex (ChatGPT)', // TODO: translate + oauth_codex_step1: 'Step 1: Visit this URL and enter the code', // TODO: translate + oauth_codex_step2: 'Step 2: Enter this code on the page', // TODO: translate + oauth_codex_polling: 'Waiting for authorization...', // TODO: translate + oauth_codex_success: 'Codex OAuth login successful!', // TODO: translate + oauth_codex_error: 'OAuth login failed', // TODO: translate + oauth_codex_expired: 'Code expired, please try again', // TODO: translate + onboarding_api_key_placeholder: 'Mevcut kayıtlı anahtarı korumak için boş bırakın', + onboarding_api_key_label_optional: 'API key (optional)', // TODO: translate + onboarding_api_key_placeholder_optional: 'Leave blank for keyless servers', // TODO: translate + onboarding_api_key_help_keyless: 'Most LM Studio / Ollama / vLLM installs run keyless — leave this blank if your server doesn\'t require authentication. Use the Test connection button to verify.', // TODO: translate + onboarding_api_key_help_prefix: 'Hermes .env dosyanızda gizli olarak kaydedildi', + onboarding_base_url_label: 'Temel URL', + onboarding_base_url_placeholder: 'https://uç noktanız.example/v1', + onboarding_base_url_help: 'Bunu OpenAI uyumlu yönlendiriciler, şirket içinde barındırılan sunucular, LiteLLM, Ollama, LM Studio, vLLM veya benzer uç noktalar için kullanın.', + onboarding_model_label: 'Varsayılan model', + onboarding_workspace_help: 'Kurulum tamamlandıktan sonra Hermes\'in yeni sohbetler için kullanması gereken modeli seçin.', + onboarding_custom_model_placeholder: 'modelinizin adı', + onboarding_custom_model_help: 'Özel uç noktalar için sunucunuzun beklediği tam model kimliğini girin.', + onboarding_notice_password_enabled: 'Bir parola zaten yapılandırılmıştır. Yalnızca değiştirmek istiyorsanız yeni bir tane girin.', + onboarding_notice_password_recommended: 'İsteğe bağlıdır ancak kullanıcı arayüzünü localhost\'un ötesinde gösterecekseniz önerilir.', + onboarding_password_label: 'Şifre (isteğe bağlı)', + onboarding_password_placeholder: 'Atlamak için boş bırakın', + onboarding_password_help: 'Parolalar, mevcut ayarlar API\'si aracılığıyla ve karma sunucu tarafında saklanır.', + onboarding_notice_finish: 'Bunlardan herhangi birini değiştirmek için Ayarları daha sonra yeniden açabilirsiniz.', + onboarding_not_set: 'Ayarlanmadı', + onboarding_password_will_enable: 'Etkinleştirilecek', + onboarding_password_will_replace: 'Değiştirilecek', + onboarding_password_keep_existing: 'Mevcut şifreyi koru', + onboarding_password_remains_disabled: 'Engelli kalacak', + onboarding_password_skipped: 'Şimdilik atlandı', + onboarding_finish_help: 'Bitirme, ayarlarda onboarding_completed kodunu saklar ve sizi normal uygulamaya bırakır.', + onboarding_error_choose_workspace: 'Devam etmeden önce bir çalışma alanı seçin.', + onboarding_error_choose_model: 'Devam etmeden önce bir model seçin.', + onboarding_error_provider_required: 'Devam etmeden önce bir kurulum modu seçin.', + onboarding_error_base_url_required: 'Özel uç noktalar için temel URL gereklidir.', + onboarding_probe_test_button: 'Test connection', // TODO: translate + onboarding_probe_probing: 'Testing connection…', // TODO: translate + onboarding_probe_ok: 'Connected. {n} model(s) available.', // TODO: translate + onboarding_probe_error_generic: 'Could not reach the configured base URL.', // TODO: translate + onboarding_probe_error_invalid_url: 'Base URL must start with http:// or https://.', // TODO: translate + onboarding_probe_error_dns: 'Could not resolve the host. Check the URL or use the host\'s IP address.', // TODO: translate + onboarding_probe_error_connect_refused: 'Connection refused — the server may not be running on that address. From inside Docker, try the host IP instead of localhost.', // TODO: translate + onboarding_probe_error_timeout: 'The endpoint did not respond in time. Check that the server is running and the URL is correct.', // TODO: translate + onboarding_probe_error_http_4xx: 'The endpoint returned a client error. Check authentication and the URL path (typically ends in /v1).', // TODO: translate + onboarding_probe_error_http_5xx: 'The endpoint returned a server error. Check the LM Studio / Ollama server logs.', // TODO: translate + onboarding_probe_error_parse: 'The endpoint did not return a model list in the expected shape. Verify the URL points to the OpenAI-compatible API root.', // TODO: translate + onboarding_probe_error_unreachable: 'Could not reach the configured base URL.', // TODO: translate + onboarding_error_probe_failed: 'Could not validate the configured base URL.', // TODO: translate + onboarding_error_workspace_required: 'Çalışma alanı gerekli.', + onboarding_error_model_required: 'Model gerekli.', + onboarding_complete: 'İlk katılım tamamlandı', + + // panel/runtime i18n + error_prefix: 'Hata:', + not_available: 'Yok', + never: 'Asla', + add: 'Eklemek', + add_failed: 'Ekleme başarısız oldu:', + remove_failed: 'Kaldırma başarısız oldu:', + switch_failed: 'Geçiş başarısız oldu:', + name_required: 'Ad gerekli', + content_required: 'İçerik gerekli', + view: 'Görüş', + dismiss: 'Azletmek', + disable: 'Devre dışı bırakmak', + cron_no_jobs: 'Planlanmış iş bulunamadı.', + cron_status_off: 'kapalı', + cron_status_paused: 'duraklatıldı', + cron_status_error: 'hata', + cron_status_active: 'aktif', + cron_status_running: 'koşuyor\\u2026', + cron_status_needs_attention: 'dikkat edilmesi gerekiyor', + cron_attention_desc: 'Bu yinelenen işin bir sonraki çalışma süresi yoktur. Zamanlayıcı bir sonraki çalıştırmayı hesaplamada başarısız olmuş olabilir.', + cron_attention_croniter_hint: 'Ağ Geçidi çalışma zamanında croniter paketi eksik olabilir. Ağ Geçidini cron desteğiyle yeniden başlatın, ardından bu işe devam edin.', + cron_attention_resume: 'Devam ettir ve yeniden hesapla', + cron_jobs_project: 'Cron İşleri', + cron_attention_run_once: 'Şimdi bir kez koş', + cron_attention_copy_diagnostics: 'Tanılamayı kopyala', + cron_diagnostics_copied: 'Cron teşhisi kopyalandı', + cron_next: 'Sonraki', + cron_last: 'Son', + cron_run_now: 'Şimdi koş', + cron_pause: 'Duraklat', + cron_resume: 'Sürdürmek', + cron_job_name_placeholder: 'İşin adı', + cron_schedule_placeholder: 'Takvim', + cron_prompt_placeholder: 'Çabuk', + cron_last_output: 'Son çıktı', + cron_expand_prompt: 'İstemi genişlet', + cron_collapse_prompt: 'İstemi daralt', + cron_expand_output: 'Çıktıyı genişlet', + cron_collapse_output: 'Çıktıyı daralt', + cron_all_runs: 'Tüm koşular', + cron_hide_runs: 'Çalıştırmaları gizle', + cron_no_runs_yet: '(henüz koşu yok)', + cron_schedule_required_example: 'Program gereklidir (ör. "0 9 * * *" veya "her 1 saatte bir")', + cron_schedule_required: 'Program gerekli', + cron_prompt_required: 'İstem gerekli', + cron_job_created: 'İş oluşturuldu', + cron_duplicate: 'Kopyalamak', + cron_duplicated: 'İş kopyalandı (duraklatıldı)', + cron_job_triggered: 'İş tetiklendi', + cron_job_paused: 'İş duraklatıldı', + cron_job_resumed: 'İş devam ettirildi', + cron_job_updated: 'İş güncellendi', + cron_delete_confirm_title: 'Cron işini sil', + cron_delete_confirm_message: 'Bu geri alınamaz.', + cron_job_deleted: 'İş silindi', + cron_completion_status: (name, status) => `Cron "${name}" ${status}`, + status_failed: 'arızalı', + status_completed: 'tamamlanmış', + todos_no_active: 'Bu oturumda etkin görev listesi yok.', + clear_conversation_title: 'Görüşmeyi temizle', + clear_conversation_message: 'Tüm mesajlar silinsin mi? Bu geri alınamaz.', + clear_failed: 'Temizleme başarısız oldu:', + skills_no_match: 'Beceri eşleşmesi yok.', + skill_enabled: 'Etkinleştirilmiş', + skill_disabled: 'Engelli', + skill_toggle_failed: 'Beceri değiştirilemedi:', + linked_files: 'Bağlantılı Dosyalar', + skill_load_failed: 'Beceri yüklenemedi:', + skill_file_load_failed: 'Dosya yüklenemedi:', + skill_name_required: 'Beceri adı gerekli', + skill_updated: 'Beceri güncellendi', + skill_created: 'Beceri oluşturuldu', + skill_deleted: 'Beceri silindi', + skill_delete_confirm: '"{0}" becerisi silinsin mi?', + skills_empty_title: 'Bir beceri seçin', + skills_empty_sub: 'İçeriğini görüntülemek için kenar çubuğundan bir beceri seçin veya yeni bir beceri oluşturun.', + skills_edit: 'Düzenlemek', + skills_delete: 'Silmek', + skills_back_to: '{0}\'a geri dön', + tasks_empty_title: 'Planlanmış bir iş seçin', + tasks_empty_sub: 'Ayrıntılarını ve çalışmalarını görüntülemek için kenar çubuğundan bir iş seçin veya yeni bir iş oluşturun.', + workspaces_empty_title: 'Bir alan seçin', + workspaces_empty_sub: 'Dosyalarını ve ayarlarını görüntülemek veya yeni bir tane eklemek için kenar çubuğundan bir alan seçin.', + profiles_empty_title: 'Bir profil seçin', + profiles_empty_sub: 'Ayarlarını görüntülemek ve düzenlemek için kenar çubuğundan bir temsilci profili seçin veya yeni bir tane oluşturun.', + memory_notes_label: 'hafıza (notlar)', + memory_saved: 'Bellek kaydedildi', + my_notes: 'Notlarım', + user_profile: 'Kullanıcı Profili', + no_notes_yet: 'Henüz not yok.', + no_profile_yet: 'Henüz profil yok.', + agent_soul: 'Ajan Ruhu', + no_soul_yet: 'Henüz tanımlanmış bir ruh yok.', + workspace_choose_path: 'Çalışma alanı yolunu seçin', + workspace_choose_path_meta: 'Doğrulanmış bir yol ekleyin ve bu görüşmeyi değiştirin', + workspace_manage: 'Çalışma alanlarını yönet', + workspace_manage_meta: 'Spaces panelini açın', + workspace_use_title: 'Geçerli oturumda kullan', + workspace_use: 'Kullanmak', + workspace_add_path_placeholder: 'Çalışma alanı yolu ekleyin (ör. /home/user/my-project)', + workspace_paths_validated_hint: 'Yollar, kaydedilmeden önce mevcut dizinler olarak doğrulanır.', + + workspace_drag_hint: 'Yeniden sıralamak için sürükleyin', + workspace_reorder_failed: 'Yeniden sıralama başarısız oldu', + workspace_added: 'Çalışma alanı eklendi', + workspace_renamed: 'Çalışma alanı yeniden adlandırıldı', + workspace_remove_confirm_title: 'Çalışma alanını kaldır', + workspace_remove_confirm_message: (path) => `"${path}" kaldırılsın mı?`, + workspace_removed: 'Çalışma alanı kaldırıldı', + workspace_switch_prompt_title: 'Çalışma alanını değiştir', + workspace_switch_prompt_message: 'Bu görüşmeyi eklemek ve bu görüşmeye geçiş yapmak için mutlak bir çalışma alanı yolu girin.', + workspace_switch_prompt_confirm: 'Anahtar', + workspace_switch_prompt_placeholder: '/Kullanıcılar/siz/proje', + workspace_not_added: 'Çalışma alanı eklenmedi', + workspace_already_saved: 'Çalışma alanı zaten kayıtlı; onu listeden seçin', + workspace_busy_switch: 'Aracı çalışırken çalışma alanı değiştirilemiyor', + discard_file_edits_title: 'Dosya düzenlemeleri silinsin mi?', + discard_file_edits_message: 'Çalışma alanlarının değiştirilmesi, önizlemedeki kaydedilmemiş dosya düzenlemelerinin silinmesine neden olur.', + workspace_switched_to: (name) => `${name}'a geçildi`, + profiles_no_profiles: 'Hiçbir profil bulunamadı.', + profile_api_keys_configured: 'API anahtarları yapılandırıldı', + profile_gateway_running: 'Ağ geçidi çalışıyor', + profile_gateway_stopped: 'Ağ geçidi durduruldu', + profile_active: 'AKTİF', + profile_no_configuration: 'Yapılandırma yok', + profile_skill_count: (count) => `${count} beceri${count === 1 ? '' : 'S'}`, + profile_use: 'Kullanmak', + profile_switch_title: 'Bu profile geç', + profile_delete_title: 'Bu profili sil', + profile_default_label: '(varsayılan)', + profile_name_placeholder: 'Profil adı (küçük harf, a-z 0-9 kısa çizgiler)', + profile_clone_label: 'Etkin profilden yapılandırmayı kopyala', + profile_model_label: 'Model / sağlayıcı', + profile_model_hint: 'Bu yeni profil için yapılandırılmış sağlayıcılar ve modeller arasından seçim yapın.', + profile_model_use_default: 'Etkin profil varsayılanını kullan', + profile_base_url_placeholder: 'Temel URL (isteğe bağlı, örneğin http://localhost:11434)', + profile_api_key_placeholder: 'API anahtarı (isteğe bağlı)', + manage_profiles: 'Profilleri yönet', + profiles_load_failed: 'Profiller yüklenemedi', + profile_switched_new_conversation: (name) => `Profile geçildi: ${name} — yeni görüşme başladı`, + profile_switched: (name) => `Profile geçildi: ${name}`, + profile_name_rule: 'Yalnızca küçük harfler, sayılar, kısa çizgiler ve alt çizgiler', + profile_base_url_rule: 'Temel URL http:// veya https:// ile başlamalıdır', + profile_created: (name) => `Profil oluşturuldu: ${name}`, + profile_delete_confirm_title: (name) => `"${name}" profili silinsin mi?`, + profile_delete_confirm_message: 'Bu profilin tüm oturumları, yapılandırmaları, becerileri ve belleği kalıcı olarak silinecek. Bu geri alınamaz.', + profile_deleted: (name) => `Profil silindi: ${name}`, + active_conversation_none: 'Aktif görüşme seçilmedi.', + active_conversation_meta: (title, count) => `${title} · ${count} mesaj${count === 1 ? '' : 'S'}`, + settings_unsaved_changes: 'Kaydedilmemiş değişiklikleriniz var.', + sign_out_failed: 'Oturumu kapatma başarısız oldu:', + disable_auth_confirm_title: 'Şifre korumasını devre dışı bırak', + disable_auth_confirm_message: 'Bu örneğe herkes erişebilecek.', + auth_disabled: 'Kimlik doğrulama devre dışı bırakıldı — şifre koruması kaldırıldı', + disable_auth_failed: 'Kimlik doğrulama devre dışı bırakılamadı:', + bg_error_single: (title) => `"${title}" bir hatayla karşılaştı`, + bg_error_multi: (count) => `${count} oturum bir hatayla karşılaştı`, + // skill form + skill_name: 'İsim', + skill_category: 'Kategori', + skill_category_placeholder: 'İsteğe bağlı, ör. devops', + skill_content: 'SKILL.md içeriği', + skill_content_placeholder: 'YAML ön maddesi + işaretleme gövdesi', + skill_rename_not_supported: 'Bir becerinin yeniden adlandırılması desteklenmiyor. Yeni bir beceri oluşturun ve yeniden adlandırmak için eskisini silin.', + skill_metadata: 'Meta veriler', + // cron form + cron_name_label: 'İsim', + cron_name_placeholder: 'İsteğe bağlı', + cron_schedule_label: 'Takvim', + cron_schedule_hint: "Use 'every 1h' or a cron expression for recurring jobs. Bare durations like '30m' run once.", + cron_schedule_once_warning: "Duration forms like '30m' run once and are removed after running. Use 'every 30m' to keep a recurring job.", + cron_prompt_label: 'Çabuk', + cron_deliver_label: 'Çıktıyı şuraya ilet:', + cron_deliver_local: 'Yerel (yalnızca çıktıyı kaydet)', + cron_profile_label: 'Profil', + cron_profile_server_default: 'sunucu varsayılanı', + cron_profile_server_default_hint: 'Çalışma zamanında WebUI sunucusunun varsayılan profilini kullanır. Profili olmayan mevcut işler bu eski davranışı sürdürüyor.', + cron_toast_notifications_label: 'Tamamlama kadehleri', + cron_toast_notifications_hint: 'Bu cron bittiğinde kadeh kaldır. Görevler rozeti ve yeni çalıştırma işaretçisi bu kapalıyken de güncellenir.', + cron_toast_notifications_enabled: 'Etkinleştirilmiş', + cron_toast_notifications_disabled: 'Engelli', + cron_skills_label: 'Yetenekler', + cron_skills_placeholder: 'Beceri ekleyin (isteğe bağlı)\\u2026', + cron_skills_edit_hint: 'Beceri listesi oluşturulduktan sonra düzenlenemez.', + // workspace form + workspace_name_label: 'İsim', + workspace_name_placeholder: 'İsteğe bağlı kolay ad', + workspace_path_label: 'Yol', + workspace_path_required: 'Yol gerekli', + workspace_path_readonly: 'Yol değiştirilemez. Yalnızca yeniden adlandırın.', + workspace_new_title: 'Yeni alan', + // profile form + profile_name_label: 'İsim', + profile_base_url_label: 'Temel URL', + profile_api_key_label: 'API anahtarı', + cmd_yolo: 'YOLO modunu değiştir (onayları atla)', + cmd_branch: 'Bu konuşmayı yeni bir oturuma aktarın', + cmd_branch_usage: '/branch [isim] - konuşmayı çatallayın (isteğe bağlı olarak bir adla)', + branch_forked: 'Yeni oturuma çatallandı', + branch_failed: 'Çatal başarısız oldu:', + fork_from_here: 'Buradan çatal', + forked_from: 'çatallı', + yolo_no_session: 'Aktif oturum yok', + yolo_enabled: '⚡ YOLO modu AÇIK — onaylar bu oturumu atladı', + yolo_disabled: 'YOLO modu KAPALI', + yolo_pill_label: 'YOLO', + yolo_pill_title_active: 'YOLO modu etkin — devre dışı bırakmak için tıklayın', + approval_skip_all: '⚡ Tüm bu oturumu atla', + approval_skip_all_title: 'Bu oturuma ilişkin tüm onay istemlerini atla', + // composer action tooltips + composer_send: 'Mesaj gönder', + composer_queue: 'Sıra mesajı', + composer_interrupt: 'Kes ve gönder', + composer_steer: 'Akım tepkisini yönlendir', + composer_stop: 'Üretimi durdur', + composer_disabled_clarify: 'Açıklama isteğine yanıt verin', + composer_disabled_compression: 'Sıkıştırmanın bitmesi bekleniyor', + composer_disabled_empty: 'Göndermek için bir mesaj yazın', + composer_mobile_workspace: 'Çalışma alanı', + composer_mobile_model: 'Modeli', + composer_mobile_reasoning: 'muhakeme', + composer_mobile_context: 'Bağlam', + + pdf_loading: 'PDF {0} yükleniyor\\u2026', + pdf_too_large: 'PDF satır içi önizleme için çok büyük', + pdf_no_pages: 'PDF\'de sayfa yok', + pdf_error: 'PDF önizlemesi oluşturulamadı', + pdf_download: 'PDF\'yi indir', + html_loading: 'HTML önizlemesi yükleniyor\\u2026', + html_too_large: 'HTML satır içi önizleme için çok büyük', + html_error: 'HTML önizlemesi oluşturulamadı', + html_open_full: 'Tam sayfayı aç', + html_sandbox_label: 'HTML Önizlemesi (korumalı alan)', + media_audio_label: 'Ses', + media_svg_label: 'Diyagram', + media_video_label: 'Video', + csv_loading: 'CSV yükleniyor', + csv_too_large: 'CSV dosyası satır içi oluşturma için çok büyük', + csv_no_data: 'CSV dosyasında tablo olarak oluşturmak için yeterli veri yok', + csv_error: 'CSV dosyası yüklenemedi', + csv_header_note: 'Tablo başlığı olarak gösterilen ilk satır', + excalidraw_loading: 'Yükleme diyagramı', + excalidraw_too_large: 'Excalidraw dosyası satır içi oluşturma için çok büyük', + excalidraw_invalid: 'Geçersiz Excalidraw dosya biçimi', + excalidraw_error: 'Excalidraw dosyası yüklenemedi', + excalidraw_label: 'Diyagram', + excalidraw_download: 'İndirmek', + excalidraw_empty: 'Boş diyagram', + excalidraw_render_error: 'Diyagram oluşturulamadı', + excalidraw_simplified: 'Basitleştirilmiş SVG önizlemesi — Excalidraw tuvaliyle piksel açısından aynı değil', + // TTS (#499) + tts_listen: 'Dinlemek', + tts_not_supported: 'Konuşma sentezi bu tarayıcıda desteklenmiyor.', + settings_label_tts: 'Yanıtlar için Metinden Konuşmaya', + settings_desc_tts: '도움말 메시지에 스피커 버튼 표시', + settings_label_tts_auto_read: 'Yanıtları sesli olarak otomatik oku', + settings_desc_tts_auto_read: 'Tamamlandığında her yeni asistanın yanıtını otomatik olarak söyleyin. Yazmaya başladığınızda duraklar.', + // Composer voice-mode pref (#1488) + settings_label_voice_mode: 'Hands-free voice mode button', // TODO: translate + settings_desc_voice_mode: 'Show the voice-mode button (audio waveform) next to the dictation mic. Lets you speak naturally — Hermes auto-sends after a pause and reads replies aloud. Requires a browser that supports both speech recognition and TTS.', // TODO: translate + settings_label_tts_voice: 'Ses', + settings_desc_tts_voice: '음성 합성 음성 선택', + settings_label_tts_rate: 'Konuşma hızı', + settings_label_tts_pitch: 'Konuşma perdesi', + checkpoint_date: 'Date', // TODO: translate + checkpoint_diff_files_changed: (n) => `${n} file${n === 1 ? '' : 's'} changed`, // TODO: translate + checkpoint_diff_no_changes: 'No differences found between this checkpoint and the current workspace.', // TODO: translate + checkpoint_diff_title: 'Changes in checkpoint', // TODO: translate + checkpoint_empty: 'No checkpoints found for this workspace.', // TODO: translate + checkpoint_error: 'Failed to load checkpoints', // TODO: translate + checkpoint_files: 'Files', // TODO: translate + checkpoint_loading: 'Loading checkpoints…', // TODO: translate + checkpoint_message: 'Message', // TODO: translate + checkpoint_restore: 'Restore', // TODO: translate + checkpoint_restore_confirm_message: (ckpt) => `Restore workspace to checkpoint "${ckpt}"? This will overwrite files with the saved versions. Files added after this checkpoint will not be deleted.`, // TODO: translate + checkpoint_restore_confirm_title: 'Restore checkpoint?', // TODO: translate + checkpoint_restored: 'Checkpoint restored', // TODO: translate + checkpoint_title: 'Checkpoints', // TODO: translate + checkpoint_view_diff: 'View diff', // TODO: translate + insights_activity_by_day: 'Activity by Day', // TODO: translate + insights_activity_by_hour: 'Activity by Hour', // TODO: translate + insights_cost: 'Estimated Cost', // TODO: translate + insights_daily_tokens: 'Günlük Jetonlar', + insights_model_name: 'Modeli', + insights_model_sessions: 'Oturumlar', + insights_model_tokens: 'Jetonlar', + insights_model_cost: 'Maliyet', + insights_model_share: 'Paylaşmak', + insights_no_usage_data: 'Henüz kullanım verisi yok', + insights_footer: 'Showing data from the last {days} days', // TODO: translate + insights_input_tokens: 'Input', // TODO: translate + insights_messages: 'Messages', // TODO: translate + insights_models: 'Models', // TODO: translate + insights_no_cost: 'N/A', // TODO: translate + insights_output_tokens: 'Output', // TODO: translate + insights_peak_hour: 'Peak: {hour}', // TODO: translate + insights_sessions: 'Sessions', // TODO: translate + insights_title: 'Usage Analytics', // TODO: translate + insights_token_breakdown: 'Token Breakdown', // TODO: translate + insights_tokens: 'Tokens', // TODO: translate + insights_total: 'Total', // TODO: translate + settings_desc_api_redact: 'Self-hosted users can disable for transparency (not recommended for shared instances).', // TODO: translate + settings_label_api_redact: 'Redact sensitive data in API responses', // TODO: translate + voice_error: 'Voice not supported in this browser', // TODO: translate + voice_listening: 'Listening…', // TODO: translate + voice_mode_active: 'Voice mode on', // TODO: translate + voice_mode_off: 'Voice mode off', // TODO: translate + voice_speaking: 'Speaking…', // TODO: translate + voice_thinking: 'Thinking…', // TODO: translate + // Composer voice buttons (#1488) + voice_dictate: 'Dictate', // TODO: translate + voice_dictate_active: 'Stop dictation', // TODO: translate + voice_mode_toggle: 'Voice mode', // TODO: translate + voice_mode_toggle_active: 'Exit voice mode', // TODO: translate + subagent_children: 'Subagent sessions', // TODO: translate } }; diff --git a/tests/test_1560_password_env_var_no_op.py b/tests/test_1560_password_env_var_no_op.py index bebc25c8..1e8723cb 100644 --- a/tests/test_1560_password_env_var_no_op.py +++ b/tests/test_1560_password_env_var_no_op.py @@ -333,7 +333,7 @@ def test_panels_js_uses_locked_placeholder_i18n_key(): # (en/es/de/zh/zh-Hant/ru/ja/fr/pt). The repo currently ships 9 locales but # substitutes 'ko' for 'fr' — we test what the repo actually has, not what the # issue body lists, so a future addition of fr won't fail the suite either. -EXPECTED_LOCALES = ("en", "it", "ja", "ru", "es", "de", "zh", "zh-Hant", "pt", "ko") +EXPECTED_LOCALES = ("en", "it", "ja", "ru", "es", "de", "zh", "zh-Hant", "pt", "ko", "tr") def _locale_block(locale_key: str) -> str: diff --git a/tests/test_issue1488_composer_voice_buttons.py b/tests/test_issue1488_composer_voice_buttons.py index f1e1a78e..72870e19 100644 --- a/tests/test_issue1488_composer_voice_buttons.py +++ b/tests/test_issue1488_composer_voice_buttons.py @@ -123,7 +123,7 @@ class TestComposerVoiceButtonI18n: "voice_mode_toggle_active", ) - LOCALES = ("en", "fr", "it", "ja", "ru", "es", "de", "zh", "zh-Hant", "pt", "ko") + LOCALES = ("en", "fr", "it", "ja", "ru", "es", "de", "zh", "zh-Hant", "pt", "ko", "tr") def test_legacy_voice_toggle_key_removed(self): """The old key whose string was 'Voice input' caused the duplicate- @@ -171,7 +171,7 @@ class TestComposerVoiceButtonI18n: class TestVoiceModePreferenceGate: """boot.js must hide btnVoiceMode by default, surface it via Preferences.""" - LOCALES = ("en", "fr", "it", "ja", "ru", "es", "de", "zh", "zh-Hant", "pt", "ko") + LOCALES = ("en", "fr", "it", "ja", "ru", "es", "de", "zh", "zh-Hant", "pt", "ko", "tr") def test_voice_mode_pref_is_localstorage_backed(self): """The pref reads from localStorage key 'hermes-voice-mode-button'.""" diff --git a/tests/test_issue2419_cache_usage_display.py b/tests/test_issue2419_cache_usage_display.py index e6cf94e2..e5cd8848 100644 --- a/tests/test_issue2419_cache_usage_display.py +++ b/tests/test_issue2419_cache_usage_display.py @@ -63,8 +63,8 @@ def test_context_indicator_surfaces_cache_hit_rate(): def test_cache_usage_labels_are_localized(): src = (ROOT / "static" / "i18n.js").read_text() - assert src.count("usage_cache_hit_detail:") == 11 - assert src.count("usage_cached_percent:") == 11 + assert src.count("usage_cache_hit_detail:") == 12 + assert src.count("usage_cached_percent:") == 12 assert "usage_cache_hit_detail: 'Cache: {0}% hit ({1} read / {2} write)'" in src assert "usage_cached_percent: '{0}% cached'" in src diff --git a/tests/test_issue2462_theme_i18n.py b/tests/test_issue2462_theme_i18n.py index 07e77302..0b83b3fb 100644 --- a/tests/test_issue2462_theme_i18n.py +++ b/tests/test_issue2462_theme_i18n.py @@ -31,7 +31,7 @@ def test_theme_command_help_mentions_current_theme_and_skin_values(): "system/dark/light", "default/ares/mono/slate/poseidon/sisyphus/charizard/sienna/catppuccin/nous/geist-contrast", ) - for locale in ("en", "it", "ja", "ru", "es", "de", "zh", "zh-Hant", "pt", "ko", "fr"): + for locale in ("en", "it", "ja", "ru", "es", "de", "zh", "zh-Hant", "pt", "ko", "fr", "tr"): value = _literal_value(_locale_block(locale), "cmd_theme") for fragment in required_fragments: assert fragment in value, f"{locale} cmd_theme missing {fragment!r}: {value!r}" diff --git a/tests/test_issue2679_hide_suggestions.py b/tests/test_issue2679_hide_suggestions.py index b00b047b..1b4f24e8 100644 --- a/tests/test_issue2679_hide_suggestions.py +++ b/tests/test_issue2679_hide_suggestions.py @@ -50,8 +50,8 @@ def test_panels_round_trip_and_hot_apply_hide_suggestions(): def test_hide_suggestions_i18n_all_locales_and_changelog(): js = I18N.read_text(encoding="utf-8") - assert js.count("settings_label_hide_suggestions:") == 11 - assert js.count("settings_desc_hide_suggestions:") == 11 + assert js.count("settings_label_hide_suggestions:") == 12 + assert js.count("settings_desc_hide_suggestions:") == 12 changelog = CHANGELOG.read_text(encoding="utf-8") assert "#2679" in changelog assert "hide_empty_state_suggestions" in changelog diff --git a/tests/test_pr1721_rtl_salvage.py b/tests/test_pr1721_rtl_salvage.py index f7cd1d7a..bc7c8445 100644 --- a/tests/test_pr1721_rtl_salvage.py +++ b/tests/test_pr1721_rtl_salvage.py @@ -112,5 +112,5 @@ def test_rtl_in_config_defaults_and_writable_keys(): def test_rtl_localized_in_all_locales(): js = I18N.read_text(encoding="utf-8") # Count occurrences — should match the 11 locale blocks - assert js.count("settings_label_rtl:") == 11 - assert js.count("settings_desc_rtl:") == 11 + assert js.count("settings_label_rtl:") == 12 + assert js.count("settings_desc_rtl:") == 12 diff --git a/tests/test_quota_chip_settings_toggle.py b/tests/test_quota_chip_settings_toggle.py index d5cda58e..91c90de7 100644 --- a/tests/test_quota_chip_settings_toggle.py +++ b/tests/test_quota_chip_settings_toggle.py @@ -88,5 +88,5 @@ def test_quota_chip_panels_round_trip(): def test_quota_chip_localized_in_all_locales(): js = I18N.read_text(encoding="utf-8") - assert js.count("settings_label_quota_chip:") == 11, "11 locales expected" - assert js.count("settings_desc_quota_chip:") == 11, "11 locales expected" + assert js.count("settings_label_quota_chip:") == 12, "12 locales expected" + assert js.count("settings_desc_quota_chip:") == 12, "12 locales expected" diff --git a/tests/test_sidebar_tab_visibility.py b/tests/test_sidebar_tab_visibility.py index 43ce2f66..2d80187b 100644 --- a/tests/test_sidebar_tab_visibility.py +++ b/tests/test_sidebar_tab_visibility.py @@ -99,8 +99,8 @@ def test_i18n_coverage(): """Label and description keys must exist in all locales with matching counts.""" label_count = I18N_JS.count("settings_label_tab_visibility") desc_count = I18N_JS.count("settings_desc_tab_visibility") - assert label_count >= 11, f"Expected ≥11 locales, found {label_count}" - assert desc_count >= 11, f"Expected ≥11 locales, found {desc_count}" + assert label_count >= 12, f"Expected ≥12 locales, found {label_count}" + assert desc_count >= 12, f"Expected ≥12 locales, found {desc_count}" assert label_count == desc_count, \ f"Label ({label_count}) and desc ({desc_count}) counts must match" diff --git a/tests/test_turkish_locale.py b/tests/test_turkish_locale.py new file mode 100644 index 00000000..254774af --- /dev/null +++ b/tests/test_turkish_locale.py @@ -0,0 +1,146 @@ +from collections import Counter +from pathlib import Path +import re + + +REPO = Path(__file__).resolve().parent.parent + + +def read(path: Path) -> str: + return path.read_text(encoding="utf-8") + + +def extract_locale_block(src: str, locale_key: str) -> str: + start_match = re.search(rf"\b{re.escape(locale_key)}\s*:\s*\{{", src) + assert start_match, f"{locale_key} locale block not found" + + start = start_match.end() - 1 + depth = 0 + in_single = False + in_double = False + in_backtick = False + escape = False + + for i in range(start, len(src)): + ch = src[i] + + if escape: + escape = False + continue + + if in_single: + if ch == "\\": + escape = True + elif ch == "'": + in_single = False + continue + + if in_double: + if ch == "\\": + escape = True + elif ch == '"': + in_double = False + continue + + if in_backtick: + if ch == "\\": + escape = True + elif ch == "`": + in_backtick = False + continue + + if ch == "'": + in_single = True + continue + if ch == '"': + in_double = True + continue + if ch == "`": + in_backtick = True + continue + + if ch == "{": + depth += 1 + continue + if ch == "}": + depth -= 1 + if depth == 0: + return src[start + 1 : i] + + raise AssertionError(f"{locale_key} locale block braces are not balanced") + + +def locale_keys(src: str, locale_key: str) -> list[str]: + key_pattern = re.compile(r"^\s*([a-zA-Z0-9_]+)\s*:", re.MULTILINE) + return key_pattern.findall(extract_locale_block(src, locale_key)) + + +def test_turkish_locale_block_exists(): + src = read(REPO / "static" / "i18n.js") + assert "\n tr: {" in src + assert "_lang: 'tr'" in src + assert "_label: 'Türkçe'" in src + assert "_speech: 'tr-TR'" in src + + +def test_turkish_locale_includes_representative_translations(): + src = read(REPO / "static" / "i18n.js") + tr_block = extract_locale_block(src, "tr") + expected = [ + "settings_title: 'Ayarlar'", + "settings_label_language: 'Dil'", + "login_title: 'Oturum aç'", + "approval_heading: 'Onay gerekli'", + "tab_chat: 'Sohbet'", + "tab_tasks: 'Görevler'", + "tab_profiles: 'Agent profilleri'", + "empty_title: 'Hangi konuda yardımcı olabilirim?'", + "onboarding_title: 'Hermes Web Kullanıcı Arayüzüne Hoş Geldiniz'", + ] + for entry in expected: + assert entry in tr_block + + +def test_turkish_settings_detail_descriptions_are_translated(): + src = read(REPO / "static" / "i18n.js") + tr_block = extract_locale_block(src, "tr") + expected = [ + "settings_desc_workspace_panel_open: 'Etkinleştirildiğinde, çalışma alanı / dosya tarayıcı paneli her yeni oturumda otomatik olarak açılır. Yine de istediğiniz zaman manuel olarak kapatabilirsiniz.'", + "settings_desc_notifications: 'Uygulama arka plandayken bir yanıt tamamlandığında bir sistem bildirimi gösterin.'", + "settings_desc_token_usage: 'Her Asistan yanıtının altında giriş/çıkış jeton sayılarını gösterir. /usage ile de değiştirilebilir.'", + "settings_desc_sidebar_density: 'Oturum listesinin sol kenar çubuğunda ne kadar meta veri göstereceğini kontrol eder.'", + "settings_desc_auto_title_refresh: 'Oturum başlıklarını en son konuşmaya göre otomatik olarak yeniden oluşturarak konuşma ilerledikçe başlıkların alakalı kalmasını sağlar. LLM başlık oluşturma modeli yapılandırması gerektirir.'", + "settings_desc_external_sessions: 'Oturum listesinde CLI, Telegram, Discord, Slack ve diğer kanallardan gelen konuşmaları gösterin. İçe aktarmak ve devam etmek için tıklayın.'", + "settings_desc_sync_insights: 'WebUI belirteci kullanımını state.db\\'ye yansıtır, böylece hermes /insights tarayıcı oturum verilerini içerir. Varsayılan olarak kapalıdır.'", + "settings_desc_check_updates: 'WebUI veya Agent\\'ın daha yeni sürümleri mevcut olduğunda bir banner gösterin. Periyodik olarak bir arka plan git getirme işlemi çalıştırır.'", + "settings_desc_bot_name: 'Yalnızca varsayılan profil için kullanılır. Diğer profiller kendi profil adlarını kullanır.'", + "settings_desc_password: 'Ayarlamak veya değiştirmek için yeni bir şifre girin. Geçerli ayarı korumak için boş bırakın.'", + ] + for entry in expected: + assert entry in tr_block + + +def test_turkish_locale_matches_english_key_coverage(): + src = read(REPO / "static" / "i18n.js") + en_keys = set(locale_keys(src, "en")) + tr_keys = set(locale_keys(src, "tr")) + assert sorted(en_keys - tr_keys) == [] + assert sorted(tr_keys - en_keys) == [] + + +def test_turkish_locale_has_no_duplicate_keys(): + src = read(REPO / "static" / "i18n.js") + keys = locale_keys(src, "tr") + duplicates = sorted(k for k, count in Counter(keys).items() if count > 1) + assert not duplicates, f"Turkish locale has duplicate keys: {duplicates}" + + +def test_turkish_locale_keys_use_standard_indentation(): + src = read(REPO / "static" / "i18n.js") + tr_block = extract_locale_block(src, "tr") + badly_indented = [ + line.strip() + for line in tr_block.splitlines() + if re.match(r"^\s{1,3}[a-zA-Z0-9_]+\s*:", line) + ] + assert badly_indented == []