copy: drop em-dashes from user-facing strings
Mechanical AI-tell sweep across UI copy, hover text, log lines, and error
messages: em-dash replaced with a colon, semicolon, or split sentence per
context. No behavior change.
13 files changed,
+22 insertions,
-23 deletions
| 286 |
286 |
|
"Trial expired".to_string()
|
| 287 |
287 |
|
}
|
| 288 |
288 |
|
}
|
| 289 |
|
- |
None => "Start free trial — 30 days, no card".to_string(),
|
|
289 |
+ |
None => "Start free trial: 30 days, no card".to_string(),
|
| 290 |
290 |
|
}
|
| 291 |
291 |
|
}
|
| 292 |
292 |
|
|
| 375 |
375 |
|
fn label_no_trial_offers_start() {
|
| 376 |
376 |
|
assert_eq!(
|
| 377 |
377 |
|
trial_button_label(None),
|
| 378 |
|
- |
"Start free trial — 30 days, no card"
|
|
378 |
+ |
"Start free trial: 30 days, no card"
|
| 379 |
379 |
|
);
|
| 380 |
380 |
|
}
|
| 381 |
381 |
|
|
| 228 |
228 |
|
let test_suite_dir = samples_dir.join("test-suite");
|
| 229 |
229 |
|
|
| 230 |
230 |
|
println!("╔══════════════════════════════════════════════════════════════╗");
|
| 231 |
|
- |
println!("║ Audiofiles Analysis Pipeline — Benchmark Report ║");
|
|
231 |
+ |
println!("║ Audiofiles Analysis Pipeline: Benchmark Report ║");
|
| 232 |
232 |
|
println!("╚══════════════════════════════════════════════════════════════╝");
|
| 233 |
233 |
|
println!();
|
| 234 |
234 |
|
|
| 181 |
181 |
|
self.classifier.last_apply = Some(n);
|
| 182 |
182 |
|
self.refresh_selected_tags();
|
| 183 |
183 |
|
self.status = format!(
|
| 184 |
|
- |
"Rules applied — {n} sample{} updated",
|
|
184 |
+ |
"Rules applied: {n} sample{} updated",
|
| 185 |
185 |
|
if n == 1 { "" } else { "s" }
|
| 186 |
186 |
|
);
|
| 187 |
187 |
|
}
|
| 426 |
426 |
|
pub fn classifier_clear_head(&mut self) {
|
| 427 |
427 |
|
match self.backend.clear_classifier_head() {
|
| 428 |
428 |
|
Ok(()) => {
|
| 429 |
|
- |
self.status =
|
| 430 |
|
- |
"Trained model cleared — using nearest-neighbor matching.".to_string();
|
|
429 |
+ |
self.status = "Trained model cleared. Using nearest-neighbor matching.".to_string();
|
| 431 |
430 |
|
}
|
| 432 |
431 |
|
Err(e) => self.status = format!("Could not clear model: {e}"),
|
| 433 |
432 |
|
}
|
| 606 |
606 |
|
ForgeOvershoot::Trimmed { peak_dbfs, gain_db } => {
|
| 607 |
607 |
|
let _ = write!(
|
| 608 |
608 |
|
msg,
|
| 609 |
|
- |
" — true-peak +{:.1} dB trimmed {:.1} dB to avoid clipping",
|
|
609 |
+ |
"; true-peak +{:.1} dB trimmed {:.1} dB to avoid clipping",
|
| 610 |
610 |
|
peak_dbfs,
|
| 611 |
611 |
|
gain_db.abs()
|
| 612 |
612 |
|
);
|
| 614 |
614 |
|
ForgeOvershoot::Flagged { peak_dbfs } => {
|
| 615 |
615 |
|
let _ = write!(
|
| 616 |
616 |
|
msg,
|
| 617 |
|
- |
" — warning: true-peak +{peak_dbfs:.1} dB will clip (enable auto-trim in Settings to prevent)"
|
|
617 |
+ |
"; warning: true-peak +{peak_dbfs:.1} dB will clip (enable auto-trim in Settings to prevent)"
|
| 618 |
618 |
|
);
|
| 619 |
619 |
|
}
|
| 620 |
620 |
|
}
|
| 620 |
620 |
|
ui.label(
|
| 621 |
621 |
|
egui::RichText::new(
|
| 622 |
622 |
|
"For large libraries, distil your tagged samples into a compact model so \
|
| 623 |
|
- |
auto-tagging runs much faster. Optional — auto-tagging works without it.",
|
|
623 |
+ |
auto-tagging runs much faster. Optional: auto-tagging works without it.",
|
| 624 |
624 |
|
)
|
| 625 |
625 |
|
.small()
|
| 626 |
626 |
|
.color(theme::content_muted()),
|
| 630 |
630 |
|
Some(info) => {
|
| 631 |
631 |
|
ui.label(
|
| 632 |
632 |
|
egui::RichText::new(format!(
|
| 633 |
|
- |
"Active — {} tag{} from {} sample{}.",
|
|
633 |
+ |
"Active: {} tag{} from {} sample{}.",
|
| 634 |
634 |
|
info.class_count,
|
| 635 |
635 |
|
if info.class_count == 1 { "" } else { "s" },
|
| 636 |
636 |
|
info.exemplar_count,
|
| 646 |
646 |
|
format!("No model yet. With {n} tagged samples, training is recommended.")
|
| 647 |
647 |
|
} else {
|
| 648 |
648 |
|
format!(
|
| 649 |
|
- |
"No model — nearest-neighbor matching is fast enough at {n} tagged \
|
|
649 |
+ |
"No model: nearest-neighbor matching is fast enough at {n} tagged \
|
| 650 |
650 |
|
sample{}.",
|
| 651 |
651 |
|
if n == 1 { "" } else { "s" }
|
| 652 |
652 |
|
)
|
| 443 |
443 |
|
state.status = format!("Downloading {}...", node.node.name);
|
| 444 |
444 |
|
} else {
|
| 445 |
445 |
|
state.status =
|
| 446 |
|
- |
"Sync not ready — open the Sync panel first".to_string();
|
|
446 |
+ |
"Sync not ready: open the Sync panel first".to_string();
|
| 447 |
447 |
|
}
|
| 448 |
448 |
|
}
|
| 449 |
449 |
|
} else {
|
| 573 |
573 |
|
#[cfg(any(target_os = "macos", target_os = "windows"))]
|
| 574 |
574 |
|
let resp = if !node.cloud_only && node.node.node_type == NodeType::Sample {
|
| 575 |
575 |
|
let hover = if os_drag_blocked {
|
| 576 |
|
- |
"Just dragged — ready again in a moment."
|
|
576 |
+ |
"Just dragged. Ready again in a moment."
|
| 577 |
577 |
|
} else {
|
| 578 |
578 |
|
"Drag to Finder or DAW"
|
| 579 |
579 |
|
};
|
| 307 |
307 |
|
/// only; not built for this launch.
|
| 308 |
308 |
|
fn draw_foreshadow_section(ui: &mut egui::Ui) {
|
| 309 |
309 |
|
ui.label(
|
| 310 |
|
- |
egui::RichText::new("Plugin processing (CLAP/VST) — coming soon")
|
|
310 |
+ |
egui::RichText::new("Plugin processing (CLAP/VST): coming soon")
|
| 311 |
311 |
|
.small()
|
| 312 |
312 |
|
.italics()
|
| 313 |
313 |
|
.color(theme::content_muted()),
|
| 204 |
204 |
|
if walking {
|
| 205 |
205 |
|
let _ = ui
|
| 206 |
206 |
|
.add_enabled(false, egui::Button::new("Cancel"))
|
| 207 |
|
- |
.on_disabled_hover_text("Scanning — cancel available once the scan completes.");
|
|
207 |
+ |
.on_disabled_hover_text("Scanning. Cancel available once the scan completes.");
|
| 208 |
208 |
|
} else if ui.button("Cancel").clicked() {
|
| 209 |
209 |
|
state.cancel_import();
|
| 210 |
210 |
|
}
|
| 644 |
644 |
|
.small()
|
| 645 |
645 |
|
.color(theme::content_secondary()),
|
| 646 |
646 |
|
)
|
| 647 |
|
- |
.on_hover_text("Attack — time to reach full volume after key press");
|
|
647 |
+ |
.on_hover_text("Attack: time to reach full volume after key press");
|
| 648 |
648 |
|
let slider = egui::Slider::new(&mut envelope.attack, 0.001..=5.0)
|
| 649 |
649 |
|
.logarithmic(true)
|
| 650 |
650 |
|
.max_decimals(3)
|
| 656 |
656 |
|
.small()
|
| 657 |
657 |
|
.color(theme::content_secondary()),
|
| 658 |
658 |
|
)
|
| 659 |
|
- |
.on_hover_text("Decay — time to fall from peak to sustain level");
|
|
659 |
+ |
.on_hover_text("Decay: time to fall from peak to sustain level");
|
| 660 |
660 |
|
let slider = egui::Slider::new(&mut envelope.decay, 0.001..=5.0)
|
| 661 |
661 |
|
.logarithmic(true)
|
| 662 |
662 |
|
.max_decimals(3)
|
| 670 |
670 |
|
.small()
|
| 671 |
671 |
|
.color(theme::content_secondary()),
|
| 672 |
672 |
|
)
|
| 673 |
|
- |
.on_hover_text("Sustain — held volume level while the key is down (0 to 1)");
|
|
673 |
+ |
.on_hover_text("Sustain: held volume level while the key is down (0 to 1)");
|
| 674 |
674 |
|
let slider = egui::Slider::new(&mut envelope.sustain, 0.0..=1.0).max_decimals(2);
|
| 675 |
675 |
|
ui.add(slider);
|
| 676 |
676 |
|
|
| 679 |
679 |
|
.small()
|
| 680 |
680 |
|
.color(theme::content_secondary()),
|
| 681 |
681 |
|
)
|
| 682 |
|
- |
.on_hover_text("Release — time to fade to silence after key release");
|
|
682 |
+ |
.on_hover_text("Release: time to fade to silence after key release");
|
| 683 |
683 |
|
let slider = egui::Slider::new(&mut envelope.release, 0.001..=10.0)
|
| 684 |
684 |
|
.logarithmic(true)
|
| 685 |
685 |
|
.max_decimals(3)
|
| 252 |
252 |
|
ui.add_space(theme::space::XS);
|
| 253 |
253 |
|
ui.label(
|
| 254 |
254 |
|
egui::RichText::new(
|
| 255 |
|
- |
"Annual is 2 months free — fewer Stripe fees, so we pass the savings on.",
|
|
255 |
+ |
"Annual is 2 months free, so fewer Stripe fees, and we pass the savings on.",
|
| 256 |
256 |
|
)
|
| 257 |
257 |
|
.weak()
|
| 258 |
258 |
|
.size(11.0),
|
| 779 |
779 |
|
|
| 780 |
780 |
|
if computed != hash {
|
| 781 |
781 |
|
return Err(CoreError::Internal(format!(
|
| 782 |
|
- |
"hash mismatch: expected {hash}, got {computed} — this is a different file"
|
|
782 |
+ |
"hash mismatch: expected {hash}, got {computed}; this is a different file"
|
| 783 |
783 |
|
)));
|
| 784 |
784 |
|
}
|
| 785 |
785 |
|
|
| 56 |
56 |
|
// User plugin overrides another user plugin, warn about ambiguity
|
| 57 |
57 |
|
tracing::warn!(
|
| 58 |
58 |
|
device = %plugin.profile.name,
|
| 59 |
|
- |
"Multiple user plugins with the same device name — last one loaded wins"
|
|
59 |
+ |
"Multiple user plugins with the same device name; last one loaded wins"
|
| 60 |
60 |
|
);
|
| 61 |
61 |
|
}
|
| 62 |
62 |
|
}
|
| 95 |
95 |
|
// Parse GET /callback?code=X&state=Y or GET /?code=X&state=Y
|
| 96 |
96 |
|
if let Some((code, cb_state)) = parse_oauth_callback(&request) {
|
| 97 |
97 |
|
if cb_state != thread_expected_state {
|
| 98 |
|
- |
tracing::warn!("OAuth callback state mismatch — rejecting");
|
|
98 |
+ |
tracing::warn!("OAuth callback state mismatch: rejecting");
|
| 99 |
99 |
|
let body = "<html><body><h1>Authentication failed</h1><p>CSRF state mismatch. Please try again.</p></body></html>";
|
| 100 |
100 |
|
let response = format!(
|
| 101 |
101 |
|
"HTTP/1.1 403 Forbidden\r\nContent-Type: text/html\r\nContent-Length: {}\r\nAccess-Control-Allow-Origin: *\r\nConnection: close\r\n\r\n{}",
|