Files
pdfcraft/crates/engine/src/edit/labels.rs
T
Claude 03fdf97cde Merge remote-tracking branch 'upstream/main' into feat/bookmarks-from-text-styles
# Conflicts:
#	crates/ui-egui/src/commands.rs
#	crates/ui-egui/src/dialogs.rs

Main split the command and dialog dispatch for its stricter clippy
rules; New bookmarks from text styles goes into the command list after
New bookmarks from structure, and its dialog into the dialog dispatch
next to the other dialogs with their own buttons.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GbuSKAS2k5248LGFEapMUR
2026-10-28 06:07:14 +00:00

339 lines
16 KiB
Rust

use super::{Edit, FillMark, ImageEdit, Label, LineEnding, MarkKind, Markup, PageBox, ReviewState, Shape, field_table};
/// Every wording [`Edit::label`] can produce, for an interface to translate. `Edit::Batch` is not
/// here: its wording is only the hole, because a batch carries its name as text (see
/// [`BATCH_LABELS`]).
pub const EDIT_LABELS: &[&str] = &[
"Rotate page",
"Change tag properties",
"Rotate pages",
"Delete page",
"Delete pages",
"Move page",
"Move pages",
"Reverse pages",
"Insert blank page",
"Duplicate page",
"Duplicate pages",
"Replace page",
"Replace pages",
"Crop page",
"Crop pages",
"Set page boxes",
"Set page transitions",
"Change Title",
"Change Author",
"Change Subject",
"Change Keywords",
"Change {key}",
"Insert pages from {name}",
"Insert pages from {name} — 1 field renamed",
"Insert pages from {name} — fields renamed",
"Attach {name}",
"Delete attachment {key}",
"Add bookmark",
"Rename bookmark",
"Delete bookmark",
"Move bookmark",
"Set bookmark destination",
"Colour",
"Style",
"New bookmarks from structure",
"New bookmarks from text styles",
"Number pages",
"Measure distance",
"Measure perimeter",
"Measure area",
"Set measurement scale",
"Add sticky note",
"Add highlight",
"Add underline",
"Add strikethrough",
"Add squiggly underline",
"Add rectangle",
"Add oval",
"Add arrow",
"Add line",
"Add drawing",
"Add text box",
"Add checkmark",
"Add cross",
"Add dot",
"Add signature",
"Add redaction mark",
"Add cloud",
"Add polygon",
"Add connected lines",
"Add callout",
"Add inserted text",
"Add file attachment",
"Add stamp",
"Delete comment",
"Edit comment",
"Reply",
"Set status None",
"Set status Accepted",
"Set status Rejected",
"Set status Cancelled",
"Set status Completed",
"Replace text",
"Erase",
"Mark with checkmark",
"Remove checkmark",
"Lock comment",
"Unlock comment",
"Move comment",
"Reshape comment",
"Resize comment",
"Change comment properties",
"Fill in {name}",
"Set the image of {name}",
"Clear form",
"Add field",
"Change field properties",
"Delete field",
"Duplicate field",
"Set tab order",
"Set calculation order",
"Change initial view",
"Set alternate text",
"Mark figure as decorative",
"Recognize text",
"Run JavaScript",
"Run form script",
"Save as {level}",
"Remove {standard} identification",
"Edit script of {name}",
"Delete document JavaScript",
"Edit document JavaScript",
"Edit text",
"Load document font",
"Move object",
"Move objects",
"Move image",
"Rotate image",
"Flip image",
"Replace image",
"Delete image",
"Add header & footer",
"Update header & footer",
"Add watermark",
"Update watermark",
"Add background",
"Update background",
"Remove header & footer",
"Remove watermark",
"Remove background",
"Add text",
"Add image",
"Edit content",
"Delete content",
"Paste",
"Apply redactions",
"Remove redaction marks",
"Remove hidden information",
"Import {name}",
"Add link",
"Change link properties",
"Delete link",
"Remove all links",
"Create link",
"Create links",
"Sanitize document",
"Flatten comments",
"Flatten form fields",
"Flatten",
"Flatten Fill & Sign",
"Protect with password",
"Remove security",
];
/// The names of the batches built below L7, which an interface shows in the same places as
/// [`EDIT_LABELS`] and so translates the same way. A batch built in the interface itself arrives
/// already worded in the interface's language.
pub const BATCH_LABELS: &[&str] =
&["Set document title", "Mark differences", "Detect form fields", "Run JavaScript", "Recognize text", field_table::LABEL, "Style"];
impl Edit {
/// Label for the Edit menu and history ("Undo Rotate pages").
pub fn label(&self) -> Label {
match self {
Edit::RotatePages { pages, .. } => plural("Rotate page", "Rotate pages", pages.len()),
Edit::DeletePages { pages } => plural("Delete page", "Delete pages", pages.len()),
Edit::MovePages { pages, .. } => plural("Move page", "Move pages", pages.len()),
Edit::ReversePages { .. } => Label::of("Reverse pages"),
Edit::InsertBlankPage { .. } => Label::of("Insert blank page"),
Edit::DuplicatePages { pages, .. } => plural("Duplicate page", "Duplicate pages", pages.len()),
Edit::ReplacePages { pages, .. } => plural("Replace page", "Replace pages", pages.len()),
Edit::SetPageBox { pages, which: PageBox::Crop, .. } => plural("Crop page", "Crop pages", pages.len()),
Edit::SetPageBox { .. } => Label::of("Set page boxes"),
Edit::SetTransition { .. } => Label::of("Set page transitions"),
// The four `/Info` keys PdfCraft itself offers get a wording of their own, so each can
// be said in another language; any other key is the document's and goes in as it stands.
Edit::SetInfo { key, .. } => match key.as_str() {
"Title" => Label::of("Change Title"),
"Author" => Label::of("Change Author"),
"Subject" => Label::of("Change Subject"),
"Keywords" => Label::of("Change Keywords"),
_ => Label::with("Change {key}", key.as_str()),
},
Edit::InsertPagesFrom { name, .. } => Label::with("Insert pages from {name}", name.as_str()),
Edit::AddBookmark { .. } => Label::of("Add bookmark"),
Edit::RenameBookmark { .. } => Label::of("Rename bookmark"),
Edit::DeleteBookmark { .. } => Label::of("Delete bookmark"),
Edit::MoveBookmark { .. } => Label::of("Move bookmark"),
Edit::SetBookmarkPage { .. } => Label::of("Set bookmark destination"),
// The bookmark Style and Colour menus' own names, already said in every language.
Edit::SetBookmarkColor { .. } => Label::of("Colour"),
Edit::SetBookmarkStyle { .. } => Label::of("Style"),
Edit::BookmarksFromStructure => Label::of("New bookmarks from structure"),
Edit::BookmarksFromTextStyles { .. } => Label::of("New bookmarks from text styles"),
Edit::NumberPages { .. } => Label::of("Number pages"),
// What was measured is part of the wording too, for the same reason.
Edit::AddMeasurement(m) => Label::of(match m.kind {
pdfcraft_measure::Kind::Distance => "Measure distance",
pdfcraft_measure::Kind::Perimeter => "Measure perimeter",
pdfcraft_measure::Kind::Area => "Measure area",
}),
Edit::SetMeasurementScale { .. } => Label::of("Set measurement scale"),
Edit::AddAnnotation(a) => Label::of(add_annotation(&a.shape)),
Edit::AddCustomStamp { .. } => Label::of("Add stamp"),
Edit::DeleteAnnotation { .. } => Label::of("Delete comment"),
Edit::SetAnnotationContents { .. } => Label::of("Edit comment"),
Edit::ReplyToAnnotation { .. } => Label::of("Reply"),
// The state's name is part of the wording: a language may need to agree it with the rest.
Edit::SetAnnotationStatus { state, .. } => Label::of(match state {
ReviewState::None => "Set status None",
ReviewState::Accepted => "Set status Accepted",
ReviewState::Rejected => "Set status Rejected",
ReviewState::Cancelled => "Set status Cancelled",
ReviewState::Completed => "Set status Completed",
}),
Edit::ReplaceText { .. } => Label::of("Replace text"),
Edit::EraseInk { .. } => Label::of("Erase"),
Edit::MarkAnnotation { marked: true, .. } => Label::of("Mark with checkmark"),
Edit::MarkAnnotation { .. } => Label::of("Remove checkmark"),
Edit::LockAnnotation { locked: true, .. } => Label::of("Lock comment"),
Edit::LockAnnotation { .. } => Label::of("Unlock comment"),
Edit::MoveAnnotation { .. } => Label::of("Move comment"),
Edit::ReshapeAnnotation { .. } => Label::of("Reshape comment"),
Edit::ResizeAnnotation { .. } => Label::of("Resize comment"),
Edit::StyleAnnotation { .. } | Edit::FillAnnotation { .. } | Edit::FontSizeAnnotation { .. } | Edit::SetAnnotationInfo { .. } => {
Label::of("Change comment properties")
}
Edit::SetFieldValue { name, .. } => Label::with("Fill in {name}", name.as_str()),
Edit::SetFieldImage { name, .. } => Label::with("Set the image of {name}", name.as_str()),
Edit::ResetForm { .. } => Label::of("Clear form"),
Edit::AddField { .. } => Label::of("Add field"),
Edit::SetFieldProps { .. } => Label::of("Change field properties"),
Edit::DeleteField { .. } => Label::of("Delete field"),
Edit::DuplicateField { .. } => Label::of("Duplicate field"),
Edit::SetTabOrder { .. } | Edit::MoveInTabOrder { .. } => Label::of("Set tab order"),
Edit::SetCalculationOrder { .. } => Label::of("Set calculation order"),
Edit::SetInitialView(_) => Label::of("Change initial view"),
Edit::AddAttachment { name, .. } => Label::with("Attach {name}", name.as_str()),
Edit::DeleteAttachment { key } => Label::with("Delete attachment {key}", key.as_str()),
Edit::AutoTagText => Label::of("Automatically tag text"),
Edit::SetAltText { .. } => Label::of("Set alternate text"),
Edit::AutoTagFormFields => Label::of("Tag form fields"),
Edit::SetTagProperty { .. } => Label::of("Change tag properties"),
Edit::MoveTag { .. } => Label::of("Move object"),
Edit::MarkDecorative { .. } => Label::of("Mark figure as decorative"),
Edit::MarkTagArtifact { .. } => Label::of("Mark content as artifact"),
Edit::AddOcrText { .. } => Label::of("Recognize text"),
Edit::ApplyScriptChanges { .. } => Label::of("Run JavaScript"),
Edit::XfaEvent { .. } => Label::of("Run form script"),
// The level is the standard's own name ("PDF/A-2b"), so it goes in as it stands.
Edit::ConvertPdfA { level } => Label::with("Save as {level}", level.label()),
Edit::RemoveStandardId { standard } => Label::with("Remove {standard} identification", standard.label()),
Edit::SetFieldScript { name, .. } => Label::with("Edit script of {name}", name.as_str()),
Edit::SetDocumentScript { script: None, .. } => Label::of("Delete document JavaScript"),
Edit::SetDocumentScript { .. } => Label::of("Edit document JavaScript"),
Edit::EditTextLine { .. } | Edit::EditTextBlock { .. } => Label::of("Edit text"),
Edit::RegisterTextFont { .. } => Label::of("Load document font"),
Edit::MoveObjects { objects, .. } => plural("Move object", "Move objects", objects.len()),
Edit::EditPageImage { change, .. } => Label::of(match change {
ImageEdit::Move(_) => "Move image",
ImageEdit::Rotate(_) | ImageEdit::RotateBy(_) => "Rotate image",
ImageEdit::Crop(_) => "Crop image",
ImageEdit::Flip { .. } => "Flip image",
ImageEdit::Replace { .. } => "Replace image",
ImageEdit::Delete => "Delete image",
}),
Edit::AddHeaderFooter { replace: false, .. } => Label::of("Add header & footer"),
Edit::AddHeaderFooter { .. } => Label::of("Update header & footer"),
Edit::AddWatermark { replace: false, .. } => Label::of("Add watermark"),
Edit::AddWatermark { .. } => Label::of("Update watermark"),
Edit::AddBackground { replace: false, .. } => Label::of("Add background"),
Edit::AddBackground { .. } => Label::of("Update background"),
Edit::RemoveMarks { kind: MarkKind::HeaderFooter } => Label::of("Remove header & footer"),
Edit::RemoveMarks { kind: MarkKind::Watermark } => Label::of("Remove watermark"),
Edit::RemoveMarks { kind: MarkKind::Background } => Label::of("Remove background"),
Edit::AddText { .. } => Label::of("Add text"),
Edit::AddImage { .. } => Label::of("Add image"),
Edit::UpdateContent { .. } => Label::of("Edit content"),
Edit::DeleteContent { .. } => Label::of("Delete content"),
Edit::ReplaceImage { .. } => Label::of("Replace image"),
Edit::PasteContent { .. } => Label::of("Paste"),
Edit::ApplyRedactions { .. } => Label::of("Apply redactions"),
Edit::ClearRedactions => Label::of("Remove redaction marks"),
Edit::RemoveHidden { .. } => Label::of("Remove hidden information"),
Edit::ImportData { name, .. } => Label::with("Import {name}", name.as_str()),
Edit::AddLink { .. } => Label::of("Add link"),
Edit::SetLink { .. } => Label::of("Change link properties"),
Edit::DeleteLink { .. } => Label::of("Delete link"),
Edit::RemoveLinks { .. } => Label::of("Remove all links"),
Edit::AddLinks { links, .. } => plural("Create link", "Create links", links.len()),
Edit::Sanitize => Label::of("Sanitize document"),
Edit::XfaToStatic => Label::of("Convert to a static form"),
Edit::Flatten { comments: true, fields: false } => Label::of("Flatten comments"),
Edit::Flatten { comments: false, fields: true } => Label::of("Flatten form fields"),
Edit::Flatten { .. } => Label::of("Flatten"),
Edit::FlattenFillSign => Label::of("Flatten Fill & Sign"),
Edit::Protect(_) => Label::of("Protect with password"),
Edit::RemoveProtection => Label::of("Remove security"),
// A batch carries its own name, already worded by whoever built it.
// A batch carries its name as text, so the wording is only the hole (see `BATCH_LABELS`).
Edit::Batch { label, .. } => Label::with("{batch}", label.as_str()),
}
}
}
/// What the Edit menu calls a new comment ("Undo Add highlight"). A whole wording for each kind,
/// so a language can give the noun the article and the gender its own grammar asks for.
fn add_annotation(s: &Shape) -> &'static str {
match s {
Shape::Note { .. } => "Add sticky note",
Shape::TextMarkup { kind: Markup::Highlight, .. } => "Add highlight",
Shape::TextMarkup { kind: Markup::Underline, .. } => "Add underline",
Shape::TextMarkup { kind: Markup::StrikeOut, .. } => "Add strikethrough",
Shape::TextMarkup { kind: Markup::Squiggly, .. } => "Add squiggly underline",
Shape::Rectangle { .. } => "Add rectangle",
Shape::Oval { .. } => "Add oval",
Shape::Line { start: LineEnding::None, end: LineEnding::OpenArrow, .. } => "Add arrow",
Shape::Line { .. } => "Add line",
Shape::Ink { .. } => "Add drawing",
Shape::TextBox { .. } => "Add text box",
Shape::Typewriter { .. } => "Add text",
Shape::Mark { mark: FillMark::Check, .. } => "Add checkmark",
Shape::Mark { mark: FillMark::Cross, .. } => "Add cross",
Shape::Mark { mark: FillMark::Dot, .. } => "Add dot",
Shape::Mark { mark: FillMark::Line, .. } => "Add line",
Shape::Signature { .. } | Shape::TypedSignature { .. } => "Add signature",
Shape::Redact { .. } => "Add redaction mark",
Shape::Stamp { .. } | Shape::CustomStamp { .. } => "Add stamp",
Shape::Polygon { cloud: true, .. } => "Add cloud",
Shape::Polygon { .. } => "Add polygon",
Shape::PolyLine { .. } => "Add connected lines",
Shape::Callout { .. } => "Add callout",
Shape::Caret { .. } => "Add inserted text",
Shape::Attachment { .. } => "Add file attachment",
}
}
/// The singular or the plural wording, by count. Both are written out: a language forms its plural
/// its own way, and `one` and `many` may differ in more than an "s".
fn plural(one: &'static str, many: &'static str, n: usize) -> Label {
Label::of(if n == 1 { one } else { many })
}