diff --git a/contributors/people.toml b/contributors/people.toml index be84b5b01..0bc376396 100644 --- a/contributors/people.toml +++ b/contributors/people.toml @@ -60,11 +60,14 @@ sync_github_name = true [people.jsymes21-byte] real_name = "James Symes" sync_github_name = true - - [people.Silvertree2010] display_name = "Netter" sync_github_name = false [people.Shnrqpdr] sync_github_name = true + +[people.yeniufuklar-com] +real_name = "Ufuk Efe" +display_name = "Ufuk Efe" +sync_github_name = true diff --git a/crates/ui-egui/examples/snapshot.rs b/crates/ui-egui/examples/snapshot.rs index a171199a1..dcee71173 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|es|zh|ja|ko|ru|pt|de|cs|fr|tr] //! [--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 2ea5cfae0..96f474739 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\"|\"fr\"|\"tr\"} (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 98919f8a4..43830e106 100644 --- a/crates/ui-egui/src/i18n.rs +++ b/crates/ui-egui/src/i18n.rs @@ -17,6 +17,7 @@ mod ko; mod pt; mod ru; mod sr; +mod tr; mod zh; #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] @@ -35,10 +36,12 @@ pub enum Language { Cs, Fr, Sr, + Tr, } 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::Tr]; /// 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::Tr => "Türkçe", } } @@ -71,6 +75,7 @@ impl Language { Self::Cs => "cs", Self::Fr => "fr", Self::Sr => "sr", + Self::Tr => "tr", } } @@ -91,6 +96,7 @@ impl Language { "cs" => Some(Self::Cs), "fr" => Some(Self::Fr), "sr" => Some(Self::Sr), + "tr" => Some(Self::Tr), _ => None, } } @@ -129,6 +135,7 @@ impl Language { Self::Cs => cs::translate(text), Self::Fr => fr::translate(text), Self::Sr => sr::translate(text), + Self::Tr => tr::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!(tr::translate(english).is_some_and(|text| !text.is_empty()), "missing Turkish: {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::Tr.tr("Data"), "Veri"); + assert_eq!(Language::Tr.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"); @@ -634,6 +644,7 @@ mod tests { assert_eq!(Language::Cs.tr("Data"), "Data"); assert_eq!(Language::Cs.tr("Formulas"), "Vzorce"); assert_eq!(Language::Cs.tr("Sheet1!A1"), "Sheet1!A1"); + assert_eq!(Language::Tr.tr("Formulas"), "Formüller"); // A `context|label` key shows only its label in English and splits the translation. assert_eq!(Language::En.tr("Page Layout|Orientation"), "Orientation"); assert_eq!(Language::Ja.tr("Page Layout|Orientation"), "印刷の向き"); @@ -644,6 +655,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::Tr.tr("Page Layout|Orientation"), "Sayfa Yönü"); + assert_eq!(Language::Tr.tr("Orientation"), "Yönlendirme"); assert_eq!(Language::parse("xx"), None); } @@ -738,6 +751,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("tr-TR"), Some(Language::Tr)); + assert_eq!(Language::from_tag("tr_TR.UTF-8"), Some(Language::Tr)); + assert_eq!(Language::parse("tr"), Some(Language::Tr)); } #[test] diff --git a/crates/ui-egui/src/i18n/tr.rs b/crates/ui-egui/src/i18n/tr.rs new file mode 100644 index 000000000..becbc3f5f --- /dev/null +++ b/crates/ui-egui/src/i18n/tr.rs @@ -0,0 +1,414 @@ +//! Turkish translations for the interface strings in i18n.rs. Labels follow the wording Turkish +//! spreadsheet users know; anything absent falls back to English. + +pub(super) fn translate(text: &str) -> Option<&'static str> { + Some(match text { + "Paste" => "Yapıştır", + "Paste Values" => "Değerleri Yapıştır", + "Paste Formulas" => "Formülleri Yapıştır", + "Paste Formatting" => "Biçimlendirmeyi Yapıştır", + "Transpose" => "Devrik Dönüştür", + "Paste Link" => "Bağlantı Yapıştır", + "Paste Special…" => "Özel Yapıştır…", + "Cut (⌘X)" => "Kes (⌘X)", + "Copy (⌘C)" => "Kopyala (⌘C)", + "Format Painter (double-click to keep it on)" => "Biçim Boyacısı (açık tutmak için çift tıklayın)", + "Bold (⌘B)" => "Kalın (⌘B)", + "Italic (⌘I)" => "İtalik (⌘I)", + "Underline (⌘U)" => "Altı Çizili (⌘U)", + "Double Underline" => "Çift Alt Çizgi", + "Strikethrough" => "Üstü Çizili", + "Underline" => "Altı Çizili", + "Increase Font Size" => "Yazı Tipi Boyutunu Büyüt", + "Decrease Font Size" => "Yazı Tipi Boyutunu Küçült", + "Wrap Text" => "Metni Kaydır", + "Merge & Center" => "Birleştir ve Ortala", + "Merge Cells" => "Hücreleri Birleştir", + "Merge Across" => "Yatay Birleştir", + "Unmerge Cells" => "Hücreleri Çöz", + "Fill Color" => "Dolgu Rengi", + "Font Color" => "Yazı Tipi Rengi", + "Borders" => "Kenarlıklar", + "Top\nAlign" => "Üste\nHizala", + "Middle\nAlign" => "Ortaya\nHizala", + "Bottom\nAlign" => "Alta\nHizala", + "Left" => "Sol", + "Right" => "Sağ", + "Center" => "Orta", + "Horizontal" => "Yatay", + "Vertical Text" => "Dikey Metin", + "Decrease Indent" => "Girintiyi Azalt", + "Increase Indent" => "Girintiyi Artır", + "Orientation" => "Yönlendirme", + "Angle Counterclockwise" => "Saat Yönünün Tersine Açılı", + "Angle Clockwise" => "Saat Yönünde Açılı", + "Rotate Text Up" => "Metni Yukarı Döndür", + "Rotate Text Down" => "Metni Aşağı Döndür", + "Accounting Number Format" => "Muhasebe Sayı Biçimi", + "Percent Style" => "Yüzde Stili", + "Comma Style" => "Virgül Stili", + "Increase Decimal" => "Ondalık Artır", + "Decrease Decimal" => "Ondalık Azalt", + "More Accounting Formats…" => "Diğer Muhasebe Biçimleri…", + "Conditional\nFormatting" => "Koşullu\nBiçimlendirme", + "Conditional Formatting" => "Koşullu Biçimlendirme", + "Format\nas Table" => "Tablo Olarak\nBiçimlendir", + "Cell\nStyles" => "Hücre\nStilleri", + "Format Cells…" => "Hücreleri Biçimlendir…", + "Format Cell Alignment…" => "Hücre Hizalamayı Biçimlendir…", + "Format\nPane" => "Biçim\nBölmesi", + "Format" => "Biçim", + "Insert" => "Ekle", + "Insert Cells…" => "Hücre Ekle…", + "Delete" => "Sil", + "Delete Cells…" => "Hücreleri Sil…", + "Insert Sheet Rows" => "Sayfa Satırları Ekle", + "Insert Sheet Columns" => "Sayfa Sütunları Ekle", + "Delete Sheet Rows" => "Sayfa Satırlarını Sil", + "Delete Sheet Columns" => "Sayfa Sütunlarını Sil", + "Row Height…" => "Satır Yüksekliği…", + "AutoFit Row Height" => "Satır Yüksekliğini En Uygun Yap", + "Column Width…" => "Sütun Genişliği…", + "AutoFit Column Width" => "Sütun Genişliğini En Uygun Yap", + "Default Width…" => "Varsayılan Genişlik…", + "Hide Rows" => "Satırları Gizle", + "Unhide Rows" => "Satırları Göster", + "Hide Columns" => "Sütunları Gizle", + "Unhide Columns" => "Sütunları Göster", + "Lock Cell" => "Hücreyi Kilitle", + "Clear" => "Temizle", + "Clear All" => "Tümünü Temizle", + "Clear Formats" => "Biçimleri Temizle", + "Clear Contents" => "İçeriği Temizle", + "Clear Comments and Notes" => "Açıklamaları ve Notları Temizle", + "Clear Hyperlinks" => "Köprüleri Temizle", + "AutoSum" => "Otomatik Toplam", + "AutoSum (⌘⇧T)" => "Otomatik Toplam (⌘⇧T)", + "Flash\nFill" => "Hızlı\nDoldurma", + "Flash Fill" => "Hızlı Doldurma", + "Fill" => "Doldur", + "Clear Print Area" => "Yazdırma Alanını Temizle", + "Find &\nSelect" => "Bul ve\nSeç", + "Find…" => "Bul…", + "Replace…" => "Değiştir…", + "Go To…" => "Git…", + "Go To Special…" => "Özel Git…", + "PivotTable" => "Özet Tablo", + "Recommended\nCharts" => "Önerilen\nGrafikler", + "Table" => "Tablo", + "Pictures" => "Resimler", + "Shapes" => "Şekiller", + "Icons" => "Simgeler", + "Text\nBox" => "Metin\nKutusu", + "Comment" => "Açıklama", + "New\nComment" => "Yeni\nAçıklama", + "New Note" => "Yeni Not", + "Show/Hide Note" => "Notu Göster/Gizle", + "Header &\nFooter" => "Üstbilgi ve\nAltbilgi", + "Text to\nColumns" => "Metni Sütunlara\nDönüştür", + "Link" => "Köprü", + "Symbol" => "Simge", + "Sparklines" => "Mini Grafikler", + "Header & Footer" => "Üstbilgi ve Altbilgi", + "Draw with ink" => "Mürekkeple Çiz", + "Eraser" => "Silgi", + "Ink to\nShape" => "Mürekkebi\nŞekle Dönüştür", + "Select\nObjects" => "Nesneleri\nSeç", + "Themes" => "Temalar", + "Margins" => "Kenar Boşlukları", + "Left Margin" => "Sol Kenar Boşluğu", + "Right Margin" => "Sağ Kenar Boşluğu", + "Top Margin" => "Üst Kenar Boşluğu", + "Bottom Margin" => "Alt Kenar Boşluğu", + "Header Margin" => "Üstbilgi Kenar Boşluğu", + "Footer Margin" => "Altbilgi Kenar Boşluğu", + "Size" => "Boyut", + "Print\nArea" => "Yazdırma\nAlanı", + "Set Print Area" => "Yazdırma Alanını Belirle", + "Breaks" => "Kesmeler", + "Insert Page Break" => "Sayfa Sonu Ekle", + "Remove Page Break" => "Sayfa Sonunu Kaldır", + "Reset All Page Breaks" => "Tüm Sayfa Sonlarını Sıfırla", + "Print\nTitles" => "Başlıkları\nYazdır", + "Narrow" => "Dar", + "Wide" => "Geniş", + "Normal" => "Normal", + "Portrait" => "Dikey", + "Landscape" => "Yatay", + "Custom Margins…" => "Özel Kenar Boşlukları…", + "Insert\nFunction" => "İşlev\nEkle", + "Name\nManager" => "Ad\nYöneticisi", + "Define Name" => "Ad Tanımla", + "Use in Formula" => "Formülde Kullan", + "Create from Selection" => "Seçimden Oluştur", + "Trace Precedents" => "Etkileyenleri İzle", + "Trace Dependents" => "Etkilenenleri İzle", + "Remove Arrows" => "Okları Kaldır", + "Show Formulas" => "Formülleri Göster", + "Error Checking" => "Hata Denetimi", + "Evaluate Formula" => "Formülü Değerlendir", + "Watch Window" => "Gözcü Penceresi", + "Calculation\nOptions" => "Hesaplama\nSeçenekleri", + "Calculate Now" => "Şimdi Hesapla", + "Calculate Sheet" => "Sayfayı Hesapla", + "Automatic" => "Otomatik", + "Automatic Except for Data Tables" => "Veri Tabloları Dışında Otomatik", + "Manual" => "El ile", + "Sort &\nFilter" => "Sırala ve\nFiltre Uygula", + "Sort" => "Sırala", + "Sort A to Z" => "A'dan Z'ye Sırala", + "Sort Z to A" => "Z'den A'ya Sırala", + "Custom Sort…" => "Özel Sıralama…", + "Filter" => "Filtre", + "Reapply" => "Yeniden Uygula", + "Get Data\n(Text/CSV)" => "Veri Al\n(Metin/CSV)", + "Remove\nDuplicates" => "Yinelenenleri\nKaldır", + "Data\nValidation" => "Veri\nDoğrulama", + "Data Validation" => "Veri Doğrulama", + "Data Validation…" => "Veri Doğrulama…", + "Circle Invalid Data" => "Geçersiz Verileri Daire İçine Al", + "Clear Validation" => "Doğrulamayı Temizle", + "Group" => "Gruplandır", + "Ungroup" => "Grubu Çöz", + "Show Detail" => "Ayrıntıyı Göster", + "Hide Detail" => "Ayrıntıyı Gizle", + "Subtotal" => "Alt Toplam", + "What-If\nAnalysis" => "Durum\nÇözümlemesi", + "Data Table…" => "Veri Tablosu…", + "Scenario Manager…" => "Senaryo Yöneticisi…", + "Goal Seek…" => "Hedef Ara…", + "Spelling" => "Yazım Denetimi", + "Check\nAccessibility" => "Erişilebilirliği\nDenetle", + "Threaded Comments" => "Yanıtlanan Açıklamalar", + "Show\nComments" => "Açıklamaları\nGöster", + "Protect\nWorkbook" => "Çalışma Kitabını\nKoru", + "Unprotect\nSheet" => "Sayfa Korumasını\nKaldır", + "Protect Sheet…" => "Sayfayı Koru…", + "Comments" => "Açıklamalar", + "Notes" => "Notlar", + "Page Break\nPreview" => "Sayfa Sonu\nÖnizleme", + "Page\nLayout" => "Sayfa\nDüzeni", + "Formula Bar" => "Formül Çubuğu", + "Gridlines" => "Kılavuz Çizgileri", + "Headings" => "Başlıklar", + "Zoom" => "Yakınlaştır", + "Forecast\nSheet" => "Tahmin\nSayfası", + "Add footer" => "Altbilgi ekle", + "Add header" => "Üstbilgi ekle", + "Click to add data" => "Veri eklemek için tıklayın", + "Current Date" => "Geçerli Tarih", + "Current\nDate" => "Geçerli\nTarih", + "Current\nTime" => "Geçerli\nSaat", + "Current Time" => "Geçerli Saat", + "File Name" => "Dosya Adı", + "File\nName" => "Dosya\nAdı", + "File\nPath" => "Dosya\nYolu", + "File Path" => "Dosya Yolu", + "Footer" => "Altbilgi", + "Different First Page" => "İlk Sayfada Farklı", + "Different Odd & Even Pages" => "Tek ve Çift Sayfalarda Farklı", + "Go to Footer" => "Altbilgiye Git", + "Go to Header" => "Üstbilgiye Git", + "Go to\nFooter" => "Altbilgiye\nGit", + "Go to\nHeader" => "Üstbilgiye\nGit", + "Header" => "Üstbilgi", + "(none)" => "(yok)", + "Number\nof Pages" => "Sayfa\nSayısı", + "Number of Pages" => "Sayfa Sayısı", + "Page\nNumber" => "Sayfa\nNumarası", + "Page Number" => "Sayfa Numarası", + "Ruler" => "Cetvel", + "Sheet Name" => "Sayfa Adı", + "Sheet\nName" => "Sayfa\nAdı", + "Animations" => "Animasyonlar", + "Glide the selection outline to the cell you move to instead of jumping there" => { + "Seçim çerçevesini atlamak yerine taşındığınız hücreye kaydırarak hareket ettir" + } + "Insert Copied Cells" => "Kopyalanan Hücreleri Ekle", + "Insert Copied Cells…" => "Kopyalanan Hücreleri Ekle…", + "Insert Cut Cells" => "Kesilen Hücreleri Ekle", + "Insert Paste" => "Ekleyerek Yapıştır", + "Previous" => "Önceki", + "Next" => "Sonraki", + "Previous Comment" => "Önceki Açıklama", + "Next Comment" => "Sonraki Açıklama", + "Show All Notes" => "Tüm Notları Göster", + "Convert to Comments" => "Açıklamalara Dönüştür", + "Checkbox" => "Onay Kutusu", + "Insert checkboxes in the selected cells" => "Seçili hücrelere onay kutuları ekle", + "Sheet\nRight-to-Left" => "Sayfa\nSağdan Sola", + "Sheet Right-to-Left" => "Sayfa Sağdan Sola", + "Data\nAnalysis" => "Veri\nAnalizi", + "Data Analysis" => "Veri Analizi", + "Solver" => "Çözücü", + "Allow Edit\nRanges" => "Aralıkları Düzenlemeye\nİzin Ver", + "Allow Edit Ranges" => "Aralıkları Düzenlemeye İzin Ver", + "Drag to freeze columns" => "Sütunları dondurmak için sürükleyin", + "Drag to freeze rows" => "Satırları dondurmak için sürükleyin", + "Select\nData" => "Veri\nSeç", + "File" => "Dosya", + "Back" => "Geri", + "New" => "Yeni", + "Open" => "Aç", + "Info" => "Bilgi", + "Save" => "Kaydet", + "Save As" => "Farklı Kaydet", + "Export" => "Dışarı Aktar", + "Close" => "Kapat", + "Options" => "Seçenekler", + "Blank workbook" => "Boş çalışma kitabı", + "Recent" => "Son Kullanılanlar", + "No recent workbooks yet." => "Henüz son kullanılan çalışma kitabı yok.", + "More workbooks" => "Diğer çalışma kitapları", + "Modified" => "Değiştirilme Tarihi", + "Not available" => "Kullanılamıyor", + "Just now" => "Az önce", + "Yesterday" => "Dün", + "{n} min ago" => "{n} dk. önce", + "{n} h ago" => "{n} sa. önce", + "{n} days ago" => "{n} gün önce", + "{n} weeks ago" => "{n} hafta önce", + "{n} months ago" => "{n} ay önce", + "{n} years ago" => "{n} yıl önce", + "Browse…" => "Gözat…", + "Not saved yet" => "Henüz kaydedilmedi", + "Location" => "Konum", + "Sheets" => "Sayfalar", + "Protect Workbook" => "Çalışma Kitabını Koru", + "Sheet structure is locked: sheets can't be added, moved, renamed or deleted." => { + "Sayfa yapısı kilitli: sayfalar eklenemez, taşınamaz, yeniden adlandırılamaz veya silinemez." + } + "Lock the sheet structure so sheets can't be added, moved, renamed or deleted." => { + "Sayfaların eklenmesini, taşınmasını, yeniden adlandırılmasını veya silinmesini önlemek için sayfa yapısını kilitleyin." + } + "Properties" => "Özellikler", + "Title" => "Başlık", + "Subject" => "Konu", + "Author" => "Yazar", + "Company" => "Şirket", + "Keywords" => "Anahtar Sözcükler", + "Description" => "Açıklama", + "No workbook is open." => "Açık çalışma kitabı yok.", + "Save as type" => "Kayıt türü", + "Excel Workbook (*.xlsx)" => "Excel Çalışma Kitabı (*.xlsx)", + "CSV UTF-8 (Comma delimited) (*.csv)" => "CSV UTF-8 (Virgülle ayrılmış) (*.csv)", + "Web Page (*.html)" => "Web Sayfası (*.html)", + "PDF (*.pdf)" => "PDF Belgesi (*.pdf)", + "Download" => "İndir", + "A CSV file, web page or PDF is a copy: the workbook keeps its own file." => { + "CSV dosyası, web sayfası veya PDF bir kopyadır: çalışma kitabı kendi dosyasını korur." + } + "Save the workbook under another name or in another folder." => "Çalışma kitabını başka bir adla veya başka bir klasöre kaydedin.", + "Print Active Sheets" => "Etkin Sayfaları Yazdır", + "Print Entire Workbook" => "Tüm Çalışma Kitabını Yazdır", + "Fit Sheet on One Page" => "Sayfayı Bir Sayfaya Sığdır", + "Page Setup…" => "Sayfa Yapısı…", + "Page {page} of {pages}" => "Sayfa {page} / {pages}", + "Nothing to print." => "Yazdırılacak bir şey yok.", + "Previous page" => "Önceki sayfa", + "Next page" => "Sonraki sayfa", + "Create PDF" => "PDF Oluştur", + "Save the sheet as a PDF document that keeps its page layout." => "Sayfayı, sayfa düzenini koruyan bir PDF belgesi olarak kaydedin.", + "Change File Type" => "Dosya Türünü Değiştir", + "CSV (Comma delimited)" => "CSV (Virgülle ayrılmış)", + "Save the active sheet as comma-separated text." => "Etkin sayfayı virgülle ayrılmış metin olarak kaydedin.", + "Web Page (.html)" => "Web Sayfası (.html)", + "Save the workbook as a web page." => "Çalışma kitabını web sayfası olarak kaydedin.", + "Options|General" => "Genel", + "Options|Save" => "Kaydet", + "Show formula bar" => "Formül çubuğunu göster", + "Enable AutoComplete for cell values" => "Hücre değerleri için Otomatik Tamamla'yı etkinleştir", + "Save .xlsx workbooks automatically after every change" => ".xlsx çalışma kitaplarını her değişiklikten sonra otomatik olarak kaydet", + "Workbook calculation" => "Çalışma kitabı hesaplaması", + "Enable iterative calculation" => "Yinelemeli hesaplamayı etkinleştir", + "Calculation settings are saved with the workbook." => "Hesaplama ayarları çalışma kitabıyla birlikte kaydedilir.", + "Interface size" => "Arayüz boyutu", + "Auto" => "Otomatik", + "100%" => "%100", + "Zoom to\nSelection" => "Seçimi\nYakınlaştır", + "Freeze\nPanes" => "Bölmeleri\nDondur", + "Freeze Panes" => "Bölmeleri Dondur", + "Freeze Top Row" => "Üst Satırı Dondur", + "Freeze First Column" => "İlk Sütunu Dondur", + "Unfreeze Panes" => "Bölmeleri Çöz", + "Dark Mode" => "Koyu Mod", + "Interface language" => "Arayüz dili", + "Command\nPalette" => "Komut\nPaleti", + "Agent\nControl" => "Ajan\nKontrolü", + "Action\nJournal" => "İşlem\nGünlüğü", + "About\nGridCraft" => "GridCraft\nHakkında", + "Share" => "Paylaş", + "Add Chart\nElement" => "Grafik Öğesi\nEkle", + "Change\nChart Type" => "Grafik Türünü\nDeğiştir", + "Switch\nRow/Column" => "Satır/Sütun\nDeğiştir", + "Data Labels: None" => "Veri Etiketleri: Yok", + "Data Labels: Show" => "Veri Etiketleri: Göster", + "Legend: None" => "Gösterge: Yok", + "Legend: Bottom" => "Gösterge: Alt", + "Legend: Top" => "Gösterge: Üst", + "Legend: Right" => "Gösterge: Sağ", + "Gridlines: None" => "Kılavuz Çizgileri: Yok", + "Gridlines: Show" => "Kılavuz Çizgileri: Göster", + "Chart\nTitle" => "Grafik\nBaşlığı", + "Delete\nChart" => "Grafiği\nSil", + "Convert\nto Range" => "Aralığa\nDönüştür", + "Table\nStyles" => "Tablo\nStilleri", + "Top 10 Items" => "İlk 10 Öğe", + "Top 10%" => "İlk %10", + "Bottom 10 Items" => "Son 10 Öğe", + "Bottom 10%" => "Son %10", + "Above Average" => "Ortalamanın Üstünde", + "Below Average" => "Ortalamanın Altında", + "Clear Rules from Entire Sheet" => "Kuralları Tüm Sayfadan Temizle", + "Clear Rules from Selected Cells" => "Kuralları Seçili Hücrelerden Temizle", + "Constants" => "Sabitler", + "Data Bars" => "Veri Çubukları", + "Color Scales" => "Renk Ölçekleri", + "Icon Sets" => "Simge Kümeleri", + "Home" => "Giriş", + "Draw" => "Çiz", + "Page Layout" => "Sayfa Düzeni", + "Formulas" => "Formüller", + "Data" => "Veri", + "Review" => "Gözden Geçir", + "View" => "Görünüm", + "Automate" => "Otomatikleştir", + "Table Design" => "Tablo Tasarımı", + "Chart Design" => "Grafik Tasarımı", + "Ready" => "Hazır", + "Enter" => "Giriş", + "Edit" => "Düzenle", + "Point" => "İşaretle", + "Calculate" => "Hesapla", + "Select destination and press Enter or choose Paste" => "Hedefi seçip Enter tuşuna basın veya Yapıştır'ı seçin", + "General" => "Genel", + "Number" => "Sayı", + "Currency" => "Para Birimi", + "Accounting" => "Muhasebe", + "Date" => "Tarih", + "Time" => "Saat", + "Percentage" => "Yüzde", + "Fraction" => "Kesir", + "Scientific" => "Bilimsel", + "Text" => "Metin", + "Special" => "Özel", + "Custom" => "İsteğe Uyarlanmış", + "Short Date" => "Kısa Tarih", + "Long Date" => "Uzun Tarih", + "More Number Formats…" => "Diğer Sayı Biçimleri…", + "Financial" => "Finansal", + "Logical" => "Mantıksal", + "Date &\nTime" => "Tarih ve\nSaat", + "Lookup &\nReference" => "Arama ve\nBaşvuru", + "Math &\nTrig" => "Matematik ve\nTrigonometri", + "More\nFunctions" => "Diğer\nİşlevler", + "Page Layout|Orientation" => "Sayfa Yönü", + "Display theme" => "Görüntü teması", + "System" => "Sistem", + "Light" => "Açık", + "Dark" => "Koyu", + "Sheet Options|View" => "Görünüm", + "Print" => "Yazdır", + _ => return None, + }) +} diff --git a/crates/ui-egui/src/lib.rs b/crates/ui-egui/src/lib.rs index f549aec2b..74a09d536 100644 --- a/crates/ui-egui/src/lib.rs +++ b/crates/ui-egui/src/lib.rs @@ -654,7 +654,9 @@ 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\", \"de\", \"cs\", \"fr\" or \"tr\")" + )), } } "app.language.english" => { diff --git a/crates/ui-egui/src/theme.rs b/crates/ui-egui/src/theme.rs index 08097ba27..613814d03 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::Fr, Language::Tr] { 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 855869377..16f4dac15 100644 --- a/crates/ui-egui/tests/formula_locale.rs +++ b/crates/ui-egui/tests/formula_locale.rs @@ -219,3 +219,18 @@ fn user_defined_prefix_is_hidden_while_editing_and_kept_on_commit() { assert!(app.commit_edit(0, 0, false, false)); assert_eq!(formula(&app), "_xludf.EOMONTH()&_xludf.CONCAT(\"_xludf.x\")"); } + +#[test] +fn turkish_interface_retains_its_canonical_formula_fallback() { + let mut app = app(); + app.run("app.language.set", json!({"code":"tr-TR"})).unwrap(); + assert_eq!(app.ui.language, Language::Tr); + assert_eq!(app.ui.language.tr("Data"), "Veri"); + assert_eq!(app.ui.language.tr("Formulas"), "Formüller"); + 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, "=TOPLA(1;2)")); + let restored: UiState = serde_json::from_str(&serde_json::to_string(&app.ui).unwrap()).unwrap(); + assert_eq!(restored.language, Language::Tr); +} diff --git a/crates/ui-egui/tests/interaction.rs b/crates/ui-egui/tests/interaction.rs index 02084ffb8..8bbdc5333 100644 --- a/crates/ui-egui/tests/interaction.rs +++ b/crates/ui-egui/tests/interaction.rs @@ -364,6 +364,8 @@ fn language_switch_translates_the_ribbon_and_persists() { (Language::Ru, "Данные"), (Language::PtBr, "Dados"), (Language::De, "Daten"), + (Language::Fr, "Données"), + (Language::Tr, "Veri"), ] { 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 64876633d..9109311f9 100644 --- a/docs/localization-parity.md +++ b/docs/localization-parity.md @@ -60,8 +60,9 @@ separators, number/date formats, machine translation with agent review, and scri | German | de | 266 (~12%) | no | Latin: yes | no | menus only | 4–8 h | | 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 | +| Turkish | tr | 382 (~17%) | no | Latin: yes | yes | menus only | 4–8 h | -Other shipped languages: Russian (ru) and German (de), 266 labels each (~12%), menus only. +Other shipped languages: Russian (ru), German (de), Czech (cs), French (fr) and Turkish (tr), menus only. **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 | Turkish ribbon catalog (`i18n/tr.rs`, 382 labels); `tr` locale tags (tr-TR, tr_TR…) resolve to Turkish | | 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 |