feat: Englische Oberfläche

Alle Oberflächentexte und Fehlermeldungen stehen in t!("…"); der deutsche
Text ist zugleich der Schlüssel für die englische Fassung in
src/i18n/en.rs (430 Einträge). Platzhalter heißen {name}. ink-notes folgt
der Systemsprache (Deutsch bei de…, sonst Englisch); im ☰-Menü lässt sie
sich unter „Sprache / Language“ auf System, Deutsch oder English
festlegen, gespeichert in ui.json.

Ein Test prüft, dass jeder markierte Text übersetzt ist, keine
Übersetzung verwaist und die Platzhalter übereinstimmen.
Konsolenausgaben bleiben deutsch.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-09 15:37:41 +02:00
co-authored by Claude Opus 5.5
parent ec6a5259d5
commit 6c0db643c4
23 changed files with 1576 additions and 617 deletions
+6 -5
View File
@@ -24,6 +24,7 @@ use crate::background::{PatternColor, DOT_SIZE, GRID_5MM_SPACING, LINED_SPACING}
use crate::document::{
Notebook, Page, PageBackground, Stroke, A4_HEIGHT_MM, A4_WIDTH_MM, PAGE_HEIGHT, PAGE_WIDTH,
};
use crate::t;
use ab_glyph::Font as _;
use crate::text::TextFont;
@@ -384,15 +385,15 @@ fn generate_pdf_document_with(
raster_pdf_pages: &std::collections::HashSet<usize>,
) -> Result<PdfDocumentReference, Box<dyn Error>> {
if notebook.pages.is_empty() {
return Err("Notizbuch enthält keine Seiten".into());
return Err(t!("Notizbuch enthält keine Seiten").into());
}
// Nicht geladene Seiten würden sonst stillschweigend als leere Seiten exportiert
if let Some(page) = notebook.pages.iter().find(|p| {
!p.is_loaded || p.persist == crate::document::PersistState::ReadOnlyAfterLoadError
}) {
return Err(format!(
"Seite {} ist nicht geladen – Export abgebrochen (vorher storage::load_all_pages aufrufen)",
page.id
return Err(t!(
"Seite {id} ist nicht geladen – Export abgebrochen (vorher storage::load_all_pages aufrufen)",
id = page.id
)
.into());
}
@@ -823,7 +824,7 @@ fn render_pdf_raster(
let longest_pt = pdf.width_pt.max(pdf.height_pt);
let max_pixels = (longest_pt / 72.0 * PDF_RASTER_DPI).ceil() as u32;
let rendered = assets
.ok_or_else(|| "kein Asset-Ordner".to_string())
.ok_or_else(|| t!("kein Asset-Ordner").to_string())
.and_then(|a| a.path_of(&pdf.asset).map_err(|e| e.to_string()))
.and_then(|path| crate::pdf_doc::render_file_page(&path, pdf.page as usize, max_pixels));
let xobject = match rendered {