//! Strings for the releases and CI pages. One variant per phrase, an exhaustive `t` match, and //! `fmt`-style helpers for sentences that carry numbers or names. use std::fmt::Display; use super::Lang; #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum K { // Repo home page: the latest release card. LatestReleaseHeading, // CI notices, shown after a run action. CiNoticeStarted, CiNoticeCancelled, CiNoticeApproved, CiNoticeRerun, CiNoticeFinished, CiNoticeNotWaiting, CiNoticeNoBranch, CiNoticeNoManual, // CI run list and run page. RunWorkflow, RunWorkflowHelp, Branch, ApproveAndRun, Cancel, Rerun, Runs, NoRunsYet, Jobs, NoJobs, ColRun, ColState, ColTrigger, ColRef, ColCommit, ColActor, ColAge, ColJob, ColDuration, ColRunner, ColMessage, Newer, Older, DeletedUser, RunNumber, Started, Finished, Runner, Exit, Log, FullLog, LogTruncated, Artifacts, // CI state words. StateWaitingApproval, StateQueued, StateRunning, StateSuccess, StateFailure, StateCancelled, StateError, StateBlocked, StateSkipped, // Release notices, shown after a release action. RelSaved, RelDeleted, RelAssetUploaded, RelAssetDeleted, RelAssetTooLarge, RelAssetExists, RelAssetName, RelAssetInvalid, RelConfirm, RelInvalid, RelAssetEmpty, // Release form errors. RelErrTagName, RelErrReleaseExists, RelErrChooseBranch, // Release pages. Releases, NewRelease, EditRelease, SaveRelease, TagHint, Tag, TargetBranch, Title, ReleaseNotes, PrereleaseHelp, DraftHelp, PreRelease, Draft, Latest, NoReleasesYet, NoAssetsYet, NoAssets, File, Size, Downloads, Edit, Assets, AllReleases, SourceCode, Confirm, DeleteRelease, BackToRelease, UploadAsset, DeleteReleaseHelp, YesDeleteRelease, } pub fn t(lang: Lang, key: K) -> &'static str { use K::*; use Lang::*; match (key, lang) { (LatestReleaseHeading, En) => "Latest release", (LatestReleaseHeading, Tr) => "Son sürüm", (CiNoticeStarted, En) => "Workflow run queued.", (CiNoticeStarted, Tr) => "İş akışı çalıştırması sıraya alındı.", (CiNoticeCancelled, En) => { "Cancellation requested. Queued jobs were cancelled; running jobs stop at their next heartbeat." } (CiNoticeCancelled, Tr) => { "İptal istendi. Sıradaki işler iptal edildi; çalışan işler bir sonraki kalp atışında duracak." } (CiNoticeApproved, En) => "Run approved. Its jobs are queued.", (CiNoticeApproved, Tr) => "Çalıştırma onaylandı. İşler sıraya alındı.", (CiNoticeRerun, En) => "A new run was created from the same commit.", (CiNoticeRerun, Tr) => "Aynı commit'ten yeni bir çalıştırma oluşturuldu.", (CiNoticeFinished, En) => "This run has already finished. Nothing was changed.", (CiNoticeFinished, Tr) => "Bu çalıştırma zaten tamamlanmış. Hiçbir şey değiştirilmedi.", (CiNoticeNotWaiting, En) => "This run is not waiting for approval. Nothing was changed.", (CiNoticeNotWaiting, Tr) => "Bu çalıştırma onay beklemiyor. Hiçbir şey değiştirilmedi.", (CiNoticeNoBranch, En) => "Choose a branch of this repository.", (CiNoticeNoBranch, Tr) => "Bu depodaki bir dal seçin.", (CiNoticeNoManual, En) => { "Nothing was started: the branch has no usable workflow file, or the workflow does not allow manual runs." } (CiNoticeNoManual, Tr) => { "Hiçbir şey başlatılmadı: dalda kullanılabilir bir iş akışı dosyası yok ya da iş akışı elle çalıştırmaya izin vermiyor." } (RunWorkflow, En) => "Run workflow", (RunWorkflow, Tr) => "İş akışını çalıştır", (RunWorkflowHelp, En) => { "Starts the workflow on a branch's head, if its .forge/ci.toml allows manual runs." } (RunWorkflowHelp, Tr) => { "Bir dalın ucundaki iş akışını başlatır; .forge/ci.toml dosyası elle çalıştırmaya izin veriyorsa." } (Branch, En) => "Branch", (Branch, Tr) => "Dal", (ApproveAndRun, En) => "Approve and run", (ApproveAndRun, Tr) => "Onayla ve çalıştır", (Cancel, En) => "Cancel", (Cancel, Tr) => "İptal et", (Rerun, En) => "Re-run", (Rerun, Tr) => "Yeniden çalıştır", (Runs, En) => "Runs", (Runs, Tr) => "Çalıştırmalar", (NoRunsYet, En) => "No runs yet.", (NoRunsYet, Tr) => "Henüz çalıştırma yok.", (Jobs, En) => "Jobs", (Jobs, Tr) => "İşler", (NoJobs, En) => "No jobs.", (NoJobs, Tr) => "İş yok.", (ColRun, En) => "Run", (ColRun, Tr) => "Çalıştırma", (ColState, En) => "State", (ColState, Tr) => "Durum", (ColTrigger, En) => "Trigger", (ColTrigger, Tr) => "Tetikleyici", (ColRef, En) => "Ref", (ColRef, Tr) => "Referans", (ColCommit, En) => "Commit", (ColCommit, Tr) => "Commit", (ColActor, En) => "Actor", (ColActor, Tr) => "Kullanıcı", (ColAge, En) => "Age", (ColAge, Tr) => "Zaman", (ColJob, En) => "Job", (ColJob, Tr) => "İş", (ColDuration, En) => "Duration", (ColDuration, Tr) => "Süre", (ColRunner, En) => "Runner", (ColRunner, Tr) => "Çalıştırıcı", (ColMessage, En) => "Message", (ColMessage, Tr) => "Mesaj", (Newer, En) => "Newer", (Newer, Tr) => "Daha yeni", (Older, En) => "Older", (Older, Tr) => "Daha eski", (DeletedUser, En) => "deleted user", (DeletedUser, Tr) => "silinmiş kullanıcı", (RunNumber, En) => "Run #", (RunNumber, Tr) => "Çalıştırma #", (Started, En) => "Started", (Started, Tr) => "Başlangıç", (Finished, En) => "Finished", (Finished, Tr) => "Bitiş", (Runner, En) => "runner", (Runner, Tr) => "çalıştırıcı", (Exit, En) => "exit", (Exit, Tr) => "çıkış", (Log, En) => "Log", (Log, Tr) => "Günlük", (FullLog, En) => "Full log (log.txt)", (FullLog, Tr) => "Tam günlük (log.txt)", (LogTruncated, En) => "Showing the last 512 KiB of the log. The full log is linked above.", (LogTruncated, Tr) => { "Günlüğün son 512 KiB'ı gösteriliyor. Tam günlük yukarıda bağlantılı." } (Artifacts, En) => "Artifacts", (Artifacts, Tr) => "Yapıtlar", (StateWaitingApproval, En) => "waiting approval", (StateWaitingApproval, Tr) => "onay bekliyor", (StateQueued, En) => "queued", (StateQueued, Tr) => "sırada", (StateRunning, En) => "running", (StateRunning, Tr) => "çalışıyor", (StateSuccess, En) => "success", (StateSuccess, Tr) => "başarılı", (StateFailure, En) => "failure", (StateFailure, Tr) => "başarısız", (StateCancelled, En) => "cancelled", (StateCancelled, Tr) => "iptal edildi", (StateError, En) => "error", (StateError, Tr) => "hata", (StateBlocked, En) => "blocked", (StateBlocked, Tr) => "engellendi", (StateSkipped, En) => "skipped", (StateSkipped, Tr) => "atlandı", (RelSaved, En) => "Release saved.", (RelSaved, Tr) => "Sürüm kaydedildi.", (RelDeleted, En) => "Release deleted. The tag was kept.", (RelDeleted, Tr) => "Sürüm silindi. Etiket korundu.", (RelAssetUploaded, En) => "Asset uploaded.", (RelAssetUploaded, Tr) => "Dosya yüklendi.", (RelAssetDeleted, En) => "Asset deleted.", (RelAssetDeleted, Tr) => "Dosya silindi.", (RelAssetTooLarge, En) => { "The file is larger than this instance allows for a release asset." } (RelAssetTooLarge, Tr) => { "Dosya, bu sunucunun sürüm dosyaları için izin verdiğinden büyük." } (RelAssetExists, En) => { "An asset with this file name already exists on the release. Nothing was changed." } (RelAssetExists, Tr) => { "Bu sürümde bu adı taşıyan bir dosya zaten var. Hiçbir şey değiştirilmedi." } (RelAssetName, En) => { "The file name may only contain letters, digits, and . _ - +, and cannot start with a dot." } (RelAssetName, Tr) => { "Dosya adı yalnızca harf, rakam ve . _ - + karakterlerini içerebilir ve nokta ile başlayamaz." } (RelAssetInvalid, En) => "The upload could not be read. Nothing was changed; try again.", (RelAssetInvalid, Tr) => { "Yüklenen dosya okunamadı. Hiçbir şey değiştirilmedi; yeniden deneyin." } (RelConfirm, En) => "Tick the confirmation box to delete the release. Nothing was deleted.", (RelConfirm, Tr) => "Sürümü silmek için onay kutusunu işaretleyin. Hiçbir şey silinmedi.", (RelInvalid, En) => { "Enter a title of up to 200 characters and release notes of up to 65536 characters. Nothing was changed." } (RelInvalid, Tr) => { "En fazla 200 karakterlik bir başlık ve en fazla 65536 karakterlik sürüm notları girin. Hiçbir şey değiştirilmedi." } (RelAssetEmpty, En) => "Choose a file to upload. Nothing was changed.", (RelAssetEmpty, Tr) => "Yüklemek için bir dosya seçin. Hiçbir şey değiştirilmedi.", (RelErrTagName, En) => { "Enter a tag name using letters, digits, and . _ - + (no slashes), up to 100 characters." } (RelErrTagName, Tr) => { "En fazla 100 karakterlik bir etiket adı girin; yalnızca harf, rakam ve . _ - + kullanın, eğik çizgi kullanmayın." } (RelErrReleaseExists, En) => { "A release already exists for this tag. Edit that release instead." } (RelErrReleaseExists, Tr) => { "Bu etiket için zaten bir sürüm var. Bunun yerine o sürümü düzenleyin." } (RelErrChooseBranch, En) => "Choose a branch to create the tag on.", (RelErrChooseBranch, Tr) => "Etiketin oluşturulacağı bir dal seçin.", (Releases, En) => "Releases", (Releases, Tr) => "Sürümler", (NewRelease, En) => "New release", (NewRelease, Tr) => "Yeni sürüm", (EditRelease, En) => "Edit release", (EditRelease, Tr) => "Sürümü düzenle", (SaveRelease, En) => "Save release", (SaveRelease, Tr) => "Sürümü kaydet", (TagHint, En) => { "Use letters, digits, and . _ - +. Slashes are not allowed. If the tag does not exist yet, it is created at the head of the branch you choose." } (TagHint, Tr) => { "Harf, rakam ve . _ - + kullanın; eğik çizgi kullanılamaz. Etiket yoksa, seçtiğiniz dalın ucunda oluşturulur." } (Tag, En) => "Tag", (Tag, Tr) => "Etiket", (TargetBranch, En) => "Target branch (used only when the tag is created)", (TargetBranch, Tr) => "Hedef dal (yalnızca etiket oluşturulurken kullanılır)", (Title, En) => "Title", (Title, Tr) => "Başlık", (ReleaseNotes, En) => "Release notes (Markdown)", (ReleaseNotes, Tr) => "Sürüm notları (Markdown)", (PrereleaseHelp, En) => "Pre-release: never shown as the latest release", (PrereleaseHelp, Tr) => "Ön sürüm: asla en son sürüm olarak gösterilmez", (DraftHelp, En) => "Draft: visible only to people who can write to the repository", (DraftHelp, Tr) => "Taslak: yalnızca depoya yazabilen kişiler görebilir", (PreRelease, En) => "Pre-release", (PreRelease, Tr) => "Ön sürüm", (Draft, En) => "Draft", (Draft, Tr) => "Taslak", (Latest, En) => "Latest", (Latest, Tr) => "En son", (NoReleasesYet, En) => "No releases yet.", (NoReleasesYet, Tr) => "Henüz sürüm yok.", (NoAssetsYet, En) => "No assets yet.", (NoAssetsYet, Tr) => "Henüz dosya yok.", (NoAssets, En) => "No assets.", (NoAssets, Tr) => "Dosya yok.", (File, En) => "File", (File, Tr) => "Dosya", (Size, En) => "Size", (Size, Tr) => "Boyut", (Downloads, En) => "Downloads", (Downloads, Tr) => "İndirmeler", (Edit, En) => "Edit", (Edit, Tr) => "Düzenle", (Assets, En) => "Assets", (Assets, Tr) => "Dosyalar", (AllReleases, En) => "All releases", (AllReleases, Tr) => "Tüm sürümler", (SourceCode, En) => "Source code", (SourceCode, Tr) => "Kaynak kodu", (Confirm, En) => "Confirm", (Confirm, Tr) => "Onayla", (DeleteRelease, En) => "Delete release", (DeleteRelease, Tr) => "Sürümü sil", (BackToRelease, En) => "Back to the release", (BackToRelease, Tr) => "Sürüme dön", (UploadAsset, En) => "Upload asset", (UploadAsset, Tr) => "Dosya yükle", (DeleteReleaseHelp, En) => { "Deleting removes the release and its assets. The git tag is kept." } (DeleteReleaseHelp, Tr) => "Sürümü ve dosyalarını siler. Git etiketi korunur.", (YesDeleteRelease, En) => "Yes, delete this release", (YesDeleteRelease, Tr) => "Evet, bu sürümü sil", } } /// "Page 2". pub fn page_label(lang: Lang, page: u32) -> String { match lang { Lang::En => format!("Page {page}"), Lang::Tr => format!("Sayfa {page}"), } } /// "1m 5s". pub fn duration_minutes(lang: Lang, minutes: i64, secs: i64) -> String { match lang { Lang::En => format!("{minutes}m {secs}s"), Lang::Tr => format!("{minutes} dk {secs} sn"), } } /// "9s". pub fn duration_seconds(lang: Lang, secs: i64) -> String { match lang { Lang::En => format!("{secs}s"), Lang::Tr => format!("{secs} sn"), } } /// "3 downloads". pub fn download_count(lang: Lang, count: u64) -> String { match lang { Lang::En => format!("{count} downloads"), Lang::Tr => format!("{count} indirme"), } } /// The title length refusal, with the limit. pub fn title_too_long(lang: Lang, max: usize) -> String { match lang { Lang::En => format!("Enter a title of up to {max} characters."), Lang::Tr => format!("En fazla {max} karakterlik bir başlık girin."), } } /// The release notes length refusal, with the limit. pub fn body_too_long(lang: Lang, max: usize) -> String { match lang { Lang::En => format!("The release notes can be at most {max} characters."), Lang::Tr => format!("Sürüm notları en fazla {max} karakter olabilir."), } } /// "Edit v1.0", the edit page's title part. pub fn edit_title(lang: Lang, tag: &str) -> String { match lang { Lang::En => format!("Edit {tag}"), Lang::Tr => format!("{tag} sürümünü düzenle"), } } /// The upload limit hint under the assets heading. pub fn upload_hint(lang: Lang, max_mb: impl Display) -> String { match lang { Lang::En => format!( "Up to {max_mb} MiB per file. Names may contain letters, digits, and . _ - +. Files are served as downloads." ), Lang::Tr => format!( "Dosya başına en fazla {max_mb} MiB. Adlar harf, rakam ve . _ - + içerebilir. Dosyalar indirme olarak sunulur." ), } } #[cfg(test)] mod tests { use super::*; const ALL: &[K] = &[ K::LatestReleaseHeading, K::CiNoticeStarted, K::CiNoticeCancelled, K::CiNoticeApproved, K::CiNoticeRerun, K::CiNoticeFinished, K::CiNoticeNotWaiting, K::CiNoticeNoBranch, K::CiNoticeNoManual, K::RunWorkflow, K::RunWorkflowHelp, K::Branch, K::ApproveAndRun, K::Cancel, K::Rerun, K::Runs, K::NoRunsYet, K::Jobs, K::NoJobs, K::ColRun, K::ColState, K::ColTrigger, K::ColRef, K::ColCommit, K::ColActor, K::ColAge, K::ColJob, K::ColDuration, K::ColRunner, K::ColMessage, K::Newer, K::Older, K::DeletedUser, K::RunNumber, K::Started, K::Finished, K::Runner, K::Exit, K::Log, K::FullLog, K::LogTruncated, K::Artifacts, K::StateWaitingApproval, K::StateQueued, K::StateRunning, K::StateSuccess, K::StateFailure, K::StateCancelled, K::StateError, K::StateBlocked, K::StateSkipped, K::RelSaved, K::RelDeleted, K::RelAssetUploaded, K::RelAssetDeleted, K::RelAssetTooLarge, K::RelAssetExists, K::RelAssetName, K::RelAssetInvalid, K::RelConfirm, K::RelInvalid, K::RelAssetEmpty, K::RelErrTagName, K::RelErrReleaseExists, K::RelErrChooseBranch, K::Releases, K::NewRelease, K::EditRelease, K::SaveRelease, K::TagHint, K::Tag, K::TargetBranch, K::Title, K::ReleaseNotes, K::PrereleaseHelp, K::DraftHelp, K::PreRelease, K::Draft, K::Latest, K::NoReleasesYet, K::NoAssetsYet, K::NoAssets, K::File, K::Size, K::Downloads, K::Edit, K::Assets, K::AllReleases, K::SourceCode, K::Confirm, K::DeleteRelease, K::BackToRelease, K::UploadAsset, K::DeleteReleaseHelp, K::YesDeleteRelease, ]; #[test] fn every_key_has_text_in_both_languages() { for key in ALL { assert!(!t(Lang::En, *key).is_empty(), "{key:?} has no English"); assert!(!t(Lang::Tr, *key).is_empty(), "{key:?} has no Turkish"); } } #[test] fn turkish_differs_from_english_for_translated_keys() { let differing = ALL .iter() .filter(|key| t(Lang::En, **key) != t(Lang::Tr, **key)) .count(); assert!(differing >= 3); assert_eq!(t(Lang::Tr, K::Releases), "Sürümler"); assert_eq!(t(Lang::En, K::Releases), "Releases"); } #[test] fn counted_sentences_read_in_both_languages() { assert_eq!(download_count(Lang::En, 3), "3 downloads"); assert_eq!(download_count(Lang::Tr, 3), "3 indirme"); assert_eq!(duration_minutes(Lang::En, 1, 5), "1m 5s"); assert_eq!(duration_minutes(Lang::Tr, 1, 5), "1 dk 5 sn"); assert_eq!(page_label(Lang::Tr, 2), "Sayfa 2"); } }