From 0c2d3440b8f5cf0d025de31b012a66589b074709 Mon Sep 17 00:00:00 2001 From: Andreas Stefl Date: Sat, 10 Oct 2026 13:29:46 +0200 Subject: [PATCH 1/2] Take core 7.5.1, and edit rows, columns and CSV files - A spreadsheet can insert and delete rows and columns. The tools are Pro only. - A CSV file opens as a sheet, so it can be edited and saved. - The reader says when a sheet is too large to edit in full. Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01B54axSaN5uQ37tShVNBYrP --- CHANGELOG.md | 9 ++ OpenDocumentReader.xcodeproj/project.pbxproj | 2 +- .../xcshareddata/swiftpm/Package.resolved | 4 +- OpenDocumentReader/CoreWrapper.swift | 23 +++-- .../DocumentViewController.swift | 28 ++++-- OpenDocumentReader/EditToolBar.swift | 85 ++++++++++++++++++- .../ca.lproj/Localizable.strings | 10 +++ .../cs.lproj/Localizable.strings | 10 +++ .../da.lproj/Localizable.strings | 10 +++ .../de.lproj/Localizable.strings | 10 +++ .../en.lproj/Localizable.strings | 10 +++ .../es.lproj/Localizable.strings | 10 +++ .../fr.lproj/Localizable.strings | 10 +++ .../ga.lproj/Localizable.strings | 10 +++ .../it.lproj/Localizable.strings | 10 +++ .../ja.lproj/Localizable.strings | 10 +++ .../pl.lproj/Localizable.strings | 10 +++ .../pt-BR.lproj/Localizable.strings | 10 +++ .../ru.lproj/Localizable.strings | 10 +++ .../sl.lproj/Localizable.strings | 10 +++ .../tr.lproj/Localizable.strings | 10 +++ .../zh-Hans.lproj/Localizable.strings | 10 +++ .../EditWorkflowTests.swift | 38 +++++++-- .../OpenDocumentReaderTests.swift | 14 +-- README.md | 6 +- 25 files changed, 339 insertions(+), 30 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b197fd1..503b31d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,15 @@ Rules: ## [Unreleased] +### Added + +- Spreadsheets can insert and delete rows and columns in Pro. +- A CSV file can be edited and saved. + +### Changed + +- The engine is odrcore 7.5.1, up from 7.4.0. + ### Fixed - A PDF prints as the file itself, one page to a sheet. A PDF with a password diff --git a/OpenDocumentReader.xcodeproj/project.pbxproj b/OpenDocumentReader.xcodeproj/project.pbxproj index fdfa0e9..3c3ae36 100644 --- a/OpenDocumentReader.xcodeproj/project.pbxproj +++ b/OpenDocumentReader.xcodeproj/project.pbxproj @@ -830,7 +830,7 @@ repositoryURL = "https://github.com/opendocument-app/OpenDocument.core.git"; requirement = { kind = upToNextMajorVersion; - minimumVersion = 7.4.0; + minimumVersion = 7.5.1; }; }; AD584FCD41577C8CDEE974AA /* XCRemoteSwiftPackageReference "swift-package-manager-google-mobile-ads" */ = { diff --git a/OpenDocumentReader.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/OpenDocumentReader.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 6fd68fa..74df187 100644 --- a/OpenDocumentReader.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/OpenDocumentReader.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -6,8 +6,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/opendocument-app/OpenDocument.core.git", "state" : { - "revision" : "426f465031f6ef9d33bd8cb6de6c513320c45d88", - "version" : "7.4.0" + "revision" : "703b931de526abc2d64cfe4de443bfab4be34098", + "version" : "7.5.1" } }, { diff --git a/OpenDocumentReader/CoreWrapper.swift b/OpenDocumentReader/CoreWrapper.swift index 92550a9..1d9d6d6 100644 --- a/OpenDocumentReader/CoreWrapper.swift +++ b/OpenDocumentReader/CoreWrapper.swift @@ -194,11 +194,8 @@ private func selectViews(_ views: [HtmlView], _ documentType: DocumentType) -> [ var openedPageSize: CGSize? let service: HtmlService - if file.isDocumentFile { - let documentFile = try file.asDocumentFile() - let document = try documentFile.document() - - documentType = documentFile.documentType + if let document = try Self.document(of: file) { + documentType = document.documentType // the document's own answer: a format odrcore renders but cannot write // back would otherwise offer Edit and fail at the save openedDocument = document.isEditable && document.isSavable ? document : nil @@ -244,6 +241,18 @@ private func selectViews(_ views: [HtmlView], _ documentType: DocumentType) -> [ pageURLs = views.map { base.appendingPathComponent($0.path) } } + /// The document behind the file. A csv is a one-sheet spreadsheet, but an + /// encoding odrcore cannot decode leaves it only the text view. + private static func document(of file: DecodedFile) throws -> OdrCoreObjC.Document? { + if file.isDocumentFile { + return try file.asDocumentFile().document() + } + if file.isCsvFile { + return try? file.asCsvFile().document() + } + return nil + } + /// The first page's: a presentation has one size, and a drawing seldom more. private static func pageSize(of document: OdrCoreObjC.Document) -> CGSize? { guard let root = try? document.rootElement() else { @@ -274,8 +283,8 @@ private func selectViews(_ views: [HtmlView], _ documentType: DocumentType) -> [ lock.lock() defer { lock.unlock() } - // odrcore streams the parts an edit did not touch out of the file it opened, and - // truncates the destination first - so saving onto the open file empties it + // every kind of file is written beside the output and swapped in, so a + // failed save leaves the open file as it was let output = URL(fileURLWithPath: outputPath) let staging = try stagingDirectory(for: output) diff --git a/OpenDocumentReader/DocumentViewController.swift b/OpenDocumentReader/DocumentViewController.swift index 29d2a37..2fec2f4 100644 --- a/OpenDocumentReader/DocumentViewController.swift +++ b/OpenDocumentReader/DocumentViewController.swift @@ -779,7 +779,8 @@ class DocumentViewController: UIViewController, DocumentDelegate, UISearchBarDel } /// Turns the mode on in the page already on screen and shows its tools. A - /// plain text file takes no formatting, so it gets no strip. + /// plain text file takes no formatting, so it gets no strip. A csv states + /// that its cells take no style, so it gets only the row and column tools. private func beginEditSession() { hasOfferedProForThisEdit = false hasUnsavedEdits = false @@ -802,13 +803,23 @@ class DocumentViewController: UIViewController, DocumentDelegate, UISearchBarDel let isPlainText = document?.isPlainText == true - webview.evaluateJavaScript("odr.editing.enable(); typeof odr.sheet === 'object'") { [weak self] isSheet, _ in + let script = """ + odr.editing.enable(); + typeof odr.sheet !== 'object' ? 'text' + : document.body.getAttribute('data-odr-sheet-styles') === 'false' ? 'values' : 'sheet' + """ + + webview.evaluateJavaScript(script) { [weak self] kind, _ in guard let self, self.isEditingDocument else { return } if isPlainText { self.editToolBar.layout = nil } else { - self.editToolBar.layout = isSheet as? Bool == true ? .sheet : .text + switch kind as? String { + case "sheet": self.editToolBar.layout = .sheet + case "values": self.editToolBar.layout = .values + default: self.editToolBar.layout = .text + } self.editToolBar.setColor(.highlight, self.highlightColor) self.editToolBar.setColor(.fill, self.highlightColor) } @@ -840,7 +851,7 @@ class DocumentViewController: UIViewController, DocumentDelegate, UISearchBarDel /// Pro, and the highlighter beside it works in every edition. private func editToolTapped(_ tool: EditToolBar.Tool) { if !tool.isFree, !Features.advancedEditing { - offerPro(canMark ? .pdf : .formatting) + offerPro(canMark ? .pdf : tool.structures.isEmpty ? .formatting : .structure) return } @@ -912,6 +923,8 @@ class DocumentViewController: UIViewController, DocumentDelegate, UISearchBarDel markColors[tool] = UIColor(hex: hex ?? tool.defaultColor ?? EditToolBar.markColors[0].hex) editToolBar.setColor(tool, markColor(of: tool)) pressMarker(tool, recolor: true) + case (_, .structure(let structure)): + run(structure.script) case (_, .customColor): colorPickerTool = tool @@ -955,22 +968,27 @@ class DocumentViewController: UIViewController, DocumentDelegate, UISearchBarDel case "rich", "shapes": key = "edit_refused_rich" case "readOnly": key = "edit_refused_read_only" case "range": key = "edit_refused_range" + case "sheetCut": key = "edit_refused_sheet_cut" default: key = "edit_refused_generic" } AnalyticsManager.shared.report("edit_refused", parameters: ["reason": reason]) - showToast(controller: self, message: NSLocalizedString(key, comment: ""), seconds: 1.5) + // the cut sheet is said once, as the edit starts, so it stays longer + let seconds: Double = reason == "sheetCut" ? 3 : 1.5 + showToast(controller: self, message: NSLocalizedString(key, comment: ""), seconds: seconds) } /// What Pro adds, as the reader runs into it. enum ProFeature { case formatting + case structure case pdf var message: String { switch self { case .formatting: return NSLocalizedString("pro_feature_formatting", comment: "") + case .structure: return NSLocalizedString("pro_feature_structure", comment: "") case .pdf: return NSLocalizedString("pro_feature_pdf", comment: "") } } diff --git a/OpenDocumentReader/EditToolBar.swift b/OpenDocumentReader/EditToolBar.swift index 6db827a..0801b71 100644 --- a/OpenDocumentReader/EditToolBar.swift +++ b/OpenDocumentReader/EditToolBar.swift @@ -8,6 +8,7 @@ final class EditToolBar: UIView { enum Tool: CaseIterable { case bold, italic, underline, strikethrough case textColor, highlight, fill, fontSize, align + case rows, columns case markHighlight, markUnderline, markStrikeOut, markSquiggly, markDraw var symbol: String { @@ -21,6 +22,8 @@ final class EditToolBar: UIView { case .fill: return "paintbrush" case .fontSize: return "textformat.size" case .align: return Alignment.left.symbol + case .rows: return "rectangle.split.1x2" + case .columns: return "rectangle.split.2x1" case .markUnderline: return "underline" case .markStrikeOut: return "strikethrough" // not in the system set, so it is drawn - see ``squigglyImage`` @@ -45,6 +48,8 @@ final class EditToolBar: UIView { case .fill: return NSLocalizedString("edit_fill", comment: "") case .fontSize: return NSLocalizedString("edit_font_size", comment: "") case .align: return NSLocalizedString("edit_align", comment: "") + case .rows: return NSLocalizedString("edit_rows", comment: "") + case .columns: return NSLocalizedString("edit_columns", comment: "") case .markHighlight: return NSLocalizedString("mark_highlight", comment: "") case .markUnderline: return NSLocalizedString("mark_underline", comment: "") case .markStrikeOut: return NSLocalizedString("mark_strike_out", comment: "") @@ -79,7 +84,17 @@ final class EditToolBar: UIView { /// Whether a tap opens the tool's choices. None of these has any state /// to turn off. var opensOnTap: Bool { - self == .textColor || self == .fontSize || self == .align + self == .textColor || self == .fontSize || self == .align || !structures.isEmpty + } + + /// What the tool's menu inserts or deletes; empty for a tool that + /// changes no rows or columns. + var structures: [Structure] { + switch self { + case .rows: return [.insertRowsAbove, .insertRowsBelow, .deleteRows] + case .columns: return [.insertColumnsLeft, .insertColumnsRight, .deleteColumns] + default: return [] + } } /// Whether the tool paints behind the text, and so offers to paint @@ -122,6 +137,8 @@ final class EditToolBar: UIView { case text /// a spreadsheet, whose cells take a style case sheet + /// a sheet whose cells take no style, such as a csv + case values /// a pdf, which takes marks case pdf @@ -130,7 +147,11 @@ final class EditToolBar: UIView { case .text: return [.bold, .italic, .underline, .strikethrough, .textColor, .highlight, .fontSize, .align] case .sheet: - return [.bold, .italic, .underline, .strikethrough, .textColor, .fill, .fontSize, .align] + return [ + .bold, .italic, .underline, .strikethrough, .textColor, .fill, .fontSize, .align, .rows, .columns, + ] + case .values: + return [.rows, .columns] case .pdf: return [.markHighlight, .markUnderline, .markStrikeOut, .markSquiggly, .markDraw] } @@ -165,6 +186,50 @@ final class EditToolBar: UIView { } } + /// A row or column edit, applied to the rows or columns the selection + /// spans. + enum Structure: CaseIterable { + case insertRowsAbove, insertRowsBelow, deleteRows + case insertColumnsLeft, insertColumnsRight, deleteColumns + + /// The call to `odr.editing` that does it. + var script: String { + switch self { + case .insertRowsAbove: return "odr.editing.insertRows('above')" + case .insertRowsBelow: return "odr.editing.insertRows('below')" + case .deleteRows: return "odr.editing.deleteRows()" + case .insertColumnsLeft: return "odr.editing.insertColumns('left')" + case .insertColumnsRight: return "odr.editing.insertColumns('right')" + case .deleteColumns: return "odr.editing.deleteColumns()" + } + } + + var symbol: String { + switch self { + case .insertRowsAbove: return "arrow.up" + case .insertRowsBelow: return "arrow.down" + case .insertColumnsLeft: return "arrow.left" + case .insertColumnsRight: return "arrow.right" + case .deleteRows, .deleteColumns: return "trash" + } + } + + var label: String { + switch self { + case .insertRowsAbove: return NSLocalizedString("edit_insert_rows_above", comment: "") + case .insertRowsBelow: return NSLocalizedString("edit_insert_rows_below", comment: "") + case .deleteRows: return NSLocalizedString("edit_delete_rows", comment: "") + case .insertColumnsLeft: return NSLocalizedString("edit_insert_columns_left", comment: "") + case .insertColumnsRight: return NSLocalizedString("edit_insert_columns_right", comment: "") + case .deleteColumns: return NSLocalizedString("edit_delete_columns", comment: "") + } + } + + var isDelete: Bool { + self == .deleteRows || self == .deleteColumns + } + } + /// A pick from one of the menus. enum Choice { /// `#rrggbb`, or nil for no highlight @@ -174,6 +239,7 @@ final class EditToolBar: UIView { /// in points case size(Int) case align(Alignment) + case structure(Structure) } /// A colour the menus offer. @@ -553,6 +619,7 @@ final class EditToolBar: UIView { switch tool { case .fontSize: return sizeMenu() case .align: return alignMenu() + case .rows, .columns: return structureMenu(for: tool) default: return colorMenu(for: tool, swatches: tool.swatches, offersNone: tool.offersNone) } } @@ -572,6 +639,20 @@ final class EditToolBar: UIView { }) } + /// Insert before, insert after, and delete what the selection spans. + private func structureMenu(for tool: Tool) -> UIMenu { + UIMenu( + title: tool.label, + children: tool.structures.map { structure in + UIAction( + title: structure.label, image: UIImage(systemName: structure.symbol), + attributes: structure.isDelete ? .destructive : [] + ) { [weak self] _ in + self?.onChoice?(tool, .structure(structure)) + } + }) + } + /// The fourteen sizes, with the one the text is in marked. private func sizeMenu() -> UIMenu { UIMenu( diff --git a/OpenDocumentReader/ca.lproj/Localizable.strings b/OpenDocumentReader/ca.lproj/Localizable.strings index 48bbeac..3f52427 100644 --- a/OpenDocumentReader/ca.lproj/Localizable.strings +++ b/OpenDocumentReader/ca.lproj/Localizable.strings @@ -121,6 +121,14 @@ "edit_align_center" = "Centre"; "edit_align_right" = "Dreta"; "edit_align_justify" = "Justificat"; +"edit_rows" = "Files"; +"edit_columns" = "Columnes"; +"edit_insert_rows_above" = "Insereix una fila a sobre"; +"edit_insert_rows_below" = "Insereix una fila a sota"; +"edit_delete_rows" = "Suprimeix la fila"; +"edit_insert_columns_left" = "Insereix una columna a l’esquerra"; +"edit_insert_columns_right" = "Insereix una columna a la dreta"; +"edit_delete_columns" = "Suprimeix la columna"; "edit_undo" = "Desfés"; "edit_redo" = "Refés"; @@ -150,11 +158,13 @@ "edit_refused_new_line" = "Un salt de línia dins d’un paràgraf no es pot desar. Prem Retorn per a un paràgraf nou."; "edit_refused_read_only" = "Aquest document no es pot editar."; "edit_refused_range" = "Una edició no pot passar per sobre d’una imatge o d’una taula."; +"edit_refused_sheet_cut" = "Aquest full és massa gran per mostrar-lo sencer. Només es pot editar la part que es mostra."; /* What Pro adds, shown in the Lite app */ "pro_feature_title" = "Part de Pro"; "pro_feature_formatting" = "La negreta, la cursiva, els colors i la mida del text, i afegir o unir paràgrafs, formen part d’OpenDocument Reader Pro. El marcador hi és a totes les edicions."; "pro_feature_pdf" = "Subratllar, ratllar i dibuixar en un PDF formen part d’OpenDocument Reader Pro. El marcador hi és a totes les edicions."; +"pro_feature_structure" = "Afegir i suprimir files i columnes forma part d’OpenDocument Reader Pro. El marcador hi és a totes les edicions."; "not_now" = "Ara no"; /* Shown when the marking tools come up on a PDF */ diff --git a/OpenDocumentReader/cs.lproj/Localizable.strings b/OpenDocumentReader/cs.lproj/Localizable.strings index 1d0aa17..285bdbb 100644 --- a/OpenDocumentReader/cs.lproj/Localizable.strings +++ b/OpenDocumentReader/cs.lproj/Localizable.strings @@ -121,6 +121,14 @@ "edit_align_center" = "Na střed"; "edit_align_right" = "Vpravo"; "edit_align_justify" = "Do bloku"; +"edit_rows" = "Řádky"; +"edit_columns" = "Sloupce"; +"edit_insert_rows_above" = "Vložit řádek nad"; +"edit_insert_rows_below" = "Vložit řádek pod"; +"edit_delete_rows" = "Odstranit řádek"; +"edit_insert_columns_left" = "Vložit sloupec vlevo"; +"edit_insert_columns_right" = "Vložit sloupec vpravo"; +"edit_delete_columns" = "Odstranit sloupec"; "edit_undo" = "Zpět"; "edit_redo" = "Znovu"; @@ -150,11 +158,13 @@ "edit_refused_new_line" = "Zalomení řádku uvnitř odstavce nelze uložit. Stiskněte Enter pro nový odstavec."; "edit_refused_read_only" = "Tento dokument nelze upravovat."; "edit_refused_range" = "Úprava nemůže sahat přes obrázek nebo tabulku."; +"edit_refused_sheet_cut" = "Tento list je příliš velký na úplné zobrazení. Upravit lze jen zobrazenou část."; /* What Pro adds, shown in the Lite app */ "pro_feature_title" = "Součást Pro"; "pro_feature_formatting" = "Tučné písmo, kurzíva, barvy a velikost textu a přidávání nebo spojování odstavců jsou součástí OpenDocument Reader Pro. Zvýrazňovač je v každé edici."; "pro_feature_pdf" = "Podtržení, přeškrtnutí a kreslení v PDF jsou součástí OpenDocument Reader Pro. Zvýrazňovač je v každé edici."; +"pro_feature_structure" = "Přidávání a odstraňování řádků a sloupců je součástí OpenDocument Reader Pro. Zvýrazňovač je v každé edici."; "not_now" = "Teď ne"; /* Shown when the marking tools come up on a PDF */ diff --git a/OpenDocumentReader/da.lproj/Localizable.strings b/OpenDocumentReader/da.lproj/Localizable.strings index 6db60f7..5c836a3 100644 --- a/OpenDocumentReader/da.lproj/Localizable.strings +++ b/OpenDocumentReader/da.lproj/Localizable.strings @@ -121,6 +121,14 @@ "edit_align_center" = "Centreret"; "edit_align_right" = "Højre"; "edit_align_justify" = "Lige margener"; +"edit_rows" = "Rækker"; +"edit_columns" = "Kolonner"; +"edit_insert_rows_above" = "Indsæt række over"; +"edit_insert_rows_below" = "Indsæt række under"; +"edit_delete_rows" = "Slet række"; +"edit_insert_columns_left" = "Indsæt kolonne til venstre"; +"edit_insert_columns_right" = "Indsæt kolonne til højre"; +"edit_delete_columns" = "Slet kolonne"; "edit_undo" = "Fortryd"; "edit_redo" = "Gentag"; @@ -150,11 +158,13 @@ "edit_refused_new_line" = "Et linjeskift inde i et afsnit kan ikke gemmes. Tryk på Enter for et nyt afsnit."; "edit_refused_read_only" = "Dette dokument kan ikke redigeres."; "edit_refused_range" = "En redigering kan ikke række hen over et billede eller en tabel."; +"edit_refused_sheet_cut" = "Dette ark er for stort til at blive vist helt. Kun den viste del kan redigeres."; /* What Pro adds, shown in the Lite app */ "pro_feature_title" = "En del af Pro"; "pro_feature_formatting" = "Fed, kursiv, farver og tekststørrelse samt tilføjelse eller sammenføjning af afsnit er en del af OpenDocument Reader Pro. Overstregningstuschen er med i alle udgaver."; "pro_feature_pdf" = "Understregning, gennemstregning og tegning i en PDF er en del af OpenDocument Reader Pro. Overstregningstuschen er med i alle udgaver."; +"pro_feature_structure" = "Indsættelse og sletning af rækker og kolonner er en del af OpenDocument Reader Pro. Overstregningstuschen er med i alle udgaver."; "not_now" = "Ikke nu"; /* Shown when the marking tools come up on a PDF */ diff --git a/OpenDocumentReader/de.lproj/Localizable.strings b/OpenDocumentReader/de.lproj/Localizable.strings index 2a71c8f..7e663af 100644 --- a/OpenDocumentReader/de.lproj/Localizable.strings +++ b/OpenDocumentReader/de.lproj/Localizable.strings @@ -121,6 +121,14 @@ "edit_align_center" = "Zentriert"; "edit_align_right" = "Rechts"; "edit_align_justify" = "Blocksatz"; +"edit_rows" = "Zeilen"; +"edit_columns" = "Spalten"; +"edit_insert_rows_above" = "Zeile oberhalb einfügen"; +"edit_insert_rows_below" = "Zeile unterhalb einfügen"; +"edit_delete_rows" = "Zeile löschen"; +"edit_insert_columns_left" = "Spalte links einfügen"; +"edit_insert_columns_right" = "Spalte rechts einfügen"; +"edit_delete_columns" = "Spalte löschen"; "edit_undo" = "Rückgängig"; "edit_redo" = "Wiederholen"; @@ -150,11 +158,13 @@ "edit_refused_new_line" = "Ein Zeilenumbruch innerhalb eines Absatzes kann nicht gespeichert werden. Drücke die Eingabetaste für einen neuen Absatz."; "edit_refused_read_only" = "Dieses Dokument kann nicht bearbeitet werden."; "edit_refused_range" = "Eine Änderung kann nicht über ein Bild oder eine Tabelle hinausreichen."; +"edit_refused_sheet_cut" = "Diese Tabelle ist zu groß, um sie ganz anzuzeigen. Nur der angezeigte Teil kann bearbeitet werden."; /* What Pro adds, shown in the Lite app */ "pro_feature_title" = "Teil von Pro"; "pro_feature_formatting" = "Fett, kursiv, Farben und Schriftgröße sowie Absätze einfügen oder zusammenführen sind Teil von OpenDocument Reader Pro. Der Textmarker ist in jeder Ausgabe dabei."; "pro_feature_pdf" = "Unterstreichen, Durchstreichen und Zeichnen in einem PDF sind Teil von OpenDocument Reader Pro. Der Textmarker ist in jeder Ausgabe dabei."; +"pro_feature_structure" = "Zeilen und Spalten einfügen und löschen ist Teil von OpenDocument Reader Pro. Der Textmarker ist in jeder Ausgabe dabei."; "not_now" = "Nicht jetzt"; /* Shown when the marking tools come up on a PDF */ diff --git a/OpenDocumentReader/en.lproj/Localizable.strings b/OpenDocumentReader/en.lproj/Localizable.strings index b6e51ec..7c7ffab 100644 --- a/OpenDocumentReader/en.lproj/Localizable.strings +++ b/OpenDocumentReader/en.lproj/Localizable.strings @@ -121,6 +121,14 @@ "edit_align_center" = "Center"; "edit_align_right" = "Right"; "edit_align_justify" = "Justify"; +"edit_rows" = "Rows"; +"edit_columns" = "Columns"; +"edit_insert_rows_above" = "Insert row above"; +"edit_insert_rows_below" = "Insert row below"; +"edit_delete_rows" = "Delete row"; +"edit_insert_columns_left" = "Insert column left"; +"edit_insert_columns_right" = "Insert column right"; +"edit_delete_columns" = "Delete column"; "edit_undo" = "Undo"; "edit_redo" = "Redo"; @@ -150,11 +158,13 @@ "edit_refused_new_line" = "A line break inside a paragraph cannot be saved. Press Return for a new paragraph."; "edit_refused_read_only" = "This document cannot be edited."; "edit_refused_range" = "An edit cannot reach over a picture or a table."; +"edit_refused_sheet_cut" = "This sheet is too large to show in full. Only the part on screen can be edited."; /* What Pro adds, shown in the Lite app. The highlighter is free in both kinds */ "pro_feature_title" = "Part of Pro"; "pro_feature_formatting" = "Bold, italic, colors and text size, and adding or joining paragraphs, are part of OpenDocument Reader Pro. The highlighter is in every edition."; "pro_feature_pdf" = "Underlining, striking out and drawing on a PDF are part of OpenDocument Reader Pro. The highlighter is in every edition."; +"pro_feature_structure" = "Adding and deleting rows and columns is part of OpenDocument Reader Pro. The highlighter is in every edition."; "not_now" = "Not now"; /* Shown when the marking tools come up on a PDF */ diff --git a/OpenDocumentReader/es.lproj/Localizable.strings b/OpenDocumentReader/es.lproj/Localizable.strings index e7beb3a..1fb0ff5 100644 --- a/OpenDocumentReader/es.lproj/Localizable.strings +++ b/OpenDocumentReader/es.lproj/Localizable.strings @@ -121,6 +121,14 @@ "edit_align_center" = "Centro"; "edit_align_right" = "Derecha"; "edit_align_justify" = "Justificado"; +"edit_rows" = "Filas"; +"edit_columns" = "Columnas"; +"edit_insert_rows_above" = "Insertar fila arriba"; +"edit_insert_rows_below" = "Insertar fila debajo"; +"edit_delete_rows" = "Eliminar fila"; +"edit_insert_columns_left" = "Insertar columna a la izquierda"; +"edit_insert_columns_right" = "Insertar columna a la derecha"; +"edit_delete_columns" = "Eliminar columna"; "edit_undo" = "Deshacer"; "edit_redo" = "Rehacer"; @@ -150,11 +158,13 @@ "edit_refused_new_line" = "Un salto de línea dentro de un párrafo no se puede guardar. Pulsa Intro para un párrafo nuevo."; "edit_refused_read_only" = "Este documento no se puede editar."; "edit_refused_range" = "Una edición no puede pasar por encima de una imagen o una tabla."; +"edit_refused_sheet_cut" = "Esta hoja es demasiado grande para mostrarla entera. Solo se puede editar la parte que se muestra."; /* What Pro adds, shown in the Lite app */ "pro_feature_title" = "Parte de Pro"; "pro_feature_formatting" = "La negrita, la cursiva, los colores y el tamaño del texto, y añadir o unir párrafos, forman parte de OpenDocument Reader Pro. El marcador está en todas las ediciones."; "pro_feature_pdf" = "Subrayar, tachar y dibujar en un PDF forman parte de OpenDocument Reader Pro. El marcador está en todas las ediciones."; +"pro_feature_structure" = "Añadir y eliminar filas y columnas forma parte de OpenDocument Reader Pro. El marcador está en todas las ediciones."; "not_now" = "Ahora no"; /* Shown when the marking tools come up on a PDF */ diff --git a/OpenDocumentReader/fr.lproj/Localizable.strings b/OpenDocumentReader/fr.lproj/Localizable.strings index e74333c..b08735c 100644 --- a/OpenDocumentReader/fr.lproj/Localizable.strings +++ b/OpenDocumentReader/fr.lproj/Localizable.strings @@ -121,6 +121,14 @@ "edit_align_center" = "Centré"; "edit_align_right" = "À droite"; "edit_align_justify" = "Justifié"; +"edit_rows" = "Lignes"; +"edit_columns" = "Colonnes"; +"edit_insert_rows_above" = "Insérer une ligne au-dessus"; +"edit_insert_rows_below" = "Insérer une ligne en dessous"; +"edit_delete_rows" = "Supprimer la ligne"; +"edit_insert_columns_left" = "Insérer une colonne à gauche"; +"edit_insert_columns_right" = "Insérer une colonne à droite"; +"edit_delete_columns" = "Supprimer la colonne"; "edit_undo" = "Annuler"; "edit_redo" = "Rétablir"; @@ -150,11 +158,13 @@ "edit_refused_new_line" = "Un saut de ligne à l’intérieur d’un paragraphe ne peut pas être enregistré. Appuyez sur Entrée pour un nouveau paragraphe."; "edit_refused_read_only" = "Ce document ne peut pas être modifié."; "edit_refused_range" = "Une modification ne peut pas passer par-dessus une image ou un tableau."; +"edit_refused_sheet_cut" = "Cette feuille est trop grande pour être affichée en entier. Seule la partie affichée peut être modifiée."; /* What Pro adds, shown in the Lite app */ "pro_feature_title" = "Réservé à Pro"; "pro_feature_formatting" = "Le gras, l’italique, les couleurs et la taille du texte, ainsi que l’ajout ou la fusion de paragraphes, font partie d’OpenDocument Reader Pro. Le surligneur est dans toutes les éditions."; "pro_feature_pdf" = "Souligner, barrer et dessiner sur un PDF font partie d’OpenDocument Reader Pro. Le surligneur est dans toutes les éditions."; +"pro_feature_structure" = "Ajouter et supprimer des lignes et des colonnes fait partie d’OpenDocument Reader Pro. Le surligneur est dans toutes les éditions."; "not_now" = "Pas maintenant"; /* Shown when the marking tools come up on a PDF */ diff --git a/OpenDocumentReader/ga.lproj/Localizable.strings b/OpenDocumentReader/ga.lproj/Localizable.strings index 2087090..2ce69e3 100644 --- a/OpenDocumentReader/ga.lproj/Localizable.strings +++ b/OpenDocumentReader/ga.lproj/Localizable.strings @@ -121,6 +121,14 @@ "edit_align_center" = "Lár"; "edit_align_right" = "Deas"; "edit_align_justify" = "Comhfhadaigh"; +"edit_rows" = "Rónna"; +"edit_columns" = "Colúin"; +"edit_insert_rows_above" = "Cuir isteach ró os a chionn"; +"edit_insert_rows_below" = "Cuir isteach ró faoi"; +"edit_delete_rows" = "Scrios an ró"; +"edit_insert_columns_left" = "Cuir isteach colún ar chlé"; +"edit_insert_columns_right" = "Cuir isteach colún ar dheis"; +"edit_delete_columns" = "Scrios an colún"; "edit_undo" = "Cealaigh"; "edit_redo" = "Athdhéan"; @@ -150,11 +158,13 @@ "edit_refused_new_line" = "Ní féidir briseadh líne laistigh d’alt a shábháil. Brúigh Iontráil le haghaidh alt nua."; "edit_refused_read_only" = "Ní féidir an doiciméad seo a chur in eagar."; "edit_refused_range" = "Ní féidir le hathrú dul thar phictiúr ná thar thábla."; +"edit_refused_sheet_cut" = "Tá an bhileog seo rómhór le taispeáint ina hiomláine. Ní féidir ach an chuid a thaispeántar a chur in eagar."; /* What Pro adds, shown in the Lite app */ "pro_feature_title" = "Cuid de Pro"; "pro_feature_formatting" = "Is cuid de OpenDocument Reader Pro iad cló trom, cló iodálach, dathanna agus méid an téacs, agus ailt a chur leis nó a nascadh. Tá an marcóir i ngach eagrán."; "pro_feature_pdf" = "Is cuid de OpenDocument Reader Pro iad líne a chur faoi théacs, líne a chur tríd agus líníocht a dhéanamh ar PDF. Tá an marcóir i ngach eagrán."; +"pro_feature_structure" = "Is cuid de OpenDocument Reader Pro é rónna agus colúin a chur leis agus a scriosadh. Tá an marcóir i ngach eagrán."; "not_now" = "Ní anois"; /* Shown when the marking tools come up on a PDF */ diff --git a/OpenDocumentReader/it.lproj/Localizable.strings b/OpenDocumentReader/it.lproj/Localizable.strings index ca8c445..deab166 100644 --- a/OpenDocumentReader/it.lproj/Localizable.strings +++ b/OpenDocumentReader/it.lproj/Localizable.strings @@ -121,6 +121,14 @@ "edit_align_center" = "Centro"; "edit_align_right" = "Destra"; "edit_align_justify" = "Giustificato"; +"edit_rows" = "Righe"; +"edit_columns" = "Colonne"; +"edit_insert_rows_above" = "Inserisci riga sopra"; +"edit_insert_rows_below" = "Inserisci riga sotto"; +"edit_delete_rows" = "Elimina riga"; +"edit_insert_columns_left" = "Inserisci colonna a sinistra"; +"edit_insert_columns_right" = "Inserisci colonna a destra"; +"edit_delete_columns" = "Elimina colonna"; "edit_undo" = "Annulla"; "edit_redo" = "Ripeti"; @@ -150,11 +158,13 @@ "edit_refused_new_line" = "Un’interruzione di riga dentro un paragrafo non può essere salvata. Premi Invio per un nuovo paragrafo."; "edit_refused_read_only" = "Questo documento non può essere modificato."; "edit_refused_range" = "Una modifica non può passare sopra un’immagine o una tabella."; +"edit_refused_sheet_cut" = "Questo foglio è troppo grande per essere mostrato per intero. Si può modificare solo la parte mostrata."; /* What Pro adds, shown in the Lite app */ "pro_feature_title" = "Parte di Pro"; "pro_feature_formatting" = "Il grassetto, il corsivo, i colori e la dimensione del testo, e aggiungere o unire paragrafi, fanno parte di OpenDocument Reader Pro. L’evidenziatore c’è in ogni edizione."; "pro_feature_pdf" = "Sottolineare, barrare e disegnare su un PDF fanno parte di OpenDocument Reader Pro. L’evidenziatore c’è in ogni edizione."; +"pro_feature_structure" = "Aggiungere ed eliminare righe e colonne fa parte di OpenDocument Reader Pro. L’evidenziatore c’è in ogni edizione."; "not_now" = "Non ora"; /* Shown when the marking tools come up on a PDF */ diff --git a/OpenDocumentReader/ja.lproj/Localizable.strings b/OpenDocumentReader/ja.lproj/Localizable.strings index 53364e0..10f876d 100644 --- a/OpenDocumentReader/ja.lproj/Localizable.strings +++ b/OpenDocumentReader/ja.lproj/Localizable.strings @@ -121,6 +121,14 @@ "edit_align_center" = "中央揃え"; "edit_align_right" = "右揃え"; "edit_align_justify" = "両端揃え"; +"edit_rows" = "行"; +"edit_columns" = "列"; +"edit_insert_rows_above" = "上に行を挿入"; +"edit_insert_rows_below" = "下に行を挿入"; +"edit_delete_rows" = "行を削除"; +"edit_insert_columns_left" = "左に列を挿入"; +"edit_insert_columns_right" = "右に列を挿入"; +"edit_delete_columns" = "列を削除"; "edit_undo" = "元に戻す"; "edit_redo" = "やり直す"; @@ -150,11 +158,13 @@ "edit_refused_new_line" = "段落内の改行は保存できません。新しい段落にはReturnキーを押してください。"; "edit_refused_read_only" = "この書類は編集できません。"; "edit_refused_range" = "画像や表をまたぐ編集はできません。"; +"edit_refused_sheet_cut" = "このシートは大きすぎてすべてを表示できません。編集できるのは表示されている部分だけです。"; /* What Pro adds, shown in the Lite app */ "pro_feature_title" = "Proの機能"; "pro_feature_formatting" = "太字、斜体、色、文字サイズと、段落の追加や結合はOpenDocument Reader Proの機能です。蛍光ペンはどの版でも使えます。"; "pro_feature_pdf" = "PDFへの下線、取り消し線、手書きはOpenDocument Reader Proの機能です。蛍光ペンはどの版でも使えます。"; +"pro_feature_structure" = "行と列の追加と削除はOpenDocument Reader Proの機能です。蛍光ペンはどの版でも使えます。"; "not_now" = "あとで"; /* Shown when the marking tools come up on a PDF */ diff --git a/OpenDocumentReader/pl.lproj/Localizable.strings b/OpenDocumentReader/pl.lproj/Localizable.strings index 721c925..1279c9f 100644 --- a/OpenDocumentReader/pl.lproj/Localizable.strings +++ b/OpenDocumentReader/pl.lproj/Localizable.strings @@ -121,6 +121,14 @@ "edit_align_center" = "Do środka"; "edit_align_right" = "Do prawej"; "edit_align_justify" = "Wyjustuj"; +"edit_rows" = "Wiersze"; +"edit_columns" = "Kolumny"; +"edit_insert_rows_above" = "Wstaw wiersz powyżej"; +"edit_insert_rows_below" = "Wstaw wiersz poniżej"; +"edit_delete_rows" = "Usuń wiersz"; +"edit_insert_columns_left" = "Wstaw kolumnę z lewej"; +"edit_insert_columns_right" = "Wstaw kolumnę z prawej"; +"edit_delete_columns" = "Usuń kolumnę"; "edit_undo" = "Cofnij"; "edit_redo" = "Ponów"; @@ -150,11 +158,13 @@ "edit_refused_new_line" = "Podziału wiersza wewnątrz akapitu nie można zapisać. Naciśnij Enter, aby zacząć nowy akapit."; "edit_refused_read_only" = "Tego dokumentu nie można edytować."; "edit_refused_range" = "Zmiana nie może sięgać przez obraz ani tabelę."; +"edit_refused_sheet_cut" = "Ten arkusz jest za duży, aby pokazać go w całości. Można edytować tylko pokazaną część."; /* What Pro adds, shown in the Lite app */ "pro_feature_title" = "Część wersji Pro"; "pro_feature_formatting" = "Pogrubienie, kursywa, kolory i rozmiar tekstu oraz dodawanie i łączenie akapitów to część OpenDocument Reader Pro. Zakreślacz jest w każdej edycji."; "pro_feature_pdf" = "Podkreślanie, przekreślanie i rysowanie w PDF to część OpenDocument Reader Pro. Zakreślacz jest w każdej edycji."; +"pro_feature_structure" = "Dodawanie i usuwanie wierszy i kolumn to część OpenDocument Reader Pro. Zakreślacz jest w każdej edycji."; "not_now" = "Nie teraz"; /* Shown when the marking tools come up on a PDF */ diff --git a/OpenDocumentReader/pt-BR.lproj/Localizable.strings b/OpenDocumentReader/pt-BR.lproj/Localizable.strings index e5e26b3..7a19253 100644 --- a/OpenDocumentReader/pt-BR.lproj/Localizable.strings +++ b/OpenDocumentReader/pt-BR.lproj/Localizable.strings @@ -121,6 +121,14 @@ "edit_align_center" = "Centralizado"; "edit_align_right" = "À direita"; "edit_align_justify" = "Justificado"; +"edit_rows" = "Linhas"; +"edit_columns" = "Colunas"; +"edit_insert_rows_above" = "Inserir linha acima"; +"edit_insert_rows_below" = "Inserir linha abaixo"; +"edit_delete_rows" = "Excluir linha"; +"edit_insert_columns_left" = "Inserir coluna à esquerda"; +"edit_insert_columns_right" = "Inserir coluna à direita"; +"edit_delete_columns" = "Excluir coluna"; "edit_undo" = "Desfazer"; "edit_redo" = "Refazer"; @@ -150,11 +158,13 @@ "edit_refused_new_line" = "Uma quebra de linha dentro de um parágrafo não pode ser salva. Pressione Enter para um novo parágrafo."; "edit_refused_read_only" = "Este documento não pode ser editado."; "edit_refused_range" = "Uma edição não pode passar por cima de uma imagem ou de uma tabela."; +"edit_refused_sheet_cut" = "Esta planilha é grande demais para ser mostrada inteira. Só a parte mostrada pode ser editada."; /* What Pro adds, shown in the Lite app */ "pro_feature_title" = "Parte do Pro"; "pro_feature_formatting" = "Negrito, itálico, cores e tamanho do texto, e adicionar ou juntar parágrafos, fazem parte do OpenDocument Reader Pro. O marca-texto está em todas as edições."; "pro_feature_pdf" = "Sublinhar, riscar e desenhar em um PDF fazem parte do OpenDocument Reader Pro. O marca-texto está em todas as edições."; +"pro_feature_structure" = "Adicionar e excluir linhas e colunas faz parte do OpenDocument Reader Pro. O marca-texto está em todas as edições."; "not_now" = "Agora não"; /* Shown when the marking tools come up on a PDF */ diff --git a/OpenDocumentReader/ru.lproj/Localizable.strings b/OpenDocumentReader/ru.lproj/Localizable.strings index d6c45de..75cec93 100644 --- a/OpenDocumentReader/ru.lproj/Localizable.strings +++ b/OpenDocumentReader/ru.lproj/Localizable.strings @@ -121,6 +121,14 @@ "edit_align_center" = "По центру"; "edit_align_right" = "По правому краю"; "edit_align_justify" = "По ширине"; +"edit_rows" = "Строки"; +"edit_columns" = "Столбцы"; +"edit_insert_rows_above" = "Вставить строку выше"; +"edit_insert_rows_below" = "Вставить строку ниже"; +"edit_delete_rows" = "Удалить строку"; +"edit_insert_columns_left" = "Вставить столбец слева"; +"edit_insert_columns_right" = "Вставить столбец справа"; +"edit_delete_columns" = "Удалить столбец"; "edit_undo" = "Отменить"; "edit_redo" = "Повторить"; @@ -150,11 +158,13 @@ "edit_refused_new_line" = "Перенос строки внутри абзаца нельзя сохранить. Нажмите Ввод, чтобы начать новый абзац."; "edit_refused_read_only" = "Этот документ нельзя редактировать."; "edit_refused_range" = "Изменение не может проходить через картинку или таблицу."; +"edit_refused_sheet_cut" = "Этот лист слишком большой, чтобы показать его целиком. Изменить можно только показанную часть."; /* What Pro adds, shown in the Lite app */ "pro_feature_title" = "Часть Pro"; "pro_feature_formatting" = "Полужирный, курсив, цвета и размер текста, а также добавление и объединение абзацев — часть OpenDocument Reader Pro. Маркер есть в любом издании."; "pro_feature_pdf" = "Подчёркивание, зачёркивание и рисование в PDF — часть OpenDocument Reader Pro. Маркер есть в любом издании."; +"pro_feature_structure" = "Добавление и удаление строк и столбцов — часть OpenDocument Reader Pro. Маркер есть в любом издании."; "not_now" = "Не сейчас"; /* Shown when the marking tools come up on a PDF */ diff --git a/OpenDocumentReader/sl.lproj/Localizable.strings b/OpenDocumentReader/sl.lproj/Localizable.strings index c7ce2c0..2348a4a 100644 --- a/OpenDocumentReader/sl.lproj/Localizable.strings +++ b/OpenDocumentReader/sl.lproj/Localizable.strings @@ -121,6 +121,14 @@ "edit_align_center" = "Sredinsko"; "edit_align_right" = "Desno"; "edit_align_justify" = "Obojestransko"; +"edit_rows" = "Vrstice"; +"edit_columns" = "Stolpci"; +"edit_insert_rows_above" = "Vstavi vrstico zgoraj"; +"edit_insert_rows_below" = "Vstavi vrstico spodaj"; +"edit_delete_rows" = "Izbriši vrstico"; +"edit_insert_columns_left" = "Vstavi stolpec levo"; +"edit_insert_columns_right" = "Vstavi stolpec desno"; +"edit_delete_columns" = "Izbriši stolpec"; "edit_undo" = "Razveljavi"; "edit_redo" = "Ponovi"; @@ -150,11 +158,13 @@ "edit_refused_new_line" = "Preloma vrstice znotraj odstavka ni mogoče shraniti. Pritisnite Enter za nov odstavek."; "edit_refused_read_only" = "Tega dokumenta ni mogoče urejati."; "edit_refused_range" = "Urejanje ne more segati čez sliko ali tabelo."; +"edit_refused_sheet_cut" = "Ta list je prevelik, da bi ga prikazali v celoti. Urejati je mogoče le prikazani del."; /* What Pro adds, shown in the Lite app */ "pro_feature_title" = "Del različice Pro"; "pro_feature_formatting" = "Krepko, ležeče, barve in velikost besedila ter dodajanje ali združevanje odstavkov so del OpenDocument Reader Pro. Označevalnik je v vsaki izdaji."; "pro_feature_pdf" = "Podčrtovanje, prečrtovanje in risanje v PDF so del OpenDocument Reader Pro. Označevalnik je v vsaki izdaji."; +"pro_feature_structure" = "Dodajanje in brisanje vrstic in stolpcev je del OpenDocument Reader Pro. Označevalnik je v vsaki izdaji."; "not_now" = "Ne zdaj"; /* Shown when the marking tools come up on a PDF */ diff --git a/OpenDocumentReader/tr.lproj/Localizable.strings b/OpenDocumentReader/tr.lproj/Localizable.strings index 058c185..78c9122 100644 --- a/OpenDocumentReader/tr.lproj/Localizable.strings +++ b/OpenDocumentReader/tr.lproj/Localizable.strings @@ -121,6 +121,14 @@ "edit_align_center" = "Ortaya"; "edit_align_right" = "Sağa"; "edit_align_justify" = "İki yana"; +"edit_rows" = "Satırlar"; +"edit_columns" = "Sütunlar"; +"edit_insert_rows_above" = "Üste satır ekle"; +"edit_insert_rows_below" = "Alta satır ekle"; +"edit_delete_rows" = "Satırı sil"; +"edit_insert_columns_left" = "Sola sütun ekle"; +"edit_insert_columns_right" = "Sağa sütun ekle"; +"edit_delete_columns" = "Sütunu sil"; "edit_undo" = "Geri al"; "edit_redo" = "Yinele"; @@ -150,11 +158,13 @@ "edit_refused_new_line" = "Paragraf içindeki satır sonu kaydedilemez. Yeni paragraf için Enter’a basın."; "edit_refused_read_only" = "Bu belge düzenlenemez."; "edit_refused_range" = "Bir düzenleme bir resmin ya da tablonun üzerinden geçemez."; +"edit_refused_sheet_cut" = "Bu sayfa tamamı gösterilemeyecek kadar büyük. Yalnızca gösterilen kısım düzenlenebilir."; /* What Pro adds, shown in the Lite app */ "pro_feature_title" = "Pro’nun parçası"; "pro_feature_formatting" = "Kalın, italik, renkler ve metin boyutu ile paragraf eklemek ya da birleştirmek OpenDocument Reader Pro’nun bir parçasıdır. Fosforlu kalem her sürümde vardır."; "pro_feature_pdf" = "Bir PDF’te altını çizmek, üstünü çizmek ve çizim yapmak OpenDocument Reader Pro’nun bir parçasıdır. Fosforlu kalem her sürümde vardır."; +"pro_feature_structure" = "Satır ve sütun eklemek ve silmek OpenDocument Reader Pro’nun bir parçasıdır. Fosforlu kalem her sürümde vardır."; "not_now" = "Şimdi değil"; /* Shown when the marking tools come up on a PDF */ diff --git a/OpenDocumentReader/zh-Hans.lproj/Localizable.strings b/OpenDocumentReader/zh-Hans.lproj/Localizable.strings index 0dc832e..48ba883 100644 --- a/OpenDocumentReader/zh-Hans.lproj/Localizable.strings +++ b/OpenDocumentReader/zh-Hans.lproj/Localizable.strings @@ -121,6 +121,14 @@ "edit_align_center" = "居中"; "edit_align_right" = "右对齐"; "edit_align_justify" = "两端对齐"; +"edit_rows" = "行"; +"edit_columns" = "列"; +"edit_insert_rows_above" = "在上方插入行"; +"edit_insert_rows_below" = "在下方插入行"; +"edit_delete_rows" = "删除行"; +"edit_insert_columns_left" = "在左侧插入列"; +"edit_insert_columns_right" = "在右侧插入列"; +"edit_delete_columns" = "删除列"; "edit_undo" = "撤销"; "edit_redo" = "重做"; @@ -150,11 +158,13 @@ "edit_refused_new_line" = "段落内的换行无法保存。请按回车键开始新段落。"; "edit_refused_read_only" = "此文档无法编辑。"; "edit_refused_range" = "编辑不能跨越图片或表格。"; +"edit_refused_sheet_cut" = "此工作表太大,无法完整显示。只能编辑显示的部分。"; /* What Pro adds, shown in the Lite app */ "pro_feature_title" = "Pro 功能"; "pro_feature_formatting" = "粗体、斜体、颜色和文字大小,以及添加或合并段落,都是 OpenDocument Reader Pro 的功能。荧光笔在每个版本中都能用。"; "pro_feature_pdf" = "在 PDF 上添加下划线、删除线和手绘是 OpenDocument Reader Pro 的功能。荧光笔在每个版本中都能用。"; +"pro_feature_structure" = "添加和删除行与列是 OpenDocument Reader Pro 的功能。荧光笔在每个版本中都能用。"; "not_now" = "暂不"; /* Shown when the marking tools come up on a PDF */ diff --git a/OpenDocumentReaderTests/EditWorkflowTests.swift b/OpenDocumentReaderTests/EditWorkflowTests.swift index c9f0545..5f772f4 100644 --- a/OpenDocumentReaderTests/EditWorkflowTests.swift +++ b/OpenDocumentReaderTests/EditWorkflowTests.swift @@ -195,14 +195,23 @@ class EditWorkflowTests: XCTestCase { XCTAssertNil(controller.editToolBar.layout) } - /// A document nothing can be written back to keeps the room for itself. - func testACsvOffersNoEditButton() throws { + /// A csv takes values but no cell style, so it gets only the row and + /// column tools. + func testACsvEditsWithTheRowAndColumnTools() throws { documentURL = try copyFixture(ofType: "csv") try present(documentURL) - openDocument(where: "typeof odr === 'object'") + openDocument(where: "document.querySelectorAll('td').length > 0") + + XCTAssertTrue(controller.document?.isEditable ?? false) + XCTAssertTrue(barContains(controller.editButton)) - XCTAssertFalse(controller.document?.isEditable ?? true) - XCTAssertFalse(barContains(controller.editButton)) + controller.toggleEdit(controller.editButton) + waitForTools() + + XCTAssertEqual(controller.editToolBar.layout, .values) + XCTAssertTrue(controller.editToolBar.shows(.rows)) + XCTAssertTrue(controller.editToolBar.shows(.columns)) + XCTAssertFalse(controller.editToolBar.shows(.bold)) } // MARK: - the page @@ -280,6 +289,8 @@ class EditWorkflowTests: XCTestCase { XCTAssertTrue(controller.editToolBar.shows(.bold)) XCTAssertTrue(controller.editToolBar.shows(.fill)) XCTAssertTrue(controller.editToolBar.shows(.align)) + XCTAssertTrue(controller.editToolBar.shows(.rows)) + XCTAssertTrue(controller.editToolBar.shows(.columns)) XCTAssertFalse(controller.editToolBar.shows(.highlight)) XCTAssertTrue(barContains(controller.undoButton)) XCTAssertTrue(barContains(controller.redoButton)) @@ -297,6 +308,19 @@ class EditWorkflowTests: XCTestCase { waitUntil { self.controller.saveButton.isEnabled } } + /// A row inserted above the pinned cell pushes the rows down, and the + /// edit goes into the log. + func testTheRowsToolInsertsARow() throws { + try openSheetForEditing() + + let rows = evaluate("document.querySelectorAll('tr').length") as? Int ?? 0 + _ = evaluate("odr.sheet.pin({ column: 0, row: 0 })") + controller.editToolBar.onChoice?(.rows, .structure(.insertRowsAbove)) + + waitForPage(where: "document.querySelectorAll('tr').length === \(rows + 1)") + waitUntil { self.controller.saveButton.isEnabled } + } + /// A style the caret sits in is shown pressed, the way the page reports it. func testTheSelectionStyleReachesTheButtons() throws { openDocument() @@ -399,6 +423,8 @@ class EditWorkflowTests: XCTestCase { XCTAssertTrue(tools.isDimmed(.bold)) XCTAssertTrue(tools.isDimmed(.align)) + XCTAssertTrue(tools.isDimmed(.rows)) + XCTAssertTrue(tools.isDimmed(.columns)) XCTAssertFalse(tools.isDimmed(.fill)) tools.layout = .pdf @@ -427,6 +453,8 @@ class EditWorkflowTests: XCTestCase { tools.layout = .sheet XCTAssertNotNil(tools.menu(of: .fill)) + XCTAssertEqual(tools.menu(of: .rows)?.children.count, 3) + XCTAssertEqual(tools.menu(of: .columns)?.children.count, 3) tools.layout = .pdf diff --git a/OpenDocumentReaderTests/OpenDocumentReaderTests.swift b/OpenDocumentReaderTests/OpenDocumentReaderTests.swift index 6ab81d5..a61001b 100644 --- a/OpenDocumentReaderTests/OpenDocumentReaderTests.swift +++ b/OpenDocumentReaderTests/OpenDocumentReaderTests.swift @@ -76,7 +76,7 @@ class OpenDocumentReaderTests: XCTestCase { XCTAssertEqual(wrapper.pageNames, ["document"]) } - /// A csv reaches odrcore only through the decoded file — see `isCsv`. + /// A csv is a spreadsheet of one sheet, so it gets one page. func testCsvIsTranslated() throws { let wrapper = CoreWrapper() let url = try copyFixture(ofType: "csv") @@ -84,7 +84,7 @@ class OpenDocumentReaderTests: XCTestCase { try wrapper.translate( url.path, into: temporaryDirectory, with: nil, editable: false, scope: .document) - XCTAssertEqual(wrapper.pageNames, ["document"]) + XCTAssertEqual(wrapper.pageNames.count, 1) } /// odrcore renders these now; they used to be handed to the web view. @@ -165,18 +165,20 @@ class OpenDocumentReaderTests: XCTestCase { XCTAssertEqual(wrapper.pageNames, ["image"]) } - /// And it has no document behind it, so the menu must not offer to edit one. - func testCsvIsNotEditable() throws { + /// The cells of a csv take edits, but the csv is not plain text, so it + /// gets the sheet tools. + func testCsvIsEditableAsASheet() throws { let wrapper = CoreWrapper() let url = try copyFixture(ofType: "csv") try wrapper.translate( url.path, into: temporaryDirectory, with: nil, editable: true, scope: .document) - XCTAssertFalse(wrapper.isEditable) + XCTAssertTrue(wrapper.isEditable) + XCTAssertFalse(wrapper.isPlainText) } - /// The odt does, which is what keeps the check above from passing vacuously. + /// The odt takes edits too. func testATextDocumentIsEditable() throws { let wrapper = CoreWrapper() diff --git a/README.md b/README.md index 2952532..49519d4 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,8 @@ Rules: id. The constants behind them live in `Ads/Linked.swift` and `NoAds/Linked.swift`. - Lite edits with the scope `paragraph`. odrcore refuses a larger change with - `outOfScope`, and the app offers Pro. + `outOfScope`, and the app offers Pro. The scope does not reach a sheet, so + the app locks the row and column tools itself. - The gate is on the tool, not on the mode. Both apps open every editable document, and a locked `EditToolBar` dims the Pro tools. The highlighter works in both apps. Do not gate the whole edit mode. @@ -74,7 +75,8 @@ Security blocks plain HTTP. - The pencil calls `odr.editing.enable()`. The page stays in place. The same pencil marks up a PDF. - The bar holds undo, redo and save. The strip (`EditToolBar`) holds the text - and cell formatting. Plain text files show no formatting strip. + and cell formatting, and the row and column tools of a sheet. Plain text + files show no strip. A CSV file shows only the row and column tools. - A tap uses a tool. A long press opens its colours. Do not add chevrons. - Redo is hidden over a PDF. The magnifier is hidden during an edit. - A PDF tool is armed by the page (`odr.annotation.press`), and the app never From 9b3dd7a5018476fae07e78bda48aed9a29b32da4 Mon Sep 17 00:00:00 2001 From: Andreas Stefl Date: Sat, 10 Oct 2026 14:18:26 +0200 Subject: [PATCH 2/2] Take core 7.5.2 Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01B54axSaN5uQ37tShVNBYrP --- CHANGELOG.md | 2 +- OpenDocumentReader.xcodeproj/project.pbxproj | 2 +- .../project.xcworkspace/xcshareddata/swiftpm/Package.resolved | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 503b31d..ae65085 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,7 +22,7 @@ Rules: ### Changed -- The engine is odrcore 7.5.1, up from 7.4.0. +- The engine is odrcore 7.5.2, up from 7.4.0. ### Fixed diff --git a/OpenDocumentReader.xcodeproj/project.pbxproj b/OpenDocumentReader.xcodeproj/project.pbxproj index 3c3ae36..c437981 100644 --- a/OpenDocumentReader.xcodeproj/project.pbxproj +++ b/OpenDocumentReader.xcodeproj/project.pbxproj @@ -830,7 +830,7 @@ repositoryURL = "https://github.com/opendocument-app/OpenDocument.core.git"; requirement = { kind = upToNextMajorVersion; - minimumVersion = 7.5.1; + minimumVersion = 7.5.2; }; }; AD584FCD41577C8CDEE974AA /* XCRemoteSwiftPackageReference "swift-package-manager-google-mobile-ads" */ = { diff --git a/OpenDocumentReader.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/OpenDocumentReader.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 74df187..dd61562 100644 --- a/OpenDocumentReader.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/OpenDocumentReader.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -6,8 +6,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/opendocument-app/OpenDocument.core.git", "state" : { - "revision" : "703b931de526abc2d64cfe4de443bfab4be34098", - "version" : "7.5.1" + "revision" : "77e2a0a6e4b33c33a5aee64551fcd0d7493c9101", + "version" : "7.5.2" } }, {