diff --git a/ROADMAP.md b/ROADMAP.md index 070552d07e..ce1568f183 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -111,7 +111,7 @@ Localized German formulas and numbers are in PR #163. Detail: [localization-pari | Korean | ko | menus only | ~12% | | Vietnamese | vi | none | 0% | -Other shipped languages: 2 (Russian and German, menus only, ~12%). +Other shipped languages: 3 (Russian, German and Polish, menus only, ~12%). ## Upcoming diff --git a/crates/ui-egui/examples/snapshot.rs b/crates/ui-egui/examples/snapshot.rs index a171199a1c..2d8b4b7ceb 100644 --- a/crates/ui-egui/examples/snapshot.rs +++ b/crates/ui-egui/examples/snapshot.rs @@ -1,7 +1,7 @@ //! Renders the whole GridCraft window offscreen (wgpu, no window) to a PNG. //! //! `cargo run --release -p gridcraft-ui-egui --example snapshot -- [--sample sales] [--in file.xlsx] -//! [--size 1440x900] [--scale 2] [--cmd 'id={json}']... [--tab Insert] [--dark] [--language en|zh|ja|ko|ru|pt|cs] +//! [--size 1440x900] [--scale 2] [--cmd 'id={json}']... [--tab Insert] [--dark] [--language en|zh|ja|ko|ru|pt|cs|pl] //! [--dialog 'name={json}'] [--hf-edit header|footer] out.png` use gridcraft_engine::Session; diff --git a/crates/ui-egui/src/control.rs b/crates/ui-egui/src/control.rs index 2ea5cfae01..b013ee0033 100644 --- a/crates/ui-egui/src/control.rs +++ b/crates/ui-egui/src/control.rs @@ -195,7 +195,11 @@ pub fn handle(app: &mut SheetApp, ctx: &egui::Context, method: &str, p: &Json) - "Submit Print Job", "existing file.print sheet/pagination params → {printing,bytes,pending}; submits without opening a dialog", ), - ("app.language.set", "Interface Language", "{language: \"en\"|\"zh\"|\"ja\"|\"ko\"|\"ru\"|\"pt\"|\"de\"|\"cs\"} (alias: code)"), + ( + "app.language.set", + "Interface Language", + "{language: \"en\"|\"zh\"|\"ja\"|\"ko\"|\"ru\"|\"pt\"|\"de\"|\"cs\"|\"pl\"} (alias: code)", + ), ("app.language.english", "Interface Language: English", ""), ("app.language.japanese", "Interface Language: Japanese", ""), ] { diff --git a/crates/ui-egui/src/i18n.rs b/crates/ui-egui/src/i18n.rs index 98919f8a43..793b41446b 100644 --- a/crates/ui-egui/src/i18n.rs +++ b/crates/ui-egui/src/i18n.rs @@ -14,6 +14,7 @@ mod de; mod es; mod fr; mod ko; +mod pl; mod pt; mod ru; mod sr; @@ -35,10 +36,12 @@ pub enum Language { Cs, Fr, Sr, + Pl, } impl Language { - pub const ALL: [Self; 11] = [Self::En, Self::Es, Self::Zh, Self::Ja, Self::Ko, Self::Ru, Self::PtBr, Self::De, Self::Cs, Self::Fr, Self::Sr]; + pub const ALL: [Self; 12] = + [Self::En, Self::Es, Self::Zh, Self::Ja, Self::Ko, Self::Ru, Self::PtBr, Self::De, Self::Cs, Self::Fr, Self::Sr, Self::Pl]; /// The language's own name, shown in the switcher. pub fn name(self) -> &'static str { @@ -54,6 +57,7 @@ impl Language { Self::Cs => "Čeština", Self::Fr => "Français", Self::Sr => "Srpski", + Self::Pl => "Polski", } } @@ -71,6 +75,7 @@ impl Language { Self::Cs => "cs", Self::Fr => "fr", Self::Sr => "sr", + Self::Pl => "pl", } } @@ -91,6 +96,7 @@ impl Language { "cs" => Some(Self::Cs), "fr" => Some(Self::Fr), "sr" => Some(Self::Sr), + "pl" => Some(Self::Pl), _ => None, } } @@ -129,6 +135,7 @@ impl Language { Self::Cs => cs::translate(text), Self::Fr => fr::translate(text), Self::Sr => sr::translate(text), + Self::Pl => pl::translate(text), }; translated.unwrap_or_else(|| text.rsplit_once('|').map_or(text, |(_, label)| label)) } @@ -611,6 +618,7 @@ mod tests { assert!(cs::translate(english).is_some_and(|text| !text.is_empty()), "missing Czech: {english}"); assert!(fr::translate(english).is_some_and(|text| !text.is_empty()), "missing French: {english}"); assert!(sr::translate(english).is_some_and(|text| !text.is_empty()), "missing Serbian: {english}"); + assert!(pl::translate(english).is_some_and(|text| !text.is_empty()), "missing Polish: {english}"); } assert_eq!(Language::Ja.tr("Data"), "データ"); assert_eq!(Language::Zh.tr("Data"), "数据"); @@ -624,6 +632,8 @@ mod tests { assert_eq!(Language::De.tr("Sheet1!A1"), "Sheet1!A1"); assert_eq!(Language::Fr.tr("Data"), "Données"); assert_eq!(Language::Fr.tr("Sheet1!A1"), "Sheet1!A1"); + assert_eq!(Language::Pl.tr("Data"), "Dane"); + assert_eq!(Language::Pl.tr("Sheet1!A1"), "Sheet1!A1"); assert_eq!(Language::PtBr.tr("Date"), "Data"); assert_eq!(Language::PtBr.tr("Sheet1!A1"), "Sheet1!A1"); assert_eq!(Language::Ja.tr("Sheet1!A1"), "Sheet1!A1"); @@ -644,6 +654,8 @@ mod tests { assert_eq!(Language::Sr.tr("Sheet1!A1"), "Sheet1!A1"); assert_eq!(Language::Sr.tr("Page Layout|Orientation"), "Orijentacija"); assert_eq!(Language::Sr.tr("Orientation"), "Orijentacija"); + assert_eq!(Language::Pl.tr("Page Layout|Orientation"), "Orientacja"); + assert_eq!(Language::Pl.tr("Orientation"), "Kierunek tekstu"); assert_eq!(Language::parse("xx"), None); } @@ -738,6 +750,9 @@ mod tests { assert_eq!(Language::from_tag("sr-Latn-RS"), Some(Language::Sr)); assert_eq!(Language::from_tag("sr-RS"), Some(Language::Sr)); assert_eq!(Language::parse("sr"), Some(Language::Sr)); + assert_eq!(Language::from_tag("pl-PL"), Some(Language::Pl)); + assert_eq!(Language::from_tag("pl_PL.UTF-8"), Some(Language::Pl)); + assert_eq!(Language::parse("pl"), Some(Language::Pl)); } #[test] diff --git a/crates/ui-egui/src/i18n/pl.rs b/crates/ui-egui/src/i18n/pl.rs new file mode 100644 index 0000000000..31bd3ea241 --- /dev/null +++ b/crates/ui-egui/src/i18n/pl.rs @@ -0,0 +1,464 @@ +//! Polish translations for the interface strings in i18n.rs. Written from the meaning of the +//! English labels in ordinary Polish computing vocabulary; anything absent falls back to English. + +pub(super) fn translate(text: &str) -> Option<&'static str> { + Some(match text { + "Paste" => "Wklej", + "Paste Values" => "Wklej wartości", + "Paste Formulas" => "Wklej formuły", + "Paste Formatting" => "Wklej formatowanie", + "Transpose" => "Transponuj", + "Paste Link" => "Wklej łącze", + "Paste Special…" => "Wklej specjalnie…", + "Insert Copied Cells" => "Wstaw skopiowane komórki", + "Insert Copied Cells…" => "Wstaw skopiowane komórki…", + "Insert Cut Cells" => "Wstaw wycięte komórki", + "Insert Paste" => "Wstaw i wklej", + "Cut (⌘X)" => "Wytnij (⌘X)", + "Copy (⌘C)" => "Kopiuj (⌘C)", + "Format Painter (double-click to keep it on)" => "Malarz formatów (kliknij dwukrotnie, aby pozostał włączony)", + "Bold (⌘B)" => "Pogrubienie (⌘B)", + "Italic (⌘I)" => "Kursywa (⌘I)", + "Underline (⌘U)" => "Podkreślenie (⌘U)", + "Double Underline" => "Podwójne podkreślenie", + "Strikethrough" => "Przekreślenie", + "Underline" => "Podkreślenie", + "Increase Font Size" => "Zwiększ rozmiar czcionki", + "Decrease Font Size" => "Zmniejsz rozmiar czcionki", + "Wrap Text" => "Zawijaj tekst", + "Merge & Center" => "Scal i wyśrodkuj", + "Merge Cells" => "Scal komórki", + "Merge Across" => "Scal wierszami", + "Unmerge Cells" => "Rozdziel komórki", + "Fill Color" => "Kolor wypełnienia", + "Font Color" => "Kolor czcionki", + "Borders" => "Obramowania", + "Top\nAlign" => "Do\ngóry", + "Middle\nAlign" => "Do\nśrodka", + "Bottom\nAlign" => "Do\ndołu", + "Left" => "Do lewej", + "Right" => "Do prawej", + "Center" => "Wyśrodkuj", + "Horizontal" => "Poziomo", + "Vertical Text" => "Tekst pionowy", + "Decrease Indent" => "Zmniejsz wcięcie", + "Increase Indent" => "Zwiększ wcięcie", + "Orientation" => "Kierunek tekstu", + "Page Layout|Orientation" => "Orientacja", + "Angle Counterclockwise" => "Obróć w lewo pod kątem", + "Angle Clockwise" => "Obróć w prawo pod kątem", + "Rotate Text Up" => "Obróć tekst w górę", + "Rotate Text Down" => "Obróć tekst w dół", + "Accounting Number Format" => "Format księgowy", + "Percent Style" => "Styl procentowy", + "Comma Style" => "Styl z separatorem tysięcy", + "Increase Decimal" => "Zwiększ liczbę miejsc dziesiętnych", + "Decrease Decimal" => "Zmniejsz liczbę miejsc dziesiętnych", + "More Accounting Formats…" => "Więcej formatów księgowych…", + "Conditional\nFormatting" => "Formatowanie\nwarunkowe", + "Conditional Formatting" => "Formatowanie warunkowe", + "Format\nas Table" => "Formatuj\njako tabelę", + "Cell\nStyles" => "Style\nkomórek", + "Format Cells…" => "Formatuj komórki…", + "Format Cell Alignment…" => "Wyrównanie komórek…", + "Format\nPane" => "Panel\nformatowania", + "Format" => "Format", + "Insert" => "Wstaw", + "Insert Cells…" => "Wstaw komórki…", + "Delete" => "Usuń", + "Delete Cells…" => "Usuń komórki…", + "Insert Sheet Rows" => "Wstaw wiersze arkusza", + "Insert Sheet Columns" => "Wstaw kolumny arkusza", + "Delete Sheet Rows" => "Usuń wiersze arkusza", + "Delete Sheet Columns" => "Usuń kolumny arkusza", + "Row Height…" => "Wysokość wiersza…", + "AutoFit Row Height" => "Dopasuj wysokość wiersza", + "Column Width…" => "Szerokość kolumny…", + "AutoFit Column Width" => "Dopasuj szerokość kolumny", + "Default Width…" => "Szerokość domyślna…", + "Hide Rows" => "Ukryj wiersze", + "Unhide Rows" => "Odkryj wiersze", + "Hide Columns" => "Ukryj kolumny", + "Unhide Columns" => "Odkryj kolumny", + "Lock Cell" => "Zablokuj komórkę", + "Clear" => "Wyczyść", + "Clear All" => "Wyczyść wszystko", + "Clear Formats" => "Wyczyść formaty", + "Clear Contents" => "Wyczyść zawartość", + "Clear Comments and Notes" => "Wyczyść komentarze i notatki", + "Clear Hyperlinks" => "Wyczyść hiperłącza", + "AutoSum" => "Autosumowanie", + "AutoSum (⌘⇧T)" => "Autosumowanie (⌘⇧T)", + "Flash\nFill" => "Wypełnianie\nbłyskawiczne", + "Flash Fill" => "Wypełnianie błyskawiczne", + "Fill" => "Wypełnij", + "Clear Print Area" => "Wyczyść obszar wydruku", + "Find &\nSelect" => "Znajdź\ni zaznacz", + "Find…" => "Znajdź…", + "Replace…" => "Zamień…", + "Go To…" => "Przejdź do…", + "Go To Special…" => "Przejdź do — specjalnie…", + "PivotTable" => "Tabela przestawna", + "Recommended\nCharts" => "Polecane\nwykresy", + "Table" => "Tabela", + "Pictures" => "Obrazy", + "Shapes" => "Kształty", + "Icons" => "Ikony", + "Text\nBox" => "Pole\ntekstowe", + "Comment" => "Komentarz", + "New\nComment" => "Nowy\nkomentarz", + "New Note" => "Nowa notatka", + "Show/Hide Note" => "Pokaż/ukryj notatkę", + "Header &\nFooter" => "Nagłówek\ni stopka", + "Text to\nColumns" => "Tekst jako\nkolumny", + "Link" => "Łącze", + "Symbol" => "Symbol", + "Sparklines" => "Wykresy przebiegu w czasie", + "Checkbox" => "Pole wyboru", + "Insert checkboxes in the selected cells" => "Wstaw pola wyboru w zaznaczonych komórkach", + "Header & Footer" => "Nagłówek i stopka", + "Draw with ink" => "Rysuj odręcznie", + "Eraser" => "Gumka", + "Ink to\nShape" => "Odręczne\nna kształt", + "Select\nObjects" => "Zaznacz\nobiekty", + "Themes" => "Motywy", + "Margins" => "Marginesy", + "Size" => "Rozmiar", + "Print\nArea" => "Obszar\nwydruku", + "Set Print Area" => "Ustaw obszar wydruku", + "Breaks" => "Podziały", + "Insert Page Break" => "Wstaw podział strony", + "Remove Page Break" => "Usuń podział strony", + "Reset All Page Breaks" => "Resetuj wszystkie podziały stron", + "Print\nTitles" => "Tytuły\nwydruku", + "Sheet\nRight-to-Left" => "Arkusz od prawej\ndo lewej", + "Sheet Right-to-Left" => "Arkusz od prawej do lewej", + "Narrow" => "Wąskie", + "Wide" => "Szerokie", + "Normal" => "Normalne", + "Portrait" => "Pionowa", + "Landscape" => "Pozioma", + "Custom Margins…" => "Marginesy niestandardowe…", + "Insert\nFunction" => "Wstaw\nfunkcję", + "Name\nManager" => "Menedżer\nnazw", + "Define Name" => "Definiuj nazwę", + "Use in Formula" => "Użyj w formule", + "Create from Selection" => "Utwórz z zaznaczenia", + "Trace Precedents" => "Śledź poprzedniki", + "Trace Dependents" => "Śledź zależności", + "Remove Arrows" => "Usuń strzałki", + "Show Formulas" => "Pokaż formuły", + "Error Checking" => "Sprawdzanie błędów", + "Evaluate Formula" => "Szacuj formułę", + "Watch Window" => "Okno czujki", + "Calculation\nOptions" => "Opcje\nobliczania", + "Calculate Now" => "Oblicz teraz", + "Calculate Sheet" => "Oblicz arkusz", + "Automatic" => "Automatycznie", + "Automatic Except for Data Tables" => "Automatycznie z wyjątkiem tabel danych", + "Manual" => "Ręcznie", + "Sort &\nFilter" => "Sortuj\ni filtruj", + "Sort" => "Sortuj", + "Sort A to Z" => "Sortuj od A do Z", + "Sort Z to A" => "Sortuj od Z do A", + "Custom Sort…" => "Sortowanie niestandardowe…", + "Filter" => "Filtruj", + "Reapply" => "Zastosuj ponownie", + "Get Data\n(Text/CSV)" => "Pobierz dane\n(tekst/CSV)", + "Remove\nDuplicates" => "Usuń\nduplikaty", + "Data\nValidation" => "Poprawność\ndanych", + "Data Validation" => "Poprawność danych", + "Data Validation…" => "Poprawność danych…", + "Circle Invalid Data" => "Zakreśl nieprawidłowe dane", + "Clear Validation" => "Wyczyść reguły poprawności", + "Group" => "Grupuj", + "Ungroup" => "Rozgrupuj", + "Show Detail" => "Pokaż szczegóły", + "Hide Detail" => "Ukryj szczegóły", + "Subtotal" => "Suma częściowa", + "Data\nAnalysis" => "Analiza\ndanych", + "Data Analysis" => "Analiza danych", + "Solver" => "Solver", + "What-If\nAnalysis" => "Analiza\nwarunkowa", + "Data Table…" => "Tabela danych…", + "Scenario Manager…" => "Menedżer scenariuszy…", + "Goal Seek…" => "Szukaj wyniku…", + "Forecast\nSheet" => "Arkusz\nprognozy", + "Spelling" => "Pisownia", + "Check\nAccessibility" => "Sprawdź\ndostępność", + "Threaded Comments" => "Komentarze w wątkach", + "Show\nComments" => "Pokaż\nkomentarze", + "Previous" => "Poprzedni", + "Next" => "Następny", + "Previous Comment" => "Poprzedni komentarz", + "Next Comment" => "Następny komentarz", + "Show All Notes" => "Pokaż wszystkie notatki", + "Convert to Comments" => "Konwertuj na komentarze", + "Protect\nWorkbook" => "Chroń\nskoroszyt", + "Allow Edit\nRanges" => "Zezwól na edycję\nzakresów", + "Allow Edit Ranges" => "Zezwól na edycję zakresów", + "Unprotect\nSheet" => "Nie chroń\narkusza", + "Protect Sheet…" => "Chroń arkusz…", + "Comments" => "Komentarze", + "Notes" => "Notatki", + "Page Break\nPreview" => "Podgląd\npodziału stron", + "Page\nLayout" => "Układ\nstrony", + "Formula Bar" => "Pasek formuły", + "Gridlines" => "Linie siatki", + "Headings" => "Nagłówki", + "Zoom" => "Powiększenie", + "100%" => "100%", + "Zoom to\nSelection" => "Powiększ do\nzaznaczenia", + "Freeze\nPanes" => "Zablokuj\nokienka", + "Freeze Panes" => "Zablokuj okienka", + "Freeze Top Row" => "Zablokuj górny wiersz", + "Freeze First Column" => "Zablokuj pierwszą kolumnę", + "Unfreeze Panes" => "Odblokuj okienka", + "Dark Mode" => "Tryb ciemny", + "Display theme" => "Motyw wyświetlania", + "Animations" => "Animacje", + "Glide the selection outline to the cell you move to instead of jumping there" => { + "Płynnie przesuwaj obramowanie zaznaczenia do komórki docelowej, zamiast przeskakiwać" + } + "System" => "Systemowy", + "Light" => "Jasny", + "Dark" => "Ciemny", + "Interface language" => "Język interfejsu", + "Interface size" => "Rozmiar interfejsu", + "Auto" => "Automatycznie", + "Drag to freeze columns" => "Przeciągnij, aby zablokować kolumny", + "Drag to freeze rows" => "Przeciągnij, aby zablokować wiersze", + "Command\nPalette" => "Paleta\npoleceń", + "Agent\nControl" => "Sterowanie\nprzez agenta", + "Action\nJournal" => "Dziennik\nakcji", + "About\nGridCraft" => "GridCraft —\ninformacje", + "Share" => "Udostępnij", + "Add Chart\nElement" => "Dodaj element\nwykresu", + "Change\nChart Type" => "Zmień typ\nwykresu", + "Switch\nRow/Column" => "Przełącz\nwiersz/kolumnę", + "Select\nData" => "Zaznacz\ndane", + "Data Labels: None" => "Etykiety danych: brak", + "Data Labels: Show" => "Etykiety danych: pokaż", + "Legend: None" => "Legenda: brak", + "Legend: Bottom" => "Legenda: na dole", + "Legend: Top" => "Legenda: u góry", + "Legend: Right" => "Legenda: z prawej", + "Gridlines: None" => "Linie siatki: brak", + "Gridlines: Show" => "Linie siatki: pokaż", + "Chart\nTitle" => "Tytuł\nwykresu", + "Delete\nChart" => "Usuń\nwykres", + "Convert\nto Range" => "Konwertuj\nna zakres", + "Table\nStyles" => "Style\ntabeli", + "Top 10 Items" => "10 największych wartości", + "Top 10%" => "10% największych wartości", + "Bottom 10 Items" => "10 najmniejszych wartości", + "Bottom 10%" => "10% najmniejszych wartości", + "Above Average" => "Powyżej średniej", + "Below Average" => "Poniżej średniej", + "Clear Rules from Entire Sheet" => "Wyczyść reguły z całego arkusza", + "Clear Rules from Selected Cells" => "Wyczyść reguły z zaznaczonych komórek", + "Constants" => "Stałe", + "Data Bars" => "Paski danych", + "Color Scales" => "Skale kolorów", + "Icon Sets" => "Zestawy ikon", + "Home" => "Narzędzia główne", + "Draw" => "Rysowanie", + "Page Layout" => "Układ strony", + "Formulas" => "Formuły", + "Data" => "Dane", + "Review" => "Recenzja", + "View" => "Widok", + "Automate" => "Automatyzacja", + "Table Design" => "Projekt tabeli", + "Chart Design" => "Projekt wykresu", + "Ready" => "Gotowy", + "Enter" => "Wprowadzanie", + "Edit" => "Edycja", + "Point" => "Wskazywanie", + "Calculate" => "Oblicz", + "Select destination and press Enter or choose Paste" => "Zaznacz miejsce docelowe i naciśnij Enter albo wybierz Wklej", + "General" => "Ogólne", + "Number" => "Liczbowe", + "Currency" => "Walutowe", + "Accounting" => "Księgowe", + "Date" => "Data", + "Time" => "Czas", + "Percentage" => "Procentowe", + "Fraction" => "Ułamkowe", + "Scientific" => "Naukowe", + "Text" => "Tekstowe", + "Special" => "Specjalne", + "Custom" => "Niestandardowe", + "Short Date" => "Data krótka", + "Long Date" => "Data długa", + "More Number Formats…" => "Więcej formatów liczb…", + "Financial" => "Finansowe", + "Logical" => "Logiczne", + "Date &\nTime" => "Data\ni czas", + "Lookup &\nReference" => "Wyszukiwanie\ni odwołania", + "Math &\nTrig" => "Matematyczne\ni trygonometryczne", + "More\nFunctions" => "Więcej\nfunkcji", + "Sheet Options|View" => "Wyświetl", + "Print" => "Drukuj", + "Click to add data" => "Kliknij, aby dodać dane", + "Add header" => "Dodaj nagłówek", + "Add footer" => "Dodaj stopkę", + "(none)" => "(brak)", + "Header" => "Nagłówek", + "Footer" => "Stopka", + "Page\nNumber" => "Numer\nstrony", + "Number\nof Pages" => "Liczba\nstron", + "Current\nDate" => "Bieżąca\ndata", + "Current\nTime" => "Bieżąca\ngodzina", + "File\nPath" => "Ścieżka\npliku", + "File\nName" => "Nazwa\npliku", + "Sheet\nName" => "Nazwa\narkusza", + "Go to\nHeader" => "Przejdź do\nnagłówka", + "Go to\nFooter" => "Przejdź do\nstopki", + "Page Number" => "Numer strony", + "Number of Pages" => "Liczba stron", + "Current Date" => "Bieżąca data", + "Current Time" => "Bieżąca godzina", + "File Path" => "Ścieżka pliku", + "File Name" => "Nazwa pliku", + "Sheet Name" => "Nazwa arkusza", + "Go to Header" => "Przejdź do nagłówka", + "Different First Page" => "Inna pierwsza strona", + "Different Odd & Even Pages" => "Inne strony parzyste i nieparzyste", + "Go to Footer" => "Przejdź do stopki", + "Ruler" => "Linijka", + "File" => "Plik", + "Back" => "Wstecz", + "New" => "Nowy", + "Open" => "Otwórz", + "Info" => "Informacje", + "Save" => "Zapisz", + "Save As" => "Zapisz jako", + "Export" => "Eksportuj", + "Close" => "Zamknij", + "Options" => "Opcje", + "Blank workbook" => "Pusty skoroszyt", + "Recent" => "Ostatnie", + "No recent workbooks yet." => "Nie ma jeszcze ostatnio używanych skoroszytów.", + "More workbooks" => "Więcej skoroszytów", + "Browse…" => "Przeglądaj…", + "Not saved yet" => "Jeszcze nie zapisano", + "Location" => "Lokalizacja", + "Sheets" => "Arkusze", + "Protect Workbook" => "Chroń skoroszyt", + "Sheet structure is locked: sheets can't be added, moved, renamed or deleted." => { + "Struktura arkuszy jest zablokowana: arkuszy nie można dodawać, przenosić ani usuwać, ani zmieniać ich nazw." + } + "Lock the sheet structure so sheets can't be added, moved, renamed or deleted." => { + "Zablokuj strukturę arkuszy, aby nie można było ich dodawać, przenosić ani usuwać, ani zmieniać ich nazw." + } + "Properties" => "Właściwości", + "Title" => "Tytuł", + "Subject" => "Temat", + "Author" => "Autor", + "Company" => "Firma", + "Keywords" => "Słowa kluczowe", + "Description" => "Opis", + "No workbook is open." => "Żaden skoroszyt nie jest otwarty.", + "Save as type" => "Zapisz jako typ", + "Excel Workbook (*.xlsx)" => "Skoroszyt programu Excel (*.xlsx)", + "CSV UTF-8 (Comma delimited) (*.csv)" => "CSV UTF-8 (rozdzielany przecinkami) (*.csv)", + "Web Page (*.html)" => "Strona internetowa (*.html)", + "PDF (*.pdf)" => "PDF (*.pdf)", + "Download" => "Pobierz", + "A CSV file, web page or PDF is a copy: the workbook keeps its own file." => { + "Plik CSV, strona internetowa i PDF to kopie: skoroszyt zachowuje własny plik." + } + "Save the workbook under another name or in another folder." => "Zapisz skoroszyt pod inną nazwą lub w innym folderze.", + "Print Active Sheets" => "Drukuj aktywne arkusze", + "Print Entire Workbook" => "Drukuj cały skoroszyt", + "Fit Sheet on One Page" => "Dopasuj arkusz do jednej strony", + "Page Setup…" => "Ustawienia strony…", + "Page {page} of {pages}" => "Strona {page} z {pages}", + "Nothing to print." => "Nie ma nic do wydrukowania.", + "Previous page" => "Poprzednia strona", + "Next page" => "Następna strona", + "Create PDF" => "Utwórz plik PDF", + "Save the sheet as a PDF document that keeps its page layout." => "Zapisz arkusz jako dokument PDF z zachowaniem układu strony.", + "Change File Type" => "Zmień typ pliku", + "CSV (Comma delimited)" => "CSV (rozdzielany przecinkami)", + "Save the active sheet as comma-separated text." => "Zapisz aktywny arkusz jako tekst rozdzielany przecinkami.", + "Web Page (.html)" => "Strona internetowa (.html)", + "Save the workbook as a web page." => "Zapisz skoroszyt jako stronę internetową.", + "Options|General" => "Ogólne", + "Options|Save" => "Zapisywanie", + "Show formula bar" => "Pokaż pasek formuły", + "Save .xlsx workbooks automatically after every change" => "Automatycznie zapisuj skoroszyty .xlsx po każdej zmianie", + "Workbook calculation" => "Obliczanie skoroszytu", + "Enable iterative calculation" => "Włącz obliczanie iteracyjne", + "Calculation settings are saved with the workbook." => "Ustawienia obliczania są zapisywane razem ze skoroszytem.", + "Left Margin" => "Margines lewy", + "Right Margin" => "Margines prawy", + "Top Margin" => "Margines górny", + "Bottom Margin" => "Margines dolny", + "Header Margin" => "Margines nagłówka", + "Footer Margin" => "Margines stopki", + "Enable AutoComplete for cell values" => "Włącz autouzupełnianie wartości komórek", + // Recent list ages. Counts are never one; weeks, months and years are abbreviated because + // their Polish plural changes with the number (2 tygodnie, 5 tygodni). + "Modified" => "Zmodyfikowano", + "Not available" => "Niedostępne", + "Just now" => "Przed chwilą", + "Yesterday" => "Wczoraj", + "{n} min ago" => "{n} min temu", + "{n} h ago" => "{n} godz. temu", + "{n} days ago" => "{n} dni temu", + "{n} weeks ago" => "{n} tyg. temu", + "{n} months ago" => "{n} mies. temu", + "{n} years ago" => "{n} l. temu", + // Format Cells dialog (looked up through `Language::tr` since storytold/gridcraft#788). + "Format Cells" => "Formatuj komórki", + "Cancel" => "Anuluj", + "Alignment" => "Wyrównanie", + "Font" => "Czcionka", + "Border" => "Obramowanie", + "Protection" => "Ochrona", + "Category:" => "Kategoria:", + "Sample" => "Przykład", + "Type (custom format code):" => "Typ (własny kod formatu):", + "Vertical" => "Pionowo", + "Top" => "Góra", + "Bottom" => "Dół", + "Justify" => "Wyjustuj", + "Distributed" => "Rozłożone", + "Center Across Selection" => "Wyśrodkuj w zaznaczeniu", + "Indent" => "Wcięcie", + "Orientation (degrees)" => "Orientacja (stopnie)", + "Wrap text" => "Zawijaj tekst", + "Shrink to fit" => "Zmniejsz, aby dopasować", + "Bold" => "Pogrubienie", + "Italic" => "Kursywa", + "Subscript" => "Indeks dolny", + "Superscript" => "Indeks górny", + "None" => "Brak", + "Single" => "Pojedyncze", + "Double" => "Podwójne", + "Single Accounting" => "Pojedyncze księgowe", + "Double Accounting" => "Podwójne księgowe", + "Color:" => "Kolor:", + "Background Color:" => "Kolor tła:", + "No Color" => "Brak koloru", + "Outline" => "Kontur", + "Diagonal ↗" => "Ukośna ↗", + "Diagonal ↘" => "Ukośna ↘", + "Locked" => "Zablokowane", + "Hidden" => "Ukryte", + "Format Cells|Fill" => "Wypełnienie", + "none" => "brak", + "thin" => "cienka", + "medium" => "średnia", + "thick" => "gruba", + "dashed" => "kreskowana", + "dotted" => "kropkowana", + "double" => "podwójna", + "Locking cells or hiding formulas has no effect until you protect the worksheet (Review › Protect Sheet)." => { + "Blokowanie komórek i ukrywanie formuł działa dopiero po włączeniu ochrony arkusza (Recenzja › Chroń arkusz)." + } + _ => return None, + }) +} diff --git a/crates/ui-egui/src/lib.rs b/crates/ui-egui/src/lib.rs index f549aec2b5..f5eeae25be 100644 --- a/crates/ui-egui/src/lib.rs +++ b/crates/ui-egui/src/lib.rs @@ -654,7 +654,7 @@ impl SheetApp { self.ui.language = l; Ok(json!({"language": l})) } - None => Err(format!("unknown language {code:?} (use \"en\", \"es\", \"zh\", \"ja\", \"ko\", \"ru\", \"pt\" or \"cs\")")), + None => Err(format!("unknown language {code:?} (use \"en\", \"es\", \"zh\", \"ja\", \"ko\", \"ru\", \"pt\", \"cs\" or \"pl\")")), } } "app.language.english" => { diff --git a/crates/ui-egui/src/theme.rs b/crates/ui-egui/src/theme.rs index 08097ba270..c97cf68952 100644 --- a/crates/ui-egui/src/theme.rs +++ b/crates/ui-egui/src/theme.rs @@ -837,7 +837,7 @@ mod tests { ["sys-cjk-han-zh", "sys-cjk-han-ja", "sys-cjk-hangul", "sys-thai", "sys-hebrew", "sys-symbols", "sys-symbols-2"] ); assert_eq!(HanOrder::of(Language::Ja), HanOrder::Japanese); - for l in [Language::En, Language::Zh, Language::Ko, Language::Ru, Language::PtBr, Language::De, Language::Cs] { + for l in [Language::En, Language::Zh, Language::Ko, Language::Ru, Language::PtBr, Language::De, Language::Cs, Language::Pl] { assert_eq!(HanOrder::of(l), HanOrder::Chinese, "{l:?} shares the default order (no font rebuild)"); } } diff --git a/crates/ui-egui/tests/formula_locale.rs b/crates/ui-egui/tests/formula_locale.rs index 855869377c..3436e291a8 100644 --- a/crates/ui-egui/tests/formula_locale.rs +++ b/crates/ui-egui/tests/formula_locale.rs @@ -202,6 +202,22 @@ fn czech_interface_retains_its_canonical_formula_fallback() { assert_eq!(restored.language, Language::Cs); } +#[test] +fn polish_interface_retains_its_canonical_formula_fallback() { + // The Polish table translates interface labels only: formulas keep canonical English names, + // `,` separators and `.` decimals until a Polish formula locale exists. + let mut app = app(); + app.run("app.language.set", json!({"code":"pl-PL"})).unwrap(); + assert_eq!(app.ui.language, Language::Pl); + assert_eq!(app.ui.language.tr("Formulas"), "Formuły"); + assert!(enter(&mut app, "=SUM(1.5,2.25)")); + app.begin_edit(None, true); + assert_eq!(app.editor.as_ref().unwrap().text, "=SUM(1.5,2.25)"); + assert!(!enter(&mut app, "=SUMA(1;2)")); + let restored: UiState = serde_json::from_str(&serde_json::to_string(&app.ui).unwrap()).unwrap(); + assert_eq!(restored.language, Language::Pl); +} + #[test] fn user_defined_prefix_is_hidden_while_editing_and_kept_on_commit() { // Excel shows `_xludf.EOMONTH()` as `=EOMONTH()`; the cell still holds the user-defined call diff --git a/crates/ui-egui/tests/interaction.rs b/crates/ui-egui/tests/interaction.rs index 02084ffb8c..95657d646f 100644 --- a/crates/ui-egui/tests/interaction.rs +++ b/crates/ui-egui/tests/interaction.rs @@ -364,6 +364,7 @@ fn language_switch_translates_the_ribbon_and_persists() { (Language::Ru, "Данные"), (Language::PtBr, "Dados"), (Language::De, "Daten"), + (Language::Pl, "Dane"), ] { h.state_mut().run("app.language.set", json!({"language": language.code()})).unwrap(); h.run_steps(2); // every locale renders the ribbon without panicking diff --git a/docs/localization-parity.md b/docs/localization-parity.md index 64876633da..d968277863 100644 --- a/docs/localization-parity.md +++ b/docs/localization-parity.md @@ -1,6 +1,6 @@ # Localization parity -> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-19 · **Change:** minor (defined-name length limit counts characters, so long Arabic names are accepted; Table names are limited to 255 characters; right-to-left sheets in `.xls` files open right-to-left; text boxes and shapes keep right-to-left paragraph direction through XLSX save; Save as Web Page and copied HTML keep right-to-left; French and Serbian `context|label` translations no longer show the context) · **Target:** Microsoft Excel (Microsoft 365), Excel for Mac 16.113.4 +> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-19 · **Change:** minor (Polish ribbon catalog added; previous: minor, defined-name length limit counts characters, so long Arabic names are accepted; Table names are limited to 255 characters; right-to-left sheets in `.xls` files open right-to-left; text boxes and shapes keep right-to-left paragraph direction through XLSX save; Save as Web Page and copied HTML keep right-to-left; French and Serbian `context|label` translations no longer show the context) · **Target:** Microsoft Excel (Microsoft 365), Excel for Mac 16.113.4 Per-language status against Excel, which ships its UI in dozens of languages (Windows language packs cover 100+), with localized function names, argument separators, number and date formats, @@ -61,7 +61,8 @@ separators, number/date formats, machine translation with agent review, and scri | Korean | ko | 266 (~12%) | no | Hangul via the CJK fallback; IME unverified | no | menus only | 6–10 h | | Vietnamese | vi | 0 (0%) | no | Latin with stacked diacritics: unverified | no | none | 6–10 h | -Other shipped languages: Russian (ru) and German (de), 266 labels each (~12%), menus only. +Other shipped languages: Russian (ru) and German (de), 266 labels each (~12%), menus only; Polish +(pl), 381 labels (the full reference table), menus only, not yet reviewed by a second native speaker. **Total:** catalog work 10–20 h + languages 92–144 h ≈ **100–165 h**. Parallelizes almost fully once the catalog covers dialogs and commands. **Needs a human:** native-speaker review of every @@ -89,6 +90,7 @@ language (none so far) and of localized function names. | 2026-10-19 | trivial | Text boxes and shapes keep right-to-left paragraph direction (`a:pPr rtl`) on XLSX save, so Excel-authored Arabic and Hebrew text boxes reopen right to left | | 2026-10-19 | minor | Save as Web Page and copied HTML mark right-to-left sheets `dir="rtl"`, let General-aligned Arabic and Hebrew text align by its own direction (`dir="auto"`), and keep numbers on right-to-left sheets left to right and on the left | | 2026-10-19 | minor | French and Serbian kept the context in three `context\|label` translations ("Options\|Général", "Opcije\|Opšte" for `Options\|General`; also `Options\|Save`, `Sheet Options\|View`). `tr` shows a found translation as it is, so File › Options headings and the Sheet Options "View" checkboxes showed the prefix. Fixed; a test checks that no catalog shows a `\|` | +| 2026-10-12 | minor | Polish (pl) ribbon table (`i18n/pl.rs`, 381 labels: every key of the reference table); `pl` locale tags (pl-PL, pl_PL.UTF-8) resolve to Polish; formulas and number formats stay en-US | | 2026-10-12 | minor | Format Cells looks up its tabs, labels, options and note through `Language::tr` (Fill tab keyed `Format Cells\|Fill`); dialog titles and OK/Cancel too. Labels already in a table (Number, Currency, Fill…) show translated; the rest fall back to English until the tables add them | | 2026-10-12 | minor | Brazilian Portuguese catalog (`i18n/pt.rs`) grows from 377 to 923 entries: every key the other catalogs translate, including the dialog strings #669 starts looking up (~42%) | | 2026-10-11 | minor | German ribbon catalog (`i18n/de.rs`, 266 labels, ~12%); `de` locale tags (de-DE, de-AT, de-CH…) resolve to German. PR #163 (localized German formulas/numbers) still open |