Tahinli/forge
public0 watching
★ 0
| 1 | //! Strings for this page group. See `docs` in `super` for the pattern. |
| 2 | //! |
| 3 | //! Covers the notifications inbox, the repo security page, the appearance settings, the new |
| 4 | //! repository form and the repo header tab helpers. Shared strings (Save, Security, Notifications, |
| 5 | //! New repository) come from `super::Key`. |
| 6 | |
| 7 | use std::fmt::Display; |
| 8 | |
| 9 | use super::Lang; |
| 10 | |
| 11 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] |
| 12 | pub enum K { |
| 13 | // Appearance settings. |
| 14 | Appearance, |
| 15 | ThemeLabel, |
| 16 | LanguageLabel, |
| 17 | ThemeAndLanguage, |
| 18 | MatchSystemHelp, |
| 19 | MatchSystem, |
| 20 | Light, |
| 21 | Dark, |
| 22 | MatchBrowser, |
| 23 | // Top-bar theme button: what it switches to next. |
| 24 | SwitchToLight, |
| 25 | SwitchToDark, |
| 26 | SwitchToMatchSystem, |
| 27 | AppearanceSaved, |
| 28 | ChooseTheme, |
| 29 | ChooseLanguage, |
| 30 | // Notifications: row kinds. |
| 31 | KindOpenIssue, |
| 32 | KindClosedIssue, |
| 33 | KindOpenPull, |
| 34 | KindClosedPull, |
| 35 | KindDiscussion, |
| 36 | KindSecurityAlerts, |
| 37 | // Notifications: reason badges. |
| 38 | ReasonMentioned, |
| 39 | ReasonAssigned, |
| 40 | ReasonReviewRequested, |
| 41 | ReasonAuthor, |
| 42 | ReasonCommented, |
| 43 | ReasonStateChange, |
| 44 | ReasonSubscribed, |
| 45 | ReasonWatching, |
| 46 | ReasonReplied, |
| 47 | ReasonSecurity, |
| 48 | // Notifications: activity verbs (`activity_line` adds the actor). |
| 49 | VerbOpened, |
| 50 | VerbCommented, |
| 51 | VerbClosed, |
| 52 | VerbReopened, |
| 53 | VerbMerged, |
| 54 | VerbReviewed, |
| 55 | VerbAssigned, |
| 56 | VerbMentionedYou, |
| 57 | VerbPushedTo, |
| 58 | VerbUpdated, |
| 59 | VerbDiscussionReply, |
| 60 | // Notifications: why the viewer is subscribed (`receiving_because` wraps them). |
| 61 | WhyMentioned, |
| 62 | WhyAssigned, |
| 63 | WhyReviewRequested, |
| 64 | WhyAuthor, |
| 65 | WhyCommented, |
| 66 | WhySubscribed, |
| 67 | WhyWatching, |
| 68 | NotReceivingRepo, |
| 69 | NotReceivingThread, |
| 70 | // Notifications: inbox page. |
| 71 | MarkAllAsRead, |
| 72 | MarkAllRead, |
| 73 | MarkRead, |
| 74 | NoNotificationsYet, |
| 75 | NoUnreadNotifications, |
| 76 | NotificationFilter, |
| 77 | Unread, |
| 78 | AllTab, |
| 79 | Older, |
| 80 | // Notifications: subscription box and watch control. |
| 81 | Subscribe, |
| 82 | Unsubscribe, |
| 83 | OptParticipating, |
| 84 | OptWatching, |
| 85 | OptIgnoring, |
| 86 | WatchDescParticipating, |
| 87 | WatchDescWatching, |
| 88 | WatchDescIgnoring, |
| 89 | // Repo security page. |
| 90 | SecurityOff, |
| 91 | LockfilesRead, |
| 92 | NoAlerts, |
| 93 | ColAdvisory, |
| 94 | ColPackage, |
| 95 | ColVersion, |
| 96 | ColSeverity, |
| 97 | ColSummary, |
| 98 | ColState, |
| 99 | ColOpened, |
| 100 | StateOpen, |
| 101 | StateDismissed, |
| 102 | StateFixed, |
| 103 | Dismiss, |
| 104 | Reopen, |
| 105 | // New repository form. |
| 106 | NewOwner, |
| 107 | RepoName, |
| 108 | DescriptionOptional, |
| 109 | VisibilityLegend, |
| 110 | PrivateHelp, |
| 111 | PublicHelp, |
| 112 | DefaultBranch, |
| 113 | AddDefaultLabels, |
| 114 | MirrorLegend, |
| 115 | MirrorIntro, |
| 116 | SourceUrl, |
| 117 | UsernameOptional, |
| 118 | PasswordOrToken, |
| 119 | SyncInterval, |
| 120 | CreateRepository, |
| 121 | OwnerRefused, |
| 122 | InvalidRepoName, |
| 123 | // Dashboard contribution calendar (`views::heatmap`). |
| 124 | ContributionsTitle, |
| 125 | ContributionsLastYear, |
| 126 | CurrentStreak, |
| 127 | LongestStreak, |
| 128 | BestDay, |
| 129 | Less, |
| 130 | More, |
| 131 | MonLabel, |
| 132 | WedLabel, |
| 133 | FriLabel, |
| 134 | // Dashboard greeting and "Needs your attention" column. |
| 135 | GoodMorning, |
| 136 | GoodAfternoon, |
| 137 | GoodEvening, |
| 138 | NeedsAttention, |
| 139 | NothingNeedsYou, |
| 140 | ViewAllNotifications, |
| 141 | // Shell chrome (`views::mod`): breadcrumb landmark, theme picker, ref selector. |
| 142 | BreadcrumbNav, |
| 143 | ApplyTheme, |
| 144 | RefLabel, |
| 145 | // Top-bar user menu: the viewer's public profile and the settings editor. |
| 146 | YourProfile, |
| 147 | EditProfile, |
| 148 | } |
| 149 | |
| 150 | /// Every variant, for the coverage test below. |
| 151 | #[cfg(test)] |
| 152 | const ALL: &[K] = &[ |
| 153 | K::Appearance, |
| 154 | K::ThemeLabel, |
| 155 | K::LanguageLabel, |
| 156 | K::ThemeAndLanguage, |
| 157 | K::MatchSystemHelp, |
| 158 | K::MatchSystem, |
| 159 | K::Light, |
| 160 | K::Dark, |
| 161 | K::MatchBrowser, |
| 162 | K::SwitchToLight, |
| 163 | K::SwitchToDark, |
| 164 | K::SwitchToMatchSystem, |
| 165 | K::AppearanceSaved, |
| 166 | K::ChooseTheme, |
| 167 | K::ChooseLanguage, |
| 168 | K::KindOpenIssue, |
| 169 | K::KindClosedIssue, |
| 170 | K::KindOpenPull, |
| 171 | K::KindClosedPull, |
| 172 | K::KindDiscussion, |
| 173 | K::KindSecurityAlerts, |
| 174 | K::ReasonMentioned, |
| 175 | K::ReasonAssigned, |
| 176 | K::ReasonReviewRequested, |
| 177 | K::ReasonAuthor, |
| 178 | K::ReasonCommented, |
| 179 | K::ReasonStateChange, |
| 180 | K::ReasonSubscribed, |
| 181 | K::ReasonWatching, |
| 182 | K::ReasonReplied, |
| 183 | K::ReasonSecurity, |
| 184 | K::VerbOpened, |
| 185 | K::VerbCommented, |
| 186 | K::VerbClosed, |
| 187 | K::VerbReopened, |
| 188 | K::VerbMerged, |
| 189 | K::VerbReviewed, |
| 190 | K::VerbAssigned, |
| 191 | K::VerbMentionedYou, |
| 192 | K::VerbPushedTo, |
| 193 | K::VerbUpdated, |
| 194 | K::VerbDiscussionReply, |
| 195 | K::WhyMentioned, |
| 196 | K::WhyAssigned, |
| 197 | K::WhyReviewRequested, |
| 198 | K::WhyAuthor, |
| 199 | K::WhyCommented, |
| 200 | K::WhySubscribed, |
| 201 | K::WhyWatching, |
| 202 | K::NotReceivingRepo, |
| 203 | K::NotReceivingThread, |
| 204 | K::MarkAllAsRead, |
| 205 | K::MarkAllRead, |
| 206 | K::MarkRead, |
| 207 | K::NoNotificationsYet, |
| 208 | K::NoUnreadNotifications, |
| 209 | K::NotificationFilter, |
| 210 | K::Unread, |
| 211 | K::AllTab, |
| 212 | K::Older, |
| 213 | K::Subscribe, |
| 214 | K::Unsubscribe, |
| 215 | K::OptParticipating, |
| 216 | K::OptWatching, |
| 217 | K::OptIgnoring, |
| 218 | K::WatchDescParticipating, |
| 219 | K::WatchDescWatching, |
| 220 | K::WatchDescIgnoring, |
| 221 | K::SecurityOff, |
| 222 | K::LockfilesRead, |
| 223 | K::NoAlerts, |
| 224 | K::ColAdvisory, |
| 225 | K::ColPackage, |
| 226 | K::ColVersion, |
| 227 | K::ColSeverity, |
| 228 | K::ColSummary, |
| 229 | K::ColState, |
| 230 | K::ColOpened, |
| 231 | K::StateOpen, |
| 232 | K::StateDismissed, |
| 233 | K::StateFixed, |
| 234 | K::Dismiss, |
| 235 | K::Reopen, |
| 236 | K::NewOwner, |
| 237 | K::RepoName, |
| 238 | K::DescriptionOptional, |
| 239 | K::VisibilityLegend, |
| 240 | K::PrivateHelp, |
| 241 | K::PublicHelp, |
| 242 | K::DefaultBranch, |
| 243 | K::AddDefaultLabels, |
| 244 | K::MirrorLegend, |
| 245 | K::MirrorIntro, |
| 246 | K::SourceUrl, |
| 247 | K::UsernameOptional, |
| 248 | K::PasswordOrToken, |
| 249 | K::SyncInterval, |
| 250 | K::CreateRepository, |
| 251 | K::OwnerRefused, |
| 252 | K::InvalidRepoName, |
| 253 | K::ContributionsTitle, |
| 254 | K::ContributionsLastYear, |
| 255 | K::CurrentStreak, |
| 256 | K::LongestStreak, |
| 257 | K::BestDay, |
| 258 | K::Less, |
| 259 | K::More, |
| 260 | K::MonLabel, |
| 261 | K::WedLabel, |
| 262 | K::FriLabel, |
| 263 | K::GoodMorning, |
| 264 | K::GoodAfternoon, |
| 265 | K::GoodEvening, |
| 266 | K::NeedsAttention, |
| 267 | K::NothingNeedsYou, |
| 268 | K::ViewAllNotifications, |
| 269 | K::BreadcrumbNav, |
| 270 | K::ApplyTheme, |
| 271 | K::RefLabel, |
| 272 | K::YourProfile, |
| 273 | K::EditProfile, |
| 274 | ]; |
| 275 | |
| 276 | pub fn t(lang: Lang, key: K) -> &'static str { |
| 277 | use K::*; |
| 278 | use Lang::*; |
| 279 | match (key, lang) { |
| 280 | (Appearance, En) => "Appearance", |
| 281 | (Appearance, Tr) => "Görünüm", |
| 282 | (ThemeLabel, En) => "Theme", |
| 283 | (ThemeLabel, Tr) => "Tema", |
| 284 | (LanguageLabel, En) => "Language", |
| 285 | (LanguageLabel, Tr) => "Dil", |
| 286 | (ThemeAndLanguage, En) => "Theme and language", |
| 287 | (ThemeAndLanguage, Tr) => "Tema ve dil", |
| 288 | (MatchSystemHelp, En) => { |
| 289 | "Match the system follows your operating system's light or dark setting." |
| 290 | } |
| 291 | (MatchSystemHelp, Tr) => { |
| 292 | "Sistem ile eşleştir, işletim sisteminizin açık veya koyu ayarını izler." |
| 293 | } |
| 294 | (MatchSystem, En) => "Match the system", |
| 295 | (MatchSystem, Tr) => "Sistem ile eşleştir", |
| 296 | (Light, En) => "Light", |
| 297 | (Light, Tr) => "Açık", |
| 298 | (Dark, En) => "Dark", |
| 299 | (Dark, Tr) => "Koyu", |
| 300 | (MatchBrowser, En) => "Match the browser", |
| 301 | (MatchBrowser, Tr) => "Tarayıcı ile eşleştir", |
| 302 | (SwitchToLight, En) => "Switch to Light", |
| 303 | (SwitchToLight, Tr) => "Açık temaya geç", |
| 304 | (SwitchToDark, En) => "Switch to Dark", |
| 305 | (SwitchToDark, Tr) => "Koyu temaya geç", |
| 306 | (SwitchToMatchSystem, En) => "Switch to match the system", |
| 307 | (SwitchToMatchSystem, Tr) => "Sistem ile eşleştir moduna geç", |
| 308 | (AppearanceSaved, En) => "Appearance saved.", |
| 309 | (AppearanceSaved, Tr) => "Görünüm kaydedildi.", |
| 310 | (ChooseTheme, En) => "Choose a theme from the list.", |
| 311 | (ChooseTheme, Tr) => "Listeden bir tema seçin.", |
| 312 | (ChooseLanguage, En) => "Choose a language from the list.", |
| 313 | (ChooseLanguage, Tr) => "Listeden bir dil seçin.", |
| 314 | (KindOpenIssue, En) => "Open issue", |
| 315 | (KindOpenIssue, Tr) => "Açık sorun", |
| 316 | (KindClosedIssue, En) => "Closed issue", |
| 317 | (KindClosedIssue, Tr) => "Kapalı sorun", |
| 318 | (KindOpenPull, En) => "Open pull request", |
| 319 | (KindOpenPull, Tr) => "Açık çekme isteği", |
| 320 | (KindClosedPull, En) => "Closed pull request", |
| 321 | (KindClosedPull, Tr) => "Kapalı çekme isteği", |
| 322 | (KindDiscussion, En) => "Discussion", |
| 323 | (KindDiscussion, Tr) => "Tartışma", |
| 324 | (KindSecurityAlerts, En) => "Security alerts", |
| 325 | (KindSecurityAlerts, Tr) => "Güvenlik uyarıları", |
| 326 | (ReasonMentioned, En) => "mentioned", |
| 327 | (ReasonMentioned, Tr) => "bahsedildi", |
| 328 | (ReasonAssigned, En) => "assigned", |
| 329 | (ReasonAssigned, Tr) => "atandı", |
| 330 | (ReasonReviewRequested, En) => "review requested", |
| 331 | (ReasonReviewRequested, Tr) => "inceleme istendi", |
| 332 | (ReasonAuthor, En) => "author", |
| 333 | (ReasonAuthor, Tr) => "yazar", |
| 334 | (ReasonCommented, En) => "commented", |
| 335 | (ReasonCommented, Tr) => "yorumladı", |
| 336 | (ReasonStateChange, En) => "state change", |
| 337 | (ReasonStateChange, Tr) => "durum değişikliği", |
| 338 | (ReasonSubscribed, En) => "subscribed", |
| 339 | (ReasonSubscribed, Tr) => "abone", |
| 340 | (ReasonWatching, En) => "watching", |
| 341 | (ReasonWatching, Tr) => "izleniyor", |
| 342 | (ReasonReplied, En) => "replied", |
| 343 | (ReasonReplied, Tr) => "yanıtladı", |
| 344 | (ReasonSecurity, En) => "security", |
| 345 | (ReasonSecurity, Tr) => "güvenlik", |
| 346 | (VerbOpened, En) => "opened", |
| 347 | (VerbOpened, Tr) => "açıldı", |
| 348 | (VerbCommented, En) => "commented", |
| 349 | (VerbCommented, Tr) => "yorumlandı", |
| 350 | (VerbClosed, En) => "closed", |
| 351 | (VerbClosed, Tr) => "kapatıldı", |
| 352 | (VerbReopened, En) => "reopened", |
| 353 | (VerbReopened, Tr) => "yeniden açıldı", |
| 354 | (VerbMerged, En) => "merged", |
| 355 | (VerbMerged, Tr) => "birleştirildi", |
| 356 | (VerbReviewed, En) => "reviewed", |
| 357 | (VerbReviewed, Tr) => "incelendi", |
| 358 | (VerbAssigned, En) => "assigned", |
| 359 | (VerbAssigned, Tr) => "atandı", |
| 360 | (VerbMentionedYou, En) => "mentioned you", |
| 361 | (VerbMentionedYou, Tr) => "sizden bahsedildi", |
| 362 | (VerbPushedTo, En) => "pushed to", |
| 363 | (VerbPushedTo, Tr) => "gönderim yapıldı", |
| 364 | (VerbUpdated, En) => "updated", |
| 365 | (VerbUpdated, Tr) => "güncellendi", |
| 366 | (VerbDiscussionReply, En) => "commented on your discussion", |
| 367 | (VerbDiscussionReply, Tr) => "tartışmanıza yorum yapıldı", |
| 368 | (WhyMentioned, En) => "you were mentioned", |
| 369 | (WhyMentioned, Tr) => "sizden bahsedildiği için", |
| 370 | (WhyAssigned, En) => "you were assigned", |
| 371 | (WhyAssigned, Tr) => "size atandığınız için", |
| 372 | (WhyReviewRequested, En) => "you were asked to review", |
| 373 | (WhyReviewRequested, Tr) => "incelemeniz istendiği için", |
| 374 | (WhyAuthor, En) => "you authored this", |
| 375 | (WhyAuthor, Tr) => "bunu siz yazdığınız için", |
| 376 | (WhyCommented, En) => "you commented on this", |
| 377 | (WhyCommented, Tr) => "buna yorum yaptığınız için", |
| 378 | (WhySubscribed, En) => "you subscribed to this", |
| 379 | (WhySubscribed, Tr) => "buna abone olduğunuz için", |
| 380 | (WhyWatching, En) => "you are watching this repository", |
| 381 | (WhyWatching, Tr) => "bu depoyu izlediğiniz için", |
| 382 | (NotReceivingRepo, En) => { |
| 383 | "You're not receiving notifications from this repository. Mentions still notify you." |
| 384 | } |
| 385 | (NotReceivingRepo, Tr) => { |
| 386 | "Bu depodan bildirim almıyorsunuz. Yine de bahsedildiğinizde bildirim alırsınız." |
| 387 | } |
| 388 | (NotReceivingThread, En) => "You're not receiving notifications from this thread.", |
| 389 | (NotReceivingThread, Tr) => "Bu konudan bildirim almıyorsunuz.", |
| 390 | (MarkAllAsRead, En) => "Mark all as read", |
| 391 | (MarkAllAsRead, Tr) => "Tümünü okundu olarak işaretle", |
| 392 | (MarkAllRead, En) => "Mark all read", |
| 393 | (MarkAllRead, Tr) => "Tümünü okundu işaretle", |
| 394 | (MarkRead, En) => "Mark read", |
| 395 | (MarkRead, Tr) => "Okundu işaretle", |
| 396 | (NoNotificationsYet, En) => "No notifications yet.", |
| 397 | (NoNotificationsYet, Tr) => "Henüz bildirim yok.", |
| 398 | (NoUnreadNotifications, En) => "You have no unread notifications.", |
| 399 | (NoUnreadNotifications, Tr) => "Okunmamış bildiriminiz yok.", |
| 400 | (NotificationFilter, En) => "Notification filter", |
| 401 | (NotificationFilter, Tr) => "Bildirim filtresi", |
| 402 | (Unread, En) => "Unread", |
| 403 | (Unread, Tr) => "Okunmamış", |
| 404 | (AllTab, En) => "All", |
| 405 | (AllTab, Tr) => "Tümü", |
| 406 | (Older, En) => "Older", |
| 407 | (Older, Tr) => "Daha eski", |
| 408 | (Subscribe, En) => "Subscribe", |
| 409 | (Subscribe, Tr) => "Abone ol", |
| 410 | (Unsubscribe, En) => "Unsubscribe", |
| 411 | (Unsubscribe, Tr) => "Abonelikten çık", |
| 412 | (OptParticipating, En) => "Participating", |
| 413 | (OptParticipating, Tr) => "Katılımcı", |
| 414 | (OptWatching, En) => "Watching", |
| 415 | (OptWatching, Tr) => "İzleniyor", |
| 416 | (OptIgnoring, En) => "Ignoring", |
| 417 | (OptIgnoring, Tr) => "Yok sayılıyor", |
| 418 | (WatchDescParticipating, En) => "Only threads you start, join or are mentioned in.", |
| 419 | (WatchDescParticipating, Tr) => { |
| 420 | "Yalnızca başlattığın, katıldığın veya adının geçtiği konular." |
| 421 | } |
| 422 | (WatchDescWatching, En) => "All activity in this repository.", |
| 423 | (WatchDescWatching, Tr) => "Bu depodaki tüm etkinlik.", |
| 424 | (WatchDescIgnoring, En) => "Nothing from this repository, except mentions.", |
| 425 | (WatchDescIgnoring, Tr) => "Bu depodan hiçbir şey, yalnızca adınızın geçtikleri hariç.", |
| 426 | (SecurityOff, En) => { |
| 427 | "Security advisories are off on this instance, so no lockfile is scanned. An administrator can turn them on with the [advisories] section of the config." |
| 428 | } |
| 429 | (SecurityOff, Tr) => { |
| 430 | "Bu sunucuda güvenlik tavsiyeleri kapalı, bu yüzden hiçbir kilit dosyası taranmıyor. Bir yönetici bunları yapılandırma dosyasındaki [advisories] bölümünden açabilir." |
| 431 | } |
| 432 | (LockfilesRead, En) => { |
| 433 | "Lockfiles read: Cargo.lock, package-lock.json (v2 and v3) and go.sum, up to three directories deep. Alerts open after a push to the default branch, and close when the dependency moves past the fix." |
| 434 | } |
| 435 | (LockfilesRead, Tr) => { |
| 436 | "Okunan kilit dosyaları: Cargo.lock, package-lock.json (v2 ve v3) ve go.sum; en fazla üç dizin derinliğine kadar. Uyarılar varsayılan dala gönderim yapıldıktan sonra açılır ve bağımlılık düzeltme sürümünü geçtiğinde kapanır." |
| 437 | } |
| 438 | (NoAlerts, En) => "No alerts.", |
| 439 | (NoAlerts, Tr) => "Uyarı yok.", |
| 440 | (ColAdvisory, En) => "Advisory", |
| 441 | (ColAdvisory, Tr) => "Güvenlik tavsiyesi", |
| 442 | (ColPackage, En) => "Package", |
| 443 | (ColPackage, Tr) => "Paket", |
| 444 | (ColVersion, En) => "Version", |
| 445 | (ColVersion, Tr) => "Sürüm", |
| 446 | (ColSeverity, En) => "Severity", |
| 447 | (ColSeverity, Tr) => "Önem", |
| 448 | (ColSummary, En) => "Summary", |
| 449 | (ColSummary, Tr) => "Özet", |
| 450 | (ColState, En) => "State", |
| 451 | (ColState, Tr) => "Durum", |
| 452 | (ColOpened, En) => "Opened", |
| 453 | (ColOpened, Tr) => "Açılış", |
| 454 | (StateOpen, En) => "Open", |
| 455 | (StateOpen, Tr) => "Açık", |
| 456 | (StateDismissed, En) => "Dismissed", |
| 457 | (StateDismissed, Tr) => "Yoksayıldı", |
| 458 | (StateFixed, En) => "Fixed", |
| 459 | (StateFixed, Tr) => "Düzeltildi", |
| 460 | (Dismiss, En) => "Dismiss", |
| 461 | (Dismiss, Tr) => "Yoksay", |
| 462 | (Reopen, En) => "Reopen", |
| 463 | (Reopen, Tr) => "Yeniden aç", |
| 464 | (NewOwner, En) => "Owner", |
| 465 | (NewOwner, Tr) => "Sahip", |
| 466 | (RepoName, En) => "Repository name", |
| 467 | (RepoName, Tr) => "Depo adı", |
| 468 | (DescriptionOptional, En) => "Description (optional)", |
| 469 | (DescriptionOptional, Tr) => "Açıklama (isteğe bağlı)", |
| 470 | (VisibilityLegend, En) => "Visibility", |
| 471 | (VisibilityLegend, Tr) => "Görünürlük", |
| 472 | (PrivateHelp, En) => "Private: only you and collaborators can see it", |
| 473 | (PrivateHelp, Tr) => "Özel: yalnızca siz ve ortak çalışanlar görebilir", |
| 474 | (PublicHelp, En) => "Public: anyone can read it", |
| 475 | (PublicHelp, Tr) => "Herkese açık: herkes okuyabilir", |
| 476 | (DefaultBranch, En) => "Default branch", |
| 477 | (DefaultBranch, Tr) => "Varsayılan dal", |
| 478 | (AddDefaultLabels, En) => { |
| 479 | "Add default labels (bug, documentation, enhancement and the rest)" |
| 480 | } |
| 481 | (AddDefaultLabels, Tr) => { |
| 482 | "Varsayılan etiketleri ekle (bug, documentation, enhancement ve diğerleri)" |
| 483 | } |
| 484 | (MirrorLegend, En) => "Mirror an existing repository (optional)", |
| 485 | (MirrorLegend, Tr) => "Mevcut bir depoyu yansıt (isteğe bağlı)", |
| 486 | (MirrorIntro, En) => { |
| 487 | "The new repository starts empty and is filled from this URL: branches and tags are fetched now and on the interval. Pushes to it are refused." |
| 488 | } |
| 489 | (MirrorIntro, Tr) => { |
| 490 | "Yeni depo boş başlar ve bu URL'den doldurulur: dallar ve etiketler şimdi ve belirli aralıklarla çekilir. Bu depoya yapılan gönderimler reddedilir." |
| 491 | } |
| 492 | (SourceUrl, En) => "Source URL", |
| 493 | (SourceUrl, Tr) => "Kaynak URL", |
| 494 | (UsernameOptional, En) => "Username (optional)", |
| 495 | (UsernameOptional, Tr) => "Kullanıcı adı (isteğe bağlı)", |
| 496 | (PasswordOrToken, En) => "Password or token (optional)", |
| 497 | (PasswordOrToken, Tr) => "Parola veya belirteç (isteğe bağlı)", |
| 498 | (SyncInterval, En) => "Sync interval in minutes (0 = manual only, at least 10)", |
| 499 | (SyncInterval, Tr) => "Eşitleme aralığı (dakika; 0 = yalnızca elle, en az 10)", |
| 500 | (CreateRepository, En) => "Create repository", |
| 501 | (CreateRepository, Tr) => "Depo oluştur", |
| 502 | (OwnerRefused, En) => "you cannot create repositories for that owner", |
| 503 | (OwnerRefused, Tr) => "bu sahip için depo oluşturamazsınız", |
| 504 | (InvalidRepoName, En) => "invalid repository name", |
| 505 | (InvalidRepoName, Tr) => "geçersiz depo adı", |
| 506 | (ContributionsTitle, En) => "Contributions", |
| 507 | (ContributionsTitle, Tr) => "Katkılar", |
| 508 | (ContributionsLastYear, En) => "contributions in the last year", |
| 509 | (ContributionsLastYear, Tr) => "son bir yılda katkı", |
| 510 | (CurrentStreak, En) => "Current streak", |
| 511 | (CurrentStreak, Tr) => "Mevcut seri", |
| 512 | (LongestStreak, En) => "Longest streak", |
| 513 | (LongestStreak, Tr) => "En uzun seri", |
| 514 | (BestDay, En) => "Best day", |
| 515 | (BestDay, Tr) => "En iyi gün", |
| 516 | (Less, En) => "Less", |
| 517 | (Less, Tr) => "Az", |
| 518 | (More, En) => "More", |
| 519 | (More, Tr) => "Çok", |
| 520 | (MonLabel, En) => "Mon", |
| 521 | (MonLabel, Tr) => "Pzt", |
| 522 | (WedLabel, En) => "Wed", |
| 523 | (WedLabel, Tr) => "Çar", |
| 524 | (FriLabel, En) => "Fri", |
| 525 | (FriLabel, Tr) => "Cum", |
| 526 | (GoodMorning, En) => "Good morning", |
| 527 | (GoodMorning, Tr) => "Günaydın", |
| 528 | (GoodAfternoon, En) => "Good afternoon", |
| 529 | (GoodAfternoon, Tr) => "İyi günler", |
| 530 | (GoodEvening, En) => "Good evening", |
| 531 | (GoodEvening, Tr) => "İyi akşamlar", |
| 532 | (NeedsAttention, En) => "Needs your attention", |
| 533 | (NeedsAttention, Tr) => "Dikkatinizi bekleyenler", |
| 534 | (NothingNeedsYou, En) => "Nothing needs you right now.", |
| 535 | (NothingNeedsYou, Tr) => "Şu an dikkatinizi bekleyen bir şey yok.", |
| 536 | (ViewAllNotifications, En) => "View all notifications", |
| 537 | (ViewAllNotifications, Tr) => "Tüm bildirimleri gör", |
| 538 | (BreadcrumbNav, En) => "Path", |
| 539 | (BreadcrumbNav, Tr) => "Yol", |
| 540 | (ApplyTheme, En) => "Apply", |
| 541 | (ApplyTheme, Tr) => "Uygula", |
| 542 | (RefLabel, En) => "Ref", |
| 543 | (RefLabel, Tr) => "Referans", |
| 544 | (YourProfile, En) => "Your profile", |
| 545 | (YourProfile, Tr) => "Profilin", |
| 546 | (EditProfile, En) => "Edit profile", |
| 547 | (EditProfile, Tr) => "Profili düzenle", |
| 548 | } |
| 549 | } |
| 550 | |
| 551 | /// `1,284` in English, `1.284` in Turkish. |
| 552 | pub fn thousands(lang: Lang, n: u64) -> String { |
| 553 | let sep = match lang { |
| 554 | Lang::En => ',', |
| 555 | Lang::Tr => '.', |
| 556 | }; |
| 557 | let digits = n.to_string(); |
| 558 | let mut out = String::with_capacity(digits.len() + digits.len() / 3); |
| 559 | for (i, ch) in digits.chars().enumerate() { |
| 560 | if i > 0 && (digits.len() - i).is_multiple_of(3) { |
| 561 | out.push(sep); |
| 562 | } |
| 563 | out.push(ch); |
| 564 | } |
| 565 | out |
| 566 | } |
| 567 | |
| 568 | /// `12 days` / `12 gün`, for a streak length. |
| 569 | pub fn streak_days(lang: Lang, n: u64) -> String { |
| 570 | match lang { |
| 571 | Lang::En => format!("{n} day{}", if n == 1 { "" } else { "s" }), |
| 572 | Lang::Tr => format!("{n} gün"), |
| 573 | } |
| 574 | } |
| 575 | |
| 576 | /// `1 contribution` / `3 contributions`, and `3 katkı` in Turkish. |
| 577 | pub fn contributions_count(lang: Lang, n: u64) -> String { |
| 578 | match lang { |
| 579 | Lang::En => format!("{n} contribution{}", if n == 1 { "" } else { "s" }), |
| 580 | Lang::Tr => format!("{n} katkı"), |
| 581 | } |
| 582 | } |
| 583 | |
| 584 | /// Short month name, `1..=12`. Turkish uses the usual three-letter forms. |
| 585 | pub fn month_abbrev(lang: Lang, month: i64) -> &'static str { |
| 586 | const EN: [&str; 12] = [ |
| 587 | "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", |
| 588 | ]; |
| 589 | const TR: [&str; 12] = [ |
| 590 | "Oca", "Şub", "Mar", "Nis", "May", "Haz", "Tem", "Ağu", "Eyl", "Eki", "Kas", "Ara", |
| 591 | ]; |
| 592 | let index = (month.clamp(1, 12) - 1) as usize; |
| 593 | match lang { |
| 594 | Lang::En => EN[index], |
| 595 | Lang::Tr => TR[index], |
| 596 | } |
| 597 | } |
| 598 | |
| 599 | /// `16 Oct 2026` in English, `16 Eki 2026` in Turkish. |
| 600 | pub fn date_text(lang: Lang, year: i64, month: i64, day: i64) -> String { |
| 601 | format!("{day} {} {year}", month_abbrev(lang, month)) |
| 602 | } |
| 603 | |
| 604 | /// `16 Oct 2025 to 16 Oct 2026` in English; Turkish joins the two dates with a dash. |
| 605 | pub fn date_range(lang: Lang, from: &str, to: &str) -> String { |
| 606 | match lang { |
| 607 | Lang::En => format!("{from} to {to}"), |
| 608 | Lang::Tr => format!("{from} – {to}"), |
| 609 | } |
| 610 | } |
| 611 | |
| 612 | /// The contribution calendar's motivating line. `today` is today's count, `streak` the current |
| 613 | /// streak (which counts today when `today > 0`). |
| 614 | pub fn heatmap_motivation(lang: Lang, today: u64, streak: u64) -> String { |
| 615 | match (lang, today > 0, streak > 0) { |
| 616 | (Lang::En, true, _) => format!("Nice \u{2014} that's a {streak}-day streak."), |
| 617 | (Lang::En, false, true) => format!( |
| 618 | "Keep it going: one commit today makes it a {}-day streak.", |
| 619 | streak + 1 |
| 620 | ), |
| 621 | (Lang::En, false, false) => "Start a new streak today.".to_owned(), |
| 622 | (Lang::Tr, true, _) => format!("Harika \u{2014} {streak} günlük bir seri!"), |
| 623 | (Lang::Tr, false, true) => format!( |
| 624 | "Devam edin: bugün bir katkı, seriyi {} güne çıkarır.", |
| 625 | streak + 1 |
| 626 | ), |
| 627 | (Lang::Tr, false, false) => "Bugün yeni bir seri başlatın.".to_owned(), |
| 628 | } |
| 629 | } |
| 630 | |
| 631 | /// The calendar's accessible summary, for the grid's `aria-label`. |
| 632 | pub fn heatmap_summary(lang: Lang, total: u64, current: u64, longest: u64) -> String { |
| 633 | let total = thousands(lang, total); |
| 634 | let current = streak_days(lang, current); |
| 635 | let longest = streak_days(lang, longest); |
| 636 | match lang { |
| 637 | Lang::En => format!( |
| 638 | "Contribution calendar: {total} contributions in the last year. Current streak {current}, longest streak {longest}." |
| 639 | ), |
| 640 | Lang::Tr => format!( |
| 641 | "Katkı takvimi: son bir yılda {total} katkı. Mevcut seri {current}, en uzun seri {longest}." |
| 642 | ), |
| 643 | } |
| 644 | } |
| 645 | |
| 646 | /// A calendar cell's hover text: `3 contributions on 16 Oct 2026`. |
| 647 | pub fn contributions_on(lang: Lang, n: u64, date: &str) -> String { |
| 648 | match lang { |
| 649 | Lang::En => format!("{} on {date}", contributions_count(lang, n)), |
| 650 | Lang::Tr => format!("{date}: {}", contributions_count(lang, n)), |
| 651 | } |
| 652 | } |
| 653 | |
| 654 | /// The activity line for an inbox row: the verb, then the actor when there is one. English reads |
| 655 | /// "opened by alice"; Turkish reads "alice tarafından açıldı", or "Açıldı" with no actor. |
| 656 | pub fn activity_line(lang: Lang, verb: K, actor: Option<&str>) -> String { |
| 657 | let verb = t(lang, verb); |
| 658 | match (lang, actor) { |
| 659 | (Lang::En, Some(actor)) => format!("{verb} by {actor}"), |
| 660 | (Lang::En, None) => verb.to_owned(), |
| 661 | (Lang::Tr, Some(actor)) => format!("{actor} tarafından {verb}"), |
| 662 | (Lang::Tr, None) => capitalize(verb), |
| 663 | } |
| 664 | } |
| 665 | |
| 666 | /// "You're receiving notifications because ..." for a reason fragment such as `WhyMentioned`. |
| 667 | pub fn receiving_because(lang: Lang, why: K) -> String { |
| 668 | let why = t(lang, why); |
| 669 | match lang { |
| 670 | Lang::En => format!("You're receiving notifications because {why}."), |
| 671 | Lang::Tr => format!("{} bildirim alıyorsunuz.", capitalize(why)), |
| 672 | } |
| 673 | } |
| 674 | |
| 675 | /// "3 watching" / "3 izleyici", the watch control's count. |
| 676 | pub fn watchers_count(lang: Lang, watchers: u64) -> String { |
| 677 | match lang { |
| 678 | Lang::En => format!("{watchers} watching"), |
| 679 | Lang::Tr => format!("{watchers} izleyici"), |
| 680 | } |
| 681 | } |
| 682 | |
| 683 | /// "3 new alerts" / "3 yeni uyarı". |
| 684 | pub fn new_alerts(lang: Lang, count: u64) -> String { |
| 685 | match lang { |
| 686 | Lang::En if count == 1 => format!("{count} new alert"), |
| 687 | Lang::En => format!("{count} new alerts"), |
| 688 | Lang::Tr => format!("{count} yeni uyarı"), |
| 689 | } |
| 690 | } |
| 691 | |
| 692 | /// The security page's summary of how many dependencies were read and how many alerts are open. |
| 693 | pub fn dependencies_summary(lang: Lang, dependencies: u64, open: usize) -> String { |
| 694 | match lang { |
| 695 | Lang::En => format!( |
| 696 | "{dependencies} dependencies were read from the lockfiles on the default branch. {open} open alerts." |
| 697 | ), |
| 698 | Lang::Tr => format!( |
| 699 | "Varsayılan daldaki kilit dosyalarından {dependencies} bağımlılık okundu. {open} açık uyarı var." |
| 700 | ), |
| 701 | } |
| 702 | } |
| 703 | |
| 704 | /// The new-repo error for a description over the limit. |
| 705 | pub fn description_too_long(lang: Lang, max: usize) -> String { |
| 706 | match lang { |
| 707 | Lang::En => format!("description must be at most {max} characters"), |
| 708 | Lang::Tr => format!("açıklama en fazla {max} karakter olabilir"), |
| 709 | } |
| 710 | } |
| 711 | |
| 712 | /// The new-repo error when the git repository could not be created. |
| 713 | pub fn git_init_failed(lang: Lang, error: impl Display) -> String { |
| 714 | match lang { |
| 715 | Lang::En => format!("could not create the git repository: {error}"), |
| 716 | Lang::Tr => format!("git deposu oluşturulamadı: {error}"), |
| 717 | } |
| 718 | } |
| 719 | |
| 720 | /// Upper-cases the first character. Turkish verbs here start with a plain letter, so the |
| 721 | /// default mapping is right. |
| 722 | /// "Good morning, Ahmet" for an hour before noon, "Good afternoon" before 18:00 and "Good |
| 723 | /// evening" otherwise. `hour` is 0-23 in UTC. |
| 724 | pub fn greeting(lang: Lang, hour: u8, name: &str) -> String { |
| 725 | let phrase = match hour { |
| 726 | 0..12 => K::GoodMorning, |
| 727 | 12..18 => K::GoodAfternoon, |
| 728 | _ => K::GoodEvening, |
| 729 | }; |
| 730 | format!("{}, {name}", t(lang, phrase)) |
| 731 | } |
| 732 | |
| 733 | /// `1 repository` / `3 repositories`, and `3 depo` in Turkish. |
| 734 | pub fn repositories_count(lang: Lang, n: u64) -> String { |
| 735 | match lang { |
| 736 | Lang::En => format!("{n} repositor{}", if n == 1 { "y" } else { "ies" }), |
| 737 | Lang::Tr => format!("{n} depo"), |
| 738 | } |
| 739 | } |
| 740 | |
| 741 | fn capitalize(text: &str) -> String { |
| 742 | let mut chars = text.chars(); |
| 743 | match chars.next() { |
| 744 | Some(first) => first.to_uppercase().chain(chars).collect(), |
| 745 | None => String::new(), |
| 746 | } |
| 747 | } |
| 748 | |
| 749 | #[cfg(test)] |
| 750 | mod tests { |
| 751 | use super::*; |
| 752 | |
| 753 | #[test] |
| 754 | fn every_variant_has_both_languages() { |
| 755 | for key in ALL { |
| 756 | assert!(!t(Lang::En, *key).is_empty(), "{key:?} has no English"); |
| 757 | assert!(!t(Lang::Tr, *key).is_empty(), "{key:?} has no Turkish"); |
| 758 | } |
| 759 | } |
| 760 | |
| 761 | #[test] |
| 762 | fn turkish_differs_from_english_for_translated_phrases() { |
| 763 | let differing = ALL |
| 764 | .iter() |
| 765 | .filter(|key| t(Lang::En, **key) != t(Lang::Tr, **key)) |
| 766 | .count(); |
| 767 | assert!(differing >= 3, "only {differing} phrases are translated"); |
| 768 | assert_eq!(t(Lang::Tr, K::Appearance), "Görünüm"); |
| 769 | } |
| 770 | |
| 771 | #[test] |
| 772 | fn activity_lines_keep_the_english_wording() { |
| 773 | assert_eq!( |
| 774 | activity_line(Lang::En, K::VerbOpened, Some("alice")), |
| 775 | "opened by alice" |
| 776 | ); |
| 777 | assert_eq!(activity_line(Lang::En, K::VerbUpdated, None), "updated"); |
| 778 | assert_eq!( |
| 779 | activity_line(Lang::Tr, K::VerbOpened, Some("alice")), |
| 780 | "alice tarafından açıldı" |
| 781 | ); |
| 782 | assert_eq!(activity_line(Lang::Tr, K::VerbUpdated, None), "Güncellendi"); |
| 783 | } |
| 784 | |
| 785 | #[test] |
| 786 | fn plural_helpers_match_english() { |
| 787 | assert_eq!(new_alerts(Lang::En, 1), "1 new alert"); |
| 788 | assert_eq!(new_alerts(Lang::En, 2), "2 new alerts"); |
| 789 | assert_eq!(new_alerts(Lang::Tr, 3), "3 yeni uyarı"); |
| 790 | assert_eq!( |
| 791 | receiving_because(Lang::En, K::WhySubscribed), |
| 792 | "You're receiving notifications because you subscribed to this." |
| 793 | ); |
| 794 | } |
| 795 | } |